2012-07-19 43 views
30

Tôi biết rằng các mảng trong C chỉ là con trỏ tới dữ liệu được lưu trữ tuần tự. Nhưng sự khác biệt ngụ ý sự khác biệt trong ký hiệu [] và *. Ý tôi là trong TẤT CẢ ngữ cảnh sử dụng có thể. Ví dụ:C/C++ int [] so với int * (con trỏ so với ký hiệu mảng). Sự khác biệt là gì?

char c[] = "test"; 

nếu bạn cung cấp hướng dẫn này trong một cơ quan chức năng nó sẽ phân bổ các chuỗi trên một chồng trong khi

char* c = "test"; 

sẽ trỏ đến một dữ liệu (chỉ đọc) phân đoạn.

Bạn có thể liệt kê tất cả các khác biệt giữa hai ký hiệu này trong TẤT CẢ ngữ cảnh sử dụng để tạo thành một khung nhìn chung rõ ràng.

+2

Mặc dù tiêu đề giống hệt nhau, nhưng câu hỏi này thực sự có nhiều thông tin hơn. Chúng ta nên mở lại! – ltjax

+0

@ltjax Và bạn đã đúng. Lỗi của tôi để kích hoạt hạnh phúc. Bình chọn mở lại. – Mysticial

+2

'' char * c = "test"; '' là một mã không chuẩn. Giá trị đúng là '' const char * c = "test"; '' –

Trả lời

19

Theo tiêu chuẩn C99:

Một kiểu mảng mô tả một tập không rỗng liên tục kế nhau phân bổ của đối tượng với một loại đối tượng thành viên đặc biệt, được gọi là phần tử type.36) loại Mảng được đặc trưng bởi yếu tố của họ nhập và theo số số phần tử trong mảng. Một loại mảng được gọi là bắt nguồn từ loại phần tử của nó và nếu loại phần tử của nó là T, thì loại mảng đôi khi được gọi là ‘mảng T’ ’. Việc xây dựng một mảng kiểu từ loại phần tử được gọi là ‘dẫn xuất loại mảng’ ’.


Một loại con trỏ có thể được bắt nguồn từ một loại chức năng, một loại đối tượng, hoặc một loại không đầy đủ, được gọi là kiểu tham chiếu. Kiểu con trỏ mô tả đối tượng có giá trị cung cấp tham chiếu đến thực thể của loại được tham chiếu. Kiểu con trỏ bắt nguồn từ kiểu tham chiếu T đôi khi được gọi là ‘con trỏ đến T’ ’. Việc xây dựng con trỏ loại từ loại được tham chiếu được gọi là ‘dẫn xuất loại con trỏ’ ’.

Theo tờ khai chuẩn

char s[] = "abc", t[3] = "abc"; 
char s[] = { 'a', 'b', 'c', '\0' }, t[] = { 'a', 'b', 'c' }; 

giống hệt nhau. Nội dung của các mảng có thể sửa đổi được. Mặt khác, khai báo const char *p = "abc"; định nghĩa p với con trỏ kiểu '' đến hằng số char '' và khởi tạo nó để trỏ đến một đối tượng có mảng '' hằng số '' (trong C++) với độ dài 4 mà các phần tử được khởi tạo với chuỗi ký tự bằng chữ. Nếu một nỗ lực được thực hiện để sử dụng p để sửa đổi nội dung của mảng, hành vi là không xác định.

Theo 6.3.2.1 Array subscripting dereferencing và mảng subscripting là giống hệt nhau:

Định nghĩa của các nhà điều hành subscript [] là E1 [E2] là giống với (* ((E1) + (E2))) .

Sự khác biệt của mảng vs con trỏ là:

  • con trỏ không có thông tin về kích thước bộ nhớ đằng sau nó (không có cách nào di động để có được nó)
  • một loạt các loại không đầy đủ không thể được xây dựng
  • loại con trỏ có thể được lấy từ một loại không đầy đủ
  • con trỏ có thể xác định cấu trúc đệ quy (đây là kết quả của hai cấu hình trước)

Các liên kết này có thể hữu ích cho vấn đề này:

+3

"con trỏ liên tục đến char" không phải là "con trỏ đến hằng số char"? Sau khi tất cả con trỏ có thể sửa đổi được. – elmo

+0

Đã sửa lỗi. Cảm ơn. –

+1

"và khởi tạo nó để trỏ đến một đối tượng có loại '' mảng liên tục của char ''". Trong C++, nhưng không phải trong C. Trong C, đối tượng '" abc "' có kiểu 'char [4]'. Tuy nhiên, cố gắng sửa đổi nó là UB. Có thể là tốt để chỉ ra sự khác biệt. –

