2012-06-29 44 views
5

Tôi đã gặp rắc rối trong vài giờ qua về một vấn đề mà tôi đã hiểu. Đây là sự cố của tôi:sự khác biệt giữa char * và char [] với strcpy()

void cut_str(char* entry, int offset) { 
    strcpy(entry, entry + offset); 
} 

char works[128] = "example1\0"; 
char* doesnt = "example2\0"; 

printf("output:\n"); 

cut_str(works, 2); 
printf("%s\n", works); 

cut_str(doesnt, 2); 
printf("%s\n", doesnt); 

// output: 
// ample1 
// Segmentation: fault 

Tôi cảm thấy có điều gì đó quan trọng về char */char [] mà tôi không nhận được ở đây.

+0

Câu hỏi này được hỏi thường xuyên ở đây. Vui lòng xem, ví dụ: http://stackoverflow.com/questions/10186765/char-array-vs-char-pointer-in-c và http://stackoverflow.com/questions/4090434/strtok-char-array-versus -char-pointer –

+0

có thể trùng lặp của [Sự khác biệt giữa char s \ [\] và char * s trong C?] (http://stackoverflow.com/questions/1704407/what-is-the-difference-between -char-s-và-char-s-in-c) –

Trả lời

11

Sự khác biệt nằm trong đó doesnt điểm đến bộ nhớ thuộc về chuỗi không đổi và do đó không thể ghi được.

Khi bạn làm điều này

char works[128] = "example1\0"; 

trình biên dịch bản nội dung của một chuỗi không thể ghi vào một mảng ghi. \0 là không cần thiết, bằng cách này.

Khi bạn làm điều này, tuy nhiên,

char* doesnt = "example2\0"; 

trình biên dịch lá con trỏ trỏ đến một vùng nhớ non-ghi. Một lần nữa, \0 sẽ được chèn bởi trình biên dịch.

Nếu bạn đang sử dụng gcc, bạn có thể cảnh báo bạn về việc khởi tạo có thể ghi char * bằng chuỗi ký tự. Tùy chọn là -Wwrite-strings. Bạn sẽ nhận được một cảnh báo rằng trông như thế này:

warning: initialization discards qualifiers from pointer target type 

Cách thích hợp để khai báo con trỏ doesnt của bạn là như sau:

const char* doesnt = "example2\0"; 
+0

"trình biên dịch sao chép nội dung của chuỗi không thể ghi vào một mảng có thể ghi" - Không hoàn toàn. "example1 \ 0" ở đây không phải là một chuỗi không thể ghi, nó là chuỗi chữ - một yếu tố hoàn toàn cú pháp. Trong bối cảnh này nó đang được sử dụng như một initializer. –

+0

"Bạn đã nhận được cảnh báo về dòng char * doesnt = ..." - Không, thực sự, không. Không có trình biên dịch nào đó, may mắn thay. –

+1

@JimBalter g ++ thực hiện: "cảnh báo: chuyển đổi không được chấp nhận từ chuỗi liên tục thành 'char *'". Đó không phải là một trình biên dịch C, nhưng tôi đã không làm cho nó lên :) – dasblinkenlight

3

này phân bổ 128 byte trên stack, và sử dụng tên works để tham khảo địa chỉ của nó:

char works[128]; 

Vì vậy, works là con trỏ đến bộ nhớ có thể ghi.

Điều này tạo ra một chuỗi chữ, đó là trong bộ nhớ chỉ đọc, và sử dụng tên doesnt để tham khảo địa chỉ của nó:

char * doesnt = "example2\0"; 

Bạn có thể ghi dữ liệu vào works, bởi vì nó chỉ ra có thể ghi nhớ. Bạn không thể ghi dữ liệu vào doesnt, vì nó trỏ đến bộ nhớ chỉ đọc.

Ngoài ra, lưu ý rằng bạn không phải kết thúc chuỗi ký tự của mình bằng "\0", vì tất cả các chuỗi ký tự chuỗi ngầm thêm một byte không vào cuối chuỗi.

+0

Không, 'works' là một đối tượng mảng, không phải là một con trỏ. (Tên của nó phân rã thành biểu thức con trỏ trong hầu hết các ngữ cảnh.) –

+0

"Điều này phân bổ 128 byte trên ngăn xếp" - chúng tôi không biết lớp lưu trữ; nó có thể là bên ngoài. Và như Keith lưu ý, mảng không phải là con trỏ. (Một hệ quả là 'sizeof (works)! = Sizeof ((char *) works)'). –

4

Các loại char[]char * khá giống nhau, vì vậy bạn có quyền về điều đó. Sự khác biệt nằm ở những gì xảy ra khi các đối tượng của các kiểu được khởi tạo. Đối tượng của bạn works, thuộc loại char[], có 128 byte bộ nhớ biến được phân bổ cho nó trên ngăn xếp. Đối tượng của bạn doesnt, thuộc loại char *, không có bộ nhớ trên ngăn xếp.

Trường hợp chính xác chuỗi doesnt được lưu trữ không được chỉ định theo tiêu chuẩn C, nhưng rất có thể nó được lưu trữ trong phân đoạn dữ liệu không thể sửa đổi được tải khi chương trình của bạn được tải để thực thi. Đây không phải là bộ nhớ thay đổi. Vì vậy, segfault khi bạn cố gắng thay đổi nó.

+0

"Sự khác biệt nằm" - Có khác, đáng kể, sự khác biệt giữa mảng và con trỏ. Vấn đề ở đây thực sự không phải là về điều đó, nhưng về thực tế là không trỏ đến một chuỗi liên tục, và tiêu chuẩn nói rằng kết quả của việc sửa đổi nó là không xác định. –

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