// says: argv is a constant pointer pointing to a char*
int main(int c, char *const argv[]);
在函数内部,你将无法改变"argv"。
由于你正在学习C语言,我建议你先真正尝试理解数组和指针之间的区别,而不是常见的东西。
在参数和数组的领域中,有一些令人困惑的规则,在继续之前应该清楚。首先,在参数列表中声明的内容是特殊处理的。在C语言中,有些情况下作为函数参数是没有意义的。这些情况包括:
数组作为参数
第二个可能不是立即清楚的。但是当你考虑到数组维度的大小是C语言类型的一部分时(而且维度大小未给出的数组具有不完整的类型),它就变得清晰了。因此,如果你创建一个按值接受数组(接收副本)的函数,则只能对一个大小进行操作!此外,数组可以变得很大,C语言试图尽可能快地运行。
基于这些原因,C语言中不存在数组值。如果你想获取数组的值,实际上得到的是该数组第一个元素的指针。这已经是解决方案了。C编译器不会预先使数组参数无效,而是将相应参数的类型转换为指针类型。请记住这一点,它非常重要。该参数不会成为数组,而是成为相应元素类型的指针。
现在,如果你尝试传递一个数组,实际上传递的是指向数组第一个元素的指针。
扩展:函数作为参数
为了完整起见,并且因为我认为这将有助于更好地理解问题,让我们看看当你尝试将函数作为参数时情况如何。事实上,一开始它没有任何意义。参数怎么可能是一个函数?嗯,我们想要在那个位置放一个变量,当然!因此,当发生这种情况时,编译器将再次将函数转换为函数指针。尝试传递函数将传递指向该函数的指针。所以,以下内容是相同的(类似于数组示例):
void f(void g(void));
void f(void (*g)(void));
请注意,需要在
*g
周围加上括号。否则,它会指定返回
void*
的函数,而不是返回
void
的函数指针。
回到数组
现在,我在开始时说过,数组可以有不完整的类型——如果你还没有给出大小。由于我们已经确定一个数组参数不存在,而是任何数组参数都是指针,所以数组的大小并不重要。这意味着编译器将转换以下所有内容,并且所有内容都是相同的:
int main(int c, char **argv);
int main(int c, char *argv[]);
int main(int c, char *argv[1]);
int main(int c, char *argv[42]);
当然,将任意大小的内容放在其中并将其丢弃是没有意义的。因此,C99为这些数字提出了新的含义,并允许其他内容出现在括号中:
int main(int c, char *argv[static 5]);
int main(int c, char *argv[const]);
int main(int c, char ** const argv);
最后两行表示您无法在函数内更改“argv” - 它已成为一个
const
指针。然而,只有少数C编译器支持这些C99特性。但是,这些特性清楚地表明,“数组”实际上并不是一个数组,它是一个指针。
警告
请注意,我上面所说的只适用于您将数组作为函数的参数时。如果您使用本地数组,数组将不是指针。它将表现为指针,因为如前所述,当读取其值时,数组将转换为指针。但是它不应与指针混淆。
一个经典的例子是以下内容:
char c[10];
char **c = &c;
typedef char array[10];
array *pc = &c;
char (*array)[10] = &c;
char *const argv[]
是一个数组类型,但在这个上下文中,作为函数参数,它的类型不是char *const argv[]
,而是char *const *argv
。 - Steve Jessop