我目前正在努力学习C,所以如果这是一个愚蠢的问题,我道歉。之前有很多问题都特别强调了char* != char[]
。
然而,我能找到的所有堆数组的例子似乎都使用了char*
,例如。
char *heap_string = (char *)malloc(50*sizeof(char) + 1);
字符串
所以我的问题是,堆上有可能有一个char[]
吗(这有意义吗?)或者char[]
只是堆栈对象吗?
(我应该补充一点,我在这里没有具体的目标,我只是想学习语言/理解引擎盖下发生了什么)。
3条答案
按热度按时间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 *p
或char (*p)[]
声明,你不能用sizeof
得到数组的大小。然而,这通常没有关系,因为对于动态分配的数组,程序通常自己处理它的大小。它必须把大小传递给malloc
,所以当数组被创建时,它就有了这个值,如果需要的话,只需要保留它以供其他用途。所以一个动态分配数组的程序不需要在它们上使用sizeof
。ih99xse12#
可以在堆上放置一个
char[50]
,但它令人讨厌和困惑,并且没有特别的意义。在我的脑海中,我相信语法是:字符串
请注意,在您的代码中,
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]
,所以没有多余的空间来放置尾随的空字符,就像您在示例代码中看到的那样。hm2xizp93#
char*
和char[]
确实是不同的东西。没有指定大小的char[]
是不完整的数组,因为它没有指定大小。通常我们不能使用这样的数组,char arr[];
会导致编译器错误。然而,作为一个特殊的规则,如果我们提供了一个初始化器,那么数组将获得一个合适的大小来包含初始化器列表中的所有项:
char array[] = "hi"
实际上给了我们一个char[3]
(2个字母+空终止符)。另一个特殊的规则是,当我们写一个数组作为函数参数时,该参数被隐式调整为指向该数组第一项的指针。因此,我们可以写
void func (char array[])
,然后array
变成char*
。这种调整(有时称为“数组衰减”)发生,无论我们为数组参数指定什么大小,这就是为什么C允许空的[]
。由于
malloc
调用不符合上述char[]
语法的任何一种用法,因此我们不能真正指定动态声明的不完整类型的数组。然而,我们可以创建一个指向这样一个数组的指针:字符串
由于(
sizeof(char)
)保证总是1,我们也可以只做malloc(50+1)
。或malloc(sizeof(char[50+1]))
。所有等价。这里
heap_string
是一个指向不完整类型的笨重指针。这意味着我们每次想要访问数组时都必须写入(*heap_string)[i] = 'a';
。这很不方便,也很难阅读,因此约定是使用char* heap_string = malloc(...
。然而,上述语法对于多维数组变得很方便。然后我们可以跳过最左边的数组边界:
型
然后我们可以用
arr[i][j][k]
来访问这个数组。在指针中跳过一个维度意味着我们不必做(*arr)[i][j][k]
,这将是丑陋和繁琐的。