在C中,可以在堆上分配一个`char[]`吗?

wn9m85ua  于 2023-11-16  发布在  其他
关注(0)|答案(3)|浏览(104)

我目前正在努力学习C,所以如果这是一个愚蠢的问题,我道歉。之前有很多问题都特别强调了char* != char[]

然而,我能找到的所有堆数组的例子似乎都使用了char*,例如。

char *heap_string = (char *)malloc(50*sizeof(char) +  1);

字符串
所以我的问题是,堆上有可能有一个char[]吗(这有意义吗?)或者char[]只是堆栈对象吗?
(我应该补充一点,我在这里没有具体的目标,我只是想学习语言/理解引擎盖下发生了什么)。

pod7payv

pod7payv1#

char的数组是一个对象,C中的 object 是“执行环境中数据存储的区域,其内容可以表示值”(C 2018 3.15)。所以,当你用malloc分配内存时,该内存可以用作char []。C 2018 7.22.3表示返回的指针(如果成功)可以“用于访问所分配的空间中的这样的对象或这样的对象的数组(直到空间被显式地解除分配)”。
如果在被指向的位置有一个char数组,我们应该选择这样使用它,问题是我们通常通过指向它们的单个元素来使用数组。在成功的char *p = malloc(50);之后,在p处有一个50个char的数组,我们可以使用p[i]访问它的元素。
如果要使用char []char [50]类型引用数组,可以使用指向该类型的指针,使用char (*p)[] = malloc(50);char (*p)[50] = malloc(sizeof *p);
由于历史原因,C语言主要是通过数组的单个元素来访问数组的,而不是作为整个对象来访问。
这并没有给予一个数组的名字;你没有一个变量A作为数组。但是,你可以使用*p,就像它是数组的名字一样。这个区别是很小的;你可以为数组命名A,而你不能用*p
一个区别是数组的大小。如果你有一些数组声明为静态或自动而不是动态分配,你可以用sizeof A来获取它的大小。通过上面的char (*p)[50]声明,你也可以用sizeof *p来获取大小。通过char *pchar (*p)[]声明,你不能用sizeof得到数组的大小。然而,这通常没有关系,因为对于动态分配的数组,程序通常自己处理它的大小。它必须把大小传递给malloc,所以当数组被创建时,它就有了这个值,如果需要的话,只需要保留它以供其他用途。所以一个动态分配数组的程序不需要在它们上使用sizeof

ih99xse1

ih99xse12#

可以在堆上放置一个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]数组(或者,如果我们为它分配了空间的话)。
一般来说,开发人员会发现指向数组的 * 指针 * 非常混乱,几乎肯定会写bug,所以没有人这样做。更糟糕的是,现在代码 * 只 * 适用于char[50],而不是任何其他长度,所以代码也不太灵活,功能也不太强大。所以,再一次,没有人这样做。
还要注意,因为它是char[50],所以没有多余的空间来放置尾随的空字符,就像您在示例代码中看到的那样。

hm2xizp9

hm2xizp93#

char*char[]确实是不同的东西。没有指定大小的char[]是不完整的数组,因为它没有指定大小。通常我们不能使用这样的数组,char arr[];会导致编译器错误。
然而,作为一个特殊的规则,如果我们提供了一个初始化器,那么数组将获得一个合适的大小来包含初始化器列表中的所有项:char array[] = "hi"实际上给了我们一个char[3](2个字母+空终止符)。
另一个特殊的规则是,当我们写一个数组作为函数参数时,该参数被隐式调整为指向该数组第一项的指针。因此,我们可以写void func (char array[]),然后array变成char*。这种调整(有时称为“数组衰减”)发生,无论我们为数组参数指定什么大小,这就是为什么C允许空的[]
由于malloc调用不符合上述char[]语法的任何一种用法,因此我们不能真正指定动态声明的不完整类型的数组。然而,我们可以创建一个指向这样一个数组的指针:

char (*heap_string)[] = malloc(50*sizeof(char) +  1);

字符串
由于(sizeof(char))保证总是1,我们也可以只做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],这将是丑陋和繁琐的。

相关问题