Biểu thức con trỏ: * ptr ++, * ++ ptr và ++ * ptr


128

Gần đây tôi đã gặp phải vấn đề này mà bản thân tôi không thể hiểu được.

Ba biểu thức này thực sự có nghĩa là gì?

*ptr++
*++ptr
++*ptr

Tôi đã thử Ritchie. Nhưng thật không may là không thể làm theo những gì ông nói về 3 hoạt động này.

Tôi biết tất cả chúng được thực hiện để tăng con trỏ / giá trị được trỏ đến. Tôi cũng có thể đoán có thể có rất nhiều điều về ưu tiên và thứ tự đánh giá. Giống như người ta tăng con trỏ trước sau đó tìm nạp nội dung của con trỏ đó, người ta chỉ cần tìm nạp nội dung và sau đó tăng con trỏ, v.v. Như bạn có thể thấy, tôi không hiểu rõ về các hoạt động thực tế của họ , mà tôi muốn rõ ràng càng sớm càng tốt. Nhưng tôi thực sự lạc lối khi có cơ hội áp dụng chúng trong các chương trình. Ví dụ:

int main()
{
    const char *p = "Hello";
    while(*p++)
         printf("%c",*p);
    return 0;
}

cung cấp cho tôi đầu ra này:

ello

Nhưng kỳ vọng của tôi là nó sẽ được in Hello. Một yêu cầu cuối cùng - Vui lòng cho tôi ví dụ về cách mỗi biểu thức hoạt động trong một đoạn mã đã cho. Vì hầu hết thời gian chỉ có một đoạn lý thuyết đơn thuần bay qua đầu tôi.


6
Bạn đã bỏ lỡ cái thứ tư: (*ptr)++(dấu ngoặc đơn cần thiết để định hướng từ *ptr++)
user4815162342

15
Bởi vì bạn đã tăng con trỏ trước khi in. Bạn muốn trong khi (* p) và printf ("% c", * p ++);
dcaswell

Câu hỏi tuyệt vời cho cuộc phỏng vấn. Hạn chế sử dụng thực tế. Tôi ước C không có những gợi ý đó :)
Himanshu

5
@Himanshu Nếu điều đó làm cho món mì của người được phỏng vấn của bạn hãy thử điều này: Có một con trỏ toàn cầuchar* p , chỉ vào một chuỗi ký tự kết thúc hợp lệ của các ký tự duy nhất. Sau đó có một chức năng fn(char ch)mà bản in cả các chtham số các char hiện được trỏ đến bởi p. Bây giờ gọi fn(*p++);Q: Có fnin cùng một ký tự hai lần không? Bạn sẽ ngạc nhiên khi có nhiều giáo sư nhận được câu hỏi đó sai.
WhozCraig

1
vì p trỏ đến một chuỗi ký tự bạn nên viếtconst char* p = "Hello";
hetepeperfan

Câu trả lời:


275

Đây là một lời giải thích chi tiết mà tôi hy vọng sẽ hữu ích. Hãy bắt đầu với chương trình của bạn, vì nó đơn giản nhất để giải thích.

int main()
{
    const char *p = "Hello";
    while(*p++)
        printf("%c",*p);
    return 0;
}

Tuyên bố đầu tiên:

const char* p = "Hello";

tuyên bố pnhư một con trỏ tới char. Khi chúng ta nói "con trỏ tới một char", điều đó có nghĩa là gì? Nó có nghĩa là giá trị của plà địa chỉ của a char; pcho chúng ta biết nơi nào trong bộ nhớ có một khoảng trống được đặt sang một bên để giữ a char.

Câu lệnh cũng khởi tạo pđể trỏ đến ký tự đầu tiên trong chuỗi ký tự "Hello". Vì lợi ích của bài tập này, điều quan trọng là phải hiểu plà không chỉ toàn bộ chuỗi, mà chỉ vào ký tự đầu tiên , 'H'. Rốt cuộc, plà một con trỏ đến một char, không phải toàn bộ chuỗi. Giá trị của plà địa chỉ của 'H'trong "Hello".

Sau đó, bạn thiết lập một vòng lặp:

while (*p++)

