提问人:gowerc 提问时间:11/14/2023 最后编辑:Daniel A. Whitegowerc 更新时间:11/14/2023 访问量:123
在 C 中,是否可以在堆上分配“char[]”?
In C is it possible to allocate a `char[]` on the heap?
问:
我目前正在尝试学习 C,所以如果这是一个愚蠢的问题,我深表歉意。之前有许多问题特别强调了这一点。char* != char[]
但是,我能找到的所有堆数组示例似乎都使用例如char*
char *heap_string = (char *)malloc(50*sizeof(char) + 1);
所以我的问题是;是否有可能在堆上有一个(这甚至有意义吗?还是只是堆栈对象?char[]
char[]
(我应该补充一点,我在这里没有具体的目标,我只是想学习语言/了解引擎盖下发生的事情)。
答:
可以把一个放在堆上,但它令人讨厌和混乱,而且不是特别有意义。在我的脑海中,我相信语法是:char[50]
char (*heap_string)[50] = (char (*)[50])malloc(50*sizeof(char));
请注意,在您的代码中,类型是“指向未知数的指针”。在此代码中,类型为 “指向未知数 ” 的指针。所以指的是第一个数组,而两者都指的是第二个数组(或者,如果我们为它分配了空间的话)。heap_string
char
heap_string
char[50]
heap_string[0]
char[50]
heap_string[1]
heap_string+1
char[50]
一般来说,开发人员发现指向数组的指针非常混乱,并且几乎肯定会写出错误,所以没有人这样做。更糟糕的是,现在代码仅适用于 ,而不适用于任何其他长度,因此代码也不太灵活且功能较弱。所以再说一次,没有人这样做。char[50]
另请注意,由于它是 ,因此没有额外的空间来容纳尾随的 null 字符,就像您在示例代码中所做的那样。char[50]
评论
malloc()
char (*heap_string)[50] = malloc(sizeof *heap_string);
gcc
Apple clang version 14.0.3
.C
.c
数组是对象,C 中的对象是“执行环境中的数据存储区域,其内容可以表示值”(C 2018 3.15)。因此,当您使用 分配内存时,该内存可以用作 .C 2018 7.22.3 表示,返回的指针(如果成功)可以“用于访问分配的空间中的此类对象或此类对象的数组(直到空间被显式解除分配)”。char
malloc
char []
假设在指向的位置有一个数组,如果我们选择这样使用它,问题是我们通常通过指向它们的各个元素来使用数组。成功后,有一个 50 的数组 ,我们可以使用 访问它的元素。char
char *p = malloc(50);
char
p
p[i]
如果要使用 或 类型引用数组,可以使用指向该类型的指针 来执行此操作,请使用 或 。char []
char [50]
char (*p)[] = malloc(50);
char (*p)[50] = malloc(sizeof *p);
有了这些,在不访问其各个元素的情况下使用数组的方法有限。由于历史原因,C 语言被设计为主要通过其单个元素访问数组,而不是作为整个对象。
这不会为您提供数组的名称;您没有作为数组的某个变量。但是,您可以将其作为数组的名称使用。这种差异无关紧要;对于数组的名称,您几乎无法执行 。A
*p
A
*p
一个区别在于采用数组的大小。如果将某个数组声明为静态或自动数组,而不是动态分配的数组,则可以使用 .使用上面的声明,您还可以使用 .使用 or 声明时,无法使用 .但是,这通常无关紧要,因为对于动态分配的数组,程序通常自行处理其大小。它必须将大小传递给 ,因此在创建数组时它具有该值,并且只需要根据需要保留它以供其他用途。因此,动态分配数组的程序不需要在数组上使用。sizeof A
char (*p)[50]
sizeof *p
char *p
char (*p)[]
sizeof
malloc
sizeof
评论
malloc()
malloc
p[idx]
*(p + idx)
的确,和是不同的东西。未指定大小的数组是不完整的数组,因为它没有指定大小。通常我们不能使用这样的数组,会导致编译器错误。char*
char[]
char[]
char arr[];
然而,作为一个特殊规则,如果我们提供一个初始值设定项,那么数组将获得一个合适的大小来包含初始值设定项列表中的所有项目:实际上给了我们一个(2 个字母 + null 终止符)。char array[] = "hi"
char[3]
另一个特殊规则是,当我们将数组编写为函数参数时,该参数会隐式调整为指向该数组第一项的指针。因此,我们可以写成,然后变成一个.无论我们为数组参数指定什么大小,这种调整(有时称为“数组衰减”)都会发生,这就是为什么 C 允许在那里使用空。void func (char array[])
array
char*
[]
由于调用不符合上述语法的任何一种用法,因此我们无法真正指定动态声明的不完整类型的数组。但是,我们可以创建一个指向此类数组的指针:malloc
char[]
char (*heap_string)[] = malloc(50*sizeof(char) + 1);
由于 ( 保证始终为 1,我们也可以这样做。或。都是等效的。sizeof(char)
malloc(50+1)
malloc(sizeof(char[50+1]))
这是一个繁琐的指向不完整类型的指针。这意味着每次我们想要访问数组时都必须写入。这很不方便,也很难阅读,因此召集只是使用。heap_string
(*heap_string)[i] = 'a';
char* heap_string = malloc(...
然而,上述语法对于多维数组来说非常方便。然后,我们可以跳过最左边的数组边界:
int (*arr)[2][3] = malloc( sizeof(arr[1][2][3]) );
然后我们可以以 .在指针中跳过一个维度意味着我们不必这样做,这将是丑陋和繁琐的。arr[i][j][k]
(*arr)[i][j][k]
评论
void func (char x[])
void func (char * x)
char (*)[N]
char[]
char*
评论
malloc()
char[]
char[N]
N
char[]
malloc
char[N]
char[N]
char*
char *heap_string = malloc(sizeof(char[50 + 1]));
char *heap_string = malloc(50 + 1);