Lỗi kì lạ - giá trị pointer trên C bị tự động thay đổi

int main()
{
    int i = 0;
    
    char input[] = { 0 };
    char inputArray[20] = "xin chao ";
    
    char * pointer = inputArray;
    
    //gia tri pointer truoc khi scanf()
    for (i = 0; i < 20; i++) {
		printf("Adress: %d [%d]: %d ==> %c \n", pointer+i, i, *(pointer+i), *(pointer+i));	
	}
	
    scanf("%s", input);
    printf("Input la: %s\n", input);
    
    //gia tri pointer tu dong thay doi
    for (i = 0; i < 20; i++) {
		printf("After Adress: %d [%d]: %d ==> %c \n", pointer+i, i, *(pointer+i), *(pointer+i));	
	}
    
}

đây là kết quả khi mình chạy


thực sự rất kì lạ, rõ ràng mình không tác động gì đến biến pointer nhưng các giá trị nó lại bị thay đổi, mình xem đi xem lại nhưng không hiểu chuyện gì đang diễn ra?
Mong các bạn giúp đỡ, mình cảm ơn.

Mình chạy trên https://www.onlinegdb.com/ thấy bình thường mà. Trong mã bạn không có thay đổi thì xem ứng dụng khác có truy xuất và thay đổi không. Cũng có thể do lỗi của trình biên dịch.

3 Likes

Ban khai báo cho input chỉ có như vầy char input[] = { 0 };

Tức cùng lắm là store được một chuỗi rỗng. :kissing:

Mà 2 dòng khai báo kia nó liền nhau thì khả nằng cao là địa chỉ trên RAM cũng liền nhau. :v

Giả sử nó như này:

| x | x | x | x | x | x | x | x | x | x | ... | x |
 ^    ^ 
 |    |---- inputArray / pointer
input

Nếu bạn nhập một chuỗi không rỗng cho input, vd là Sherly1001 thì giờ nó thành như vầy:

| S | h | e | r | l | y | 1 | 0 | 0 | 1 | ... | x |
 ^    ^ 
 |    |---- inputArray / pointer
input

Vậy là bạn đã thay đổi rồi còn gì. :slight_smile:

5 Likes

không đúng, nếu như vậy thì khi in inputArray / pointer ra thì nó phải chứa kí tự mình đã nhập chứ? lúc mìh in ra thì giá trị nó hoàn toàn khác

2 Likes

Xét như hình chụp của bạn ấy thì địa chỉ con trỏ bị lùi lại 240 ô. 6487536 - 6487296 = 240.

2 Likes

lỗi trình biên dịch là sao bạn, mình dùg dev c++ đó bạn

Ừ, lạ nhỉ. :thinking:

Mình test ở đây cũng vậy. Chỉ biết code của bạn là undefined behavior th. :v :v

Summon a @tntxtnt. :kissing_smiling_eyes:

4 Likes

Chạy thử liên kết của @Sherly1001 đưa và thay đổi số phần tử của biến input thì thấy:

  • Số phần tử của input là 1 thì byte đầu của con trỏ bị gán về 00.
    0x7ffe293f8b30 -> 0x7ffe293f8b00
    0x7ffe3bbcff90 -> 0x7ffe3bbcff00
  • Số phần tử của input lớn hơn 1 thì bình thường.
2 Likes

Vẫn link đó, nhưng đổi compiler sang Clang lại hết. Kết luận là do compiler rồi :V

4 Likes

các biến trên stack ko được quy định theo thứ tự khai báo :V mặc dù khai báo input liền sau inputArray nhưng trình biên dịch có thể sắp xếp input liền trước pointer. Và scanf nó ghi vào input ko đủ chỗ thì nó ghi đè lên pointer làm thay đổi giá trị :V

#include <stdio.h>

#pragma pack(1)
typedef struct Foo {
    char inputArray[20];
    char input[1];
    char * pointer;
} foo_t;

int main()
{
    int i = 0;
    
    foo_t f = {.inputArray = "xin chao ", .input = { 0 }, .pointer = f.inputArray};
    
    //gia tri pointer truoc khi scanf()
    for (i = 0; i < 20; i++) {
		printf("Adress: %d [%d]: %d ==> %c \n", f.pointer+i, i, *(f.pointer+i), *(f.pointer+i));	
	}
	
    scanf("%s", f.input);
    printf("Input la: %s\n", f.input);
    
    //gia tri pointer tu dong thay doi
    for (i = 0; i < 20; i++) {
		printf("After Adress: %d [%d]: %d ==> %c \n", f.pointer+i, i, *(f.pointer+i), *(f.pointer+i));	
	}
    
}

cho tụi nó vào 1 cái struct thì mới tuân theo thứ tự khai báo. Ở đây pack(1) cho nó khỏi padding luôn :V Khi nhập vào input nó sẽ ghi đè lên pointer, dẫn tới “lỗi” như trên :V

5 Likes

Dù vậy, máy mình nó bảo comment đầu tiên của @Sherly1001 mới đúng, trên cả GCC lẫn Clang.

Linux 5.4.21 lts
Intel i5 8250u
Screenshot%20from%202020-03-09%2023-51-34

Trên trang wandbox, nó cũng sẽ chạy như trên nếu bật Optimization.
$ g++ prog.cc -Wall -Wextra -O2 -march=native -I/opt/wandbox/boost-1.72.0/gcc-head/include -std=gnu++2a

(tất nhiên sẽ lỗi y như trên đầu nếu tắt tối ưu hóa đi)

Hóng cao nhân tìm ra điểm tương đồng giữa Wandbox (Ubuntu) và Dev C++ (Windows) :V

4 Likes

Ngoài ra mình còn phát hiện thằng GNU nó còn đang trêu ngươi mình. :slight_smile:

Chỉ cần print ra address của pointer thì value của pointer sẽ không bị thay đổi. :v :v :v (không bật optimization)

Link test có print &pointer
Link test không print &pointer

:point_right: Kết luận: không nên dây dưa với UB. :v :v :v

4 Likes

Hi.
C là một tiêu chuẩn nó không quy định đầy đủ trình biên dịch phải làm gì. Vậy nên sẽ không xác định khi không tuân thủ các nguyên tắc lập trình. Như việc bạn đập vỡ một cái lọ hoa và cố giải thích tại sao các mảnh vỡ có hình như vậy.

5 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?