6

在下面的 C 程序中,我不明白为什么在我调用 foo.buf[0] = 'A' 之后。foo 不是在做值传递吗?

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

    void foo(char buf[])
    {
      buf[0] = 'A';
    }

    int main(int argc, char *argv[])
    {
      char buf[10];

      buf[0] = 'B';
      printf("before foo | buf[0] = %c\n", buf[0]);
      foo(buf);
      printf("after foo | buf[0] = %c\n", buf[0]);

      system("PAUSE"); 
      return 0;
      }

输出:

before foo | buf[0] = 'B' 
after foo | buf[0] = 'A'
4

12 回答 12

12
void foo(char buf[])

是相同的

void foo(char* buf)

当您调用它时foo(buf),您按值传递一个指针,因此会生成指针的副本。

指针的副本指向与原始指针相同的对象(或者,在这种情况下,指向数组的初始元素)。

C 没有按引用传递语义,因为 C++ 具有按引用传递语义。C 中的所有内容都是按值传递的。指针用于通过引用语义获得传递。

于 2010-08-05T13:30:17.900 回答
4

数组只是使用指针的一种奇特方式。当你传递buf给函数时,你是按值传递一个指针,但是当你取消引用指针时,你仍然引用它指向的字符串。

于 2010-08-05T13:29:25.983 回答
2

数组作为函数参数就相当于一个指针,所以声明

void foo( char buf[] );

是相同的

void foo( char* buf );

然后数组参数衰减为指向其第一个元素的指针。

于 2010-08-05T13:32:26.820 回答
2

数组的处理方式与其他类型不同;您不能在 C 中“按值”传递数组。

在线 C99 标准(草案 n1256),第 6.3.2.1 节,“左值、数组和函数指示符”,第 3 段:

除非它是 sizeof 运算符或一元 & 运算符的操作数,或者是用于初始化数组的字符串字面量,否则类型为 ''array of type'' 的表达式将转换为类型为 ''pointer to type'' 指向数组对象的初始元素并且不是左值。如果数组对象具有寄存器存储类,则行为未定义。

在通话中

foo(buf);

数组表达式buf不是sizeofor的操作数&,也不是用于初始化数组的字符串文字,因此它被隐式转换(“decays”)从类型“10-element array of char”到“pointer to char”,并将第一个元素的地址传递给 foo。因此,您对bufin所做的任何事情foo()都会反映在 in 的buf数组中main()。由于数组下标的定义方式,您可以在指针类型上使用下标运算符,因此看起来您正在使用数组类型,但实际上并非如此。

在函数参数声明的上下文中,T a[]T a[N]是 的同义词T *a,但只有在这种情况下才是正确的。

于 2010-08-05T13:59:07.300 回答
1

有了指针就不一样了;你是按值传递的,但是你传递的是指针的值,它与数组的值不一样。

因此,指针的值不会改变,但您正在修改它所指向的内容。

于 2010-08-05T13:30:57.823 回答
1

数组和指针(几乎)是一回事。

int* foo = malloc(...)

foo[2]是相同的*(foo+2*sizeof(int))

轶事:你写的

int main(int argc, char *argv[])

编写也是合法的(将编译和工作相同)

int main(int argc, char **argv)

并且

int main(int argc, char argv[][])

它们实际上是相同的。它比这稍微复杂一些,因为数组知道它有多少元素,而指针不知道。但它们的用法相同。

于 2010-08-05T17:29:48.520 回答
1

*char buf[] 实际上意味着 char ** 所以你通过指针/引用传递。这使您在main () 和foo () 函数中都知道 buf 是一个指针。

于 2010-08-05T13:28:29.620 回答
1

因为您正在传递一个指向buf(按值)的指针。所以被指向的内容被buf改变了。

于 2010-08-05T13:29:20.587 回答
0

为了按值传递,函数需要知道参数的大小。在这种情况下,您只是传递一个指针。

于 2010-08-05T13:29:59.617 回答
0

请注意一件事,

宣言

void foo(char buf[])

说,这将使用 [ ] 表示法。不是您将使用数组的哪个元素。

如果您想指出这一点,您想获得一些特定的值,那么您应该将此函数声明为

void foo(char buf[X]); //where X would be a constant.

当然这是不可能的,因为它没有用(在数组的第 n 个元素处操作的函数?)。您不必写下要获取数组的哪个元素的信息。您需要的一切都是简单的声明:

voi foo(char value);

所以...

void foo(char buf[])

是一个声明,它说明您要使用哪种表示法( [ ] - part ),它还包含指向某些数据的指针。

此外......你会期待什么......你向函数 foo 发送了一个数组名称

foo(buf);

相当于 &buf[0]。所以...这是一个指针。

于 2010-08-05T13:52:11.190 回答
0

C 中的数组不是按值传递的。它们甚至不是合法的函数参数。相反,编译器会看到您正在尝试传递一个数组并将其降级为指针。它默默地这样做,因为它是邪恶的。它还喜欢踢小狗。

在函数参数中使用数组是向您的 API 用户发出信号的好方法,即这个东西应该是一块内存,分割成 n 字节大小的块,但不要指望编译器会关心您是否拼写char *foo char foo[]char foo[12]在函数参数中。他们不会。

于 2010-08-05T13:58:56.777 回答
0

您在这里通过引用传递。在此示例中,您可以通过在所需数组的索引处传递单个 char 来解决问题。

如果要保留原始数组的内容,可以将字符串复制到函数中的临时存储区。

编辑:如果您将 char 数组包装在一个结构中并传递该结构会发生什么?我相信这也可能有效,尽管我不知道在编译器级别可能会产生什么样的开销。

于 2010-08-05T13:36:12.053 回答