background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wgUEhgsb9YM9wAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAADUlEQVQI12NgYGBgAAAABQABXvMqOgAAAABJRU5ErkJggg==);
foo(char *s)
foo(char *s[ ])
所有这些有什么不同?
有没有什么方法可以修改作为参数传递的数组元素,就像我们使用foo(char s[ ])
和int
传递float
或&
一样实际的参数被修改了吗?
答案 0 :(得分:4)
在C中无法按值传递数组。您列出的每个工作解决方案(不幸的是排除了#2)不仅会让您,而且会强制您修改原始数组。
由于参数衰减,foo(char* s)
和foo(char s[])
完全相同。在这两种情况下,都使用其名称传递数组:
char array[4];
foo(array); // regardless of whether foo accepts a char* or a char[]
在这两种情况下,数组都被转换为指向其第一个元素的指针。
指针到阵列解决方案不太常见。它需要以这种方式进行原型化(注意*s
周围的括号):
void foo(char (*s)[]);
没有括号,你需要一个char指针数组。
在这种情况下,要调用该函数,需要传递数组的地址:
foo(&array);
每次要访问数组元素时,还需要从foo
取消引用指针:
void foo(char (*s)[])
{
char c = (*s)[3];
}
就像那样,它不是特别方便。但是,唯一允许您指定数组长度的形式,您可能会发现它很有用。这是我个人的最爱之一。
void foo(char (*s)[4]);
如果您尝试传递的数组没有正好4个字符,编译器将发出警告。此外,sizeof
仍然按预期工作。 (明显的缺点是数组必须具有确切的元素数。)
答案 1 :(得分:2)
场景:您以数组作为参数调用该函数。
在那种情况下,
foo(char *s)
和
foo(char s[])
被视为等同于。他们都期望用char
数组调用。
OTOH,foo(char *s[ ]),
不同,因为它采用char *
数组的地址。
答案 2 :(得分:1)
foo(char *s)
非常简单,它只是一个指针,可能是指向数组第一个元素的指针。
foo(char s[])
是char数组的声明,但由于C标准中的(愚蠢)规则,它被转换为指向char的指针。同样,如果声明任何数组大小,仍然会获得指向char的指针。
提到的规则可以在C11 6.7.6.3函数声明符中找到:
参数声明为''数组类型''应调整为 ''指向类型''的合格指针
如果这个奇怪的,令人困惑的,并且会成为阵列的话,那可能会好得多。语法被完全禁止,因为它是100%多余的,并且没有任何其他目的,但是混淆了尝试加入" C俱乐部的初学者"。但那时C从来就不是一种理性的语言......
有人会说,基本原理是,出于性能原因,绝不允许您在C中按值传递数组。好吧,运气不好,因为尽管有这个规则,你仍然可以。
你可以"破解C标准"并按值传递数组:
typedef struct
{
char array[10];
} by_val_t;
foo (by_val_t arr); // bad practice but possible
现在真的没有理由为什么你想要按值传递一个数组,这是非常糟糕的程序设计,并没有任何意义。我只是在这里包含这个例子来证明6.7.6.3中的规则完全没有任何理由。
您可以将数组指针作为参数传递给函数。这是事情变得先进的地方,因为这是非常模糊的,并且实际使用非常有限:
foo(char(*s)[])
如果你在这里指定一个数组大小,你实际上得到了一些类型安全性,因为编译器倾向于警告不同大小的数组指针之间的转换。
但请注意,数组指针主要用于使C语言更加一致。你想要将一个数组指针传递给一个函数的原因很简单(here是一个有点复杂的例子,我显然找到了它的有效用法)。
答案 3 :(得分:0)
foo(char *s)
,foo(char *s[ ])
,foo(char s[ ])
,所有这些有什么不同?
在这些foo(char *s)
和foo(char s[ ])
中,两者都会期望char array
作为参数。
异常剩下这个 - foo(char *s[ ])
这将指向一个指向chars的指针数组作为参数。