Làm thế nào để so sánh các con trỏ?


88

Giả sử tôi có 2 con trỏ:

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

Nếu tôi muốn so sánh chúng và xem liệu chúng có trỏ cùng một nơi không thì (a == b) có hoạt động không?


6
Con trỏ so sánh IIRC không được xác định, trừ khi chúng trỏ đến các phần tử trong cùng một mảng
xem

1
@sehe Này, câu trả lời của bạn bên dưới sẽ hủy nhận xét cũ này.
Spencer

Câu trả lời:


72

Đúng, đó là định nghĩa của bình đẳng con trỏ: cả hai đều trỏ đến cùng một vị trí (hoặc là bí danh con trỏ )


2
Con trỏ (theo thuật ngữ của giáo dân) về cơ bản là một giá trị số nguyên cho địa chỉ bộ nhớ trong máy tính của bạn. Nó giống như so sánh các số nguyên.
Kemin Zhou

5
@KeminZhou: điều này đúng trên hầu hết các máy tính hiện tại, nhưng sai nói chung. Ngay cả trên 1980 máy tính cũ AT 8086 đó là sai sự thật
Basile Starynkevitch

109

Đối với một chút sự kiện, đây là văn bản có liên quan từ các thông số kỹ thuật

Toán tử bình đẳng (==,! =)

Con trỏ đến các đối tượng cùng loại có thể được so sánh ngang bằng với kết quả mong đợi 'trực quan':

Từ § 5.10 của tiêu chuẩn C ++ 11:

Các con trỏ cùng loại (sau khi chuyển đổi con trỏ) có thể được so sánh cho bằng nhau. Hai con trỏ cùng kiểu so sánh bằng nhau nếu và chỉ khi chúng đều rỗng, cả hai đều trỏ đến cùng một hàm hoặc cả hai đại diện cho cùng một địa chỉ ( 3.9.2 ).

(bỏ qua chi tiết về việc so sánh các con trỏ đến thành viên và hoặc các hằng số con trỏ rỗng - chúng tiếp tục xuống cùng dòng của 'Do What I Mean' :)

  • [...] Nếu cả hai toán hạng đều rỗng, chúng sẽ so sánh bằng nhau. Ngược lại, nếu chỉ có một giá trị rỗng, chúng sẽ so sánh không bằng nhau. [...]

Cảnh báo 'dễ thấy' nhất liên quan đến hình ảnh ảo, và nó dường như cũng là điều hợp lý để mong đợi:

  • [...] nếu một trong hai là một con trỏ đến một hàm thành viên ảo, kết quả là không xác định. Nếu không, chúng sẽ so sánh bằng nhau nếu và chỉ khi chúng tham chiếu đến cùng một thành viên của cùng một đối tượng dẫn xuất nhất (1.8) hoặc cùng một đối tượng nếu chúng được tham chiếu đến một đối tượng giả định của loại lớp được liên kết. [...]

Toán tử quan hệ (<,>, <=,> =)

Từ § 5.9 của tiêu chuẩn C ++ 11:

