2013-04-05 26 views
5

Tại sao mã này hoạt động? Tôi hy vọng rằng tôi sẽ cần phải dereference ptr, printf("%s\n", *ptr); trước khi tôi có thể in nó ra, nhưng tôi nhận được một Segmentation Fault nếu tôi cố gắng làm điều đó theo cách đó.Tại sao tôi không cần phải dereference một con trỏ ký tự trong C trước khi in nó?

#include <stdio.h> 

int main(int argc, char *argv[]) 
{ 
     char name[] = "Jordan"; 
     char *ptr = name; 
     printf("%s\n", ptr); 
} 

Hy vọng các bạn có thể cho tôi một số thông tin chi tiết.

Trả lời

16

Khi bạn in chuỗi chúng tôi cần địa chỉ bắt đầu của chuỗi.

printf("%s\n", ptr); 
       ^address with %s 

nó in ký tự cho đến khi \0 gặp gỡ.

Trong khi in trò chuyện int .. chúng ta cần giá trị biến:

printf("%c\n", *ptr); 
      ^* with %c print first char 

đâu như trong scanf() một chuỗi bạn luôn cần phải cung cấp địa chỉ:

scanf("%s", ptr); 
      ^string address 

Cũng cho int scanf() một char

scanf("%c", ptr); 
      ^read at first location char address 

Lưu ý:Scanf() cần giải quyết với %c để lưu trữ một giá trị quét trong bộ nhớ.

Be cẩn thậnptrtrỏ đến chuỗi không đổi để bạn không thể sử dụng trong scanf.

Tại sao Lỗi phân đoạn bằng mã sau?

printf("%s\n", *ptr); 

Khi bạn làm như thế này, vì %s diễn giải printf *ptr như địa chỉ, nhưng nó thực sự không phải là một địa chỉ và nếu bạn đối xử với nó như là địa chỉ nó chỉ ra một số vị trí đó được đọc bảo vệ cho chương trình của bạn (quá trình) Vì vậy, nó gây ra một lỗi phân đoạn.

bạn ptr qua name điểm đối với một số chuỗi liên tục trong bộ nhớ ("Jordan") như trong sơ đồ dưới đây:

name 2002 
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐ 
│ 'J' │ 'o' │ 'r' │ 'd' │ 'a' │ 'n' │'\0' │ ........ 
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘ 
^
    | 
ptr = name 

==> ptr = 2002 
    *ptr = 'J' 

Trong printf("%s\n", *ptr); giá trị *ptr = 'J' và ASCII của char 'J' được 74 nhưng 74 địa chỉ là không dưới sự kiểm soát quá trình của bạn và bạn đang cố gắng đọc từ vị trí bộ nhớ đó và một lỗi bộ nhớ và lỗi phân đoạn xảy ra.

Nếu bạn biên dịch bạn mã chứa printf("%s\n", *ptr); sau đó với tùy chọn thích hợp nói -Wall với GCC bạn sẽ nhận được một cảnh báo như dưới đây:

warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’

Says %s nhu cầu (dự đoán) một địa chỉ của kiểu char* nhưng bạn đặt giá trị

thông báo:

printf("%s\n", *ptr); 
     ^  ^argument-2 
     argument-1 
1

Trình định dạng định dạng %s yêu cầu printf để mong đợi một con trỏ tới mảng char được kết thúc bằng null. Đó là những gì nameptr.

*name*ptr thì không. Nếu bạn coi trọng chúng, bạn sẽ lấy lại một đơn char, về cơ bản là nằm ở printf - dẫn đến hành vi không xác định.

5

Điều này là do định dạng số %s trong chuỗi định dạng bạn chuyển đến printf có nghĩa là đối số tương ứng phải là một chuỗi chứ không phải một ký tự đơn. Và trong C, một chuỗi là một con trỏ đến đầu của một khối ký tự có một ký tự null (byte có giá trị là 0) ở cuối.

Về cơ bản, tính năng này hoạt động vì bạn đang thực hiện chính xác những gì bạn được cho là để in chuỗi.

0

*ptr về bản chất là tham chiếu đến một đơn char, không phải là chuỗi của char. do điều này char *char[] về cơ bản là giống nhau

1

Trình định dạng %s để printf mong đợi một "chuỗi", đây thực sự là một con trỏ đến một chuỗi ký tự kết thúc bằng null.

Tức là, printf mong muốn bạn chuyển con trỏ đến nó. Khi bạn dereference con trỏ, nó lấy chữ J, có giá trị trong ascii là 74 (thập phân), và cố gắng điều trị đó như là một con trỏ đến một mảng. Đó là một khu vực bộ nhớ không thể truy cập được, vì vậy bạn bị vi phạm phân đoạn.

0

Khi bạn khai báo char prt = tên thats, nơi bạn đang dereferencing nó. "" ở đây không phải là một phần của biến chỉ là một cách để cho thấy bạn muốn biến đó trỏ tới đâu. Nếu bạn đã đặt * prt một lần nữa trong printf của bạn, bạn đang làm điều đó hai lần. name là một mảng các ký tự và * ptr là một con trỏ trỏ tới các ký tự đó.

Mong rằng giải thích sẽ giúp :-)

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