【问题标题】:why dynamic allocated int array use & in scanf, c language?为什么动态分配的int数组在scanf、c语言中使用&?
【发布时间】:2019-11-28 01:11:50
【问题描述】:

我了解到 char 数组不要在 scanf 中使用 & 因为 char 存储点,而不是字符串本身。

char s1[10];
scanf("%s", s1);

但是,为什么动态分配的int数组在scanf中使用&虽然它使用指针?

int *arr = (int *)malloc(sizeof(int)*3);
scanf("%d", &arr[1]);

【问题讨论】:

  • arr[1] 不是指针,所以你应该在它前面加上 &
  • scanf("%s", s1); 等价于scanf("%s", &s1[0]);scanf("%d", &arr[1]); 等价于scanf("%d", arr + 1);
  • int arr[3] = (int *)malloc(sizeof(int)*3) 无论如何都不是有效代码。 malloc() 的结果,无论是否转换,都不能用于初始化数组。

标签: c malloc


【解决方案1】:

这是完全错误的:

int arr[3] = (int *)malloc(sizeof(int)*3);

因为您试图将内存分配给不允许的数组。
应该是:

int * arr = malloc(sizeof(int)*3);

当你这样做时,内存中的视图会是这样的(假设malloc 是成功的):

    +-----------+
    |   |   |   |
    +-----------+
    ^
    |
   arr

arr 是指向内存基址的指针。
arr[1] 是数组的第一个元素(整数数组arr 的单个元素),
&arr[1] 是数组arr的第一个元素的地址。

    +-----------+
    |   |   |   |
    +-----------+
        ^
        |
       &arr[1]

当您输入数组arr 的第一个元素时,您必须将数组第一个元素的地址传递给scanf(),即&arr[1]

&scanf() 参数一起使用与动态分配无关。如果你想输入一个固定长度数组的元素(大小在编译时确定),语法是一样的:

int arr[3];

scanf("%d", &arr[1]);

如果您有任何其他问题,请告诉我。

【讨论】:

  • arr = malloc(sizeof(int)*3); 的一个很好的替代品是arr = malloc(sizeof *arr * 3);。更容易正确编写、查看和维护。
  • @chux:我更喜欢malloc(3 * sizeof *arr)。那么sizeof的操作数在视觉上更容易区分。此外,如果您正在做一个多维数组,malloc(rows * columns * sizeof *p) 两者都匹配数组定义中维度的顺序,并继续从最大到最小的大小,最后是单个对象的大小。
  • @EricPostpischil rows * columns * sizeof *prows, columns 可能比size_t 窄时比sizeof *p * rows * columns 有一个劣势——例如int。带有sizeof *p * rows * columns 且未溢出的产品可能会因rows * columns * sizeof *p 而溢出。因此,我更喜欢使用 size_t 参数来引导乘法。 IOWs,从最需要的类型到可能是狭窄的类型,而不是反之亦然。当然,只有 2 个混合类型的参数或全部 3 个作为 size_t 可以满足您的偏好,而无需担心。
  • @H.S. int *arr = (int *)malloc(sizeof(int)*3); 可能是对的。所以,malloc 只是为 value 准备好内存空间,char 保存字符串指针,int 保存 num 本身。对吗?
  • @4rigener 不,你的理解是完全错误的。似乎,您对C 中的指针概念感到困惑。指针类型描述了一个对象,其值提供对被引用类型实体的引用。这意味着,当你写 - int *p; 时,这里的 p 是一个指针,它可以存储 int 类型的地址。同样,char *p;,这里的p 是一个指针,它可以存储char 类型的地址,当您想要访问指针指向的内存中的数据/值时,您需要取消引用指针。另外,不要投射malloc return.. 继续..
【解决方案2】:

s1 是一个字符数组。数组的名称 (s1) 是指向 char 的指针,因此您不需要使用 scanf 的 & - 因为 %s 期望读取字符数组。

char s1[10];
scanf("%s", s1);

注意,这种情况下你也可以在scanf中指定s1的地址,因为就地址而言,s1, &s1[0], &s1都指向同一个地址。

char s1[10];
scanf("%s", &s1); // work as well

arr 是整数数组。数组的名称(即arr)也是一个指针(指向int)是正确的。但是对于希望读取整数的 scanf %d,您必须提供正在读取的整数的地址。 它不是数组,它是数组中的单个整数,scanf 尝试读取 - 您必须相应地指定它的地址:&arr[1]

int arr[3] = (int *)malloc(sizeof(int)*3);
scanf("%d", &arr[1]);

【讨论】:

  • s1 = 地址,&s1 = 地址的地址。为什么会这样?
  • @4riener:答案不准确。 s1 是一个数组(即一个数组类型的对象),所以&s1 是一个指向数组类型对象的指针。 &s1&s1[0] 指向同一个地方,但它们是不同类型的指针。混淆来自这样一个事实,即当您使用 s1 作为函数参数时,或在许多其他上下文中,它“衰减”为指向其第一个元素的指针。见this answer
【解决方案3】:

当您扫描字符数组(字符串)时,在您的情况下 s1,您不需要 &,因为 s1 存储指向该数组的第一个元素(索引为 0 的元素)的指针。 关于动态分配,malloc 返回值是指向内存中将存储数组的某个位置的指针。所以你的声明应该是这样的:

int* arr = malloc(sizeof(int) * 3); 
scanf("%d", &add[1]); 
/* here you scanf only the second element of your massive,
 it is int so you have to put & there to pass a pointer */

如果你想初始化整个海量,你可以为它编写简单的循环。我还建议您阅读一些文档about malloc 和一篇文章"calloc vs malloc".

祝你好运:)

【讨论】:

    猜你喜欢
    • 2018-09-26
    • 1970-01-01
    • 1970-01-01
    • 2011-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-05
    • 2016-04-23
    相关资源
    最近更新 更多