C中的数组和指针有什么区别?

这个问题可能听起来很愚蠢,但我并不确定。 我的意思是,有什么区别:

char* line = (char*) malloc(MAX_LINE_LEN); 

 char line[MAX_LINE_LEN]; 

究竟? 我知道前者是一个指针而后者是一个数组,但系统如何区分呢? 如何分配/存储内存?

另外,为什么可以在声明为指针时删除line占用的内存,而不是当它是数组时? 我认为数组存储在其他地方,系统会在超出范围时自动释放内存,这在处理指针时不会发生,所以你必须自己删除它。 我错了吗?

 char* line = (char*) malloc(MAX_LINE_LEN); 

这种风格很差; 你不需要在C中malloc 。让我们把它分成两部分,因为它更容易描述和比较:

char *line; 声明一个指向char命名line的指针。 您可以将其指定为指向对象(或不指向任何对象)。 对象的大小是它的类型的大小,因此sizeof (line)sizeof (char *) ,因系统而异。 &linechar *的地址,其类型为char ** (指向char的指针)。 它的存储持续时间取决于它的声明位置:

  • 如果它在任何函数之外声明,它具有静态存储持续时间,持续时间为程序的生命周期。 具有静态存储持续时间的对象初始化为0 ,除非存在显式初始化(​​例如,在您的情况下)。 0是一个null pointer constant ,表示如果在没有初始化函数的函数之外声明它,则该对象将指向任何内容。

  • 如果它在一段代码中声明,它具有自动存储持续时间,持续到执行到达该代码块的末尾。 具有自动存储持续时间的对象必须在使用之前显式初始化或分配,因为它们的值否则是不确定的。

您的初始化为其分配了一个值,因此无论如何它都不会开始不确定。 malloc返回一个指向具有动态存储持续时间的对象的指针,这意味着指针指向的对象将持续存在,直到它明确free为止。

想想这一 line就像邮件信封上的邮政编码一样; 你可以在那里写一些东西,这些东西将指示你可以找到对象(和人)的位置。 邮政编码不会告诉您有关对象(或人员)大小的任何信息。


 char line[MAX_LINE_LEN]; 

这声明了一个MAX_LINE_LEN字符数组。

  • 如果在任何函数之外声明,它具有静态存储持续时间并且整个数组是零填充的。

  • 如果在函数或代码块中声明,它具有自动存储持续时间,并且数组中的值是不确定的; 它们需要初始化(例如char line[MAX_LINE_SIZE] = { 0 };将初始化所有这些)或分配给(例如, line[0] = '\0';将分配给数组的第一个元素) ‘使用过。

类型为char[MAX_LINE_SIZE] ,因此大小将为sizeof (char[MAX_LINE_SIZE]) ,反映为您可以通过指定的元素数量查看。 在这种情况下, &line的地址是char (*)[MAX_LINE_SIZE] (指向MAX_LINE_SIZE字符数组的指针)。

这个不能像上面那样重新分配,因此它与我们的邮政编码示例不同。 当数组用于编译器需要指针的位置时,该数组将被隐式转换为指向第一个元素的指针。 例如,让我们考虑一下:

 strcpy(line, "Hello, world!"); 

函数原型char *strcpy(char *restrict s1, const char *restrict s2); ,告诉我们strcpy接受两个char *指向char的指针 )参数。 在该示例中,其中一个参数是char[MAX_LINE_LEN] ,另一个是char[14] 。 两者都转换为char *

这个数组到指针的转换解释了为什么char *line; line = "hello"; char *line; line = "hello"; 有效,而char line[MAX_LINE_LEN]; line = "hello"; char line[MAX_LINE_LEN]; line = "hello"; 不是。 您无法更改转换产生的指针。

我知道前者是一个指针而后者是一个数组,但系统如何区分呢?

如前所述,当数组表达式在预期指针的位置使用时,它将转换为指针表达式。 例如, array array[x]中的array[x]转换为pointer[x]中的pointer[x] 。 你在问什么? 为什么需要知道数组和指针之间的区别?

我认为数组存储在其他地方,当系统超出范围时,系统会自动释放内存,

是。 我之前解释了不同的存储持续时间。

当你处理指针时不会发生这种情况,所以你必须自己删除它。 我错了吗?

是。 你将指针的概念与存储持续时间的概念混淆了。 int *p = malloc(sizeof *p); p被初始化为指向具有动态存储持续时间的int 。 直到free(p); int才会被销毁free(p); 叫做。 但是,下面的两个变量都具有自动存储持续时间,因为它们在main声明,没有任何限定符,例如staticp指向i ; p是一个指针。 不要free p,因为它不指向具有动态存储持续时间的对象。 free仅定义为销毁具有动态存储持续时间的对象。

 int main(void) { int i = 42; int *p = &i; } 
 char* line; 

在堆栈上分配指针。 当程序计数器超出本声明的范围时,它将自动释放。

 line = (char*) malloc(MAX_LINE_LEN); 

在堆上动态分配MAX_LINE_LEN个字节。 确切地说,您应该以这种方式使用malloc

 line = malloc(MAX_LINE_LEN * sizeof(char)); 

稍后你应该调用free(line)来释放这个堆内存。

sizeof(line)将返回指针占用的字节数(通常为4或8个字节)。


 char line[MAX_LINE_LEN]; 

在堆栈上分配MAX_LINE_LEN字符。 当程序计数器超出本声明的范围时,它将自动释放。

sizoef(line)将返回MAX_LINE_LEN * sizeof(char)字节。

可能是理解这一点的最佳资源是comp.lang.c FAQ 。

实际上,区别在于sizeof运算符的效果。 sizeof(pointer)给出sizeof(pointer)的大小,而sizeof(array)给你……你猜对了。

当作为函数参数传递时,数组名称会衰减为指向第一个元素的指针(丢失sizeof信息)。 在正常表达式中,它的行为就像它衰减到指针一样,因为数组语法是根据等效指针操作定义的。 (事实上​​,早期的C编译器声明了带有identifier[]指针。)

 A[X] 

根据定义,它完全等同于

 *(A + X) 

需要注意的是,在A[X]AX ( 任何一个 ) 中的一个必须是指针或数组。

答案就在那里,堆和堆栈问题。

数组,指针,局部变量是堆栈对象,而堆对象是使用malloc / free方法。

只需看一下堆栈和堆的内容和位置? 详情。