通过引用调用而不明确地将函数参数声明为指针?

时间:2015-08-18 20:27:31

标签: c pointers

我正在阅读K& R并在此处遇到问题。我不知道这个函数如何改变调用变量的值。不应该按值调用,而不是通过引用调用,因为[]和[]没有被明确声明为指针? foo的值更改为" Testing"。

#include <stdio.h>

void copy(char to[], char from[]) {
    int i = 0;
    while ((to[i] = from[i]) != '\0') i++;
}

int main() {
    char foo[] = "";
    char bar[] = "Testing";
    copy(foo, bar);
    printf("%s\n", foo);
    return 0;
} 

另外,为什么这个arr_alter函数没有改变test_arr的值?似乎循环遍历数组中的每个元素会改变调用变量的值,但这不会。

#include <stdio.h>

void arr_alter(char arr[]) {
    arr = "Changed";
}

int main() {
    char test_arr[] = "Testing";
    arr_alter(test_arr);
    printf("%s\n", test_arr);
    return 0;
} 

简而言之,为什么函数#1将参数视为指针而函数#2不是?

我有点困惑,所有的帮助将不胜感激。

3 个答案:

答案 0 :(得分:4)

数组按值传递为指针。

你可以

void copy(char to[], char from[])

等同于

void copy(char * to, char * from)

两种情况之间的区别在于第一种情况解除引用指针与数组元素运算符[]
第二种情况不会这样做,它会覆盖传递的指针。但指针是通过值传递的,因此数组内容和调用者的传递指针都不会改变。

答案 1 :(得分:2)

首先,第一个程序有未定义的行为。 数组foo被定义为只有一个元素(“空”字符串文字的终止零)

char foo[] = "";

但是,您要在数组中复制字符串“Testing”。

copy(foo, bar);

这会导致覆盖不属于数组foo的内存。

数组foo应足够大,以便能够容纳字符串“Testing”。

例如

char foo[8];

根据C标准(6.7.6.3函数声明符(包括原型))

  

7应调整参数声明为''类型数组''   ''限定指向类型'',类型限定符(如果有的话)   是在数组类型的[和]内指定的那些   推导....

另一方面(6.3.2.1 Lvalues,数组和函数指示符)

  

3除非它是sizeof运算符或一元&amp;的操作数。   operator,或者是用于初始化数组的字符串文字, an   具有类型''数组类型''的表达式将转换为   带有''指向类型'的指针的表达式,指向初始值   数组对象的元素并且不是左值。如果是数组   对象具有寄存器存储类,行为未定义。

因此在这个函数声明中

void copy(char to[], char from[]);

将参数tofrom调整为指针。所以这个函数声明等同于以下函数声明

void copy(char *to, char *from);

并且两者都声明了相同的一个函数。

您可以在程序中写入两个声明。例如

#include <stdio.h>

void copy(char to[], char from[]);
void copy(char *to, char *from);

void copy(char to[], char from[]) {
    int i = 0;
    while ((to[i] = from[i]) != '\0') i++;
}
//...

但函数的定义只能是一个。

在此函数调用中

copy(foo, bar);

根据标准数组foo的第二个引用,bar转换为指向其第一个元素的指针。

对于第二个程序的函数,函数参数是它的局部变量。函数处理其参数的副本。因此,参数副本的任何更改都不会影响参数本身。

您可以想象函数arr_alter的定义及其调用方式如下

arr_alter(test_arr);

//...

void arr_alter( /*char arr[] */) {
    char *arr = test_arr;

    arr = "Changed";
}

退出函数后,其局部变量arr将被销毁。变量test_arr不会被更改,而且数组也没有赋值运算符。你无法以这种方式重新分配数组。

答案 2 :(得分:0)

char to []和char from []相当于将char ptr赋值给数组的第一个元素。

说你有char [10] =“你好”; 印刷(一个或多个);

相同

打印(安培; S [0]);

数组中第一个插槽的地址。