Điều kiện vòng lặp *p++có nghĩa là gì? Có ba điều đang làm việc ở đây khiến điều này trở nên khó hiểu (ít nhất là cho đến khi sự quen thuộc bắt đầu):

  1. Ưu tiên của hai toán tử, postfix ++và indirection*
  2. Giá trị của biểu thức tăng hậu tố
  3. Tác dụng phụ của biểu thức tăng hậu tố

1. Ưu tiên . Nhìn lướt qua bảng ưu tiên cho các toán tử sẽ cho bạn biết rằng gia tăng hậu tố có mức ưu tiên cao hơn (16) so với quy định / quy định (15). Điều này có nghĩa là biểu thức phức tạp *p++sẽ được nhóm lại thành : *(p++). Có nghĩa là, *phần sẽ được áp dụng cho giá trị của p++phần. Vì vậy, hãy tham p++gia đầu tiên.

2. Giá trị biểu thức Postfix . Giá trị của p++là giá trị p trước khi tăng . Nếu bạn có:

int i = 7;
printf ("%d\n", i++);
printf ("%d\n", i);

đầu ra sẽ là:

7
8

bởi vì i++đánh giá itrước khi tăng. Tương tự như vậy p++sẽ đánh giá giá trị hiện tại của p. Như chúng ta biết, giá trị hiện tại plà địa chỉ của 'H'.

Vì vậy, bây giờ p++một phần của *p++đã được đánh giá; đó là giá trị hiện tại của p. Sau đó, *một phần xảy ra. *(current value of p)có nghĩa là: truy cập giá trị tại địa chỉ được tổ chức bởi p. Chúng tôi biết rằng giá trị tại địa chỉ đó là 'H'. Vì vậy, biểu thức *p++đánh giá để 'H'.

Bây giờ hãy chờ một phút, bạn đang nói. Nếu *p++đánh giá 'H', tại sao không 'H'in trong đoạn mã trên? Đó là nơi tác dụng phụ đến.

3. Tác dụng phụ biểu hiện Postfix . Postfix ++giá trị của toán hạng hiện tại, nhưng nó có tác dụng phụ là tăng toán hạng đó. Huh? Hãy xem intmã đó một lần nữa:

int i = 7;
printf ("%d\n", i++);
printf ("%d\n", i);

Như đã lưu ý trước đó, đầu ra sẽ là:

7
8

Khi i++được đánh giá trong lần đầu tiên printf(), nó ước tính là 7. Nhưng tiêu chuẩn C đảm bảo rằng tại một thời điểm nào đó trước khi lần thứ hai printf()bắt đầu thực thi, tác dụng phụ của ++toán tử sẽ xảy ra. Điều đó có nghĩa là, trước khi điều thứ hai printf()xảy ra, isẽ được tăng lên do kết quả của ++toán tử trong lần đầu tiên printf(). Nhân tiện, đây là một trong số ít đảm bảo tiêu chuẩn đưa ra về thời gian của các tác dụng phụ.

Trong mã của bạn, sau đó, khi biểu thức *p++được ước tính, nó sẽ ước lượng 'H'. Nhưng đến lúc bạn nhận được điều này:

printf ("%c", *p)

tác dụng phụ đáng tiếc đó đã xảy ra. pđã được tăng lên. Ái chà! Nó không còn chỉ đến 'H', mà là một nhân vật đã qua 'H': 'e'nói cách khác, nói cách khác. Điều đó giải thích đầu ra cockneyfied của bạn:

ello

Do đó, điệp khúc của những gợi ý hữu ích (và chính xác) trong các câu trả lời khác: để in Phát âm đã nhận "Hello"và không phải là đối tác của nó, bạn cần một cái gì đó như

while (*p)
    printf ("%c", *p++);

Quá nhiều cho nó. Phần còn lại thì sao? Bạn hỏi về ý nghĩa của những điều này:

*ptr++
*++ptr
++*ptr

Chúng ta chỉ nói về cái đầu tiên, vì vậy hãy nhìn vào cái thứ hai : *++ptr.

