因此不可能在程序内部取得实际值。那么,在何处把实参值赋予main函数的形参呢 实际上,main函数的参数值是从操作系统命令行上获得的。当我们要运行一个可执行文件时,在DOS提示符下键入文件名,再输入实际参数即可把这些实参传送到main的形参中去。
DOS提示符下命令行的一般形式为: C:\>可执行文件名 参数 参数……; 但是应该特别注意的是,main 的两个形参和命令行中的参数在
位置上不是一一对应的。因为,main的形参只有二个,而命令行中的参数个数原则上未加限制。argc参数表示了命令行中参数的个数(注意:文件名本身也算一个参数),argc的值是在输入命令行时由系统按实际参数的个数自动赋予的。例如有命令行为: C:\>E6 24 BASIC dbase FORTRAN由于文件名E6 24本身也算一个参数,所以共有4个参数,因此argc取得的值为4。argv参数是字符串指针数组,其各元素值为命令行中各字符串(参数均按字符串处理)的首地址。 指针数组的长度即为参数个数。数组元素初值由系统自动赋予。其表示如图6.8所示:
main(int argc,char *argv){
while(argc-->1)
printf("%s\n",*++argv);
}
本例是显示命令行中输入的参数如果上例的可执行文件名为e24.exe,存放在A驱动器的盘内。
因此输入的命令行为: C:\>a:e24 BASIC dBASE FORTRAN
则运行结果为:
BASIC
dBASE
FORTRAN
该行共有4个参数,执行main时,argc的初值即为4。argv的4个元素分为4个字符串的首地址。执行while语句,每循环一次 argv值减1,当argv等于1时停止循环,共循环三次, 因此共可输出三个参数。在printf函数中,由于打印项*++argv是先加1再打印, 故第一次打印的是argv[1]所指的字符串BASIC。第二、 三次循环分别打印后二个字符串。而参数e24是文件名,不必输出。
下例的命令行中有两个参数,第二个参数20即为输入的n值。在程序中*++argv的值为字符串“20”,然后用函数"atoi"把它换为整型作为while语句中的循环控制变量,输出20个偶数。
#include"stdlib.h"
main(int argc,char*argv[]){
int a=0,n;
n=atoi(*++argv);
while(n--) printf("%d ",a++*2);
}
本程序是从0开始输出n个偶数。指向指针的指针变量如果一个指针变量存放的又是另一个指针变量的地址, 则称这个指针变量为指向指针的指针变量。
在前面已经介绍过,通过指针访问变量称为间接访问, 简称间访。由于指针变量直接指向变量,所以称为单级间访。 而如果通过指向指针的指针变量来访问变量则构成了二级或多级间访。在C语言程序中,对间访的级数并未明确限制, 但是间访级数太多时不容易理解解,也容易出错,因此,一般很少超过二级间访。 指向指针的指针变量说明的一般形式为:
类型说明符** 指针变量名;
例如: int ** pp; 表示pp是一个指针变量,它指向另一个指针变量, 而这个指针变量指向一个整型量。下面举一个例子来说明这种关系。
main(){
int x,*p,**pp;
x=10;
p=&x;
pp=&p;
printf("x=%d\n",**pp);
}
上例程序中p 是一个指针变量,指向整型量x;pp也是一个指针变量, 它指向指针变量p。通过pp变量访问x的写法是**pp。程序最后输出x的值为10。通过上例,读者可以学习指向指针的指针变量的说明和使用方法。
下述程序中首先定义说明了指针数组ps并作了初始化赋值。 又说明了pps是一个指向指针的指针变量。在5次循环中, pps 分别取得了ps[0],ps[1],ps[2],ps[3],ps[4]的地址值(如图6.10所示)。再通过这些地址即可找到该字符串。
main(){
static char *ps[]={ "BASIC","DBASE","C","FORTRAN",
"PASCAL"};
char **pps;
int i;
for(i=0;i<5;i++){
pps=ps+i;
printf("%s\n",*pps);
}
}
本程序是用指向指针的指针变量编程,输出多个字符串。
本章小结
1. 指针是C语言中一个重要的组成部分,使用指针编程有以下优点:
(1)提高程序的编译效率和执行速度。
(2)通过指针可使用主调函数和被调函数之间共享变量或数据结构,便于实现双向数据通讯。
(3)可以实现动态的存储分配。
(4)便于表示各种数据结构,编写高质量的程序。
2. 指针的运算
(1)取地址运算符&:求变量的地址
(2)取内容运算符*:表示指针所指的变量
(3)赋值运算
·把变量地址赋予指针变量
·同类型指针变量相互赋值
·把数组,字符串的首地址赋予指针变量
·把函数入口地址赋予指针变量
(4)加减运算
对指向数组,字符串的指针变量可以进行加减运算,如p+n,p-n,p++,p--等。对指向同一数组的两个指针变量可以相减。对指向其它类型的指针变量作加减运算是无意义的。
(5)关系运算
指向同一数组的两个指针变量之间可以进行大于、小于、 等于比较运算。指针可与0比较,p==0表示p为空指针。
3. 与指针有关的各种说明和意义见下表。
int *p; p为指向整型量的指针变量
int *p[n]; p为指针数组,由n个指向整型量的指针元素组成。
int (*p)[n]; p为指向整型二维数组的指针变量,二维数组的列数为n
int *p() p为返回指针值的函数,该指针指向整型量
int (*p)() p为指向函数的指针,该函数返回整型量
int **p p为一个指向另一指针的指针变量,该指针指向一个整型量。
4. 有关指针的说明很多是由指针,数组,函数说明组合而成的。
但并不是可以任意组合,例如数组不能由函数组成,即数组元素不能是一个函数;函数也不能返回一个数组或返回另一个函数。例如
int a[5]();就是错误的。
5. 关于括号
在解释组合说明符时, 标识符右边的方括号和圆括号优先于标识符左边的“*”号,而方括号和圆括号以相同的优先级从左到右结合。但可以用圆括号改变约定的结合顺序。
6. 阅读组合说明符的规则是“从里向外”。
从标识符开始,先看它右边有无方括号或园括号,如有则先作出解释,再看左边有无*号。 如果在任何时候遇到了闭括号,则在继续之前必须用相同的规则处理括号内的内容。例如:
int*(*(*a)())[10]
↑ ↑↑↑↑↑↑
7 6 4 2 1 3 5
上面给出了由内向外的阅读顺序,下面来解释它:
(1)标识符a被说明为;
(2)一个指针变量,它指向;
(3)一个函数,它返回;
(4)一个指针,该指针指向;
(5)一个有10个元素的数组,其类型为;
(6)指针型,它指向;
(7)int型数据。
因此a是一个函数指针变量,该函数返回的一个指针值又指向一个指针数组,该指针数组的元素指向整型量。