【问题标题】:Why don't you need to specify the array size when using a pointer in C? [duplicate]为什么在 C 中使用指针时不需要指定数组大小? [复制]
【发布时间】:2018-02-20 17:09:20
【问题描述】:

为什么在使用指针时不需要指定数组大小?

我是 C 的新手,并试图更好地了解它的工作原理。

如果我使用指针来声明数组 greet 我不需要指定数组大小。 如果我拿走指针,我需要定义数组的大小。

为什么编译器在使用指针声明 char 变量时不需要知道要分配的数组的大小,但是当我只声明一个 char 变量时它却知道。有点困惑为什么会发生这种情况。

这是我的示例代码:

int main()
{
    char *greet; // Works fine.

    // char greet; // Doesn't work. Crashes when entering text.
    // char greet[]; // Doesn't work. Array size missing, won't compile.
    // char greet[20]; // Works fine.

    printf("Enter name\n>");
    gets(greet);

    printf("Hello %s", greet);


}

【问题讨论】:

  • “如果我使用指针来声明数组greet” - 不,指针不是数组,你没有在那里“声明数组”。您创建了一个变量,它可以指向某个东西(即保存一个地址),但它现在没有指向任何有意义的东西。

标签: c arrays string pointers memory-management


【解决方案1】:

似乎工作正常,实际上,它是undefined behavior

对于自动存储类型的任何未初始化的局部变量,如果没有显式初始化,则内容是不确定的。代码中的greet 也是如此。

因此,基本上,您正在尝试写入有效性未知的内存。 greet 指向的内存位置充其量是无效。您必须确保用作目标缓冲区的指针指向某个有效的内存位置。您可以通过以下任一方式完成此操作

  1. 使指针指向有效的内存位置,

    char *greet = NULL;
    char buf[BUFSIZ] = {0};
    greet = buf;
    
    .
    .
    .
    
    fgets(greet, BUFSIZ, stdin);
    
  2. 使用动态内存分配器分配内存(在运行时),例如

    char * greet = malloc(BUFSIZ);
    
    if (greet) {// allocation successful....}
    

    在这种情况下,您还需要进行清理工作。

也就是说, DO NOT use gets(), it is dangerous (and removed from latest standard, AFAIR). Use fgets() instead.


另一方面,对于您提到的其他选项,

  • char greet; 也是无效的,fgets()是的,甚至是 gets())需要指向 char 的指针,而不是 char type。启用警告,你的编译器会尖叫。你最好停在那里!!

  • char greet[]; 语法无效,老生常谈,没什么好讨论的。

  • char greet[20]; 这是对的,只要你在fgets() 中传递一个小于/等于数组大小的大小。这没关系,因为,

    • 这里greet是一个自动局部变量,所以存储空间会自动分配
    • 数组名称在作为函数参数传递时,会衰减为指向数组中第一个元素的指针

    您将在范围内访问有效内存。都很好。

【讨论】:

  • 哇...任何澄清以及否决票?
  • 我没有 DV,但如果没有展示如何正确使用指针的示例,我原以为您的回答会受益于至少提及 malloc
  • @ChrisTurner 确实如此(已更新),但从什么时候开始成为 DV 的标准? :) NVM,无论如何。
  • 好的,非常感谢!
  • @Brian16446 添加了更多讨论以涵盖整个问题前提。
【解决方案2】:

指针不是数组。您已经声明了一个指针,但是您没有为指针应该指向的位置分配空间(我们通过malloc() 动态分配内存),因此当您尝试写入greet 时,您调用未定义行为,这就是为什么它现在在您的机器上似乎可以正常工作,但事实并非如此!

另一方面,char greet[20]; 可以工作,因为它是一个大小为 20 的数组,可以容纳一个字符串。

此外,请考虑使用fgets() 而不是gets()Difference between fgets and gets.

把所有东西放在一起,我们可以得到:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char *greet = malloc(21); // can hold a string of 20 characters, plus NULL terminator
    // TODO: Check for malloc failure

    printf("Enter name>\n");
    fgets(greet, 21, stdin);

    printf("Hello %s", greet);

    // Never forget to deallocate your dynamic memory!
    free(greet);
    return 0;
}

通过使用固定大小的数组,代码会变成这样:

char greet[21];
printf("Enter name>\n");
fgets(greet, 21, stdin);
printf("Hello %s", greet);

【讨论】:

  • 谢谢@BLUEPIXY,我的错。你觉得我的回答怎么样? :D
猜你喜欢
  • 2021-12-15
  • 1970-01-01
  • 2021-01-20
  • 2012-06-02
  • 2014-01-26
  • 2023-04-02
  • 2010-12-11
  • 2019-11-13
  • 2017-06-01
相关资源
最近更新 更多