Chúng tôi đã thấy trong lời giải thích trước đó của chúng tôi rằng sự gia tăng hậu tố p++có một ưu tiên nhất định , một giá trịtác dụng phụ . Gia số tiền tố ++ptác dụng phụ tương tự như đối tác hậu tố của nó: nó tăng toán hạng của nó lên 1. Tuy nhiên, nó có một ưu tiên khác và một giá trị khác .

Gia tăng tiền tố có mức độ ưu tiên thấp hơn tiền tố; nó có quyền ưu tiên 15. Nói cách khác, nó có quyền ưu tiên giống như toán tử dereference / indirection *. Trong một biểu thức như

*++ptr

vấn đề không phải là ưu tiên: hai toán tử giống hệt nhau trong quyền ưu tiên. Vì vậy, tính kết hợp bắt đầu. Gia tăng tiền tố và toán tử gián tiếp có tính kết hợp phải trái. Do tính kết hợp đó, toán hạng ptrsẽ được nhóm với toán tử ngoài cùng bên phải ++trước toán tử nhiều hơn bên trái , *. Nói cách khác, biểu thức sẽ được nhóm lại *(++ptr). Vì vậy, như với *ptr++nhưng vì một lý do khác, ở đây cũng là *phần sẽ được áp dụng cho giá trị của ++ptrphần.

Vậy giá trị đó là gì? Giá trị của biểu thức tăng tiền tố là giá trị của toán hạng sau khi tăng . Điều này làm cho nó trở thành một con thú rất khác với toán tử gia tăng hậu tố. Hãy nói rằng bạn có:

int i = 7;
printf ("%d\n", ++i);
printf ("%d\n", i);

Đầu ra sẽ là:

8
8

... khác với những gì chúng ta đã thấy với toán tử postfix. Tương tự, nếu bạn có:

const char* p = "Hello";
printf ("%c ", *p);    // note space in format string
printf ("%c ", *++p);  // value of ++p is p after the increment
printf ("%c ", *p++);  // value of p++ is p before the increment
printf ("%c ", *p);    // value of p has been incremented as a side effect of p++

đầu ra sẽ là:

H e e l                // good dog

Bạn có thấy tại sao không?

Bây giờ chúng ta đến biểu thức thứ ba mà bạn đã hỏi về ++*ptr. Đó thực sự là khó khăn nhất trong số rất nhiều. Cả hai toán tử đều có cùng mức độ ưu tiên và tính kết hợp phải trái. Điều này có nghĩa là biểu thức sẽ được nhóm lại ++(*ptr). Phần ++sẽ được áp dụng cho giá trị của *ptrphần.

Vì vậy, nếu chúng ta có:

char q[] = "Hello";
char* p = q;
printf ("%c", ++*p);

sản lượng tự nhiên đáng ngạc nhiên sẽ là:

I

Gì?! Được rồi, vì vậy *pmột phần sẽ đánh giá 'H'. Sau đó, ++trò chơi bắt đầu, tại thời điểm đó, nó sẽ được áp dụng cho 'H', chứ không phải cho con trỏ! Điều gì xảy ra khi bạn thêm 1 vào 'H'? Bạn nhận được 1 cộng với giá trị ASCII là 'H'72; bạn nhận được 73. Thể hiện điều đó như một charvà bạn nhận được chargiá trị ASCII là 73 : 'I'.

Điều đó quan tâm đến ba biểu thức bạn đã hỏi trong câu hỏi của bạn. Đây là một cái khác, được đề cập trong bình luận đầu tiên cho câu hỏi của bạn:

(*ptr)++ 

Đó cũng là một điều thú vị. Nếu bạn có:

char q[] = "Hello";
char* p = q;
printf ("%c", (*p)++);
printf ("%c\n", *p);

nó sẽ cung cấp cho bạn đầu ra nhiệt tình này:

HI

Chuyện gì đang xảy ra vậy? Một lần nữa, đó là vấn đề ưu tiên , giá trị biểu hiệntác dụng phụ . Do dấu ngoặc đơn, *pphần được coi là biểu thức chính. Biểu thức chính thổi phồng mọi thứ khác; họ được đánh giá đầu tiên. Và *p, như bạn biết, đánh giá 'H'. Phần còn lại của biểu thức, ++phần, được áp dụng cho giá trị đó. Vì vậy, trong trường hợp này, (*p)++trở thành 'H'++.

