วิธีเปรียบเทียบพอยน์เตอร์


88

สมมติว่าฉันมีพอยน์เตอร์ 2 ตัว:

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

ถ้าฉันต้องการเปรียบเทียบพวกเขาและดูว่าพวกเขาชี้ไปที่ที่เดียวกัน (a == b) ได้ผลหรือไม่?


6
IIRC เปรียบเทียบพอยน์เตอร์ไม่มีการกำหนดเว้นแต่จะชี้ไปที่องค์ประกอบภายในอาร์เรย์เดียวกัน
เห็น

1
@sehe เฮ้คำตอบของคุณด้านล่างยกเลิกความคิดเห็นเก่านี้
Spencer

คำตอบ:


72

ใช่นั่นคือคำจำกัดความของความเท่าเทียมกันของตัวชี้: ทั้งคู่ชี้ไปที่ตำแหน่งเดียวกัน (หรือเป็นนามแฝงของตัวชี้ )


2
ตัวชี้คือ (ในคำของคนธรรมดา) โดยพื้นฐานแล้วเป็นค่าจำนวนเต็มสำหรับที่อยู่หน่วยความจำในคอมพิวเตอร์ของคุณ เปรียบเสมือนการเปรียบเทียบจำนวนเต็ม
Kemin Zhou

6
@KeminZhou: นี่เป็นเรื่องจริงในคอมพิวเตอร์ส่วนใหญ่ในปัจจุบัน แต่โดยทั่วไปเป็นเท็จ แม้ในพีซีรุ่นเก่าปี 1980 AT 8086 ก็เป็นเท็จ
Basile Starynkevitch

111

สำหรับข้อเท็จจริงเล็กน้อยต่อไปนี้เป็นข้อความที่เกี่ยวข้องจากข้อกำหนด

ตัวดำเนินการความเท่าเทียมกัน (==,! =)

ตัวชี้ไปยังวัตถุประเภทเดียวกันสามารถเปรียบเทียบเพื่อความเท่าเทียมกันกับผลลัพธ์ที่คาดหวัง 'ใช้งานง่าย':

จาก§ 5.10 ของมาตรฐาน C ++ 11:

พอยน์เตอร์ประเภทเดียวกัน (หลังการแปลงพอยน์เตอร์) สามารถเปรียบเทียบได้เพื่อความเท่าเทียมกัน พอยน์เตอร์ประเภทเดียวกันสองตัวจะเปรียบเทียบค่าเท่ากันถ้าทั้งคู่เป็นโมฆะทั้งคู่ชี้ไปที่ฟังก์ชันเดียวกันหรือทั้งคู่แทนแอดเดรสเดียวกัน ( 3.9.2 )

(ทิ้งรายละเอียดเกี่ยวกับการเปรียบเทียบพอยน์เตอร์กับสมาชิกและหรือค่าคงที่ของพอยน์เตอร์ว่าง - พวกมันต่อไปในบรรทัดเดียวกันของ 'Do What I Mean' :)

  • [... ] ถ้าตัวถูกดำเนินการทั้งสองเป็นโมฆะพวกเขาเปรียบเทียบเท่ากัน มิฉะนั้นหากมีเพียงหนึ่งเดียวที่เป็นโมฆะจะเปรียบเทียบไม่เท่ากัน [... ]

ข้อแม้ที่ 'เด่นชัดที่สุด' เกี่ยวข้องกับเวอร์ชวลและดูเหมือนจะเป็นสิ่งที่สมเหตุสมผลที่จะคาดหวังเช่นกัน:

  • [... ] ถ้าเป็นตัวชี้ไปยังฟังก์ชันสมาชิกเสมือนผลลัพธ์จะไม่ระบุ มิฉะนั้นพวกเขาจะเปรียบเทียบเท่ากันก็ต่อเมื่อพวกเขาจะอ้างถึงสมาชิกเดียวกันของอ็อบเจ็กต์ที่ได้รับส่วนใหญ่เดียวกัน (1.8) หรืออ็อบเจ็กต์ย่อยเดียวกันหากถูก dereferenced กับอ็อบเจ็กต์สมมุติของประเภทคลาสที่เกี่ยวข้อง [... ]

ตัวดำเนินการเชิงสัมพันธ์ (<,>, <=,> =)

จาก§ 5.9ของมาตรฐาน C ++ 11:

