【问题标题】:What's the difference between an array and a pointer in C exactly?C中的数组和指针到底有什么区别?
【发布时间】:2013-04-21 11:19:06
【问题描述】:

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

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

char line[MAX_LINE_LEN];

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

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

【问题讨论】:

  • 这个问题eben已经回答过很多次了,请寻找
  • 我不认为这是一个骗局。那更多的是关于(不可)修改的字符串。
  • 另外,您在此处列出的两行之间的主要区别在于,第二个声明是正确的,第一个声明是错误的。
  • 请不要用 dtech 的建议来结束这个问题。另一个问题与这个问题不同。

标签: c arrays pointers memory-management


【解决方案1】:

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

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

详情请看What and where are the stack and heap?

【讨论】:

  • ... 和一个废话。您不能明确声明使用静态存储持续时间声明的对象在堆栈或堆上。他们可能会排队,或者成为登记员。
  • 好吧,我不确定使用 C++ 中的概念是否正确(术语对象)
  • @Daniel 你最近读过the C standard吗?对你来说一个平庸的任务:计算“对象”在该文本中出现的次数。
  • @undefined behavior 好的,我明白了。我还没有阅读最新的标准! :) 似乎有很多地方使用对象术语。
  • @Daniel 不要将类型与存储持续时间混淆。可以使用malloc 分配数组:int (*ptr_to_array)[20] = malloc(sizeof *ptr_to_array); ptr_to_array 现在指向具有动态存储持续时间的数组。 NULL 是一个肯定不属于“堆栈对象”类别的指针。
【解决方案2】:
char* line = (char*) malloc(MAX_LINE_LEN);

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

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

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

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

您的初始化为其分配了一个值,因此无论如何它都不会开始不确定。 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 的地址是char (*)[MAX_LINE_SIZE](指向MAX_LINE_SIZE 字符数组的指针)。

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

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

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

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

我知道前者是指针,后者是数组,但怎么能 系统能分辨出来吗?

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

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

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

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

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

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

【讨论】:

    【解决方案3】:

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

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

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

    A[X]
    

    根据定义,完全等同于

    *(A + X)
    

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

    【讨论】:

      【解决方案4】:
      char* line;
      

      在堆栈上分配指针。当program counter 超出此声明的范围时,它将被自动释放。

      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 字符。当program counter 超出此声明的范围时,它将被自动释放。

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

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-21
      • 2023-03-29
      • 1970-01-01
      • 2021-05-11
      • 1970-01-01
      • 1970-01-01
      • 2010-09-30
      • 1970-01-01
      相关资源
      最近更新 更多