Bagaimana cara membandingkan pointer?


88

Misalkan saya punya 2 petunjuk:

int *a = something;
int *b = something;

Jika saya ingin membandingkannya dan melihat apakah mereka menunjuk ke tempat yang sama apakah (a == b) berhasil?


6
IIRC membandingkan pointer tidak ditentukan, kecuali mereka menunjuk ke elemen dalam array yang sama
lihat

1
@sehe Hei, jawaban Anda di bawah membatalkan komentar lama ini.
Spencer

Jawaban:


72

Ya, itulah definisi persamaan pointer: keduanya menunjuk ke lokasi yang sama (atau alias pointer )


2
Pointer (dalam istilah awam) pada dasarnya adalah nilai integer untuk alamat memori di komputer Anda. Ini seperti membandingkan bilangan bulat.
Kemin Zhou

6
@KeminZhou: ini benar di sebagian besar komputer saat ini, tetapi salah secara umum. Bahkan pada PC 1980 yang lama AT 8086 itu palsu
Basile Starynkevitch

110

Untuk sedikit fakta berikut ini adalah teks yang relevan dari spesifikasinya

Operator persamaan (==,! =)

Pointer ke objek dengan tipe yang sama dapat dibandingkan untuk persamaan dengan hasil yang diharapkan 'intuitif':

Dari § 5.10 standar C ++ 11:

Pointer dengan tipe yang sama (setelah konversi pointer) dapat dibandingkan untuk persamaan. Dua pointer berjenis sama dibandingkan jika dan hanya jika keduanya nol, keduanya mengarah ke fungsi yang sama, atau keduanya mewakili alamat yang sama ( 3.9.2 ).

(meninggalkan detail tentang perbandingan pointer ke anggota dan atau konstanta pointer nol - mereka melanjutkan ke baris yang sama dari 'Do What I Mean' :)

  • [...] Jika kedua operan bernilai nol, keduanya sama. Sebaliknya jika hanya satu yang nol, mereka membandingkan tidak sama. [...]

Peringatan yang paling 'mencolok' berkaitan dengan dunia maya, dan tampaknya juga logis untuk diharapkan:

  • [...] jika salah satu penunjuk ke fungsi anggota virtual, hasilnya tidak ditentukan. Jika tidak, mereka membandingkan sama jika dan hanya jika mereka merujuk ke anggota yang sama dari objek yang paling banyak diturunkan (1.8) atau subobjek yang sama jika mereka dirujuk dengan objek hipotetis dari tipe kelas terkait. [...]

Operator relasional (<,>, <=,> =)

Dari § 5.9 standar C ++ 11:

Pointer ke objek atau fungsi dengan tipe yang sama (setelah konversi pointer) dapat dibandingkan, dengan hasil yang ditentukan sebagai berikut:

  1. Jika dua pointer p dan q dari titik tipe yang sama ke objek yang sama atau fungsi, atau keduanya satu titik melewati akhir array yang sama, atau keduanya nol, maka p<=qdan p>=qbaik hasil yang benar dan p<qdanp>q kedua hasil palsu.
  2. Jika dua penunjuk p dan q berjenis sama mengarah ke objek berbeda yang bukan anggota objek atau elemen yang sama dari larik yang sama atau ke fungsi yang berbeda, atau jika hanya satu di antaranya yang null, hasil dari p<q, p>q, p<=q,dan p>=q tidak ditentukan .
  3. Jika dua penunjuk menunjuk ke anggota data non-statis dari objek yang sama, atau ke subobjek atau elemen larik dari anggota tersebut, secara rekursif, penunjuk ke anggota yang dideklarasikan nanti akan lebih besar asalkan kedua anggota memiliki kontrol akses yang sama (Klausul 11) dan asalkan kelas mereka bukan serikat pekerja.
  4. Jika dua pointer menunjuk ke anggota data non-statis dari objek yang sama dengan kontrol akses berbeda (Klausul 11) hasilnya tidak ditentukan.
  5. Jika dua pointer menunjuk ke anggota data non-statis dari objek gabungan yang sama, keduanya akan dibandingkan sama (setelah konversi ke void* , jika perlu). Jika dua penunjuk menunjuk ke elemen dari larik yang sama atau satu di luar akhir larik, penunjuk ke objek dengan subskrip yang lebih tinggi membandingkan lebih tinggi.
  6. Perbandingan penunjuk lainnya tidak ditentukan.

Jadi, jika Anda memiliki:

int arr[3];
int *a = arr;
int *b = a + 1;
assert(a != b); // OK! well defined

Juga Oke:

struct X { int x,y; } s;
int *a = &s.x;
int *b = &s.y;
assert(b > a); // OK! well defined

Tetapi itu tergantung pada somethingpertanyaan Anda:

int g; 
int main()
{
     int h;
     int i;

     int *a = &g;
     int *b = &h; // can't compare a <=> b
     int *c = &i; // can't compare b <=> c, or a <=> c etc.
     // but a==b, b!=c, a!=c etc. are supported just fine
}