Giá trị của là 'H'++gì? Nếu bạn nói 'I', bạn đã quên (đã!) Thảo luận của chúng tôi về giá trị so với tác dụng phụ với gia tăng hậu tố. Ghi nhớ, 'H'++đánh giá giá trị hiện tại của 'H' . Vì vậy, đầu tiên printf()là sẽ in 'H'. Sau đó, như là một tác dụng phụ , điều đó 'H'sẽ được tăng lên 'I'. Bản printf()in thứ hai đó 'I'. Và bạn có lời chào vui vẻ của bạn.

Được rồi, nhưng trong hai trường hợp cuối cùng, tại sao tôi cần

char q[] = "Hello";
char* p = q;

Tại sao tôi không thể có cái gì đó như

/*const*/ char* p = "Hello";
printf ("%c", ++*p);   // attempting to change string literal!

Bởi vì "Hello"là một chuỗi theo nghĩa đen. Nếu bạn cố gắng ++*p, bạn đang cố gắng thay đổi 'H'chuỗi thành 'I', tạo toàn bộ chuỗi "Iello". Trong C, chuỗi ký tự là chỉ đọc; cố gắng sửa đổi chúng gọi hành vi không xác định. "Iello"cũng không được xác định bằng tiếng Anh, nhưng đó chỉ là sự trùng hợp.

Ngược lại, bạn không thể có

char p[] = "Hello";
printf ("%c", *++p);  // attempting to modify value of array identifier!

Tại sao không? Bởi vì trong trường hợp này, plà một mảng. Một mảng không phải là giá trị l có thể sửa đổi; bạn không thể thay đổi pđiểm theo trước hoặc tăng hoặc giảm, vì tên của mảng hoạt động như thể đó là một con trỏ không đổi. (Đó không phải là những gì nó thực sự là; đó chỉ là một cách thuận tiện để xem xét nó.)

Tóm lại, đây là ba điều bạn đã hỏi về:

*ptr++   // effectively dereferences the pointer, then increments the pointer
*++ptr   // effectively increments the pointer, then dereferences the pointer
++*ptr   // effectively dereferences the pointer, then increments dereferenced value

Và đây là một phần tư, mọi thứ đều vui như ba người kia:

(*ptr)++ // effectively forces a dereference, then increments dereferenced value

Đầu tiên và thứ hai sẽ sụp đổ nếu ptrthực sự là một định danh mảng. Thứ ba và thứ tư sẽ sụp đổ nếu ptrtrỏ đến một chuỗi bằng chữ.

Có bạn có nó. Tôi hy vọng tất cả bây giờ là tinh thể. Bạn đã là một khán giả tuyệt vời, và tôi sẽ ở đây cả tuần.


22
Trước khi đến với diễn đàn này, tôi đã tìm kiếm 3 cuốn sách "C" mà tôi sở hữu. Tôi cũng đã thử một số hướng dẫn trực tuyến đáng chú ý. Nhưng không ai trong số họ đến gần với lời giải thích của bạn (đặc biệt là cách bạn đã kết hợp tất cả lại với nhau). Bạn đã không chỉ trả lời câu hỏi tôi đã hỏi, mà bạn cũng đã thảo luận rất nhiều điều từ cấp cơ sở. Thật ra bạn đã dạy tôi rất nhiều điều cơ bản ngày hôm nay, điều mà tôi còn thiếu trước đây. Tôi không thể giúp nhưng thay đổi câu trả lời được chấp nhận của tôi. :) Cảm ơn một lần nữa.
phân bổ

26
+1 Tôi nghĩ rằng đây là một câu trả lời dài nhất mà tôi đã đọc trên SO. Tôi nghĩ rằng tất cả mọi người có thể học được rất nhiều từ câu trả lời này.
Shafik Yaghmour

9
Thưa ngài, nên viết một cuốn sách về C.
Dillon Burton

1
Thật là một câu trả lời đẹp cho một câu hỏi hay! Làm tốt lắm @verbose!
benka

7
@verbose bạn thưa ông, đã sống đến tên của bạn .. :)
sleeping_dragon

44

