ความแตกต่างระหว่าง * ptr + = 1 และ * ptr ++ ใน C


123

ฉันเพิ่งเริ่มศึกษา C และเมื่อทำตัวอย่างหนึ่งเกี่ยวกับการส่งตัวชี้ไปยังตัวชี้เป็นพารามิเตอร์ของฟังก์ชันฉันพบปัญหา

นี่คือโค้ดตัวอย่างของฉัน:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int* allocateIntArray(int* ptr, int size){
    if (ptr != NULL){
        for (int i = 0; i < size; i++){
            ptr[i] = i;
        }
    }
    return ptr;
}

void increasePointer(int** ptr){
    if (ptr != NULL){
        *ptr += 1; /* <----------------------------- This is line 16 */
    }
}

int main()
{
    int* p1 = (int*)malloc(sizeof(int)* 10);
    allocateIntArray(p1, 10);

    for (int i = 0; i < 10; i++){
        printf("%d\n", p1[i]);
    }

    increasePointer(&p1);
    printf("%d\n", *p1);
    p1--;
    free(p1);
    fgets(string, sizeof(string), stdin);
    return 0;
}

ปัญหาเกิดขึ้นในบรรทัดที่ 16 เมื่อฉันแก้ไข*ptr+=1เป็น*ptr++. ผลลัพธ์ที่คาดไว้ควรเป็นอาร์เรย์ทั้งหมดและหมายเลข 1 แต่เมื่อฉันใช้*ptr++ผลลัพธ์คือ 0

มีความแตกต่างระหว่าง+=1และ++หรือไม่? ฉันคิดว่าทั้งสองคนเหมือนกัน


2
โปรดทราบว่ารหัสที่ระบุจะไม่รวบรวมตามที่คุณไม่ได้ประกาศstringไว้
Spikatrix

6
หมายเหตุอื่น ๆ : 1) allocateIntArrayเป็นชื่อเสียเนื่องจากดูเหมือนว่าคุณmallocเป็นอาร์เรย์จากฟังก์ชัน แต่คุณไม่ทำ ฉันขอแนะนำfillIntArrayแทน 2) คุณไม่ได้ใช้ค่าตอบแทนของallocateIntArray. voidผมขอแนะนำให้คุณเปลี่ยนชนิดกลับไป 3) ไม่ควรif (ptr != NULL)ในการทำงานincreasePointerจะเป็นif (*ptr != NULL)? 4) การแคสต์mallocเป็นสิ่งที่ไม่จำเป็น ดูความคิดเห็นของ Sourav ด้านบน 5) สิ่งนี้: for (int i = 0; i < 10; i++){ printf("%d\n", p1[i]); }และprintf("%d\n", *p1); p1--;จำเป็นต้องอยู่ในif(p1 != NULL). 6) string.hไม่ได้ใช้
Spikatrix

9
p+=1เป็นเหมือน++pไม่เหมือนp++
Kos

5
คำถามนี้ถูกถามเมื่อ 4 ปีที่แล้ว: คือ ++ เหมือนกับ + = 1 สำหรับพอยน์เตอร์
ren

3
@ren เกือบ แต่ไม่มาก คำถามที่เชื่อมโยงไม่เกี่ยวข้องกับตัวดำเนินการ dereference ซึ่งเป็นประเด็นสำคัญของปัญหาของ OP ที่นี่
Jason C

คำตอบ:


290

ความแตกต่างเกิดจากความสำคัญของตัวดำเนินการ

ผู้ประกอบการโพสต์ที่เพิ่มขึ้นมีความสำคัญสูงกว่าผู้ประกอบการ++ dereference *ดังนั้นจะเทียบเท่ากับ*ptr++ *(ptr++)กล่าวอีกนัยหนึ่งการเพิ่มโพสต์จะปรับเปลี่ยนตัวชี้ไม่ใช่สิ่งที่ชี้ไป

ผู้ประกอบการที่ได้รับมอบหมาย+=มีความสำคัญต่ำกว่าผู้ประกอบการ dereference *เพื่อให้เทียบเท่ากับ*ptr+=1 (*ptr)+=1กล่าวอีกนัยหนึ่งตัวดำเนินการกำหนดจะแก้ไขค่าที่ตัวชี้ชี้ไปและไม่เปลี่ยนตัวชี้เอง


