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 *)
,因系统而异。 &line
是char *
的地址,其类型为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
声明,没有任何限定符,例如static
。 p
指向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]
, A
或X
( 任何一个 ) 中的一个必须是指针或数组。
答案就在那里,堆和堆栈问题。
数组,指针,局部变量是堆栈对象,而堆对象是使用malloc / free方法。
只需看一下堆栈和堆的内容和位置? 详情。