为什么`int(*array)[10] = malloc(...);`有效的C代码?

Cir*_*red 6 c arrays malloc syntax pointers

我最近遇到了以下情况:

int ( *array )[10] = malloc(...);
Run Code Online (Sandbox Code Playgroud)

基于我对C语法和语法的理解,这看起来像废话.看起来像正在创建(并初始化)一个数组,其中取消引用指针的值作为其标识符.

我理解指向数组的指针,并且通常至少使用malloc()在堆上分配它们.例如,这是有道理的:

int *array = malloc(sizeof (int*) * 10);
Run Code Online (Sandbox Code Playgroud)

...但是,第一个例子看起来像不应该编译的乱码.显然,我错过了一些东西.

当我学习C时,我觉得我看到了回来的东西,但谷歌搜索并没有帮助我理解.使用术语"指针","解除引用"和"初始化"进行搜索显然会给结果带来污染,这些结果会跟踪人们如何跟踪解除引用等等.我希望人类可以帮助我.

das*_*ght 11

这是完全合法的 - 您正在分配一个指向十个整数数组的指针.

如果您只需要一个阵列*,那么...在您的完成中malloc使用的好方法是:sizeof(*array)

int ( *array )[10] = malloc(sizeof(*array));
Run Code Online (Sandbox Code Playgroud)

例如,这是有道理的: int *array = malloc(sizeof (int*) * 10);

这是一个ints 数组.第一种语法允许您创建一个ints 数组数组- 例如

int ( *array )[10] = malloc(50*sizeof(*array));
Run Code Online (Sandbox Code Playgroud)

给你一个50×10阵列.

*这里有一个很好的解释,为什么sizeof(*array)这是分配大小的好方法.


Joh*_*ode 7

int ( *array )[10] = malloc(...);
Run Code Online (Sandbox Code Playgroud)

声明array为指向10元素数组的指针int; 使用malloc调用结果初始化指针.这和写作一样

int (*array)[10] = NULL;
array = malloc( ... );
Run Code Online (Sandbox Code Playgroud)

记住这一点

T *p = malloc( sizeof *p * N );
Run Code Online (Sandbox Code Playgroud)

将分配足够的存储空间来保存N实例T并将结果指针值分配给p.这适用于任何类型T.

如果我们用T类似的数组类型替换R [10],我们得到

R (*p)[10] = malloc( sizeof *p * N );
Run Code Online (Sandbox Code Playgroud)

语义完全相同,所有改变的都是类型p; 我们正在分配足够的存储来保存N实例R [10].

基于我对C语法和语法的理解,这看起来像废话.

然后你需要重新审视这种理解.C的声明语法是很多更复杂的比大多数人的想法.请参阅在线C 2011标准的第6.7节.

编辑

以下是语法分解的方式:

int     (   *         array    )[     10     ]  = malloc( ... );
^       ^   ^           ^      ^^     ^      ^  ^ ^
|       |   |           |      ||     |      |  | |
|       | pointer     direct   ||     |      |  | assignment
|       |   |       declarator ||     |      |  | expression
|       |   |           |      ||     |      |  | |
|       |   +-----+-----+      ||     |      |  | |
|       |         |            ||     |      |  | |
|       |     declarator       ||     |      |  | |
|       |         |            ||     |      |  | |
|       +---------+------------+|     |      |  | |
|                 |             |     |      |  | |
|               direct          | assignment |  | |
|             declarator        | expression |  | |
|                 |             |     |      |  | |
|                 +-------------+-----+------+  | |
|                               |               | |
|                             direct            | |
|                           declarator          | |
type                            |               | |
specifier                   declarator          | initializer
|                               |               | |
|                               +---------------+-+
|                                               |
|                                          init-declarator
declaration                                     |
specifiers                              init-declarator-list
|                                               |
+----------------------+------------------------+
                       |
                   declaration
Run Code Online (Sandbox Code Playgroud)

我略去中间步骤10assignment-expressionmalloc(...)initializer,因为他们刚刚制作图表难以阅读.


Vla*_*cow 5

数组的地址和第一个元素的地址彼此相等.

所以如果你有一个数组,例如

int array[10];
Run Code Online (Sandbox Code Playgroud)

那么指针的值pq

int *p = array;
Run Code Online (Sandbox Code Playgroud)

int ( *q )[10] = &array;
Run Code Online (Sandbox Code Playgroud)

尽管指针的类型不同,但它们将是相同的.

这些值等于数组的第一个元素的地址.在第一种情况下,元素的类型是int在第二种情况下元素的类型是int[10]但在这两种情况下,它是分配的内存范围的地址,不会根据它在C中的解释方式而改变.

您可以通过以下方式p从指针获取指针q

p = *q;
Run Code Online (Sandbox Code Playgroud)

考虑到该函数malloc返回一个指向void的指针,该指针的类型void *在C中可以隐式转换为任何其他类型的指针.

因此这些陈述

int ( *array )[10] = malloc( 10 * sizeof( int ) );
Run Code Online (Sandbox Code Playgroud)

int *array = malloc( 10 * sizeof( int ) );
Run Code Online (Sandbox Code Playgroud)

在C中有效

另一方面,函数free再次使用类型的指针作为其参数void *.并且可以将其他类型的指针隐式转换为该类型void *.


归档时间:

查看次数:

813 次

最近记录:

9 年,5 月 前