2012-08-31 46 views
46

xem xét:Tại sao * p ++ khác với * p + = 1?

void foo1(char **p) { *p++; } 
void foo2(char **p) { *p += 1; } 

char *s = "abcd"; 
char *a = s; 
foo1(&a); 
printf("%s", a); //abcd 

nhưng nếu tôi sử dụng foo2() thay vì:

char *a = s; 
foo2(&a); 
printf("%s", a); //bcd 

Ai đó có thể giải thích nó?

+22

Vì '* p ++' giống với '* (p ++)' –

+5

[ưu tiên toán tử] (http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Operator_precedence) – chris

+3

Đồng thời thử 'void foo3 (char ** p) {(* p) ++; } ' –

Trả lời

95

Khóa là ưu tiên của số += và toán tử ++. Các ++ có độ ưu tiên cao hơn += (trên thực tế, toán tử gán có độ ưu tiên thấp thứ hai trong C), do đó hoạt động

*p++ 

nghĩa dereference con trỏ, sau đó tăng con trỏ tự 1 (như thông thường, theo các quy tắc về số học con trỏ, nó không nhất thiết phải là một byte, mà đúng hơn là sizeof(*p) liên quan đến địa chỉ kết quả). Mặt khác,

*p += 1 

phương tiện tăng giá trị trỏ đến bởi con trỏ bởi một (và không phải làm gì với con trỏ chính nó).

+8

Bạn đã làm một công việc tuyệt vời để giải thích nó, nhưng bạn có thể vui lòng thêm vào một chi tiết * p ++ tăng con trỏ chính nó bằng 1" đơn vị ", vì vậy một con trỏ char có thể tăng thêm một , trong khi một con trỏ int có thể tăng lên 4, vv, tùy thuộc vào các chi tiết cụ thể. –

+3

@EdwinBuck: Tôi không thực sự thấy sự liên quan, đó chỉ là số học con trỏ bình thường chứ không phải là trọng tâm của câu hỏi. – GManNickG

+5

@EdwinBuck cho dù con trỏ là int hay char, khi bạn tăng nó, nó sẽ tăng một con trỏ. Địa chỉ thực tế đại diện cho con trỏ đó có thể thay đổi nhiều hơn một byte, do kích thước của con trỏ. –

29

Ưu tiên. Mã bưu chính ++ liên kết chặt chẽ hơn tiền tố * để nó tăng thêm p. Các += là ở cuối thấp của danh sách ưu tiên, cùng với các nhà điều hành đồng bằng chuyển nhượng, do đó, nó thêm 1 đến *p.

0

Ưu tiên tiền tố ++ và * giống nhau. Khả năng kết hợp của cả hai từ phải sang trái. Ưu tiên của postfix ++ cao hơn cả * và tiền tố ++. Khả năng kết hợp của postfix ++ là từ trái sang phải.

0

Hãy bắt đầu với *p += 1

tôi sẽ cố gắng trả lời này từ một chút của một góc độ khác nhau ... Bước 1 Hãy nhìn vào các nhà khai thác và các toán hạng: Trong trường hợp này nó là một toán hạng (con trỏ p) và chúng tôi có hai toán tử, trong trường hợp này là * cho dereferencing và + = 1 để tăng. Bước 2 trong đó có ưu tiên cao hơn * có độ ưu tiên cao hơn + =


*P++ một Đây là một chút phức tạp hơn ... thậm chí có thể xấu xa lần nữa chúng ta có một toán hạng (p con trỏ) và hai nhà khai thác, chỉ bây giờ * cho dereference và ++ post increment có cùng mức ưu tiên. (Trong một số bảng, ++ trong một bài đăng có quyền ưu tiên cao hơn.)

Bước 1 Hãy xem các toán tử và toán hạng: Trong trường hợp này là toán hạng và bạn có hai toán tử, trong trường hợp này là * dereferencing và ++ cho gia tăng. Bước 2 có ưu tiên cao hơn? ++ có ưu tiên cao hơn * Lưu ý: ngay cả khi chúng có ưu tiên CÙNG chúng liên kết phải sang trái, một lần nữa, ++ là trước * Bước 3 (phần phức tạp ...) Ở đâu là ++? nó là bên phải của toán hạng, có nghĩa là POST tăng Trong trường hợp này, trình biên dịch có một 'lưu ý tinh thần' để thực hiện số tăng SAU nó được thực hiện với tất cả các toán tử khác ... Điều gì sau ?Nó có nghĩa là nó sẽ chỉ áp dụng số gia tăng như bước rất rất cuối cùng trước khi tiếp theo ';' do đó, nó sẽ được thực hiện với tất cả các toán tử khác trên cùng dòng ' lưu ý: nếu nó là * ++ p thì nó sẽ thực hiện nó TRƯỚC KHI bất kỳ toán tử nào khác trên cùng một dòng như vậy trong trường hợp này, nó tương đương với lấy hai thanh ghi của bộ vi xử lý, một sẽ giữ giá trị của dấu * dereferenced và giá trị kia sẽ giữ giá trị của p ++ tăng lên, lý do trong trường hợp này có hai, là hoạt động POST ... Đây là nơi trong đó trường hợp nó là khó khăn, và nó trông giống như một mâu thuẫn. Người ta sẽ mong đợi ++ được ưu tiên hơn *, mà nó làm, chỉ có POST có nghĩa là nó sẽ được áp dụng chỉ sau tất cả các toán hạng khác, TRƯỚC KHI tiếp theo ';' token ...

Như tôi đã nói, phần phức tạp là bất kỳ số gia tăng nào ở bên phải của toán hạng sẽ được đặt sang một bên và sẽ được áp dụng như thao tác LAST trước khi chuyển sang dòng tiếp theo.

Các vấn đề liên quan