如何知道 char* 库函数 arg 何时需要它可以修改的数组,而不是 char 指针

asi*_*s07 8 c c++ arrays parameters char-pointer

我是 C 编程新手。我知道char *char[]数组是不同的。然而,当涉及到函数参数时,您可以扣除char[]to 。char *所以函数声明可能是相同的。

但是我如何知道该函数是否专门需要一个char数组,而不是char *通过查看签名(声明)?

例如,如果我使用库头文件并且函数如下。我如何知道要通过哪一项?

// somelib.h
void foo(char *bar);
Run Code Online (Sandbox Code Playgroud)

因为如果函数正在修改bar参数并且我传递 a char *,它将出现段错误。这是针对 C 的,但是对于 C++ 来说也是一样的吗?

Bar*_*mar 13

如果函数修改数组,则应声明参数char *。如果它不修改数组,则应该声明该参数const char *

当声明参数时,const char *传递字符串文字是安全的。否则,您应该将数组或指针传递给使用malloc()(在 C 中)或new(在 C++ 中)动态分配的内存。

在 C++ 中,如果尝试将文字传递给不带const修饰符的参数,则会出现编译错误,因为字符串文字是const. 但由于历史原因,C 中的字符串文字类型是 non- const,即使修改它们会导致未定义的行为,因此不会出现错误(但有些编译器会产生警告)。

  • 我想问题是关于传递一个指向单个字符的指针和一个指向字符序列的指针。 (2认同)

eer*_*ika 9

作为函数参数

我知道char *char[]数组不同

虽然char *char[]是不同的类型,但作为函数和函数参数,它们并没有什么不同,因为所有声明为数组的函数参数都被调整为指向该数组元素的指针。因此,char[]函数参数被编译器调整为char *。此调整仅适用于函数参数,不适用于其他上下文。

但是,我如何通过查看签名(声明)来知道该函数是否特别需要 char 数组还是 char * ?

需要 char 数组的函数就是需要char *. 我想您的意思是问如何知道函数是否期望/要求将char *指向数组的元素。而且,也许数组是否需要以 null 终止,或者具有最小大小。

答案是单看签名是无法得知的。

我怎么知道要通过哪一项?

通过阅读描述该函数功能的文档。如果没有文档,则阅读该函数的实现。如果也没有实现,那么您可以尝试对二进制文件进行逆向工程。如果您不知道该函数的作用,则不应调用它。

因为如果函数正在修改 bar 参数并且如果我传递 char *,它将出现段错误。

我想你的意思是该函数修改指向的一个或多个字符。在这种情况下,修改指针本身应该没问题。

如果其元素所指向的数组char *是可修改的,则将其传递给修改该数组的函数不应导致段错误。如果数组是 const,则不应将其传递到修改数组的函数中。

  • @asisas07:libcurl 的 C API [有详细记录](https://curl.se/libcurl/c/libcurl.html)。但是,如果不是,那么您确实必须研究源代码才能使用它。这仍然比自己编写所有内容更容易,因此不会违背使用库的目的。 (2认同)
  • @asisas07 “如果我必须查看代码并了解它是如何实现的,这不是违背了使用库的目的吗?” 不。即使没有很好的文档记录,库仍然有用。然而,一个记录良好的库会更有用。没有来源的无证图书馆大多是无用的。 (2认同)

Pet*_*ter 6

当用作函数参数时,char *xchar x[]完全相同。在许多其他情况下,情况并非如此。

char *x对于描述为(or )的参数,char x[]函数不可能知道调用者实际传递的内容。调用者可能传递了一个数组(该数组作为指向该数组第一个元素的指针传递)。它可能已经传递了&vwherev是类型的变量char。它可能已经通过了其他事情。

该函数所能做的就是做出假设,并继续执行该假设。它可能假设它传递的是单个地址char,并且仅修改该地址char。或者,它可能假设已传递了一个 1000 的数组char,并修改所有这些字符。该函数可能会假设(正如标准 C 字符串函数在很多情况下所做的那样)调用者已传递一个以 nul 结尾的数组(可以具有任意长度的数组,但末尾由数值char为零的标记标记) 。该函数可能使用另一个参数来指定数组的长度(因此依赖于调用者传递了有效数组和正确长度的假设)。

无论做出什么假设,如果调用者传递的内容与函数假设的内容不同,函数就有可能出现未定义的行为(例如访问或覆盖不存在的字符)。

对于调用者(或试图编写代码来调用该函数的程序员)来说,情况是相同的。只有两种方法可以知道什么可以安全地传递给函数。

  1. 阅读该函数的文档,并传递与文档内容一致的内容。这样做的风险(即使代码中没有错误)是程序员和代码维护者在保持函数文档与函数实际功能一致方面非常糟糕 - 文档可能说的是一件事,但函数实际上做了另一件事。
  2. 检查函数的代码。这是确定的,除非编译器有错误并且错误地翻译了代码。更大的问题是,如果代码很复杂,可能需要花费大量精力才能弄清楚该函数的作用,并且很容易出错(对于人类来说)。还写了很多难以阅读的代码。

一些风格指南鼓励函数作者使用char *x被视为单个地址的参数char,以及char x[]需要数组的函数。对于编译器来说,这没有什么区别。许多程序员并不遵守这些准则。


Sil*_*olo 1

您阅读了文档。如果不使用像 Agda 这样的证明语言,类型系统将永远无法完全描述函数的契约。在 C 语言中,请阅读文档。

在 C++ 中,你永远不应该使用char*. 需要字符串的函数应该采用std::string. 需要修改字符的函数应该使用 a char&,并且在极少数情况下,您需要一个不是有效字符串的字符数组,std::vector<char>应该使用 a 。在现代 C++ 中,从来没有将原始指针用作公共函数参数的用例。

  • 我同意关于 C 的部分,但是关于 C++ 代码应该如何始终使用标准库的部分太过固执己见,特别是如果您使用的是没有 `std::string` 的小型嵌入式系统,或者您只是想与 C 代码互操作,或者您只想要一些简单的东西。C++ `main` 函数违反了您的规则。而且我认为无论如何这都是题外话,因为OP要求阅读特定的函数签名并理解该函数的作用。 (6认同)