0

Các mảng thực tế tương đương với con trỏ liên tục.

Ngoài ra, char c [] cấp phát bộ nhớ cho mảng, có địa chỉ cơ sở là c. Không có bộ nhớ riêng biệt được phân bổ để lưu trữ địa chỉ đó.

Viết char * c cấp phát bộ nhớ cho chuỗi có địa chỉ cơ sở được lưu trữ trong c. Ngoài ra, một vị trí bộ nhớ riêng biệt được sử dụng để lưu trữ c.

+0

Mảng không phải là con trỏ. – tenfour

+0

@tenfour: http://www.cplusplus.com/doc/tutorial/pointers/ – Cygnus

+1

Chúng tôi rõ ràng là cả hai đều biết những gì chúng tôi đang nói về, nhưng nó là liều lĩnh để nói rằng họ là tương đương. Mảng phân rã thành con trỏ, nhưng nó không giống như * là con trỏ. Trong cùng một cách 'MyClass' không tương đương với' int', ngay cả khi có một chuyển đổi ẩn. – tenfour

2

char [] biểu thị kiểu "mảng không rõ ràng buộc của char", trong khi char * biểu thị kiểu " trỏ đến char ". Như bạn đã quan sát, khi định nghĩa của một biến kiểu "mảng không xác định ràng buộc của char" được khởi tạo với một chuỗi chữ, kiểu được chuyển thành "mảng [N] của char" trong đó N là kích thước thích hợp. Điều tương tự cũng áp dụng chung cho việc khởi tạo từ tập hợp mảng:

int arr[] = { 0, 1, 2 }; 

arr được chuyển thành loại "mảng [3] của int".

Trong một định nghĩa kiểu người dùng định nghĩa (struct, class hoặc union), mảng-of-biết-bound loại đều bị cấm trong C++, mặc dù trong một số phiên bản của C họ được phép như thành viên cuối cùng của một struct , nơi chúng có thể được sử dụng để truy cập bộ nhớ được cấp phát qua phần cuối của cấu trúc; cách sử dụng này được gọi là "mảng linh hoạt".

Xây dựng kiểu đệ quy là một sự khác biệt; người ta có thể xây dựng con trỏ đến và mảng của char * (ví dụ: char **, char (*)[10]) nhưng điều này là bất hợp pháp đối với mảng không rõ ràng; người ta không thể viết char []* hoặc char [][10] (mặc dù char (*)[]char [10][] vẫn ổn).

Cuối cùng, chứng chỉ cv hoạt động khác nhau; được đưa ra typedef char *ptr_to_chartypedef char array_of_unknown_bound_of_char[], cv-qualifiying phiên bản con trỏ sẽ hoạt động như mong đợi, trong khi cv-qualifying phiên bản mảng sẽ di chuyển cv-qualification thành loại phần tử: nghĩa là, const array_of_unknown_bound_of_char tương đương với const char [] và không phải là hư cấu char (const) []. Điều này có nghĩa là trong định nghĩa hàm, trong đó phân rã mảng-con trỏ hoạt động trên các đối số trước khi tạo mẫu thử nghiệm,

void foo (int const a[]) { 
    a = 0; 
} 

là hợp pháp; không có cách nào để làm cho tham số mảng không xác định bị ràng buộc không thể sửa đổi được.

1

Toàn bộ lô trở nên rõ ràng nếu bạn biết rằng

Declaring a pointer variable does not create the type of variable, it points at. It creates a pointer variable.

Vì vậy, trong việc sử dụng, nếu bạn cần một chuỗi sau đó bạn cần phải xác định một loạt các nhân vật và một con trỏ có thể được sử dụng sau này.

7
char c[] = "test"; 

này sẽ tạo ra một mảng chứa các thử nghiệm chuỗi, do đó bạn có thể chỉnh sửa/thay đổi bất kỳ nhân vật, nói

c[2] = 'p'; 

nhưng,

char * c = "test" 

Đó là một chuỗi chữ - đó là một const char.
Vì vậy, thực hiện bất kỳ sửa đổi nào đối với chuỗi ký tự này sẽ cho chúng ta sự phân đoạn. Vì vậy,

c[2] = 'p'; 

là bất hợp pháp ngay bây giờ và cho chúng tôi segfault.

+1

'' char * c = "test" '' là một mã C xấu tạo ra cảnh báo: chuyển đổi không được chấp nhận từ hằng số chuỗi thành 'char *' [-Wwrite-strings]. Sử dụng '' const char * '' để thay thế. –

+1

vâng, tôi chỉ đưa ra một sự khác biệt khác mà anh ta đang hỏi – neel

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