3
สำหรับผู้เริ่มต้นที่ช่วยในการจำความคล้ายคลึงกันระหว่างและ*p++ *++pลำดับความสำคัญของตัวดำเนินการหลังมีความชัดเจนหนึ่งในอดีตดังต่อไปนี้
Walter Tross

21

ลำดับความสำคัญของตัวดำเนินการ 3 ตัวที่เกี่ยวข้องกับคำถามของคุณมีดังต่อไปนี้:

post-Increment ++> dereference *> assignment+=

คุณสามารถตรวจสอบหน้านี้เพื่อดูรายละเอียดเพิ่มเติมเกี่ยวกับเรื่องนี้

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

เรื่องสั้นขนาดยาวเพื่อแสดงการมอบหมายนี้*ptr+=1โดยใช้ตัวดำเนินการหลังการเพิ่มคุณต้องเพิ่มวงเล็บให้กับตัวดำเนินการ dereference เพื่อให้การดำเนินการนั้นมีความสำคัญมากกว่า++ในนี้(*ptr)++


3
ในขณะนี้นี่เป็นคำตอบเดียวที่มีโซลูชัน ... (* ptr) ++
hyde

7

มาใช้วงเล็บเพื่อแสดงลำดับการดำเนินการ

a + b / c
a + (b/c)

ลองทำอีกครั้งด้วย

*ptr   += 1
(*ptr) += 1

และอีกครั้งกับ

*ptr++
*(ptr++)
  • ใน*ptr += 1เราเพิ่มค่าของตัวแปรตัวชี้ของเราจุดไป
  • ใน*ptr++เราเพิ่มตัวชี้หลังจากคำสั่งทั้งหมดของเรา (บรรทัดของรหัส) จะทำและกลับอ้างอิงกับตัวแปรตัวชี้ของเราจุดไป

หลังช่วยให้คุณทำสิ่งต่างๆเช่น:

for(int i = 0; i < length; i++)
{
    // Copy value from *src and store it in *dest
    *dest++ = *src++;

    // Keep in mind that the above is equivalent to
    *(dest++) = *(src++);
}

นี่เป็นวิธีการทั่วไปที่ใช้ในการคัดลอกsrcอาร์เรย์ไปยังdestอาร์เรย์อื่น


"และส่งกลับการอ้างอิงไปยังตัวแปรที่ตัวชี้ของเราชี้ไป" C ไม่มีการอ้างอิง
เส้นทางไมล์

@MilesRout บางทีการเรียกมันว่า lvalue อาจจะถูกต้องกว่า? แต่ฉันไม่แน่ใจว่าจะใส่อย่างไรโดยไม่ต้องเพิ่มศัพท์แสง
Mateen Ulhaq

3

คำถามที่ดีมาก

ใน K&R "ภาษาโปรแกรมซี" "5.1 ตัวชี้และที่อยู่" เราสามารถหาคำตอบได้

"ตัวดำเนินการยูนารี * และ & ผูกแน่นกว่าตัวดำเนินการเลขคณิต"

*ptr += 1      //Increment what ptr points to.

"ตัวดำเนินการ Unary เช่น * และ ++ เชื่อมโยงจากขวาไปซ้าย "

*ptr++        //Increment prt instead of what ptr point to.

// ทำงานเหมือน * (ptr ++)

วิธีที่ถูกต้องคือ:

(*ptr)++      //This will work.

นี่เป็นครั้งแรกที่ฉันแสดงความคิดเห็นเกี่ยวกับ Stack Overflow ฉันได้อัปเดตรูปแบบของรหัสแล้ว ^^ ขอบคุณสำหรับคำแนะนำ
Nick. Sang

2

* ptr + = 1: ข้อมูลส่วนเพิ่มที่ ptr ชี้ไป * ptr ++: ตัวชี้ที่เพิ่มขึ้นซึ่งชี้ไปยังตำแหน่งหน่วยความจำถัดไปแทนที่จะเป็นข้อมูลที่ตัวชี้ชี้ไป

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.