main函数参数解析
main函数是有参数的,只是我们使用main函数时,大多数情况下会省略参数。接下来我们看一下main函数的原型,并对main函数的三个参数进行解析。
main函数原型
解析:
这里有三个参数。
第一个参数:argc是一个整形变量,表示命令行参数的个数(含第一个参数)。
第二个参数:argv是一个字符指针数组,每个元素是一个字符指针,指向一个字符串。这些字符串就是命令行中的每一个参数(字符串)
第三个参数:envp是字符指针数组,数组的每一个元素是一个指向一个环境变量(字符串)的字符指针。
如下列程序:
运行结果与分析:
argv是一个指针数组,这个数组的每个元素都是一个字符指针,数组的末尾是一个NULL指针。argc的值和这个NULL值都用于确定实际传递了多少个参数。注:第一个参数就是程序的名称
那么第三个参数有怎么解释呢?
可以看出第三个参数保存的是环境变量,envp数组的最后一个元素也存放NULL指针。
可变参数列表解析
在C语言中,可变参数是指一个函数在不同时刻接受不同的数目的参数,可以接受1个以上的任意多个参数(不固定)
先看一个例子:实现一个函数可以求任意个参数的平均值。
分析:此函数要实现求任意个参数的平均值,由于参数的个数是不固定的,所以应该使用可变参数列表。程序实现如下:
int average(int n,...)
{
va_list arg;
int i=0;
int sum = 0;
va_start(arg, n);
for(i=0; i<n; i++)
{
sum += va_arg(arg,int);
}
va_end(arg);
return sum/n;
}
int main()
{
cout<<average(5,1,2,3,4,5)<<endl;
system("pause");
}
观察上面程序我们可能会对va_list、va_start、va_arg、va_end感到陌生,通过在vc6.0编译器中转到定义出,我们可以发现va_start、va_arg、va_end个是宏,va_list 和char* 类型的变量。具体的分析如下:
通过上面的分析,我们可以看到可变参数是通过宏来实现的,这些宏定义在stdarg.h头文件中,它是标准库的一部分。这个头文件声明了一个类型va_list和三个宏----va_start、va_arg、va_end。我们可以声明一个类型为va_list的变量,与这些宏配合使用,访问参数的值。 注意参数列表中的省略号:它提示此处可能传递的数量和类型未确定的参数。参数列表中的可变部分位于一个或多个普通参数的后面。
下面这个程序具体进行分析:
1. 声明一个va_list类型的变量arg,它用于访问参数列表的未确定部分。
2. arg是通过va_list进行初始化。它的第一个参数是va_list的变量名,第2个参数是省略号前最后一个有名字的参数。初始化过程把arg变量设置为指向可变参数部分的第一个参数。
3. 使用va_arg访问参数。
4. 当访问完毕后,调用va_end将arg置为NULL指针 。
可变参数的限制
1. 可变参数必须从头到尾逐个访问。
2.参数列表中至少有一个命名参数。如果一个命名参数都没有,就无法使用va_start.
3.如果在va_arg中指定了错误的类型,那么其后果是不可预测的。
4. 这些宏是无法直接判断实际存在参数的数量,这些宏无法判断每个参数的类型。
通过上面分析,实现求任意多个数的最大值。
int Max(int n,...)
{
va_list arg;
int i=0;
int max = 0x80000000;
va_start(arg,n);
for(; i<n; i++)
{
int tmp = va_arg(arg,int);
if(max < tmp)
{
max = tmp;
}
}
va_end(arg);
return max;
}
int main()
{
int ret = Max(3, -1,-2,-3);
cout<<ret<<endl;
return 0;
}
在我们学习过程中,经常使用的printf函数就是利用可变参数实现的,printf函数中的命名参数是格式字符串,它不仅指定了参数的数量(通过几个%可以确定有几个参数),而且指定了参数的类型(d、s、ld等表示类型)。但底层实现相对比较复杂,有兴趣可以进行了解。