Trong trường hợp int (*a)[]
, sizeof *a
không hoạt động vì một lý do: không có phần tử nào được tính cho mảng. Không có phần tử đếm, kích thước không thể được tính toán.
Kết quả là, bất kỳ số học con trỏ nào trên a
sẽ không hoạt động vì nó được xác định theo kích thước của một đối tượng. Vì kích thước không xác định cho mảng, bạn không thể sử dụng số học con trỏ trên chính con trỏ. ký hiệu mảng được định nghĩa về con trỏ số học, vì vậy sizeof a[0][0]
(hoặc bất kỳ biểu hiện liên quan đến a[n]
sẽ không hoạt động trong khi sizeof (*a)[0]
chí
này có hiệu quả có nghĩa là bạn có thể làm rất ít với con trỏ Những điều chỉ được phép là:..
- dereferencing con trỏ bằng cách sử dụng unary
*
hành
- đi qua các con trỏ đến một chức năng (kiểu của tham số chức năng phải là một mảng của mảng hoặc một con trỏ đến một mảng)
- nhận được si ze của con trỏ (và liên kết hoặc loại, nếu trình biên dịch của bạn hỗ trợ một trong hai hoặc cả hai)
- gán con trỏ đến một loại tương thích
Nếu trình biên dịch của bạn hỗ trợ mảng chiều dài thay đổi (Vlas), và bạn biết kích thước, bạn có thể làm việc xung quanh vấn đề này bằng cách thêm một dòng vào lúc bắt đầu của cơ quan chức năng như trong
void
foo (int (*a0)[], size_t m, size_t n)
{
int (*a)[n] = a0;
...
}
Without Vlas, bạn phải dùng đến một số biện pháp khác.
Điều đáng lưu ý là phân bổ động không phải là yếu tố với int (*)[]
.Một mảng các mảng phân rã thành một con trỏ tới một mảng (như chúng ta có ở đây), vì vậy chúng có thể hoán đổi cho nhau khi chuyển chúng đến một hàm (sizeof
và bất kỳ từ khóa nào là toán tử, chứ không phải chức năng). Điều này có nghĩa là mảng được trỏ đến phải được phân bổ tĩnh: khi một mảng phân rã thành con trỏ, không có phân rã nào xảy ra, vì vậy bạn không thể nói con trỏ tới mảng (int (*)[]
) giống như con trỏ trỏ tới một con trỏ (int **
)). Nếu không trình biên dịch của bạn sẽ vui vẻ cho phép bạn vượt qua int [3][3]
đến một hàm chấp nhận int **
thay vì muốn tham số của biểu mẫu int (*)[]
, int (*)[n]
, int [][n]
hoặc int [m][n]
.
Do đó, ngay cả khi trình biên dịch của bạn không hỗ trợ Vlas, bạn có thể sử dụng thực tế là một mảng tĩnh được phân bổ có tất cả các yếu tố của nó nhóm lại với nhau:
void foo (int (*a0)[], size_t m, size_t n)
{
int *a = *a0;
size_t i, j;
for (i = 0; i < m; i++)
{
for (j = 0; j < n; j++)
{
// Do something with `a[i * n + j]`, which is `a0[i][j]`.
}
}
...
}
Một cấp phát động một chiều mảng đó là được sử dụng như một mảng hai chiều có cùng thuộc tính, do đó, nó vẫn hoạt động. Chỉ khi thứ nguyên thứ hai được phân bổ động, nghĩa là một vòng lặp như for (i = 0; i < m; i++) a[i] = malloc (n * sizeof *a[i]);
để phân bổ từng mảng phụ riêng lẻ, nguyên tắc này không hoạt động. Điều này là do bạn có một mảng con trỏ (int *[]
, hoặc int **
sau khi phân rã mảng), trỏ đến thành phần đầu tiên của mảng tại một vị trí khác trong bộ nhớ, chứ không phải mảng mảng, giữ tất cả các mục với nhau.
Vì vậy:
không, int (*p)[]
và int **q
không thể được sử dụng trong cùng một cách. p
là một con trỏ đến một mảng, có nghĩa là tất cả các mục được nhóm lại với nhau bắt đầu từ địa chỉ được lưu trữ trong p
. q
là con trỏ trỏ đến con trỏ, có nghĩa là các mục có thể được phân tán tại các địa chỉ khác nhau được lưu trữ trong q[0]
, q[1]
, ..., q[m - 1]
.
sizeof *p
không hoạt động vì p
trỏ đến một mảng có số phần tử không xác định. Trình biên dịch không thể tính toán kích thước của mỗi phần tử, do đó hoạt động trên p
chính nó là rất hạn chế.
Tôi không nghĩ vậy, nhưng tôi không chắc chắn. –
Không. Chỉ mảng và chức năng phân rã. Con trỏ không phân rã. –
(Thật thú vị, 'T (*) []' là một kiểu không đầy đủ mà không bao giờ có thể hoàn thành, không giống 'T []'.) –