Giả sử ptrcác điểm đến phần tử thứ i của mảng arr.

  1. *ptr++ước tính arr[i]và thiết lập ptrđể trỏ đến phần tử thứ (i + 1) của arr. Nó tương đương với *(ptr++).

  2. *++ptrthiết lập ptrđể trỏ đến phần tử thứ (i + 1) arrvà đánh giá thành arr[i+1]. Nó tương đương với *(++ptr).

  3. ++*ptrtăng arr[i]một và đánh giá giá trị tăng của nó; con trỏ ptrbị bỏ hoang Nó tương đương với ++(*ptr).

Ngoài ra còn có một, nhưng bạn cần có dấu ngoặc đơn để viết nó:

  1. (*ptr)++ tăng arr[i] một và đánh giá giá trị của nó trước khi được tăng lên; con trỏ ptrmột lần nữa bị bỏ hoang.

Phần còn lại bạn có thể tự mình tìm ra; nó cũng được trả lời bởi @Jaguar.


13

*ptr++ : post increment a pointer ptr

*++ptr : Pre Increment a pointer ptr

++*ptr : preincrement the value at ptr location

Đọc ở đây về toán tử gia tăng trước và tăng


Điều này sẽ cung cấp Hellonhư đầu ra

int main()
{
    const char *p = "Hello";
    while(*p)
         printf("%c",*p++);//Increment the pointer here 
    return 0;
}

@ Nik-Lz Có, đầu ra sẽ làHello
Jainendra

7

Điều kiện trong vòng lặp của bạn là xấu:

while(*p++)
    printf("%c",*p);

Giống như

while(*p)
{
    p++;
    printf("%c",*p);
}

Và đó là sai, điều này nên là:

while(*p)
{
    printf("%c",*p);
    p++;
} 

*ptr++giống như *(ptr++), đó là:

const char  *ptr = "example";
char  value;

value = *ptr;
++ptr;
printf("%c", value); // will print 'e'

*++ptrgiống như *(++ptr), đó là:

const char  *ptr = "example";
char  value;

++ptr;
value = *ptr;
printf("%c", value); // will print 'x'

++*ptrgiống như ++(*ptr), đó là:

const char  *ptr = "example";
char  value;

value = *ptr;
++value;
printf("%c", value); // will print 'f' ('e' + 1)

Tôi hoàn toàn đồng ý với phần đầu tiên của câu trả lời. Trong phần thứ hai, việc khởi tạo con trỏ (thành số nguyên!) Với số nguyên là khó hiểu đối với người đang đấu tranh để hiểu cách sử dụng con trỏ.
nickie

4

Bạn đúng về quyền ưu tiên, lưu ý rằng mức độ *ưu tiên so với mức tăng tiền tố, nhưng không vượt quá mức tăng tiền tố. Đây là cách những sự cố này:

*ptr++ - đi từ trái sang phải, hủy bỏ con trỏ và sau đó tăng giá trị con trỏ (không phải là điểm mà nó trỏ tới, do sự ưu tiên của postfix so với dereference)

*++ptr - tăng con trỏ và sau đó hủy bỏ nó, điều này là do tiền tố và sự bổ sung có cùng mức ưu tiên và do đó chúng được đánh giá theo thứ tự từ phải sang trái

++*ptr- tương tự như ở trên về mức độ ưu tiên, một lần nữa đi từ phải sang trái để sắp xếp lại con trỏ và sau đó tăng những gì con trỏ trỏ tới. Xin lưu ý rằng trong trường hợp của bạn, điều này sẽ dẫn đến hành vi không xác định vì bạn đang cố gắng sửa đổi biến chỉ đọc ( char* p = "Hello";).


3

Tôi sẽ thêm phần nhận của mình vì trong khi các câu trả lời khác là chính xác thì tôi nghĩ họ đang thiếu thứ gì đó.

 v = *ptr++

có nghĩa

 temp = ptr;
 ptr  = ptr + 1
 v    = *temp;

Trong khi

 v = *++ptr

có nghĩa

 ptr = ptr + 1
 v   = *ptr

Điều quan trọng là phải hiểu rằng tăng bài (và giảm bài) có nghĩa là

 temp = ptr       // Temp created here!!!
 ptr  = ptr + 1   // or - 1 if decrement)
 v    = *temp     // Temp destroyed here!!!

