2

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

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

char line[MAX_LINE_LEN];

确切地?我知道前者是指针,后者是数组,但系统如何分辨?内存是如何分配/存储的?

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

4

4 回答 4

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

这是一种糟糕的风格;您不需要malloc在 C 中进行转换。让我们将其分为两部分,因为这样更容易描述和比较:

char *line;声明一个指向名为 的 char 的指针line。您可以将其分配为指向一个对象(或什么都没有)。sizeof一个对象是它的类型的大小,所以是sizeof (line)sizeof (char *)它因系统而异。&line是 a 的地址char *,其类型为char **(指向 char 指针的指针)。它的存储时间取决于它的声明位置:

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

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

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

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在这种情况下,地址是 a(指向字符char (*)[MAX_LINE_SIZE]数组的指针)。MAX_LINE_SIZE

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

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

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

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

我知道前者是指针,后者是数组,但系统如何分辨?

如前所述,当在需要指针的地方使用数组表达式时,它会转换为指针表达式。例如,arrayinarray[x]转换为pointerin pointer[x]。你在问什么?为什么它需要知道数组和指针之间的区别?

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

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

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

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

int main(void) {
    int i = 42;
    int *p = &i;
}
于 2013-04-27T10:42:39.197 回答
2

理解这一点的最佳资源可能是comp.lang.c 常见问题解答

务实地说,区别在于sizeof操作者的效果。sizeof(pointer)给你一个指针的大小,而sizeof(array)给你......你猜对了。

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

A[X]

根据定义,完全等同于

*(A + X)

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

于 2013-04-27T10:14:50.550 回答
1
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)字节。

于 2013-04-27T10:08:48.160 回答
1

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

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

看看堆栈和堆是什么以及在哪里?详情。

于 2013-04-27T12:57:39.793 回答