Một con trỏ và một mảng là những thứ khác nhau. Một con trỏ tới một kiểu chứa địa chỉ nơi một biến kiểu khai báo được cấp phát.
Mảng thuộc loại là không gian bộ nhớ trong đó các biến của loại được khai báo là được lưu trữ liên tục.
Bây giờ bạn đang khai báo. Không có sự mơ hồ (ngay cả khi không hiển nhiên) trong các khai báo C. Trong trường hợp Một bạn đã tuyên bố:
int **M1;
Đây không phải là một mảng 2d, thậm chí không phải là một monodimensional. Bạn đang khai báo một biến, M!
, như một con trỏ trỏ đến một con trỏ khác đến một int. Trong từ phẳng M1
sẽ giữ địa chỉ của một biến khác mà lần lượt giữ địa chỉ của nơi trong bộ nhớ được lưu trữ một số nguyên. Bây giờ thực hiện:
M1 = (int **)malloc(m * sizeof(int *));
Bạn gán cho M1
địa chỉ của một khu vực bộ nhớ có thể lưu trữ lên đến m con trỏ số nguyên tiếp giáp, quyền truy cập vào bộ nhớ được trỏ bởi M1
, và liên tiếp các địa điểm hoạt động như một truy cập mảng (nhưng không phải).Đây là nhiều hay ít tương đương với việc khai báo tĩnh:
int *[m]; //an array of pointers to int
Sau đó gán mỗi yếu tố này pseudo-mảng một bộ nhớ lưu trữ cho d
số nguyên tiếp giáp:
for (int i=0; i<m; i++)
{
M1[i] = (int *)malloc(d * sizeof(int));
}
bây giờ bạn có chỗ để lưu trữ d
liên tiếp số nguyên bắt đầu tại địa chỉ được lưu trong M1[i]
cho i = 0-> d-1.
Điều gì sẽ xảy ra khi bạn cố truy cập một giá trị sử dụng các bảng con: M1[a][b]
? Trình biên dịch truy lục địa chỉ được chỉ bởi M1
và sử dụng chỉ số đầu tiên (a
), truy xuất nội dung được chỉ bởi địa chỉ trong vị trí atht của mảng con trỏ. Điều này trỏ đến số nguyên đầu tiên của không gian con mà chúng tôi đã phân bổ để giữ d
int liên tục. Đây thực sự là một mảng intodimensional của int. Áp dụng các subscript thứ hai cho nó trình biên dịch cuối cùng lấy số nguyên cần thiết. Cose để một mảng địa chỉ bidimensional, nhưng không có chuối! Nó không phải là một mảng giá trị của int. :-)
Trong trường hợp B bạn đang tuyên bố một con trỏ đến một mảng monodimensional của int, mà bạn đang gán đủ không gian để giữ mảng hai chiều của bạn. Bởi vì trong C không tồn tại khái niệm về mảng đa chiều, nhưng một nguyên tắc cơ bản của mảng của mảng của mảng .... vv (ad-libitum), tuyên bố:
int (*M1)[m] = malloc(sizeof(int[m][d]));
như một con trỏ đến modimensiional mảng có không gian được phân bổ cho một mảng gồm các phần tử [m][d]
đã thực hiện thủ thuật.
Nhưng tất nhiên cả hai giải pháp đều sai!
Bạn đang sử dụng các hiệu ứng phụ để có được những gì bạn muốn, nhưng sử dụng thay thế những gì bạn đã tuyên bố cần: một mảng giá trị của int.
Giải pháp chính xác là để xác định một con trỏ đến một mảng hai chiều các số nguyên nơi chỉ subscript đầu tiên được yêu cầu:
int (*M1)[][m]; //declare a pointer to a real array
M1 = malloc(m * d * sizeof(int)); //Allocate room for bidimensional array
for (int i=0; i<m; i++)
for (int j=0; j<d; j++)
{
(*M1)[i][j] = (i*100)+j; //Fill elements with something using bidimensional subscripting
}
for (int i=0; i<m; i++)
for (int j=0; j<d; j++)
{
printf("[%d][%d]=%d\n", i, j, (*M1)[i][j]); //Check back data...
}
Bây giờ có một cái nhìn vào những gì sẽ xảy ra nếu bạn đi ra ngoài giới hạn trong 3 các trường hợp. Trong trường hợp Một nếu bạn nhận được ngoài giới hạn với subscript đầu tiên bạn sẽ thu thập một con trỏ sai rằng sẽ gây ra ngay lập tức một bộ nhớ lỗi, trong trường hợp B bạn sẽ có lỗi bộ nhớ chỉ khi bạn đi ra khỏi quá trình bộ nhớ địa chỉ, giống nhau cho giải pháp đúng. Điều này sẽ trả lời cho câu hỏi của bạn.
cuối, bởi vì chúng ta đang nói về misunderstandigs về mảng và con trỏ, đừng hiểu sai tiêu chuẩn ISO 9899: 2011§6.7.6.3/7 nói rằng:
Một tuyên bố của một tham số như '' mảng loại '' sẽ được điều chỉnh thành '' con trỏ đủ điều kiện để nhập '', trong đó các loại vòng loại (nếu có) là các giá trị được chỉ định trong [và] của dẫn xuất loại mảng.Nếu từ khóa tĩnh cũng xuất hiện trong [và] của loại mảng dẫn xuất, sau đó cho mỗi cuộc gọi đến hàm, giá trị của đối số thực tế tương ứng sẽ cung cấp quyền truy cập vào thành phần đầu tiên của một mảng có ít nhất là nhiều phần tử được chỉ định bởi biểu thức kích thước .
Nó chỉ đơn giản nói rằng mảng sẽ chỉ được thông qua bằng cách tham khảo (tự động điều chỉnh bởi trình biên dịch), không bao giờ theo giá trị (có nghĩa là pháp luật cho struct tức). Bạn không được yêu cầu cung cấp bất kỳ con trỏ nào đủ điều kiện thay vì một mảng trong cuộc gọi hàm hoặc chương trình sẽ sụp đổ (Tuyên bố tham số là '' mảng kiểu '' sẽ được điều chỉnh thành '' con trỏ đủ điều kiện để nhập '' - có nghĩa là sẽ được điều chỉnh bởi trình biên dịch, không phải bởi bạn). Các trường hợp như char *[]
và char **
hoạt động vì lý do được báo cáo ở trên, không phải vì việc trao đổi chúng là hợp pháp!
Mã A hoạt động hoàn hảo cho tôi. Môi trường của bạn là gì? – blue112
Trường hợp bạn nhận được lỗi phân đoạn chính xác ở đâu? –
[Xin đừng bỏ kết quả của 'malloc()'] (http://stackoverflow.com/a/605858/3233393). – Quentin