สามารถเปรียบเทียบพอยน์เตอร์ไปยังอ็อบเจ็กต์หรือฟังก์ชันประเภทเดียวกัน (หลังจากการแปลงพอยน์เตอร์) โดยกำหนดผลลัพธ์ดังนี้:

  1. หากทั้งสองตัวชี้ p และ q ของจุดชนิดเดียวกันกับวัตถุเดียวกันหรือฟังก์ชั่นหรือจุดหนึ่งทั้งในอดีตปลายแถวเดียวกันหรือมีทั้ง null แล้วp<=qและp>=qอัตราผลตอบแทนทั้งจริงและp<qและp>qทั้งอัตราผลตอบแทนที่เป็นเท็จ
  2. หากทั้งสองตัวชี้ p และ q ของจุดชนิดเดียวกันกับวัตถุที่แตกต่างกันที่ไม่ได้เป็นสมาชิกของวัตถุเดียวกันหรือองค์ประกอบของอาร์เรย์เดียวกันหรือเพื่อฟังก์ชั่นที่แตกต่างกันหรือถ้ามีเพียงหนึ่งของพวกเขาเป็นโมฆะผลของp<q, p>q, p<=q,และ มีที่ไม่ได้ระบุp>=q
  3. ถ้าพอยน์เตอร์สองตัวชี้ไปที่สมาชิกข้อมูลที่ไม่คงที่ของอ็อบเจ็กต์เดียวกันหรือไปยังอ็อบเจ็กต์ย่อยหรือองค์ประกอบอาร์เรย์ของสมาชิกดังกล่าวแบบวนซ้ำตัวชี้ไปยังสมาชิกที่ประกาศในภายหลังจะเปรียบเทียบมากกว่าหากสมาชิกทั้งสองมีการควบคุมการเข้าถึงเดียวกัน (ข้อ 11) และ หากชั้นเรียนของพวกเขาไม่ใช่สหภาพ
  4. ถ้าพอยน์เตอร์สองตัวชี้ไปที่สมาชิกข้อมูลที่ไม่คงที่ของอ็อบเจ็กต์เดียวกันที่มีการควบคุมการเข้าถึงต่างกัน (ข้อ 11) ผลลัพธ์จะไม่ระบุ
  5. หากพอยน์เตอร์สองตัวชี้ไปที่สมาชิกข้อมูลที่ไม่คงที่ของอ็อบเจ็กต์ยูเนี่ยนเดียวกันก็จะเปรียบเทียบค่าเท่ากัน (หลังจากการแปลงเป็นvoid*ถ้าจำเป็น) ถ้าพอยน์เตอร์สองตัวชี้ไปที่องค์ประกอบของอาร์เรย์เดียวกันหรืออันหนึ่งเลยส่วนท้ายของอาร์เรย์ตัวชี้ไปยังอ็อบเจ็กต์ที่มีตัวห้อยที่สูงกว่าจะเปรียบเทียบได้สูงกว่า
  6. การเปรียบเทียบตัวชี้อื่น ๆ ไม่ได้ระบุไว้

ดังนั้นหากคุณมี:

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

ตกลงเช่นกัน:

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

แต่ขึ้นอยู่กับsomethingคำถามของคุณ:

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
}

โบนัส: มีอะไรอีกบ้างในไลบรารีมาตรฐาน?

§ 20.8.5 / 8 : "สำหรับแม่greater, less, greater_equalและless_equal, เฉพาะสำหรับประเภทตัวชี้ใด ๆ เพื่อให้ผลผลิตรวมแม้ว่าในตัวผู้ประกอบการ<, >, <=, >=ทำไม่ได้."

ดังนั้นคุณทั่วโลกสามารถสั่งแปลก ๆvoid*ตราบใดที่คุณใช้std::less<>และเพื่อน ๆ operator<ไม่ได้เปลือย


จะint *a = arr;ประโยชน์จากสายรวมทั้งการอ้างอิงถึงstackoverflow.com/questions/8412694/address-of-array ? ฉันไม่แน่ใจว่ามันมีความเกี่ยวข้องเพียงพอกับคำถามที่ถามว่า ...
nonsensickle

วันนี้ @JerryCoffin ที่เลียนแบบไม่ได้ทำให้ฉันทราบว่าไลบรารีมาตรฐานมีข้อกำหนดที่เข้มงวดมากขึ้นสำหรับเทมเพลตอ็อบเจ็กต์ฟังก์ชันที่กำหนดไว้ใน<functional>. เพิ่มแล้ว
ดู

ดูเหมือนว่าบทนี้มีการเปลี่ยนแปลงในร่าง C ++ ที่กำลังดำเนินอยู่ เว้นแต่ฉันจะเข้าใจผิดไม่มีพฤติกรรมที่ไม่ระบุอีกต่อไป: open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf
SomeWittyUsername


25

ตัว==ดำเนินการบนพอยน์เตอร์จะเปรียบเทียบที่อยู่ที่เป็นตัวเลขของพวกเขาและด้วยเหตุนี้จึงพิจารณาว่าพวกเขาชี้ไปที่วัตถุเดียวกันหรือไม่


12
มันซับซ้อนกว่าเล็กน้อยหากเกี่ยวข้องกับการถ่ายทอดทางพันธุกรรมหลาย ๆ
fredoverflow

17

เพื่อสรุปผล หากเราต้องการดูว่าพอยน์เตอร์สองตัวชี้ไปที่ตำแหน่งหน่วยความจำเดียวกันหรือไม่เราสามารถทำได้ นอกจากนี้หากเราต้องการเปรียบเทียบเนื้อหาของหน่วยความจำที่ชี้ไปที่พอยน์เตอร์สองตัวเราก็สามารถทำได้เช่นกันเพียงจำไว้ว่าให้หักล้างสิ่งเหล่านั้นก่อน

ถ้าเรามี

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

ซึ่งเป็นสองพอยน์เตอร์ประเภทเดียวกันที่เราทำได้:

เปรียบเทียบที่อยู่หน่วยความจำ:

a==b

และเปรียบเทียบเนื้อหา:

*a==*b

1

รหัสง่ายๆในการตรวจสอบนามแฝงของตัวชี้:

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

เอาท์พุต:

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

1

การเปรียบเทียบพอยน์เตอร์ไม่สามารถพกพาได้ตัวอย่างเช่นใน DOS ค่าพอยน์เตอร์ที่ต่างกันจะชี้ไปที่ตำแหน่งเดียวกันการเปรียบเทียบพอยน์เตอร์จะส่งกลับค่าเท็จ

/*--{++: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}--------------------------------------------------*/

รวบรวมภายใต้ Borland C 5.0 นี่คือผลลัพธ์:

/*--{++: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}--------------------------------------------------*/
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.