Bonus: apa lagi yang ada di perpustakaan standar?

§ 20.8.5 / 8 : "Untuk template greater, less, greater_equal, dan less_equal, spesialisasi untuk setiap jenis pointer menghasilkan total order, bahkan jika built-in operator <, >, <=,>= tidak."

Jadi, Anda dapat memesan ganjil secara global void*selama Anda menggunakan std::less<>dan teman, tidak telanjang operator<.


Akankah int *a = arr;garis mendapat manfaat dari menyertakan referensi ke stackoverflow.com/questions/8412694/address-of-array ? Saya tidak yakin apakah itu cukup relevan dengan pertanyaan yang diajukan ...
nonsensickle

Hari ini, @JerryCoffin yang tak ada bandingannya membuat saya sadar akan fakta bahwa pustaka standar memiliki spesifikasi yang lebih ketat untuk templat objek fungsi yang didefinisikan di <functional>. Ditambahkan.
lihat

Tampaknya bab ini telah berubah dalam draf C ++ yang sedang berlangsung. Kecuali saya salah paham, tidak ada lagi perilaku yang tidak ditentukan: open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf
SomeWittyUsername


25

The ==operator pada pointer akan membandingkan alamat numerik mereka dan karenanya menentukan apakah mereka menunjuk ke objek yang sama.


12
Ini sedikit lebih rumit jika melibatkan banyak warisan.
fredoverflow

17

Untuk menyimpulkan. Jika kita ingin melihat apakah dua penunjuk menunjuk ke lokasi memori yang sama kita bisa melakukannya. Juga jika kita ingin membandingkan isi memori yang ditunjukkan oleh dua petunjuk kita bisa melakukannya juga, ingat saja untuk membedakannya terlebih dahulu.

Jika kita punya

int *a = something; 
int *b = something;

yang merupakan dua penunjuk dari jenis yang sama yang kami dapat:

Bandingkan alamat memori:

a==b

dan bandingkan isinya:

*a==*b

1

Kode sederhana untuk memeriksa penunjuk aliasing:

int main () {
    int a = 10, b = 20;
    int *p1, *p2, *p3, *p4;

    p1 = &a;
    p2 = &a;
    if(p1 == p2){
        std::cout<<"p1 and p2 alias each other"<<std::endl;
    }
    else{
        std::cout<<"p1 and p2 do not alias each other"<<std::endl;
    }
    //------------------------
    p3 = &a;
    p4 = &b;
    if(p3 == p4){
        std::cout<<"p3 and p4 alias each other"<<std::endl;
    }
    else{
        std::cout<<"p3 and p4 do not alias each other"<<std::endl;
    }
    return 0;
}

Keluaran:

p1 and p2 alias each other
p3 and p4 do not alias each other

1

Membandingkan pointer tidak portabel, misalnya di DOS poin nilai pointer yang berbeda ke lokasi yang sama, perbandingan pointer mengembalikan false.

/*--{++:main.c}--------------------------------------------------*/
#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
  int   val_a = 123;
  int * ptr_0 = &val_a;
  int * ptr_1 = MK_FP(FP_SEG(&val_a) + 1, FP_OFF(&val_a) - 16);

  printf(" val_a = %d -> @%p\n", val_a, (void *)(&val_a));
  printf("*ptr_0 = %d -> @%p\n", *ptr_0, (void *)ptr_0);
  printf("*ptr_1 = %d -> @%p\n", *ptr_1, (void *)ptr_1);

  /* Check what returns the pointers comparison: */
  printf("&val_a == ptr_0 ====> %d\n", &val_a == ptr_0);
  printf("&val_a == ptr_1 ====> %d\n", &val_a == ptr_1);
  printf(" ptr_0 == ptr_1 ====> %d\n",  ptr_0 == ptr_1);

  printf("val_a = %d\n", val_a);

  printf(">> *ptr_0 += 100;\n");
             *ptr_0 += 100;

  printf("val_a = %d\n", val_a);

  printf(">> *ptr_1 += 500;\n");
             *ptr_1 += 500;

  printf("val_a = %d\n", val_a);

  return EXIT_SUCCESS;
}
/*--{--:main.c}--------------------------------------------------*/

Kompilasi di bawah Borland C 5.0, inilah hasilnya:

/*--{++:result}--------------------------------------------------*/
 val_a = 123 -> @167A:0FFE
*ptr_0 = 123 -> @167A:0FFE
*ptr_1 = 123 -> @167B:0FEE
&val_a == ptr_0 ====> 1
&val_a == ptr_1 ====> 0
 ptr_0 == ptr_1 ====> 0
val_a = 123
>> *ptr_0 += 100;
val_a = 223
>> *ptr_1 += 500;
val_a = 723
/*--{--:result}--------------------------------------------------*/
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.