有多少种方法可以将 char 数组传递给 C 中的函数?
Posted
技术标签:
【中文标题】有多少种方法可以将 char 数组传递给 C 中的函数?【英文标题】:How many ways are there to pass char array to function in C? 【发布时间】:2015-11-29 09:27:20 【问题描述】:foo(char *s)
foo(char *s[ ])
foo(char s[ ])
所有这些有什么区别?
有什么方法可以修改作为参数传递的数组元素,就像我们使用&
传递int
或float
并修改实际参数的值一样?
【问题讨论】:
我很难理解你的意思,但第二个选项是错误的。它是指向数组的指针,因此实际上是指向指针的指针,而不是指向值的指针。第一和第二 - 它们之间没有区别。我将使用第一个来指示,我正在传递指向 char 的指针,第二个来指示,我正在传递 char 数组(指向表中第一个 char 的指针。)。问题的第二部分我根本不明白。您可以在所有这些方法中修改元素。 我的朋友char *s[]
不是字符数组。
char (*s)[]
将是一个指向 char 数组的指针。 char *s[]
是一个字符指针数组。
感谢@DawidPi 我是 c 新手,不知道所有这些之间的区别,这就是为什么我可能列出了一个错误的选项
@Balraj 一旦最初的问题得到回答,请不要编辑问题并添加其他问题。如果您需要更多信息,可以使用答案下方的评论部分或提出新问题。谢谢。
【参考方案1】:
在 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
仍按预期工作。 (明显的缺点是数组必须有确切数量的元素。)
【讨论】:
实际上可以按值传递数组。请注意,当您将错误的指针类型显示到数组指针中时,编译器实际上不会强制警告您不兼容的指针类型,尽管好的编译器会这样做。更好的类型安全性的替代方法可能是 VLA 语法:void foo (size_t n, char s[n])
。这仍然归结为指向第一个元素的指针,因为 C 没有区分常规数组的“参数衰减”和 VLA
@Lundin,如果您向我展示如何按值传递数组(而不是包装数组的结构,请注意),您今天会教我一些东西。
@Lundin 啊,旧的“实际上可以按值传递数组”,但代码实际上是“按值传递结构”的技巧。 Maxwell Smart 会感到自豪。
@chux 就机器代码(即 C 标准之外的现实世界)而言,您的程序正在按值传递数组。【参考方案2】:
foo(char *s)
非常简单,它只是一个指针,可能是指向数组第一个元素的指针。
foo(char s[])
是一个 char 数组的声明,但由于 C 标准中的(愚蠢的)规则,它被转换为指向 char 的指针。同样,如果你声明任何数组大小,你仍然会得到一个指向 char 的指针。
提到的规则可以在 C11 6.7.6.3 函数声明器中找到:
将参数声明为“类型数组”应调整为 ‘‘限定类型指针’”
如果完全禁止这种奇怪的、令人困惑的“would-be-array”语法可能会好得多,因为它 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】:
foo(char *s)
、foo(char *s[ ])
、foo(char s[ ])
,这几个有什么区别?
在这些foo(char *s)
和foo(char s[ ])
中,两者都将char array
作为参数。
异常剩余 this -foo(char *s[ ])
this 将需要一个指向字符的指针数组作为参数。
【讨论】:
【参考方案4】:场景:您使用数组作为参数调用函数。
在这种情况下,
foo(char *s)
和
foo(char s[])
被认为等效。他们都希望用char
数组调用。
OTOH,foo(char *s[ ]),
不同,因为它采用 char *
数组的地址。
【讨论】:
一旦将 s 传递给 foo,我可以将 s 赋值为 s[] ="Hello world" 吗,或者使用循环是唯一的选择。 @Balraj 您永远不能为数组名称赋值。可以选择循环,或者memcpy()
/strcpy()
。
但是这可以在初始化一个新的字符数组时完成,对
@Balraj 准确地说,在定义时可以使用大括号括起来的初始化列表通过赋值进行初始化,所以是的。以上是关于有多少种方法可以将 char 数组传递给 C 中的函数?的主要内容,如果未能解决你的问题,请参考以下文章