Tại sao nó quan trọng? Vâng, trong C đó không quá quan trọng. Trong C ++ mặc dù ptrcó thể là một loại phức tạp như một trình vòng lặp. Ví dụ

 for (std::set<int>::iterator it = someSet.begin(); it != someSet.end(); it++)

Trong trường hợp này, vì itlà một loại phức tạp it++có thể có tác dụng phụ vì sự tempsáng tạo. Tất nhiên nếu bạn may mắn, trình biên dịch sẽ cố gắng loại bỏ mã không cần thiết nhưng nếu hàm tạo hoặc hàm hủy của iterator làm bất cứ điều gì thì it++nó sẽ hiển thị các hiệu ứng đó khi nó tạo ratemp .

Tóm lại những gì tôi đang cố nói là Viết những gì bạn muốn nói . Nếu bạn có nghĩa là tăng ptr thì viết ++ptrkhông ptr++. Nếu bạn có ý nghĩa temp = ptr, ptr += 1, tempthì viếtptr++


0
*ptr++    // 1

Điều này giống như:

    tmp = *ptr;
    ptr++;

Vì vậy, giá trị của đối tượng được trỏ đến ptrđược lấy ra, sau đó ptrđược tăng lên.

*++ptr    // 2

Điều này giống như:

    ++ptr;
    tmp = *ptr;

Vì vậy, con trỏ ptrđược tăng lên, sau đó đối tượng được trỏ đến ptrđược đọc.

++*ptr    // 3

Điều này giống như:

    ++(*ptr);

Vì vậy, đối tượng được chỉ bởi ptrtăng lên; ptrbản thân nó là không thay đổi.


0

tiền tố và tiền tố có quyền ưu tiên cao hơn so với quy định

* ptr ++ ở đây đăng ptr tăng và sau đó chỉ đến giá trị mới của ptr

* ++ ptr ở đây Pre frement nắm tay sau đó chỉ vào giá trị mới của ptr

++ * ptr ở đây trước tiên nhận giá trị của ptr trỏ tới và tăng lên mà vlaue


1
Điều này là không đúng. Postfix có mức độ ưu tiên cao hơn, nhưng tiền tố có mức độ ưu tiên tương tự như tính quy định.
dài

0

Biểu thức con trỏ: * ptr ++, * ++ ptr và ++ * ptr:

Lưu ý : con trỏ phải được khởi tạo và phải có địa chỉ hợp lệ. Bởi vì trong RAM ngoài chương trình của chúng tôi (a.out), có rất nhiều chương trình đang chạy đồng thời, tức là nếu bạn đang cố truy cập vào một số bộ nhớ không dành riêng cho bạn thì hệ điều hành sẽ thông qua lỗi Phân đoạn.

Trước khi giải thích điều này hãy xem xét ví dụ đơn giản?

#include<stdio.h>
int main()
{
        int num = 300;
        int *ptr;//uninitialized pointer.. must be initialized
        ptr = &num;
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
        *ptr = *ptr + 1;//*ptr means value/data on the address.. so here value gets incremented
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
        /** observe here that "num" got changed but manually we didn't change, it got modified by pointer **/
        ptr = ptr + 1;//ptr means address.. so here address got incremented
        /**     char pointer gets incremented by 1 bytes
          Integer pointer gets incremented by 4 bytes
         **/
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
}

phân tích đầu ra của mã trên, tôi hy vọng bạn có đầu ra của mã trên. Một điều rõ ràng từ đoạn mã trên là tên con trỏ ( ptr ) có nghĩa là chúng ta đang nói về địa chỉ* ptr có nghĩa là chúng ta đang nói về giá trị abbout / dữ liệu.

TRƯỜNG HỢP 1 : * ptr ++, * ++ ptr, * (ptr ++) và * (++ ptr):

ở trên đã đề cập tất cả 4 cú pháp là tương tự nhau, address gets incrementednhưng tất cả các địa chỉ được tăng lên đều khác nhau.

