Làm thế nào để tăng địa chỉ con trỏ và giá trị của con trỏ?


96

Hãy để chúng tôi giả sử,

int *p;
int a = 100;
p = &a;

Đoạn mã sau thực sự sẽ làm gì và như thế nào?

p++;
++p;
++*p;
++(*p);
++*(p);
*p++;
(*p)++;
*(p)++;
*++p;
*(++p);

Tôi biết, điều này khá lộn xộn về mặt mã hóa, nhưng tôi muốn biết điều gì sẽ thực sự xảy ra khi chúng tôi viết mã như thế này.

Lưu ý: Giả sử rằng địa chỉ của a=5120300nó được lưu trữ trong con trỏ pcó địa chỉ 3560200. Bây giờ, giá trị p & asau khi thực hiện mỗi câu lệnh sẽ là bao nhiêu?


3
tại sao bạn không chạy nó trong trình gỡ lỗi?
AndersK

24
Chà .. tại sao không đơn giản thử nó và xem? printfsẽ in một con trỏ với% p
Brian Roach

Nếu bạn tò mò về hành vi, chỉ cần chơi xung quanh nó. Chỉ cần viết một chương trình c đơn giản đi qua tất cả các trường hợp sử dụng này và xem nó có hợp lý với bạn không.
Cyrus

@AndersK. Có thể OP mong đợi hành vi không xác định? ... Hoặc có thể không.
Mateen Ulhaq,

Câu trả lời:


175

Đầu tiên, toán tử ++ được ưu tiên hơn toán tử * và các toán tử () được ưu tiên hơn mọi thứ khác.

Thứ hai, toán tử số ++ giống với toán tử số ++ nếu bạn không gán chúng cho bất kỳ thứ gì. Sự khác biệt là số ++ trả về số rồi sau đó tăng số, và số ++ tăng trước rồi trả về.

Thứ ba, bằng cách tăng giá trị của một con trỏ, bạn đang tăng nó theo kích thước nội dung của nó, tức là bạn đang tăng nó như thể bạn đang lặp lại trong một mảng.

Vì vậy, tóm lại tất cả:

ptr++;    // Pointer moves to the next int position (as if it was an array)
++ptr;    // Pointer moves to the next int position (as if it was an array)
++*ptr;   // The value of ptr is incremented
++(*ptr); // The value of ptr is incremented
++*(ptr); // The value of ptr is incremented
*ptr++;   // Pointer moves to the next int position (as if it was an array). But returns the old content
(*ptr)++; // The value of ptr is incremented
*(ptr)++; // Pointer moves to the next int position (as if it was an array). But returns the old content
*++ptr;   // Pointer moves to the next int position, and then get's accessed, with your code, segfault
*(++ptr); // Pointer moves to the next int position, and then get's accessed, with your code, segfault

Vì có rất nhiều trường hợp ở đây, tôi có thể đã mắc một số sai lầm, vui lòng sửa cho tôi nếu tôi sai.

BIÊN TẬP:

Vì vậy, tôi đã sai, mức độ ưu tiên phức tạp hơn một chút so với những gì tôi đã viết, hãy xem nó tại đây: http://en.cppreference.com/w/cpp/language/operator_precedence


6
* ptr ++, giá trị không tăng, con trỏ là. Các toán tử một ngôi này có cùng mức độ ưu tiên nhưng chúng được đánh giá từ phải sang trái. Mã có nghĩa là "lấy nội dung từ nơi ptr trỏ đến, sau đó tăng ptr". Nó là mã C rất phổ biến (và vâng, khá khó hiểu). Vui lòng sửa lỗi này và tôi sẽ xóa phiếu phản đối. Tương tự đối với * (ptr) ++, dấu ngoặc đơn không có tác dụng gì.
Lundin

Cảm ơn Lundin rất nhiều, tôi có bỏ lỡ điều gì khác không?
felipemaia

@Lundin Chào bạn, câu trả lời trên đã được sửa lại chưa? Cảm ơn.
Unheilig

4
@Unheilig Câu đầu tiên vẫn sai hoàn toàn, hậu tố ++ được ưu tiên hơn tiền tố đơn vị * có cùng mức độ ưu tiên với tiền tố ++. Ngoài điều đó ra, nó có vẻ ổn.
Lundin

4
@felipemaia Bạn có chắc chắn rằng nó sẽ mặc định không? Có thể chỉ là hành vi không xác định của nó?
jotik

13

đã kiểm tra chương trình và kết quả là,

p++;    // use it then move to next int position
++p;    // move to next int and then use it
++*p;   // increments the value by 1 then use it 
++(*p); // increments the value by 1 then use it
++*(p); // increments the value by 1 then use it
*p++;   // use the value of p then moves to next position
(*p)++; // use the value of p then increment the value
*(p)++; // use the value of p then moves to next position
*++p;   // moves to the next int location then use that value
*(++p); // moves to next location then use that value

