Sự khác biệt giữa * ptr + = 1 và * ptr ++ trong C


122

Tôi mới bắt đầu học C và khi thực hiện một ví dụ về việc chuyển con trỏ sang con trỏ làm tham số của hàm, tôi đã gặp một vấn đề.

Đây là mã mẫu của tôi:

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

Vấn đề xảy ra trong dòng 16, khi tôi sửa đổi *ptr+=1thành *ptr++. Kết quả dự kiến ​​sẽ là toàn bộ mảng và số 1 nhưng khi tôi sử dụng *ptr++kết quả là 0.

Có bất kỳ sự khác biệt giữa +=1++? Tôi nghĩ rằng cả hai đều giống nhau.


2
Lưu ý rằng mã đã cho sẽ không được biên dịch khi bạn chưa khai báo string.
Spikatrix

6
Các lưu ý khác: 1) allocateIntArraylà một tên xấu vì có vẻ như bạn malloclà mảng từ hàm, nhưng bạn thì không. Tôi đề nghị fillIntArraythay thế. 2) Bạn không sử dụng giá trị trả về của allocateIntArray. Tôi đề nghị bạn thay đổi loại trả lại thành void. 3) Không nên if (ptr != NULL)chức năng increasePointerđược if (*ptr != NULL)? 4) Các diễn viên trong malloclà không cần thiết. Xem bình luận của Sourav ở trên. 5) Điều này: for (int i = 0; i < 10; i++){ printf("%d\n", p1[i]); }printf("%d\n", *p1); p1--;cần được đính kèm if(p1 != NULL). 6) string.hkhông được sử dụng.
Spikatrix

9
p+=1giống như ++p, không thíchp++
Kos

5
câu hỏi này được hỏi 4 năm trước: Là ++ giống như + = 1 cho con trỏ
ren

3
@ren Hầu như, nhưng không hẳn. Câu hỏi được liên kết không liên quan đến toán tử dereference, đó là mấu chốt của vấn đề OP ở đây.
Jason C

Câu trả lời:


289

Sự khác biệt là do ưu tiên nhà điều hành.

Toán tử tăng sau ++có độ ưu tiên cao hơn toán tử dereference *. Như vậy *ptr++là tương đương với *(ptr++). Nói cách khác, gia tăng bài đăng sửa đổi con trỏ, không phải những gì nó trỏ đến.

Toán tử gán +=có độ ưu tiên thấp hơn toán tử dereference *, do đó *ptr+=1tương đương với (*ptr)+=1. Nói cách khác, toán tử gán gán sửa đổi giá trị mà con trỏ trỏ tới và không thay đổi chính con trỏ.


3
Đối với người mới bắt đầu, một bản ghi nhớ là sự tương đồng giữa *p++*++p. Toán tử ưu tiên của cái sau là rõ ràng, cái trước có sau.
Walter Tross

21

Thứ tự ưu tiên cho 3 toán tử liên quan đến câu hỏi của bạn là như sau:

sau increment ++> dereference *> nhượng+=

Bạn có thể kiểm tra trang này để biết thêm chi tiết về chủ đề này.

Khi phân tích một biểu thức, một toán tử được liệt kê trên một số hàng sẽ bị ràng buộc chặt chẽ hơn (như thể bằng dấu ngoặc đơn) với các đối số của nó so với bất kỳ toán tử nào được liệt kê trên một hàng bên dưới nó. Ví dụ, biểu thức *p++được phân tích cú pháp như *(p++), và không phải là (*p)++.

Câu chuyện dài, để thể hiện sự phân công này *ptr+=1bằng toán tử tăng sau, bạn cần thêm dấu ngoặc đơn cho toán tử dereference để ưu tiên thao tác đó ++như trong này(*ptr)++


3
Xen kẽ, đây hiện là câu trả lời duy nhất có chứa giải pháp ... (* ptr) ++
hyde

7

Hãy áp dụng dấu ngoặc đơn để hiển thị thứ tự các thao tác

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

Hãy làm lại với

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

Và một lần nữa với

*ptr++
*(ptr++)
  • Trong *ptr += 1, chúng tôi tăng giá trị của biến con trỏ của chúng tôi điểm đến.
  • Trong *ptr++, chúng tôi tăng con trỏ sau khi toàn bộ tuyên bố của chúng tôi (dòng mã) được thực hiện, và trả về một tham chiếu đến biến con trỏ của chúng tôi điểm đến.

Cái sau cho phép bạn làm những việc như:

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

Đây là một phương pháp phổ biến được sử dụng để sao chép một srcmảng vào một destmảng khác .


"và trả về một tham chiếu đến biến mà con trỏ của chúng ta trỏ tới." C không có tài liệu tham khảo.
Miles Rout

@MilesRout Có lẽ gọi nó là một giá trị có thể chính xác hơn? Nhưng tôi không chắc làm thế nào để đặt nó mà không cần thêm biệt ngữ.
Mateen Ulhaq

3

Câu hỏi rất hay.

Trong "Ngôn ngữ lập trình C" của K & R "" Con trỏ và địa chỉ 5.1 ", chúng ta có thể nhận được câu trả lời cho việc này.

"Các toán tử đơn nguyên * và & liên kết chặt chẽ hơn các toán tử số học"

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

"Các toán tử đơn nguyên như * và ++ liên kết từ phải sang trái ."

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

// Nó hoạt động như * (ptr ++).

Cách chính xác là:

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

Đây là lần đầu tiên tôi nhận xét về Stack Overflow. Tôi đã cập nhật định dạng của mã. ^^ Cảm ơn lời đề nghị của bạn.
Nick.Sang 10/03/2016

2

* ptr + = 1: Dữ liệu tăng mà ptr trỏ tới. * ptr ++: Con trỏ tăng được trỏ đến vị trí bộ nhớ tiếp theo thay vì dữ liệu mà con trỏ trỏ tới.

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.