Lưu ý : để giải quyết bất kỳ biểu thức nào, hãy tìm hiểu có bao nhiêu toán tử trong biểu thức, sau đó tìm ra các ưu tiên của toán tử. Tôi nhiều toán tử có cùng mức độ ưu tiên sau đó kiểm tra thứ tự tiến hóa hoặc kết hợp có thể từ phải (R) sang trái (L) từ trái sang phải.

* ptr ++ : Ở đây có 2 toán tử là de-Reference (*) và ++ (tăng). Cả hai đều có cùng mức độ ưu tiên sau đó kiểm tra tính kết hợp từ R đến L. Vì vậy, bắt đầu giải quyết từ Phải sang Trái, bất kỳ toán tử nào sẽ đến trước.

* ptr ++ : ++ đầu tiên xuất hiện trong khi giải từ R đến L, vì vậy địa chỉ được tăng nhưng tăng bài.

* ++ ptr : Tương tự như địa chỉ đầu tiên ở đây cũng có địa chỉ được tăng nhưng mức tăng trước của nó.

* (ptr ++) : Ở đây có 3 toán tử, trong số đó nhóm () có mức ưu tiên cao nhất, vì vậy ptr ++ đầu tiên được giải quyết tức là địa chỉ được tăng lên nhưng bài đăng.

* (++ ptr) : Tương tự như trường hợp trên đây, địa chỉ cũng được tăng lên nhưng tăng trước.

TRƯỜNG HỢP 2 : ++ * ptr, ++ (* ptr), (* ptr) ++:

ở trên đã đề cập cả 4 cú pháp tương tự nhau, trong tất cả giá trị / dữ liệu được tăng lên nhưng cách thay đổi giá trị thì khác nhau.

++ * ptr : đầu tiên * xuất hiện trong khi giải từ R sang L, vì vậy giá trị được thay đổi nhưng gia tăng trước của nó.

++ (* ptr) : Tương tự như trường hợp trên, giá trị được sửa đổi.

(* ptr) ++ : Ở đây có 3 toán tử, trong đó có nhóm () có mức ưu tiên cao nhất, Inside () * ptr ở đó, Vì vậy, đầu tiên * ptr được giải quyết tức là giá trị được tăng lên nhưng đăng.

Lưu ý : ++ * ptr và * ptr = * ptr + 1 cả hai đều giống nhau, trong cả hai trường hợp giá trị được thay đổi. ++ * ptr: chỉ có 1 lệnh (INC) được sử dụng, giá trị trực tiếp được thay đổi trong một lần chụp. * ptr = * ptr + 1: ở đây giá trị đầu tiên được tăng (INC) và sau đó được gán (MOV).

Để hiểu tất cả các cú pháp gia tăng khác nhau ở trên con trỏ, hãy xem xét mã đơn giản:

#include<stdio.h>
int main()
{
        int num = 300;
        int *ptr;
        ptr = &num;
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
        *ptr++;//address changed(post increment), value remains un-changed
//      *++ptr;//address changed(post increment), value remains un-changed
//      *(ptr)++;//address changed(post increment), value remains un-changed
//      *(++ptr);//address changed(post increment), value remains un-changed

//      ++*ptr;//value changed(pre increment), address remains un-changed
//      (*ptr)++;//value changed(pre increment), address remains un-changed
//      ++(*ptr);//value changed(post increment), address remains un-changed

        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
}

Trong đoạn mã trên, cố gắng bình luận / bỏ bình luận và phân tích kết quả đầu ra.

Con trỏ là hằng số : không có cách nào để bạn có thể biến con trỏ thành hằng số, tôi chỉ đề cập ở đây.

1) const int * p HOẶC int const * p : Ở đây valuehằng số , địa chỉ không phải là hằng số tức là nơi p đang trỏ? Một số địa chỉ? Trên địa chỉ đó giá trị là gì? Một số giá trị phải không? Giá trị đó là hằng số, bạn không thể sửa đổi giá trị đó nhưng con trỏ đang trỏ ở đâu? Một số địa chỉ phải không? Nó cũng có thể trỏ đến địa chỉ khác.

Để hiểu điều này, hãy xem xét mã dưới đây:

