第 23 章
参数……;
但是应该特别注意的是,main 的两个形参和命令行中的参数在位置上不是一一对应的。
因为,main 的形参只有二个,而命令行中的参数个数原则上未加限制。argc 参数表示了命令
行中参数的个数(注意:文件名本身也算一个参数),argc 的值是在输入命令行时由系统按
实际参数的个数自动赋予的。
例如有命令行为:
C:\>E24 BASIC foxpro FORTRAN
由于文件名 E24 本身也算一个参数,所以共有 4 个参数,因此 argc 取得的值为 4。argv 参
数是字符串指针数组,其各元素值为命令行中各字符串(参数均按字符串处理)的首地址。 指
谭浩强 C 语言程序设计 2001 年 5 月 1 日
针数组的长度即为参数个数。数组元素初值由系统自动赋予。其表示如图所示:
【例 10.38】
main(int argc,char *argv){
while(argc-->1)
printf("%s\n",*++argv);
}
本例是显示命令行中输入的参数。如果上例的可执行文件名为 e24.exe,存放在 A 驱动
器的盘内。因此输入的命令行为:
C:\>a:e24 BASIC foxpro FORTRAN
则运行结果为:
BASIC
foxpro
FORTRAN
该行共有 4 个参数,执行 main 时,argc 的初值即为 4。argv 的 4 个元素分为 4 个字符
串的首地址。执行 while 语句,每循环一次 argv 值减 1,当 argv 等于 1 时停止循环,共循
环三次,因此共可输出三个参数。在 printf 函数中,由于打印项*++argv 是先加 1 再打印,
故第一次打印的是 argv[1]所指的字符串 BASIC。第二、三次循环分别打印后二个字符串。
而参数 e24 是文件名,不必输出。
10.8 有关指针的数据类型和指针运算的小结
10.8.1 有关指针的数据类型的小结
定义
int i;
int *p
int a[n];
int *p[n];
int (*p)[n];
int f();
int *p();
int (*p)();
int **p;
含 义
定义整型变量 i
p 为指向整型数据的指针变量
定义整型数组 a,它有 n 个元素
定义指针数组 p,它由 n 个指向整型数据的指针元素组成
p 为指向含 n 个元素的一维数组的指针变量
f 为带回整型函数值的函数
p 为带回一个指针的函数,该指针指向整型数据
p 为指向函数的指针,该函数返回一个整型值
P 是一个指针变量,它指向一个指向整型数据的指针变量
10.8.2 指针运算的小结
现把全部指针运算列出如下:
1) 指针变量加(减)一个整数:
谭浩强 C 语言程序设计 2001 年 5 月 1 日
例如:p++、p--、p+i、p-i、p+=i、p-=i
一个指针变量加(减)一个整数并不是简单地将原值加(减)一个整数,而是将该指针
变量的原值(是一个地址)和它指向的变量所占用的内存单元字节数加(减)。
2) 指针变量赋值:将一个变量的地址赋给一个指针变量。
p=&a; (将变量 a 的地址赋给 p)
p=array; (将数组 array 的首地址赋给 p)
p=&array[i]; (将数组 array 第 i 个元素的地址赋给 p)
p=max; (max 为已定义的函数,将 max 的入口地址赋给 p)
p1=p2; (p1 和 p2 都是指针变量,将 p2 的值赋给 p1)
注意:不能如下:
p=1000;
3) 指针变量可以有空值,即该指针变量不指向任何变量:
p=NULL;
4) 两个指针变量可以相减:如果两个指针变量指向同一个数组的元素,则两个指针变量值
之差是两个指针之间的元素个数。
5) 两个指针变量比较:如果两个指针变量指向同一个数组的元素,则两个指针变量可以进
行比较。指向前面的元素的指针变量“小于” 指向后面的元素的指针变量。
10.8.3 void 指针类型
ANSI 新标准增加了一种“void”指针类型,即可以定义一个指针变量,但不指定它是指向
哪一种类型数据。
11 结构体与共用体
11.1 定义一个结构的一般形式
在实际问题中,一组数据往往具有不同的数据类型。例如,在学生登记表中,姓名应为
字符型;学号可为整型或字符型;年龄应为整型;xìng别应为字符型;成绩可为整型或实型。 显
然不能用一个数组来存放这一组数据。因为数组中各元素的类型和长度都必须一致,以便于
编 译 系 统 处 理 。 为 了 解 决 这 个 问 题 , C 语 言 中 给 出 了 另 一 种 构 造 数 据 类 型 ——“ 结 构
(structure)”或叫“结构体”。 它相当于其它高级语言中的记录。“结构”是一种构造类型,
它是由若干“成员”组成的。每一个成员可以是一个基本数据类型或者又是一个构造类型。结
构既是一种“构造”而成的数据类型,那么在说明和使用之前必须先定义它,也就是构造它。
如同在说明和调用函数之前要先定义函数一样。
定义一个结构的一般形式为:
struct 结构名
{成员表列};
成员表列由若干个成员组成,每个成员都是该结构的一个组成部分。对每个成员也必须
作类型说明,其形式为:
类型说明符 成员名;
成员名的命名应符合标识符的书写规定。例如:
struct stu
{
int num;
char ncom[20];
char sex;
float score;
};
在这个结构定义中,结构名为 stu,该结构由 4 个成员组成。第一个成员为 num,整型变
量;第二个成员为 ncom,字符数组;第三个成员为 sex,字符变量;第四个成员为 score,
实型变量。应注意在括号后的分号是不可少的。结构定义之后,即可进行变量说明。凡说明
为结构 stu 的变量都由上述 4 个成员组成。由此可见, 结构是一种复杂的数据类型,是数目
固定,类型不同的若干有序变量的集合。
11.2 结构类型变量的说明
说明结构变量有以下三种方法。以上面定义的 stu 为例来加以说明。
1. 先定义结构,再说明结构变量。
如:
struct stu
{
int num;
char ncom[20];
char sex;
float score;
};
struct stu boy1,boy2;
说明了两个变量 boy1 和 boy2 为 stu 结构类型。也可以用宏定义使一个符号常量来表示
一个结构类型。
例如:
#define STU struct stu
STU
{
int num;
char ncom[20];
char sex;
float score;
};
STU boy1,boy2;
2. 在定义结构类型的同时说明结构变量。
例如:
struct stu
{
int num;
char ncom[20];
char sex;
float score;
}boy1,boy2;
这种形式的说明的一般形式为:
struct 结构名
{
成员表列
}变量名表列;
3. 直接说明结构变量。
例如:
struct
{
int num;
char ncom[20];
char sex;
float score;
}boy1,boy2;
这种形式的说明的一般形式为:
struct
{
成员表列
}变量名表列;
第三种方法与第二种方法的区别在于第三种方法中省去了结构名,而直接给出结构变量。
三种方法中说明的 boy1,boy2 变量都具有下图所示的结构。
说明了 boy1,boy2 变量为 stu 类型后,即可向这两个变量中的各个成员赋值。在上述 stu
结构定义中,所有的成员都是基本数据类型或数组类型。
成员也可以又是一个结构,即构成了嵌套的结构。例如,下图给出了另一个数据结构。
按图可给出以下结构定义:
struct date
{
int month;
int day;
int year;
};
struct{
int num;
char ncom[20];
char sex;
struct date birthday;
float score;
}boy1,boy2;
首先定义一个结构 date,由 month(月)、day(日)、year(年) 三个成员组成。 在定义并
说明变量 boy1 和 boy2 时,其中的成员 birthday 被说明为 data 结构类型。成员名可与程
序中其它变量同名,互不干扰。
11.3 结构变量成员的表示方法
在程序中使用结构变量时,往往不把它作为一个整体来使用。在 ANSI C 中除了允许具有
相同类型的结构变量相互赋值以外,一般对结构变量的使用,包括赋值、输入、输出、运算
等都是通过结构变量的成员来实现的。
表示结构变量成员的一般形式是:
结构变量名.成员名
例如:
boy1.num 即第一个人的学号
boy2.sex 即第二个人的xìng别
如果成员本身又是一个结构则必须逐级找到最低级的成员才能使用。
例如:
boy1.birthday.month
即第一个人出生的月份成员可以在程序中单独使用,与普通变量完全相同。
11.4 结构变量的赋值
结构变量的赋值就是给各成员赋值。可用输入语句或赋值语句来完成。
【例 11.1】给结构变量赋值并输出其值。
main()
{
struct stu
{
int num;
char *ncom;
char sex;
float score;
} boy1,boy2;
boy1.num=102;
boy1.ncom="Zhang ping";
printf("input sex and score\n");
scanf("%c %f",&boy1.sex,&boy1.score);
boy2=boy1;
printf("Number=%d\nNcom=%s\n",boy2.num,boy2.ncom);
printf("Sex=%c\nScore=%f\n",boy2.sex,boy2.score);
}
本程序中用赋值语句给 num 和 ncom 两个成员赋值,ncom 是一个字符串指针变量。用 scanf
函数动态地输入 sex 和 score 成员值,然后把 boy1 的所有成员的值整体赋予 boy2。最后分
别输出 boy2 的各个成员值。本例表示了结构变量的赋值、输入和输出的方法。
11.5 结构变量的初始化
和其他类型变量一样,对结构变量可以在定义时进行初始化赋值。
【例 11.2】对结构变量初始化。
main()
{
struct stu /*定义结构*/
{
int num;
char *ncom;
char sex;
float score;
}boy2,boy1={102,"Zhang ping",'M',78.5};
boy2=boy1;
printf("Number=%d\nNcom=%s\n",boy2.num,boy2.ncom);
printf("Sex=%c\nScore=%f\n",boy2.sex,boy2.score);
}
本例中,boy2,boy1 均被定义为外部结构变量,并对 boy1 作了初始化赋值。在 main 函
数中,把 boy1 的值整体赋予 boy2,然后用两个 printf 语句输出 boy2 各成员的值。
11.6 结构数组的定义
数组的元素也可以是结构类型的。因此可以构成结构型数组。结构数组的每一个元素都
是具有相同结构类型的下标结构变量。在实际应用中,经常用结构数组来表示具有相同数据
结构的一个群体。如一个班的学生档案,一个车间职工的工资表等。
方法和结构变量相似,只需说明它为数组类型即可。
例如:
struct stu
{
int num;
char *ncom;
char sex;
float score;
}boy[5];
定义了一个结构数组 boy,共有 5 个元素,boy[0]~boy[4]。每个数组元素都具有 struct
stu 的结构形式。对结构数组可以作初始化赋值。
例如:
struct stu
{
int num;
char *ncom;
char sex;
float score;
}boy[5]={
{101,"Li ping","M",45},
{102,"Zhang ping","M",62.5},
{103,"He fang","F",92.5},
{104,"Cheng ling","F",87},
{105,"Wang ming","M",58};
}
当对全部元素作初始化赋值时,也可不给出数组长度。
【例 11.3】计算学生的平均成绩和不及格的人数。
struct stu
{
int num;
char *ncom;
char sex;
float score;
}boy[5]={
{101,"Li ping",'M',45},
{102,"Zhang ping",'M',62.5},
{103,"He fang",'F',92.5},
{104,"Cheng ling",'F',87},
{105,"Wang ming",'M',58},
};
main()
{
int i,c=0;
float ave,s=0;
for(i=0;i<5;i++)
{
s+=boy[i].score;
if(boy[i].score<60) c+=1;
}
printf("s=%f\n",s);
ave=s/5;
printf("average=%f\ncount=%d\n",ave,c);
}
本例程序中定义了一个外部结构数组 boy,共 5 个元素,并作了初始化赋值。在 main 函
数中用 for 语句逐个累加各元素的 score 成员值存于 s 之中,如 score 的值小于 60(不及格)
即计数器 C 加 1,循环完毕后计算平均成绩,并输出全班总分,平均分及不及格人数。
【例 11.4】建立同学通讯录
#include"stdio.h"
#define NUM 3
structcomm
{
char ncom[20];
char phone[10];
};
main()
{
structcomm man[NUM];
int i;
for(i=0;i<NUM;i++)
{
printf("input ncom:\n");
gets(man[i].ncom);
printf("input phone:\n");
gets(man[i].phone)
松语文学免费小说阅读_www.16sy.com
但是应该特别注意的是,main 的两个形参和命令行中的参数在位置上不是一一对应的。
因为,main 的形参只有二个,而命令行中的参数个数原则上未加限制。argc 参数表示了命令
行中参数的个数(注意:文件名本身也算一个参数),argc 的值是在输入命令行时由系统按
实际参数的个数自动赋予的。
例如有命令行为:
C:\>E24 BASIC foxpro FORTRAN
由于文件名 E24 本身也算一个参数,所以共有 4 个参数,因此 argc 取得的值为 4。argv 参
数是字符串指针数组,其各元素值为命令行中各字符串(参数均按字符串处理)的首地址。 指
谭浩强 C 语言程序设计 2001 年 5 月 1 日
针数组的长度即为参数个数。数组元素初值由系统自动赋予。其表示如图所示:
【例 10.38】
main(int argc,char *argv){
while(argc-->1)
printf("%s\n",*++argv);
}
本例是显示命令行中输入的参数。如果上例的可执行文件名为 e24.exe,存放在 A 驱动
器的盘内。因此输入的命令行为:
C:\>a:e24 BASIC foxpro FORTRAN
则运行结果为:
BASIC
foxpro
FORTRAN
该行共有 4 个参数,执行 main 时,argc 的初值即为 4。argv 的 4 个元素分为 4 个字符
串的首地址。执行 while 语句,每循环一次 argv 值减 1,当 argv 等于 1 时停止循环,共循
环三次,因此共可输出三个参数。在 printf 函数中,由于打印项*++argv 是先加 1 再打印,
故第一次打印的是 argv[1]所指的字符串 BASIC。第二、三次循环分别打印后二个字符串。
而参数 e24 是文件名,不必输出。
10.8 有关指针的数据类型和指针运算的小结
10.8.1 有关指针的数据类型的小结
定义
int i;
int *p
int a[n];
int *p[n];
int (*p)[n];
int f();
int *p();
int (*p)();
int **p;
含 义
定义整型变量 i
p 为指向整型数据的指针变量
定义整型数组 a,它有 n 个元素
定义指针数组 p,它由 n 个指向整型数据的指针元素组成
p 为指向含 n 个元素的一维数组的指针变量
f 为带回整型函数值的函数
p 为带回一个指针的函数,该指针指向整型数据
p 为指向函数的指针,该函数返回一个整型值
P 是一个指针变量,它指向一个指向整型数据的指针变量
10.8.2 指针运算的小结
现把全部指针运算列出如下:
1) 指针变量加(减)一个整数:
谭浩强 C 语言程序设计 2001 年 5 月 1 日
例如:p++、p--、p+i、p-i、p+=i、p-=i
一个指针变量加(减)一个整数并不是简单地将原值加(减)一个整数,而是将该指针
变量的原值(是一个地址)和它指向的变量所占用的内存单元字节数加(减)。
2) 指针变量赋值:将一个变量的地址赋给一个指针变量。
p=&a; (将变量 a 的地址赋给 p)
p=array; (将数组 array 的首地址赋给 p)
p=&array[i]; (将数组 array 第 i 个元素的地址赋给 p)
p=max; (max 为已定义的函数,将 max 的入口地址赋给 p)
p1=p2; (p1 和 p2 都是指针变量,将 p2 的值赋给 p1)
注意:不能如下:
p=1000;
3) 指针变量可以有空值,即该指针变量不指向任何变量:
p=NULL;
4) 两个指针变量可以相减:如果两个指针变量指向同一个数组的元素,则两个指针变量值
之差是两个指针之间的元素个数。
5) 两个指针变量比较:如果两个指针变量指向同一个数组的元素,则两个指针变量可以进
行比较。指向前面的元素的指针变量“小于” 指向后面的元素的指针变量。
10.8.3 void 指针类型
ANSI 新标准增加了一种“void”指针类型,即可以定义一个指针变量,但不指定它是指向
哪一种类型数据。
11 结构体与共用体
11.1 定义一个结构的一般形式
在实际问题中,一组数据往往具有不同的数据类型。例如,在学生登记表中,姓名应为
字符型;学号可为整型或字符型;年龄应为整型;xìng别应为字符型;成绩可为整型或实型。 显
然不能用一个数组来存放这一组数据。因为数组中各元素的类型和长度都必须一致,以便于
编 译 系 统 处 理 。 为 了 解 决 这 个 问 题 , C 语 言 中 给 出 了 另 一 种 构 造 数 据 类 型 ——“ 结 构
(structure)”或叫“结构体”。 它相当于其它高级语言中的记录。“结构”是一种构造类型,
它是由若干“成员”组成的。每一个成员可以是一个基本数据类型或者又是一个构造类型。结
构既是一种“构造”而成的数据类型,那么在说明和使用之前必须先定义它,也就是构造它。
如同在说明和调用函数之前要先定义函数一样。
定义一个结构的一般形式为:
struct 结构名
{成员表列};
成员表列由若干个成员组成,每个成员都是该结构的一个组成部分。对每个成员也必须
作类型说明,其形式为:
类型说明符 成员名;
成员名的命名应符合标识符的书写规定。例如:
struct stu
{
int num;
char ncom[20];
char sex;
float score;
};
在这个结构定义中,结构名为 stu,该结构由 4 个成员组成。第一个成员为 num,整型变
量;第二个成员为 ncom,字符数组;第三个成员为 sex,字符变量;第四个成员为 score,
实型变量。应注意在括号后的分号是不可少的。结构定义之后,即可进行变量说明。凡说明
为结构 stu 的变量都由上述 4 个成员组成。由此可见, 结构是一种复杂的数据类型,是数目
固定,类型不同的若干有序变量的集合。
11.2 结构类型变量的说明
说明结构变量有以下三种方法。以上面定义的 stu 为例来加以说明。
1. 先定义结构,再说明结构变量。
如:
struct stu
{
int num;
char ncom[20];
char sex;
float score;
};
struct stu boy1,boy2;
说明了两个变量 boy1 和 boy2 为 stu 结构类型。也可以用宏定义使一个符号常量来表示
一个结构类型。
例如:
#define STU struct stu
STU
{
int num;
char ncom[20];
char sex;
float score;
};
STU boy1,boy2;
2. 在定义结构类型的同时说明结构变量。
例如:
struct stu
{
int num;
char ncom[20];
char sex;
float score;
}boy1,boy2;
这种形式的说明的一般形式为:
struct 结构名
{
成员表列
}变量名表列;
3. 直接说明结构变量。
例如:
struct
{
int num;
char ncom[20];
char sex;
float score;
}boy1,boy2;
这种形式的说明的一般形式为:
struct
{
成员表列
}变量名表列;
第三种方法与第二种方法的区别在于第三种方法中省去了结构名,而直接给出结构变量。
三种方法中说明的 boy1,boy2 变量都具有下图所示的结构。
说明了 boy1,boy2 变量为 stu 类型后,即可向这两个变量中的各个成员赋值。在上述 stu
结构定义中,所有的成员都是基本数据类型或数组类型。
成员也可以又是一个结构,即构成了嵌套的结构。例如,下图给出了另一个数据结构。
按图可给出以下结构定义:
struct date
{
int month;
int day;
int year;
};
struct{
int num;
char ncom[20];
char sex;
struct date birthday;
float score;
}boy1,boy2;
首先定义一个结构 date,由 month(月)、day(日)、year(年) 三个成员组成。 在定义并
说明变量 boy1 和 boy2 时,其中的成员 birthday 被说明为 data 结构类型。成员名可与程
序中其它变量同名,互不干扰。
11.3 结构变量成员的表示方法
在程序中使用结构变量时,往往不把它作为一个整体来使用。在 ANSI C 中除了允许具有
相同类型的结构变量相互赋值以外,一般对结构变量的使用,包括赋值、输入、输出、运算
等都是通过结构变量的成员来实现的。
表示结构变量成员的一般形式是:
结构变量名.成员名
例如:
boy1.num 即第一个人的学号
boy2.sex 即第二个人的xìng别
如果成员本身又是一个结构则必须逐级找到最低级的成员才能使用。
例如:
boy1.birthday.month
即第一个人出生的月份成员可以在程序中单独使用,与普通变量完全相同。
11.4 结构变量的赋值
结构变量的赋值就是给各成员赋值。可用输入语句或赋值语句来完成。
【例 11.1】给结构变量赋值并输出其值。
main()
{
struct stu
{
int num;
char *ncom;
char sex;
float score;
} boy1,boy2;
boy1.num=102;
boy1.ncom="Zhang ping";
printf("input sex and score\n");
scanf("%c %f",&boy1.sex,&boy1.score);
boy2=boy1;
printf("Number=%d\nNcom=%s\n",boy2.num,boy2.ncom);
printf("Sex=%c\nScore=%f\n",boy2.sex,boy2.score);
}
本程序中用赋值语句给 num 和 ncom 两个成员赋值,ncom 是一个字符串指针变量。用 scanf
函数动态地输入 sex 和 score 成员值,然后把 boy1 的所有成员的值整体赋予 boy2。最后分
别输出 boy2 的各个成员值。本例表示了结构变量的赋值、输入和输出的方法。
11.5 结构变量的初始化
和其他类型变量一样,对结构变量可以在定义时进行初始化赋值。
【例 11.2】对结构变量初始化。
main()
{
struct stu /*定义结构*/
{
int num;
char *ncom;
char sex;
float score;
}boy2,boy1={102,"Zhang ping",'M',78.5};
boy2=boy1;
printf("Number=%d\nNcom=%s\n",boy2.num,boy2.ncom);
printf("Sex=%c\nScore=%f\n",boy2.sex,boy2.score);
}
本例中,boy2,boy1 均被定义为外部结构变量,并对 boy1 作了初始化赋值。在 main 函
数中,把 boy1 的值整体赋予 boy2,然后用两个 printf 语句输出 boy2 各成员的值。
11.6 结构数组的定义
数组的元素也可以是结构类型的。因此可以构成结构型数组。结构数组的每一个元素都
是具有相同结构类型的下标结构变量。在实际应用中,经常用结构数组来表示具有相同数据
结构的一个群体。如一个班的学生档案,一个车间职工的工资表等。
方法和结构变量相似,只需说明它为数组类型即可。
例如:
struct stu
{
int num;
char *ncom;
char sex;
float score;
}boy[5];
定义了一个结构数组 boy,共有 5 个元素,boy[0]~boy[4]。每个数组元素都具有 struct
stu 的结构形式。对结构数组可以作初始化赋值。
例如:
struct stu
{
int num;
char *ncom;
char sex;
float score;
}boy[5]={
{101,"Li ping","M",45},
{102,"Zhang ping","M",62.5},
{103,"He fang","F",92.5},
{104,"Cheng ling","F",87},
{105,"Wang ming","M",58};
}
当对全部元素作初始化赋值时,也可不给出数组长度。
【例 11.3】计算学生的平均成绩和不及格的人数。
struct stu
{
int num;
char *ncom;
char sex;
float score;
}boy[5]={
{101,"Li ping",'M',45},
{102,"Zhang ping",'M',62.5},
{103,"He fang",'F',92.5},
{104,"Cheng ling",'F',87},
{105,"Wang ming",'M',58},
};
main()
{
int i,c=0;
float ave,s=0;
for(i=0;i<5;i++)
{
s+=boy[i].score;
if(boy[i].score<60) c+=1;
}
printf("s=%f\n",s);
ave=s/5;
printf("average=%f\ncount=%d\n",ave,c);
}
本例程序中定义了一个外部结构数组 boy,共 5 个元素,并作了初始化赋值。在 main 函
数中用 for 语句逐个累加各元素的 score 成员值存于 s 之中,如 score 的值小于 60(不及格)
即计数器 C 加 1,循环完毕后计算平均成绩,并输出全班总分,平均分及不及格人数。
【例 11.4】建立同学通讯录
#include"stdio.h"
#define NUM 3
structcomm
{
char ncom[20];
char phone[10];
};
main()
{
structcomm man[NUM];
int i;
for(i=0;i<NUM;i++)
{
printf("input ncom:\n");
gets(man[i].ncom);
printf("input phone:\n");
gets(man[i].phone)
松语文学免费小说阅读_www.16sy.com