2
@alex sử dụng nó có nghĩa là ví dụ, hãy xem xét câu lệnh, 'int * a = p ++;' Ở đây giá trị đầu tiên của con trỏ 'p' sẽ được sử dụng để và sau đó p sẽ chuyển sang vị trí tiếp theo. Vì vậy, có hiệu lực sau khi thực hiện câu lệnh trên 'a' sẽ có địa chỉ của vị trí trước đó được trỏ bởi 'p' và 'p' sẽ được trỏ đến vị trí tiếp theo. Đó là lần đầu tiên sử dụng giá trị của 'p' cho sự biểu hiện nhiệm vụ như trên và giá trị sau đó tăng của 'p' để trỏ đến vị trí tiếp theo
Sujith R Kumar

Tóm lại, tôi nghĩ anh ấy sử dụng cụm từ "sử dụng nó" cho thuật ngữ chính thức hơn "gán". Đó là tất cả.
Apekshik Panigrahi

4

Sau đây là bản tóm tắt các gợi ý "chỉ cần in nó". Tôi thấy nó có tính hướng dẫn.

#include "stdio.h"

int main() {
    static int x = 5;
    static int *p = &x;
    printf("(int) p   => %d\n",(int) p);
    printf("(int) p++ => %d\n",(int) p++);
    x = 5; p = &x;
    printf("(int) ++p => %d\n",(int) ++p);
    x = 5; p = &x;
    printf("++*p      => %d\n",++*p);
    x = 5; p = &x;
    printf("++(*p)    => %d\n",++(*p));
    x = 5; p = &x;
    printf("++*(p)    => %d\n",++*(p));
    x = 5; p = &x;
    printf("*p++      => %d\n",*p++);
    x = 5; p = &x;
    printf("(*p)++    => %d\n",(*p)++);
    x = 5; p = &x;
    printf("*(p)++    => %d\n",*(p)++);
    x = 5; p = &x;
    printf("*++p      => %d\n",*++p);
    x = 5; p = &x;
    printf("*(++p)    => %d\n",*(++p));
    return 0;
}

Nó trở lại

(int) p   => 256688152
(int) p++ => 256688152
(int) ++p => 256688156
++*p      => 6
++(*p)    => 6
++*(p)    => 6
*p++      => 5
(*p)++    => 5
*(p)++    => 5
*++p      => 0
*(++p)    => 0

Tôi chuyển địa chỉ con trỏ thành ints để chúng có thể dễ dàng so sánh.

Tôi đã biên dịch nó với GCC.


1
Tôi sẽ thay đổi điều này để bao gồm giá trị của x và p sau hoạt động.
NetJohn

3

Liên quan đến "Làm thế nào để tăng địa chỉ con trỏ và giá trị của con trỏ?" Tôi nghĩ rằng điều đó ++(*p++);thực sự được xác định rõ ràng và thực hiện những gì bạn đang yêu cầu, ví dụ:

#include <stdio.h>

int main() {
  int a = 100;
  int *p = &a;
  printf("%p\n",(void*)p);
  ++(*p++);
  printf("%p\n",(void*)p);
  printf("%d\n",a);
  return 0;
}

Nó không sửa đổi cùng một thứ hai lần trước một điểm trình tự. Tôi không nghĩ rằng đó là phong cách tốt cho hầu hết các mục đích sử dụng - nó hơi khó hiểu so với sở thích của tôi.


Trên thực tế, dấu ngoặc đơn là không cần thiết: ++*p++sẽ tăng thành công cả giá trị và con trỏ (hậu tố ++liên kết mạnh hơn dereference *và điều đó xảy ra trước tiền tố ++do thứ tự). Dấu ngoặc đơn chỉ cần thiết khi bạn cần giá trị trước khi tăng nó (*p++)++. Nếu bạn sử dụng tất cả tiền tố, ++*++pnó cũng sẽ hoạt động tốt mà không có dấu ngoặc đơn (nhưng tăng giá trị được trỏ vào sau khoảng tăng con trỏ).
cmaster - phục hồi monica

1
        Note:
        1) Both ++ and * have same precedence(priority), so the associativity comes into picture.
        2) in this case Associativity is from **Right-Left**

        important table to remember in case of pointers and arrays: 

        operators           precedence        associativity

    1)  () , []                1               left-right
    2)  *  , identifier        2               right-left
    3)  <data type>            3               ----------

        let me give an example, this might help;

        char **str;
        str = (char **)malloc(sizeof(char*)*2); // allocate mem for 2 char*
        str[0]=(char *)malloc(sizeof(char)*10); // allocate mem for 10 char
        str[1]=(char *)malloc(sizeof(char)*10); // allocate mem for 10 char

        strcpy(str[0],"abcd");  // assigning value
        strcpy(str[1],"efgh");  // assigning value

        while(*str)
        {
            cout<<*str<<endl;   // printing the string
            *str++;             // incrementing the address(pointer)
                                // check above about the prcedence and associativity
        }
        free(str[0]);
        free(str[1]);
        free(str);

Thuyết asociativity là gì?
71GA

1
trong mã, bạn có thể thấy * str ++, bây giờ ở đây cả * và ++ đều có cùng mức ưu tiên (cùng mức ưu tiên trong thuật ngữ của giáo dân) và * str ++ cũng không được phân tách bằng dấu ngoặc đơn như * (str ++) hoặc (* str) ++, vì vậy nó trở nên cần thiết như thế nào nó nên được đánh giá. vì vậy từ phải sang trái có nghĩa là (x = str ++) và sau đó là (y = * x)
Abhishek DK
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.