#include<stdio.h>
int main()
{
        int num = 300;
        const int *ptr;//constant value, address is modifible
        ptr = &num;
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
        *ptr++;//
//      *++ptr;//possible bcz you are trying to change address which is possible
//      *(ptr)++;//possible
//      *(++ptr);//possible

//      ++*ptr;//not possible bcz you trying to change value which is not allowed
//      (*ptr)++;//not possible
//      ++(*ptr);//not possible

        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
}

Cố gắng phân tích đầu ra của mã trên

2) int const * p : nó được gọi là ' **constant pointe**r' tức là address is constant but value is not constant. Ở đây bạn không được phép thay đổi địa chỉ nhưng bạn có thể sửa đổi giá trị.

Lưu ý : con trỏ không đổi (trường hợp trên) phải khởi tạo trong khi decariung chính nó.

Để hiểu điều này cho phép kiểm tra mã đơn giản.

#include<stdio.h>
int main()
{
        int x = 300;
        int* const p;
        p = &x;
        printf("x = %d p =%p and *p = %d\n",num,p,*p);
}

Trong đoạn mã trên, nếu bạn quan sát thấy không có ++ * p hoặc * p ++ Vì vậy, bạn có thể nghĩ đây là trường hợp đơn giản vì chúng tôi không thay đổi địa chỉ hoặc giá trị nhưng nó sẽ tạo ra lỗi. Tại sao ? Lý do tôi đề cập trong ý kiến.

#include<stdio.h>
int main()
{
        int x = 300;
        /** constant pointer must initialize while decaring itself **/
        int* const p;//constant pointer i.e its pointing to some address(here its pointing to garbage), it should point to same address(i.e garbage ad
dress only 
        p = &x;// but here what we are doing ? we are changing address. we are making p to point to address of x instead of garbage address.
        printf("x = %d p =%p and *p = %d\n",num,p,*p);
}

Vì vậy, giải pháp của vấn đề này là gì?

     int* const p = &x;

để biết thêm về trường hợp này, hãy xem xét ví dụ dưới đây.

#include<stdio.h>
int main()
{
        int num = 300;
        int *const ptr = &num;//constant value, address is modifible
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
        *ptr++;//not possible
//      *++ptr;//not possible bcz you are trying to change address which is not possible
//      *(ptr)++;//not possible
//      *(++ptr);//not possible

//      ++*ptr;// possible bcz you trying to change value which is allowed
//      (*ptr)++;// possible
//      ++(*ptr);// possible
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
}

3) const int * const p : Ở đây cả địa chỉ và giá trị đều không đổi .

Để hiểu điều này, hãy kiểm tra mã bên dưới

#include<stdio.h>
int main()
{
        int num = 300;
        const int* const ptr = &num;//constant value,constant address 
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
        *ptr++;//not possible
        ++*ptr;//not possible
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
}

-1
const char *p = "Hello";   

*p means "Hello"
          ^
          | 
          p

*p++ means "Hello"
             ^
             | 
             p

*++p means "Hello"
            ^
            |     (WHILE THE STATEMENT IS EXECUTED)
            p

*++p means "Hello"
             ^
             |     (AFTER THE STATEMENT IS EXECUTED)
             p

++*pcó nghĩa là bạn đang cố gắng để tăng giá trị ASCII của *p

   is "Hello"
       ^
       | 
       p

bạn không thể tăng giá trị 'vì nó là hằng số nên bạn sẽ gặp lỗi

đối với vòng lặp while của bạn, vòng lặp chạy cho đến khi *p++kết thúc chuỗi có '\0'ký tự (NULL).

Bây giờ kể từ khi *p++bỏ qua ký tự đầu tiên, bạn sẽ chỉ nhận được đầu ra của mình bắt đầu từ ký tự thứ hai.

Đoạn mã sau sẽ không xuất ra bất cứ thứ gì vì vòng lặp while có '\0'

const char *p = "Hello";
    while('\0') 
         printf("%c",*p);

Đoạn mã sau sẽ cung cấp cho bạn cùng một đầu ra như mã tiếp theo tức là ello.

const char *p = "Hello";
    while(*++p)
         printf("%c",*p);

...................................

const char *p = "Hello";
    while(*p++)
         printf("%c",*p);
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.