【问题标题】:Difference between char[] and char* in function call函数调用中 char[] 和 char* 的区别
【发布时间】:2012-03-10 16:24:40
【问题描述】:

我发现自己无法解释为什么以下代码有效。不用说,我对 C++ 还是很陌生...

#include <cstdio>

void foo(char* p)
{
    p[0] = 'y';
}

int main()
{
    char a[1];
    a[0] = 'x';
    printf("a[0] = %c\n", a[0]);
    foo(a);
    printf("a[0] = %c\n", a[0]);
    return 0;
}

这个程序输出

a[0] = x
a[0] = y

让我感兴趣的是,我不是将指针而是数组传递给 foo.那么foo如何改变数组a的值呢?这是否仅适用于 char 数组?

Difference between char and char[1] 的回答证实了我的观察,但没有详细说明为什么会出现这种情况。

谢谢!

【问题讨论】:

  • 因为当您传递指针时,您传递的是对象的地址,因此您可以更改它的值;您的片段就是这种情况,例如在这种情况下,您不是将值传递给对象,而是将地址传递给对象 char[];
  • 拿一本好的 C 初学者书籍阅读。您无法通过教程从 Internet 学习语言。或者,如果可以的话,这比通过书本学习要花更长的时间。
  • @Aamir +1 你在写。使用教程有时可以解决问题,但无法学习新技术......
  • 记住,当像这样传入数组时,您还需要传入数组的大小,否则会发生各种“有趣”

标签: c++ c char


【解决方案1】:

当您将数组传递给函数时,它会衰减为指向第一个元素的指针。

以下是完全等价的:

void foo(char* p);
void foo(char p[]);
void foo(char p[42]); /* Or any other number. */ 

这是否仅适用于 char 数组?

它适用于任何数组。我推荐aryptr section of the C FAQ

【讨论】:

    【解决方案2】:

    在 C 中,数组,在大多数情况下 (*),衰减为指向其第一个元素的指针。

    在您的情况下,数组 a 衰减为指向 a[0] 的指针。

    数组int arr[12][23],当仅由其标识符使用时,衰减为指向其第一个元素的指针,即arr[0],其类型为int (*)[23](指向23 个整数数组的指针)。

    (*) 数组在用作sizeof 运算符的参数、用作&amp; 运算符的参数或用作字符数组的初始值设定项(字符串文字)时不会衰减。

    【讨论】:

    • 为了完整起见,我要提一下“衰减”是正式的 左值到右值转换,或“从变量”。 C 有一个奇怪的决定,即“没有数组类型的值,只有对象”,当您尝试获取数组的值时,最终会得到一个指针。而且 C 是严格按值调用的,因此您不能将数组本身传递给函数,只能将指向第一个元素的指针(如 int*)或指向整个数组的指针(如 int(*)[10]) .
    • 因此数组本身不能作为函数参数。出现了一个问题,为什么可以使用类似数组的语法来指定参数类型——这完全让我难以理解。 :-)
    【解决方案3】:

    当你说

    char a[5];
    

    编译器分配5个连续的内存块,第一个块的地址分配给a。因此,根据定义,数组的名称(在我们的例子中为 a)只是一个指向内存位置的指针。

    现在当我们说 a[0] 时,编译器将它处理为 *(a+0*sizeof(array datatype ie char, int etc.)),符号 a[i] 表示为 *(a+i*sizeof (数组数据类型,即 char、int 等))

    就函数参数传递而言,当我们将数组传递给函数时,基本上它只是传递的第一个元素的地址。有关此问题的更多详细信息,请关注this link 或阅读@cnicutar 的答案(因为他已经发布了正确答案,所以没有必要再重复一遍)...

    【讨论】:

      【解决方案4】:

      您可以尝试这个来说服自己这是如何工作的。

      int a[8], *p;
      p = a;
      printf("%p, %p, %p\n", a, &a[0], p);
      

      【讨论】:

        【解决方案5】:

        数组只不过是一个指针(指向第一个元素),至少是为了传递参数。

        【讨论】:

        • 我不会这么说(人们会开始反对这个)。
        • 我已经添加了评论(仅用于参数传递),这可能为时已晚。
        • 谢谢,我赞成你的回答(这是最好的和最详尽的)。
        • 其实pmgs是最好的,我刚到的比较早。
        • 是的,我总是对我的问题的每一个好的答案都投赞成票,不仅是最快的,然后我接受最好的或最详尽的。
        【解决方案6】:

        这里的三个原型是等价的:

        void foo(char *p);
        void foo(char p[]);
        void foo(char p[42]);
        

        C 表示T 类型数组的参数声明调整为指向T 的类型指针声明。

        【讨论】:

          【解决方案7】:

          数组名指向数组第一个元素的地址。请参考:Is an array name a pointer?

          【讨论】:

            猜你喜欢
            • 2017-12-23
            • 2013-03-22
            • 2011-11-25
            • 1970-01-01
            • 2012-04-07
            • 1970-01-01
            • 1970-01-01
            • 2017-04-02
            相关资源
            最近更新 更多