正如在 C 标准中使用的那样,“字符串 是由第一个空字符终止并包括第一个空字符的连续字符序列”(C 2018 7.1.1 1)。它不是char *。 char * 可能指向字符串的第一个字符,有时在 C 标准中称为指向字符串的指针,但这是一个草率的术语,因为 char * 必然是指向字符的指针——没有指向“序列”意味着什么的技术定义,尽管我们可能会认为它意味着指向序列的第一个元素。
据我目前的理解,char * argv[] = {"abc", "def"}; 初始化了一个包含 2 个 char 指针的数组。
没错。
而名称argv也是一个指针,指向数组argv中的第一个指针。
鉴于问题中argv 的定义,这是不正确的。定义char * argv[] = {"abc", "def"}; 将argv 定义为char * 的数组。它不是指针。
当数组用作sizeof或一元&的操作数时,它作为数组进行操作。 (此外,当数组用字符串字面量初始化时,字符串字面量被用作数组。)除这些情况外,当在表达式中使用数组时,它被转换为指向其第一个元素的指针。这种转换是自动的,并且很常见,以至于学生可能会将数组或数组的名称误认为是它转换为的指针。这是一个错误。数组不是指针。
为什么有人说argv 是char 字符串的数组呢? (就像 K&R 的 C 编程语言一样)。
Kernighan 和 Ritchie 在任何一个版本的C 编程语言 中都没有在索引中为argv 列出的任何地方提到这一点。在 1978 年的第一版中,他们在第 110 页上说“第二个 (argv) 是指向包含参数的字符串数组的指针,每个字符串一个。”在 1988 年的第二版中,他们在第 114 页上说“第二个(argv,用于参数向量)是指向包含参数的字符串数组的指针,每个字符串一个。”该索引还列出了第 163 页的 argv,但这里只是顺便提及,指的是程序名称 argv[0]。
请注意,它们将argv 称为指针而不是数组。这是因为main 的argv 参数是一个指针。虽然可以用int main(int argc, char *argv[]) 声明,但声明为数组的参数会自动调整为指针。因此char *argv[] 在main 的声明中将argv 定义为与您显示的声明char * argv[] = {"abc", "def"}; 不同的东西。在参数声明中,自动调整为指针。在单独的定义中,它是一个数组。
尽管 Kernighan 和 Ritchie 确实将 argv 称为指针,而不是您所写的数组,但他们说它是“指向数组的指针”。这也是一个草率的术语。它的类型是pointer-to-pointer-to-char,而不是pointer-to-array-of-char。它只是一个指向数组的指针,仅在它是指向char 数组的第一个元素的意义上。
如果我的假设是正确的,那么 printf("%s", argv[1]) 中的 %s 根本不期望 char string,而是指向 char string 的指针?
根据 C 2018 7.21.6.1 8,对于不带修饰符或精度的 s 说明符到 printf,“参数应是指向字符类型数组的初始元素的指针。数组中的字符被写入(但不包括)终止空字符。”因此,应该传递一个指向字符串初始字符的char *(或signed char * 或unsigned char *)。