Có thể so sánh các con trỏ đến các đối tượng hoặc hàm cùng loại (sau khi chuyển đổi con trỏ), với kết quả được xác định như sau:

  1. Nếu hai con trỏ p và q của điểm cùng loại với cùng một đối tượng hoặc chức năng, hoặc cả hai một thời điểm quá khứ cuối cùng một mảng, hoặc là cả hai null, sau đó p<=qp>=qcả năng suất trung thực và p<qp>qcả năng suất sai.
  2. Nếu hai con trỏ p và q cùng kiểu trỏ đến các đối tượng khác nhau không phải là thành viên của cùng một đối tượng hoặc các phần tử của cùng một mảng hoặc đến các hàm khác nhau, hoặc nếu chỉ một trong số chúng là rỗng, thì kết quả của p<q, p>q, p<=q,p>=q là không xác định .
  3. Nếu hai con trỏ trỏ đến các thành viên dữ liệu không tĩnh của cùng một đối tượng, hoặc đến các subobject hoặc các phần tử mảng của các thành viên đó, theo cách đệ quy, con trỏ đến thành viên được khai báo sau sẽ so sánh lớn hơn với điều kiện hai thành viên có cùng quyền kiểm soát truy cập (Điều 11) và miễn là lớp của họ không phải là một công đoàn.
  4. Nếu hai con trỏ trỏ đến các thành viên dữ liệu không tĩnh của cùng một đối tượng có điều khiển truy cập khác nhau (Điều 11) thì kết quả là không xác định.
  5. Nếu hai con trỏ trỏ đến các thành viên dữ liệu không tĩnh của cùng một đối tượng liên hợp, chúng sẽ so sánh bằng nhau (sau khi chuyển đổi thành void*, nếu cần). Nếu hai con trỏ trỏ đến các phần tử của cùng một mảng hoặc một con trỏ nằm ngoài phần cuối của mảng, thì con trỏ đến đối tượng có chỉ số con cao hơn sẽ so sánh cao hơn.
  6. Các so sánh con trỏ khác là không xác định.

Vì vậy, nếu bạn có:

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

Cũng được:

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

Nhưng nó phụ thuộc vào somethingcâu hỏi của bạn:

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
}

Phần thưởng: còn gì nữa trong thư viện tiêu chuẩn?

§ 20.8.5 / 8 : "Đối với các mẫu greater, less, greater_equal, và less_equal, các chuyên ngành cho bất kỳ loại con trỏ mang lại một trật tự tổng, thậm chí nếu được xây dựng trong các nhà khai thác <, >, <=, >=không có."

Vì vậy, bạn có thể đặt hàng toàn cầu bất kỳ số lẻ nào void*miễn là bạn sử dụng std::less<>và bạn bè, không phải để trần operator<.


Sẽ là int *a = arr;lợi ích dòng từ bao gồm một tham chiếu đến stackoverflow.com/questions/8412694/address-of-array ? Tôi không chắc chắn nếu nó là đủ liên quan đến câu hỏi hỏi mặc dù ...
nonsensickle

Hôm nay, @JerryCoffin không thể bắt chước đã làm cho tôi biết thực tế là thư viện tiêu chuẩn có các thông số kỹ thuật nghiêm ngặt hơn cho các mẫu đối tượng hàm được xác định trong <functional>. Thêm.
sehe

Có vẻ như chương này đã thay đổi trong bản nháp C ++ đang diễn ra. Trừ khi tôi hiểu lầm nó, không có là hành vi không xác định hơn: open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf
SomeWittyUsername


25

Các ==nhà điều hành trên con trỏ sẽ so sánh địa chỉ số của họ và do đó xác định xem họ trỏ đến cùng một đối tượng.


12
Nó phức tạp hơn một chút nếu liên quan đến đa kế thừa.
fredoverflow

17

Tóm lại. Nếu chúng ta muốn xem liệu hai con trỏ trỏ đến cùng một vị trí bộ nhớ, chúng ta có thể làm điều đó. Ngoài ra, nếu chúng ta muốn so sánh nội dung của bộ nhớ được trỏ đến bởi hai con trỏ, chúng ta cũng có thể làm điều đó, chỉ cần nhớ tham khảo chúng trước.

Nếu chúng ta có

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

là hai con trỏ cùng loại, chúng ta có thể:

So sánh địa chỉ bộ nhớ:

a==b

và so sánh nội dung:

*a==*b

1

Mã đơn giản để kiểm tra răng cưa con trỏ:

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;
}

Đầu ra:

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

1

So sánh các con trỏ không phải là di động, ví dụ: trong DOS các giá trị con trỏ khác nhau trỏ đến cùng một vị trí, so sánh các con trỏ trả về 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}--------------------------------------------------*/

Biên dịch nó theo Borland C 5.0, đây là kết quả:

/*--{++: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}--------------------------------------------------*/
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.