有多少种方法可以将 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[ ])

所有这些有什么区别?

有什么方法可以修改作为参数传递的数组元素,就像我们使用& 传递intfloat 并修改实际参数的值一样?

【问题讨论】:

我很难理解你的意思,但第二个选项是错误的。它是指向数组的指针,因此实际上是指向指针的指针,而不是指向值的指针。第一和第二 - 它们之间没有区别。我将使用第一个来指示,我正在传递指向 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 中的函数?的主要内容,如果未能解决你的问题,请参考以下文章

使用Struct将String数组和索引传递给C中的线程

将 C# char 数组传递给 C++ 与字节数组不同

C:将数组“即时”传递给函数

将 char 指针数组传递给函数

如何将 Swift 字符串数组传递给采用 char ** 参数的 C 函数

将多维数组传递给函数 C