您好,欢迎来到星星旅游。
搜索
您的当前位置:首页C语言程序设计笔记,知识点及例题

C语言程序设计笔记,知识点及例题

来源:星星旅游


第一章 程序设计基本概念

1.1程序和程序设计

程序:连续执行的一条条指令的集合称为“程序”。 1.1.2程序设计

1.确定数据结2.确定算法3.编码4.在计算机上调试程序 5.整理并写出文档资料 1.2算法

定义:是指为了解决某个特定的问题而采取的确定且有限的步骤。

1有穷性 2确定性 3可行性 4有零个或多个输入 5有一个或多个输出 1.3结构化程序设计和模块化结构 结构化程序由三种基本结构组成

1顺序结构 2选择结构 3循环结构 12)计算机能直接执行的程序是(B )。

A)源程序 B)目标程序 C)汇编程序 D)可执行程序 13)以下叙述中正确的是( D )

A)程序设计的任务就是编写程序代码并上机调试 B)程序设计的任务就是确定所用数据结构 C)程序设计的任务就是确定所用算法

D)以上三种说法都不完整

第二章 :C程序设计的初步知识

(11)以下叙述中正确的是( C )。

A)C 程序的基本组成单位是语句 B)C 程序中的每一行只能写一条语句 二级C 语言程序设计试卷)

C)简单C 语句必须以分号结束 D)C 语句必须在一行内写完

(11)以下叙述中正确的是( C )

A)C程序中的注释只能出现在程序的开始位置和语句的后面 B)C程序书写格式严格,要求一行内只能写一个语句 C)C程序书写格式自由,一个语句可以写在多行上 D)用C语言编写的程序只能放在一个程序文件中

第二课:C语言的基础知识

2.2标识符,常量和变量 2.2.1 标识符:

定义:由字母,数字和下划线组成,并且第一个字符必须为字母或下划线的。这样的组成就是标识符。

注意:在C中大写字母与小字字母被认为是两个不同的字符。 分类:

关键字:在C中已经定义好了的,不能用作它用的。如if double int 等等。 预定义标识符:如printf scanf

用户标识符:用户根据自己的需求来定义的。

(12)以下选项中,能用作用户标识符的是( C ) A)void B)8_8 C)_0_ D)unsigned (11)以下选项中合法的标识符是( C ) A) 1-1 B)1—1 C)-11 D)1—

(12)以下选项中不合法的标识符是 ( C ) A)print B)FOR C)&a D)_00

2.2.2常量:

定义:是指在程序的执行的过程中,其值不会被改变的量。 分类:

整型常量:没有小数的常量

如:3 9 1234等等都是。 实型常量:有小数点的常量 如:3.9 3.0 3.

字符常量:由单个字符组成的量 如:‟a‟ „b‟ „3‟

字符串常量:至少由一个字符组成的量 如:“a” “abc” “ beijing”

符号常量:符号常量的值到底是多少,这是由在来定义符号常量时来决定的

(13)以下选项中,能用作数据常量的是 ( D ) A)o115 B) 0118 C)1.5e1.5 D) 115L

(13)以下选项中不能作为C 语言合法常量的是( A )。

A)'cd' B)0.1e+6 C)\"\\a\" D)'\\011' (13)以下选项中不属于字符常量的是 ( B ) A)'C' B)\"C\" C)'\\xCC0' D)'\\072'

2.3整型常量与实型常量 整型常量的几个表示方法 十进制数:

八进制数:以0开头的数字,由0-7组成。 下列合法的八进制数是 A,0 B,028 C,-077 D,01.0

十六进制数:以0X开头,由0-9和A-F组成。 A,oxff B,0xabc C,0x11 D,0x19 实型常量 123.4 小数形式:123.4 指数形式:1.234e2

1. 字母e和E之前必须要有数字 2.字母e和E之后的数字必须是整数 3.字母e’和数字之间不能有空格。

A,2.607E-1 0.8103E 2 -77.77 456E-2 0.1e+6 1.23E1.2

2.2.4变量:

1.定义:在程序的运行过程中其值可以被改变的量,就叫变量。

2.原则:变量必须先定义后使用。变量定义的过程就是给变量开辟存储单元的过程。 3.分类:

整型变量:用关键字int来表示. short int 短整型

long int 长整型 在内存中占4个字节 如123L unsigned 无符号 如有-200U这就是错的。 变量的定义:int a 这是定义了一个整型变量a. 实型变量:用关键字 double 或float来表示。 float 单精度 在内存中占4个字节 double 双精度 在内存中占8个字节。

2.2.5 算术表达式

一、基本的算术运算符

+ - * / % 这些是双目运算符(就是指操作对象有两个) 注意:

除%外,其它的运算符的运算对象可以是整型也可以是实型。%的操作对象只能是整型。

如10%3=1 10.7%3 10%4.5 x%3=0 + - 也可以做为单目运算。-5.4 +4.9 说明:

1.如果双目运算符两边运算数的类型一致,则所得结果的类型与运算数的类型一致。如 1.0/2.0=0.5 1/2=0

2.如果双目运算符两边运算数的类型不一致,则系统会自动进行类型转换,使两边的类型一致后,再进行运算。 1.0/2=0.5

3.所有的单精度数据,在运算过程中都以双精度进行运算。 二、优先级

() + - * / % + - 由高——————低 如 (5+1)/2=???

2.5.3 强制类型转换表达式 格式:(类型名) (表达式) 例:(int)3.234=3

(double)10%3=?

(14)表达式:4-(9)%2的值是( B )

A)0 B)3 C)4 D)5

(14)设变量已正确定义并赋值,以下正确的表达式是 ( C )

A)x=y*5=x+z B)int(15.8%5) C)x=y+z+5,++y D)x=25%5.0

2.6赋值表达式

格式:变量名=表达式

注:1.不可以颠倒(左边必须是变量名,右边必须是C语言中合法的表达式)

2.功能就是先求出右边表达式的值,然后把此值赋值给赋值号左边的变量。确切的说是把数据存入以该变量为标识的存储单元中去。a=4 , a=7

3.结合性的优先级仅高于逗号表达式。顺序是自右向左的。如a=2+7/3 4.\"=\"是一个赋值号,不是一个等号。

5.x=y。变量的值也是可以传递和赋值的。它的意思就是将变量Y中的值赋值到X中去。同样N=N+1也成立

6.赋值运算符的左侧只能是变量,不能是常量或表达式 a+b=c这就是违法的 7。赋值号的右边也可以是一个赋值表达式。如a=b=7+1; 补充;表达式与语句的区别,

表达式后面加一个分号就是语句。

2.6.2复合赋值表达式 例:

a+=3------a=a+3 同理可得a*=3 /= -= a+=a-=a+a a 的初值是9 a+=a-=18 a+=(a=a-18) a+=(a=-9) a+=a -18

(15)若有定义语句:int x=10;,则表达式x-=x+x的值为( B ) A)-20 B)-10 C)0 D)10

(14)设有定义:int x=2;,以下表达式中,值不为6的是 ( D ) A) x*=x+1 x=x*(x+1) B) x++,2*x C)x*=(1+x) D)2*x,x+=2

(17)若变量均已正确定义并赋值,以下合法的C语言赋值语句是 (A) A)x=y==5; B)x=n%2.5; C)x+n=I D)x=5=4+1;

2.7 ++ 和— —的讲解 ++:自身加1 --:自身减1 如

i=3 i++_______I=i+1 i=4 单目 3++

++I I++

当++在前,先自身加1,然后再干别人让干的事情 。 当++在后,先别人让干的事情然后再干 自身加1。 int i=3; int a;

a=i++; a=3 a=++I;a=4

第三课:输入和输出语句 3.2输出语句的讲解

一、printf函数的一般调用形式

格式:printf(格式控制,输出项1,输出项2,.......); 在printf函数的最后面写上;号就是输出语句。 1,给输出项白提供输出格式说明 格式说明符:

作用:就是使数据按格式说明符的要求进行输出。 组成:由%号和紧跟在其后的格式描述符组成。 int--------%d

float或double---%f或e% char--------%c 2.提供原样输出的文字或字符

在 “ ” 中除了格式说明符之外的内容要全部原样输出。 各个输出项之间要用逗号隔开。

输出项可以是任意合法的常量,变量或表达式。

printf中常用的格式说明

在格式说明符中,每一个格式说明符都必须以%号开头由相应的类型标识字母结束。但在他们之间可以有其它的一个内容: %c :输出一个字符

%d:输出一个十进制的数据 %o:以八进制格式输出。 %X:以十六进制输出 %U:无符号十进制输出 %f:以带小数点的数字输出 %e:以指数形式输出 %s:输出一个字符串。 %%:输出一个%号

%4d:输出的数据长度是4个长度,当原来的长度大于4个时会自动突破。小于4个时会填充空格。

%x.yf: x代表数制的宽度(包括小数点)。Y代表小数点后面的小数位数。

注意事项:

1.输出比较自由一些,输出有的各个数之到底是什么,取决于格式说明符之间的内容。 2.格式说明符要与输出项一一对应。 3.输出语句中还可以有 \\n \\r \ \\a

4.尽量不要在输出语句中改变输出变量的值。

5.输出的数据中如果存在变量,一定要定义过的。

输入语句

格式: scanf(格式控制,输入项1,输入项2,...);

例如:想通过键盘输入3个数分别给变量a,b,c。并且他们分别为整型,浮点型,双精度型。

输入语句为scanf(\"%d%f%lf\说明:

1.格式说明符与输出语句一样。

2.在格式串中,必须含有与输入项一一对应的格式转换说明符。

3.在VC6.0的环境下,要收输入的DOUBLE型数据的格式说明符一定要用%lf,否则数据不能正确的输入

4.由于输入是一个字符流,所以当输入的数据少于输入项时,程序会等待用户输入,直到满足要求。当输入的数据多于输入项时,多余的数据会自动作废。 复合语句:多个语句被{}括起来,当成一条语句来执行。 空语句:最后的表示只有一个;

程序举例:

1。编写一个程序,从键盘上输入两个数字,让后让他们互换一下。 #include main() {

int a,b;

printf(\"请输入两个数字:\"); scanf(\"%2d%3d\printf(\"qian:%d%d\int c;

c=a,a=b,b=c;

printf(\"后:%d%d\}

2。编写程序,对一个double型数据进行四舍五入运算。要求保留两位有效小树。

123.4567

123'4567*100=12345.67 12345.67+0.5=12346.17 (int)(12346.17)=12346 12346/100=123.46

第四课:C语言的程序结构

4-1节、关系运算与逻辑运算 一、简介

关系表达式与逻辑表达式的运算结果都会得到一个逻辑值。就是“真”、“假” 在C语言中0表示“假”,非0(无论是负数还是正数都是真,更多时候用1来代替)表示“真”。

二、几个简单的关系运算符

< <= > >= == != 注意:

1,由两个字符组成的运算符,中间不能有空格

2,它们都是双目运算符,具有自左至右的结合性。

3,上面的6个运算符中,前4个的优先级要比后2个的优先级要高。 先计算,后判断,最后进行赋值运算。 三、几个简单的逻辑运算符

&& 与 一假则假 || 或 一真则真

! 非 非假则真,非真则假

4-2、4-3节、 if语句 一、定义:

只有两种结果。要么执行这条语句,要么执行那条语句。 if(条件表达式)

上述条件成立执行的句子 else

上述条件不成立执行的句子 如:

if(成绩>60) 显示及格 else

显示不及格 二、分类

1.不含有else的语句 2.含有else语句 if(条件) 语句1; else {

语句2; 语句3; } 注:

1.没有分号

2.控制的是与if或者else紧临的“一条”语句。 4-4节、结合一个例题来给大家分析if的嵌套

输入一个学生的成绩,评定他的等级。每十分一个等级 if() elseif() elseif() else

if(a>=90) printf(\"a\"); elseif(a>=80) printf(\"b\"); elseif(a>=70) printf(\"c\"); elseif(a>=60) printf(\"d\"); else printf(\"e\");

4-6节、条件表达式

是C语言中唯一的一个三目运算。 格式 :表达式1?表达式2:表达式3

当1成立(非零时)时,表达 式的值就是2的值,否则就是3的值。 如:

1.1<2?4:5

2.printf(\"%d\ (假定X的值为-3) 3.++X>3?(x<3?a:b):b

4-7节、switch语句(一) switch(表达式) {

case 常量表达 式1:语句1 case 常量表达 式2:语句2 case 常量表达 式3:语句3 case 常量表达 式4:语句4 case 常量表达 式5:语句5 。。。

case 常量表达 式N:语句N }

4-8节、switch语句(二) switch(A/10) {

case 10:printf(\"A\"); case 9:printf(\"A\"); case 8;printf(\"b\"); case 7;printf(\"c\"); case 6;printf(\"d\"); default :printf(\"e\"); }

第五课:循环结构

5-1、5-2节、while 语句 一、格式 : while(表达式)

循环体

注:1: 2:

3:一条 while(a<3)1 { a+=s;2 s=a;3}

1.......100

int i=1,sum=0; while(i<101)

sum=sum+i++;

printf(\"%d\

丛1开始加到哪个数时他们的和将超过1000? int i=1,sum=0;

while(sum<1000)

{sum+=i;999 +42=1041 i++;}42 43 printf(\"%d\

5-3节、do-while语句 do while() 格式: do 循环体 while(表达式)

1 2 3 5 8 13 do {

a3=a1+a2; a1=a2; a2=a3;

}while(a3<=1000); 1:1 2:;

5-4节、for语句(1)

for语句和for语句构成的循环结构 一、格式:

for(表达式1;表达式2;表达式3) 循环体 相当于while语句的 表达式1; while(表达式2) {

循环体; 表达式3; } k=0

for(;k<=10;) {printf(\"*\"); k++; }

int k=0; while(k<10) {

printf(\"*\"); k++;

}

注:

1:表达式可以省略,但分号不可以。

2:表达式可以是任意有效的C语言表达式

课后习题部分,笔记不再提供,请大家看教程。

第六课、字符型数据

6-1节、字符型常量 格式:‟a‟ „A‟ „ ‟ 要求:

1,单引号中的大写字母和小写字母代表不同的字符常量。

2.单引号中的空格也是一个字符常量,但不能是两个连续的单引号 3.字符常量只能用单引号括起来,不能用双引号。 转义字符 \\n代表回车

\\‟代表一个单引号 „ \\\\代表一个\\

\\”代表一个双引号 注意:

1. 转义字符常量,如‟\\141‟只代表一个字符

2. 反斜线后的8进制数可以不用0开头。如1中所讲的141就是一个8进制数。

0141

3. 反斜线后的16进制数只可以用x开头,不可以用X开头。 字符串常量

格式:由双引号括起来的一串字符。 同时也要知道“A”和‟A‟是不一样的。 “A” „A‟ ACSII码

A 65 a 97

„a‟-„A‟= 32

6.2节、字符变量 格式:char a=‟s‟

6.3字符的输入和输出

Printf和scanf函数输出和输入字符 对于字符型数据的格式说明符是%c Char c=‟a‟; Printf(“%c”,c); Char a,b,c,d;

Scanf(“%c%c%c”,&a, &b, &c);

6-3节、程序举例

写出26个大写字母和他们的ASCII代码要求每行输出两组数据。 #include Main() {

Char ch; int I; For(i=0;i<26:i++) {

Ch=i+65; If(i%2= =0) Printf(“\\n”);

Printf(“c=%c,ASCII=%d”,ch,ch); } }

在上面的程序中有对于字符的输入与输出,在C语言中也有另外的输入输出字符的语句。

输入:变量名=getchar() 输出:putchar(变量名)

第七章 函数

7-1节、库函数

1.调用C语言标准库函数时要求的include命令行

Include命令行必须以#开头,系统提供的头文件以.h作为文件的后缀,文件名用一对双引号或一对尖括号(需要注意include命令行不是C语句,因此不能在最后加分号) 2.标准库函数的调用 函数名(参数表) 如:putchar(ch)

(1) 出现在表达式中的 ------ch=getchar()

(2) 做为单独的语句完成某种操作。-----printf(“********”); 7.2函数的定义和返回值

由于C语言中的定义的函数不能完成用户所有的要求,所以用户可以为自己定义函数实现相应的功能。 7.2.1函数定义的语法 1:格式:

函数返回值的类型名 函数名(类型名 形式参数1,类型名 形式参数2……) {

说明部分 语句部分

}

2:函数名和形式参数都是用户命名的标识符。在同一个程序中,函数名必须唯一,形式参数名只要在同一函数中唯一即可,可以与其他函数中的变量同名。 3:C语言规定,不能在函数的内部定义函数。

4:若在函数的首部省略了函数返回值的类型名,则说明该函数的返回值是int类型

5:除了返回值类型为int类型的函数外,函数必须先定义后调用。

6:当没有函数返回值,则必须把函数定义成void类型。 例:编写求两个双精度数之和的函数。 double add(double a, double b )

{

double s; s=a+b; return s; }

7-2节、函数的返回值

函数的值通过return语句返回, return 表达式;

此表达式的值必须与函数首部所说明的类型一致,若类型不一致,则以函数值的类型为准。需要注意的是,无论函数体中有多少个return语句,只能执行一次。

函数体内可以没有return语句,这时也必须定义函数为 viod类型。

7-3节、函数的调用

7.3.1函数的两种调用方式 格式为:

函数名(实在参数表)

当实参的个数多于一个时,各实参用逗号隔开。实参的个数必须与调用函数中形参的个数相周,类型一一对应匹配。

如没有形参,则形式为 函数名() 注意后面的小括号不能丢。 如题:

#include

double add(double ,double); main() {

double m,n,z;

scanf(“%lf %lf”,m,n); z=add(m,n); printf(“%lf”,z);\\ }

double add(double a, double b )

{

double s; s=a+b; return s; }

7.3.2 函数调用时的语法要求

1.调用函数时,函数名必须与所调用的函数名字完全一致。 2.实参的个数必须与形参的个数一致。 3.C语言中规定,函数必须先定义后使用。

4.C语言中,函数可以直接或间接的自己调用自己。称为递归调用 fac(n)=fac(n-1)*n

7-4节、函数的说明

在C语言中凡是未在调用前定义的函数,C编译程序都默认函数的返回值为int 型。对于返回值是其它类型的,若把函数的定义放在调用之后,应该在调用之前对函数进行说明。

说明的格式:

类型名 函数名(参数类型1,参数类型2.。。。。) 也可以用以下格式

类型名 函数名(参数类型1 参数名1,参数类型2 参数名2,……) 函数说明的位置:

一般为了让程序早点识别出程序中的定义好了的函数,一般将其放在程序的开始部分

7-5节、调用函数和被调用函数之间的数据传递 一:三种格式进行传递

1.实在参数和形式参数之间进行数据传递 2.通过return语句把函数值返回调用函数

3.能过全局变量,但这不是一种好的方式,通常不提倡使用。 通过一个程序来看一下数据到底是怎样传递的。 #include viod try(int ,int ,int ); main() {

int x=2,y=3,z=0;

printf(“(1)x=%d y=%d z=%d\\n”,x,y,z); try(x,y,z);

printf(“(4) x=%d y=%d z=%d\\n”,x,y,z); }

void try(int x,int y,int z) {

printf(“(2) x=%d y=%d z=%d\\n”,x,y,z); z=x+y; x=x*x; y=y*y;

printf(“(3) x=%d y=%d z=%d\\n”,x,y,z”); }

屏幕上的结果是: (1) x=2 y=3 z=0 (2) x=2 y=3 z=0 (3) x=4 y=9 z=5 (4) x=2 y=3 z=0

再来一个程序 #include viod swap(int ,int); main() {

int x=10,y=20;

printf(“(1)x=%d y=%d\\n”,x,y); swap(x,y);

printf(“(4)x=%d y=%d\\n”,x,y); }

void swap (int a,int b ) { int t;

printf(“(2) a=%d b=%d\\n”,a,b); t=a;a=b;b=t;

printf(“(3)a=%d b=%d\\n”,a,b); }

程序运行结果 (1) x=10 y=20 (2) a=10 b=20 (3) a=20 b=10 (4) x=10 y=20 7.6程序应用举例

编写一个函数isprime(int a),用来判断自变量a是否为素数。若是素数,函数返回整数1,否则返回0.

#include int isprime(int) main() { int x;

printf(“enter a integer number:”); scanf(“%d”,&x); if(isprime(x))

printf(“%dis prime \\n”,x); else

printf(“%dis not prime\\n”,x); }

int isprime(int a) { int i;

for(i=2;i<=a/2;i++) if(a%i==0) return 0; return 1; }

编写函数myupper(ch),把ch中的小写字母转换成大写字母作为函数值返回,其他字符不变。主函数中不断输入字符,用字符@结束输入,同时不断输出结果。 #include #include char myupper(char ch) {

if(ch>=‟a‟&&ch<=‟z‟) ch=ch-32; return ch; }

main() {

char c;

while((c=getchar())!=‟@‟) {

c=myupper(c); putchar(c); } }

编写函数统计输入字符的个数,用@字符结束输入,在主函数中调用此函数,输出统计结果。

#include long countch(); main() {

long n;

n=countch();

printf(“n=%ld\\n”,n); }

long countch() {

long cn;

for(cn=0;getchar()!=‟@‟;cn++) ;

return cn; }

7-10----7-13节、课后习题

[7.1] 以下说法中正确的是 C

A)C语言程序总是从第一个定义的函数开始执行

B)在C语言程序中,要调用的函数必须在main函数中定义 C)C语言程序总是从main函数开始执行

D)C语言程序中的main函数必须放在程序的开始部分 [7.2] 以下函数的类型是C A)与参数x的类型相同 B)void类型 C)int类型 D)无法确定 fff(float x)

{ printf(\"%d\\n\

[7.3] 以下函数调用语句中,含有的实参个数是B A)1 B)2 C)4 D)5 func( (exp1,exp2),(exp3,exp4,exp5)); [7.4] 以下程序的输出结果是C

A)11 B)20 C)21 D)31 func(int a,int b) { int c c=a+b; return c; }

main()

{ int x=6,y=7,z=8,r;

r=func((x--,y++,x+y),z--);

printf(\"%d\\n\

}

[7.5] 以下程序的输出结果是A

A)-1 B)0 C)1

main()

{ int i=2,p;

p=f(i,i+1);

printf(\"%d\

}

int f(int a,int b)

{ int c;

c=a;

if(a>b)c=1;

else if(a==b)c=0;

else c=-1;

return(c);

}

[7.6] 以下程序的输出结果是D

A)0 B)1 C)6

D)2 D)无定值

fun( int a, int b, int c)

{ c=a*b; }

main()

{ int c;

fun(2,3,c);

printf(\"%d\\n\

}

[7.7] 以下程序的输出结果是A

A)5.500000 B)3.000000 C)4.000000

double f(int n)

{ int i; double s;

s=1.0;

for(i=1; i<=n; i++) s+=1.0/i;

return s;

}

main()

{ int i,m=3; float a=0.0;

for(i=0; iprintf(\"%f\\n\

}

二、填空题

[7.8] 以下程序的输出结果是____12____.

unsigned fun6(unsigned num)

{ unsigned k=1;

D)8.25

do

{ k*=num%10; num/=10; }

while(num);

return k;

}

main()

{ unsigned n=26;

printf(\"%d\\n\

}

[7.9] 以下程序的输出结果是___9.0_____.

double sub(double x,double y,double

{ y-=1.0;

z=z+x;

return z;

}

main()

{ double a=2.5,b=9.0;

printf(\"%f\\n\

}

[7.10] 以下程序的输出结果是___4_____.

fun1(int a,int b)

{ int c;

a+=a; b+=b;

c=fun2(a,b);

return c*c;

z)

}

fun2(int a,int b)

{ int c;

c=(a*b)%3;

return c;

}

main()

{ int x=11,y=19;

printf(\"%d\\n\

}

[7.11] 下面pi函数的功能是,根据以下公式返回满足精度要求的的值.请填空.

pi/2=1+1/3+1/3*2/5+1/3*2/5*3/7+1/3*2/5*3/7*4/9+...

double pi(double eps)

{ double s=0.0,t=1.0;

int n;

for(__n=1__;t>eps;n++)

{ s+=t;

t=n*t/(2*n+1);

}

return (2.0*__S___);

}

[7.12] 以下函数用以求x的y次方.请填空.

double fun(double x,int y)

{ int i; double z=1;

for(i=1; i___<=y__; i++)

z=___z*x__;

return z;

} n

[7.13] 以下程序的功能是计算S= S K!.请填空.

long f(int n) K=1

{ int i; long s;

s=__1___;

for(i=1; i<=n; i++) s=__s*i___;

return s;

}

main()

{ long s; int k,n;

scanf(\"%d\

s=__0___;

for(k=0; k<=n; k++)s=s+___f(k)__;

printf(\"%ld\\n\

}

三、程序调试和编程题

[7.14] 以下fun函数用以判断n是否是素数,fun函数中有逻辑错,请调试改正. fun(int n)

{ int k,yes;

for(k=2; k<=n/2; k++) if(n%k==0) return yes= 0; yes=1; return yes; }

第八章 : 指针变量

8.1变量的地址和指针:

在最开始的时候,一直给大家强调变量要先定义,后使用。为什么会这个样子?这是因为,每当我们使用一个变量系统就必须要给他开辟一个存储单元。系统要对它的值进行记录。每时每刻的记录。怎样进行记录呢?系统会自动的开辟一个地方将该变量监督起来,观察和记录它的变化。这个地方多大放什么东西?这都要求我们提前和系统说好。所以就有了变量要先定义在使用说法。其实变量定义的过程就是给他开辟存储空间的过程。那么存储空间又是什么东西呢??

计算机种有一个硬件叫内存条,当我们提起这个硬件的时候往往都会说多大的。1G,2G,4G……这都是在说他的空间大小。计算机中的内存是以字节为单位的一片连续的存储空间,每一个字节都有一个编号,这个编号就称为内存地址。如同旅馆的房间一样,单人间,双人间等等,每个房间都有自己的编号。

内存中的空间是连续的,地址号也是连续的,并且都是用二进制数来表示的。

变量在定义的时候先要说明定义的类型。如:int k; double b; char ch;等等如此的定义。这样是在和电脑系统打招呼,我们是2人要一个两人间。目的就是告诉老板你的房间要是两个人的空间。不能定的是2人间,结果来了3个人住;同时也不能定的2人间,结果就你自己来了(对自己来说多花钱了)。

综上所述:变量的定义就是给变量开辟存储空间的过程。 int a float b a a b b b b

1012 1013 1014 1015 1016 1017

这就是变量定义的时候系统给随机开辟的地址空间。在结合我们在一开始讲的不同类型的变量的大小,其实就是在说变量所占的内存单元的多少。

1012就是整型变量a的首地址,1014就是浮点型变量b 的首地址。

当要用到一个变量时,系统就会迅速的找到这个变量。所以在C程序中还有这样的一个变量的存在,就是指针。

指针就是用来存放一个变量在内存中的地址,当要调用这个变量的时候能迅速的找到。用来存放一个变量地址的变量就叫指针变量。

同时大家也要走出一个误区就是:指针变量之所以叫变量,就是因为它里面所存放的变量的地址也不断的变化的。指针是可以移到的。

8.2指针变量的定义和指针变量的基类型 一:格式:

类型名 *指针变量名1, * 指针变量名2…. 如

int *pi,*pj;

与之前不一样的地方就是在变量的前面加了一个*。*是一个说明符,用来说明该变量是指针变量。*号省略的话就和普通的变量一样了。

又如:

int *pi; char * ch; int a; char c;

指针的作用都是一样的,都是用来存放地址的,为什么还要分类型的。原因就是指针变量pi只能存放整型变量的地址,指针变量ch只能存放字符变量的地址。

如何让一个指针存放一个变量的地址呢? pi=&a; ch=&c;

&叫取址符。*叫指针运算符。

能过以上的讲解在家一定对指针有了更进一步和了解。我们共同的回顾一下; 变量的定义就是给其开辟存储单元的过程。 任何一个变量都有自己的存储地址。 指针就是用来存放变量地址的。 指针也是一个变量。 指针也要一个地址。 那,

有没有能存放指针变量地址的一个对象呢?用该怎么称呼? 有

它是专门用来存放指针的地址的。 它就是指向指针的指针。 int **p ,*s; p=&s;

**p就是一个指向指针的指针。它里面只能存放同种数据类型的指针的地址。

8.3 给指针变量赋地址值

一个指针变量可以通过不同的方式获得一个确定的地址值,从而指向一个具体的对象。(在以后的课程中,每当一个指针中存放了一个变量的地址的时候,我们就说这个指针指向了这个变量)。 int k=1,*q,*p; q=&k;

q k 1

这时可以说:q指向了变量k;

q=&k+1 q=&(k+1) 这是错误的,指针q就是用来存放地址的,前两个例子不是。 同时:

&必须放在运算对象的左边,而且运算对象的类型必须与指针变量的基类型相同。 2,通过指针变量获得地址值

可以通过赋值运算,把一个指针变量中的地址值赋给另一个指针变量,从而使这两个指针指向同一地址。 int k,*p,*q; q=&k; p=q;

也就是说指针变量p和q都指向了变量k.

注:当进行赋值运算时,赋值号两边指针变量的基类型必须相同。 3.给指针变量赋“空”值; “ 空”:

null的代码值为0,当执行了以上和赋值语句后,称P为空指针。null的代码值为0. p=‟\\0‟ p=0;

注意: p并不是指向地址为0 的存储单元,而是一个有确定的值“空”。 8.4对指针变量的操作

C语言提供了一个称作“间接访问运算符”的单目运算符:“*”当指针变量中存放了一个确切的地址值是,就可以用“间接运算预算符”通过指针来引用该地址的存储单元。

int *p,i=10,j; p=&i;

则这样的赋值语句 j=*p;

上面的这个赋值语句我们可以这样理解:j变量的值是由指针指向的空间中的值赋予的。这里的*p代表指针p中存放的变量i的地址中的值。*不是乘而是用来说明指针的说明符。

j=i~~~~~~~j=*(&i)

如果有这样的表达式代表:

j=*p+1 代表指针p指向的空间中中的值加1后的值给了变量j; 再如

int *p,k=0; p=&k; *p=100; *p+=1;

注意:当*p出现在赋值号左边时,代表的是指针所指的存储单元,当出*p出现在赋值号右边时,代表的是指针所指的存储单元的内容。 如果有: *p+=1 ++*p (*p)++

这三个表达式有什么不一样吗? ++和*两个运算符的优先级相同。但按自右至左的方向结合。因此++*p相当于++(*p)。而在(*p)++中,一对括号不可以少,(*p)++代表先取里面的值然后再加1。而如果去掉怎成了*p++,根据顺序,先++然后再取值。这样就成了先p++再取值。而P++就是指针先向后移动。 例8,1

用指针指向两个变量,通过指针运算选出值小的那个数。 #include main() {

int a,b,min,*pa,*pb,*pmin; pa=&a;pb=&b;pmin=&min; scanf(“%d%d”,pa,pb);

printf(“a=%d, b=%d\\n”,a,b); *pmin=*pa; if(*pa>*pb) *pmin=*pb;

printf(“min=%d\\n”,min); }

8.4移动指针

所谓移动指针就是对指针变量加上减去一个整数,或通过赋值运算,使指针变量指向相邻的存储单元。

(因此只有当指针指向一串连续的存储单元时,指针的移动才有意义)

a[0] a[1] a[2] a[3] a[4] 11 22 33 44 55

P

q

p=&a[0] q=p+2 q++ q++ q- - p++

对指针进行加减运算时,数字“1”不再代表十进制数1,而是指一个单位存储单元长度。这个单元到底多长,要看存储数据的类型了。

如果是int则代表1个存储单元长度就是位移4个字节。如果是char类型则代表1个存储单元长度就是位移1个字节。如果变量的类型是double,8个字节为一个单位,而指向它的指针是int,4个字节为一个单位。那么这个时候指针每移动一个单位就代表移动4个字节的长度,这个时候读取数据的时候就会出错。

8.5函数之间地址值的传递

▲形参为指针变量时参数和形参之间的数据传递

若函数的形参为指针类型,调用该函数时,对应的实参必须是基类型相同的地址值或者是已指向某个存储单元的指针变量。

例题:编写函数myadd(int*a ,int *b),函数中把指针a和b所指的存储单元中的两个值相加,然后将和值作为函数值返回。在主函数中输入两个数给变量,把变量地址做为实参,传给对应的形参。

#include

int myadd(int *a,int *b) {

int sum; sum=*a+*b; return sum; } main() {

int x,y,z; int *p,*q; p=&x,q=&y;

printf(“enter x,y:”); scanf(“%d%d”,&x,&y); z=myadd(*p,*q);

printf(“%d+%d=%d”,x,y,z); }

▲ 通过传送地址值在被调用函数中直接改变调用函数中的变量的值 之前我们已经知道形参值的改变并不能改变对应实参的值,把数据从被调用函数返回到调用函数的唯一途径是通过return语句返回函数值。

例题:调用swap函数,交换主函数中变量x和y中的数据 #include void swap(int *,int *) main() {

int x=30,y=20;

printf(“(1)x=%d y=%d \\n”,x,y); swap(&x,&y);

printf(“(4)x=%d y=%d\\n”,x,y); }

void swap(int *a,int *b) { int t;

printf(“(2)a=%d b=%d\\n”,*a,*b); t=*a;*a=*b;*b=t;

printf(“(3) a=%d b=%d\\n”,*a,*b); }

例题:编写函数order(int *a,int *b),使用函数中的第一个实参总是存放两个数中较小的数,第二个参数存放两个数中较大的数 #include

void swap(int *x1,int *x2) { int t;

t=*x1;*x1=*x2;*x2=t; }

void order(int *a,int *b) {if(*a>*b) swap(a,b); }

main() {

int x,y;

printf(“输入x,y:”); scanf(“%d%d”,&x,&y);

printf(“x=%d y=%d\\n”,x,y); order(&x,&y);

printf(“x=%d y=%d\\n”,x,y); }

8.5函数返回地址值

函数值的类型不仅可以是简单的数据类型,而且可以是指针类型

例:以下函数把主函数中变量i和j中存放较大数的那个地址作为函数值传回。

第九章 数组

之前我们只学过单个变量的定义,而有的时候就需要一片连续的存储单元。单个单个的定义第一,分配的内存空间不一定连续,这样指针就不能移动了。第二,单个单个的定义会费时费力。所以这个时候就需要一个东西来满足用用户这样一个需求。数组就在这样的条件下产生了。

数组:多个相同类型的变量被存储在一片连续的存储单元中。 9.1一维数组的定义和一维数组元素的引用

★一维数组的定义:

当数组中每个元素只带有一个下标时,称这样的数组为一维数组。 格式: 类型名 数组名【整型常量表达式】 如 int a[10] 说明:

1. 定义了一个名为a的一维数组

2. 方括号中的10规定了a数组含有10个元素,它们是(a[0]. a[1]. a[2].

a[3].a[4].a[5]. a[6]. a[7]. a[8]. a[9])

3. 类型名int规定了a数组中每个元素都是整型,在每个元素中只能存放整形数。 4. 每个元素只有一个下标,C语言规定每个数组第一个元素的下标总为0(称为数组

下界),那么最后一个9(称为数组的下标为上界)

5. 在内存中给数组中每个成员开辟了一个存储单元。总计大小:10*4=40字节。这

样每当调用数组中的一个成员时就用它们的下标。如 a[*]

注:当同时定义多个数组时彼此之间用,号隔开 如 double w[22],v[100],u[5]; 以上定义了三个数组。 需要注意的是,【】中的内容只能是整型常量或整型常量表达式。如int a[11+22]也可以。 ★ 一维数组元素的引用

格式: 数组[下标表达式]

其实x[0],x[j],x[i+k]都是对数组中元素的合法引用形式。但是需要注意的是下标表达式的值必须大于或等于0,并且小于数组上界的数。 能过上面知识讲解,大家应该建立以下概念:

1:一个数组元素实质上就是一个变量名,代表内存中一个存储单元。一个数组占有一串连续的存储单元。

2:在C语言中一个数组不能整体引用。不能说用一个数组名就代表整个数组了。这是错误的。因为在C语言中规定数组名是一个地址常量,它代表整个数组的首地址。 int *p ;int a[10] p=a(p=&a[0]) a= =&a[0] a=10 3:数组元素中下标表达式的值必须是整数。在编写程序时保证数组下标不越界是十分重要的。

a[2.5] a[10]=123 ★ 一维数组的初始化

一维数组的始化,其实就是给数组元素赋值。 格式: int a[8]={0,1,2, 4,5,6,7}

所赋的值放在等号后的一对花括号中,数值类型必须必须与所说明的类型一致,所赋值之间用逗号隔开。系统会按赋值顺序来自动分配。

当花括号中的值少于数组元素个数时,将自动给数组后面元素赋值0.如 int a[10]={1}这个时候除了a[0]=1外,其它的都是0; 对于字符数组也是一样; char a[10]={‘!’} 不够的也会赋值‘\\0’

通过赋初值定义数组的大小

C语言中规定,可以通过赋初值来定义数组的大小,这时数组说明符的一对方括号中可以不指定数组的大小。

如 int a[]={1,1,1,1,1,1,1,1,1,1}

这样相当于数组中有了10个元素

例题:编写一个程序,通过键盘给数组a中的10个成员赋初值。 #include main() {

int a[10]; int i,*p; p=a;

for(i=0;i<10;i++) {scanf(“%d”,p);

printf(“a[i]=%d”,*p);} }

编写一个程序定义一个含有30个成员的数组。并给其赋值,要求从1这样的奇数开始。当赋值完毕后,按每行10个输出。 include #define m 30 main() {

int a[m]; int i,k=1;

for(i=0;ifor(i=0;i{ printf(“a[%d]=%d”,i,a[i]); if((i+1)%10= =0) printf(“\\n”);} }

9.2一维数组和指针

★一维数组和数组元素的地址

前言:定义的数组名可以认为是一个存放地址值的指针变量名,其中的地址值是数组第一个元素的地址,也就是数组所占一串连续存储单元的起始地址。重要的是:这个指针变量中的地址值不可改变,也就是说,不可以给数组重新赋值。因此,也可以认为数组名是一个地址常量。

如: float a[10] ,*p,x;

语句a=&x或a++这样的语句都是非法的。因为不能给a重新赋地址值。一旦定义a永远指向a数组的首地址。

虽然不可以改变数组名a中的内容,但可以用对数组名加一个整数的办法,来依次表达该数组中不同元素的地址。

如:int a[10],*p; p=a+4~~~~~~~~~~p=&a[4] 再如:for(k=0;k<10;k++) p=a+k;

在循环中并没有改变数组名a中的内容,但通过表达式:a+k逐一给出了a数组中每个元素的地址,使p依次指向a数组中和每一个元素。

如果要能过类似上面的语句给数组中的元素赋值,语句为: for(k=0;k<10;k++)

scanf(“%d”,a+k);

如有p=a或p=&a[0]这两个表达式所要表达的意思是一样的。都是指指针P指向了数组a的首地址。所以当要依次访问数组中的每一个元素时可以用以下的两个形式; p++;

或a+k(k的值是不断变化的如上面的for语句一样) ★ 通过数组的首地址引用数组元素

a是数组元素的首地址,a(即a+0)的值即等于&a[0],则用a+1的值等于&a[1]. 在以前我们学过“间接访问运算符”----“*”来引用地址所在的存储单元。因此对于数组a[0],可以用表达式*&a[0]来引用也可以用*(a+0),还可以用a[0]来表示。 但需要注意的是对于*(p+k)这样的表达式不能这样写*p+k,这样写的话就错了。代表指针取值后再加K的值了。

总结:表示数组元素s[i]的表达式应当有 s[i] *(s+i) *(p+i) *p[i]

(但当p=s+2时,p=&a[2].*p[0]就是a[2]的值了) 9.3函数之间对一维数组和数组元素的引用 数组元素作实参

每个数组元素实际上代表内存中的一个存储单元,故和普通变量一样,对应的形参必须是类型相同的变量。数组元素的值可以传送给该变量,在函数中只能对该变量进行操作,而不能直接引用数组元素,更不能在函数中改变对应数组元素中的值。 数组名作实参

数组名也可以作为实参传送,但数组名是一个地址值,因此,对应的形参就应当是一个指针变量,此指针变量的基类型必须与数组的类型一致。这样就可以通过指针变量来引用调用函数中对应的数组元素,从而达到对调用函数中对应的数组元素进行操作而改变其中的值。

例:编写程序,通过一个函数给主函数中定义的数组输入若干大于或等于0的整数,用负数作为输入结束标志,调用另一个函数输出该数组中的数据。 #include #define M 100

void arrout(int *,int); int arrin(int *); main() {

int s[M],k; k=arrin(s); arrout(s,k); }

int arrin (int *a) {

int i,x; i=0;

scanf(“%d”,&x); while(x>=0) {

*(a+i)=x; i++;

scanf(“%d”,&x); }

return i; }

void arrout(int *a,int n) {

int i;

for(i=0;iprintf(((i+1)%5==0)?”%4d\\n”;”%4d”,*(a+i)); printf(“\\n”); }

当数组名作为实参时,对应的形参除了是指针外,还可以用另外两种形式。 在上面的题目中数组名作为实参时,函数的首部用的是指针arrin(int *a),还可以用以下的形式调用:、 arrin(int *a) arrin(int a[]) arrant(int a[M])

9.3.3数组元素地址作为实参

当用数组元素地址作为实参时,因为是地址值,所以对应的形参也应当是基类型相同的指针变量。

例:编写函数,对具有10个元素的char类型数组,从下标为4的元素开始,全部设置星号“*”;保持前4个元素中的内容不变。

假设数组是c[10]={‘A’,‘B’,‘C’,‘D’,‘E’,‘F’,‘G’,‘H’,‘I’,‘J’ }

根据题意可以知道想要从E开始后面的全变成* 编写一个改变的函数,编写一个输出的函数。 #include #define M 10 #define B 4

void setstar(char *,int); void arrout(char *,int); main() {

char c[M]= {‘A’,‘B’,‘C’,‘D’,‘E’,‘F’,‘G’,‘H’,‘I’,‘J’setstar(&c[4],M-B); arrout(c,M); }

void setstar(char *a,int n) {

int i;

for(i=0;ivoid arrout(char *a,int n) {

int i;

for(i=0;i9.4一维数组应用举例

编写程序,定义一个含有15个元素的数组,并编写函数分别完成以下操作。 1,调用C库函数中的随机函数给所有元素赋以0-49的随机数; 2,输出数组元素中的值。

3,按顺序对每隔三个数求一个和数,并传回主函数。 4,最后输出所有求出的和的值。 #include #include “stdlib.h” #define SIZE 15 #define N 3

void getrand(int *,int);

void getave(int * ,int *,int );

};

void priarr(int *,int ); main() {

int x[SIZE],w[SIZE/N]={0}; getrand(x,SIZE);

printf(“output%d random numbers:\\n”,SIZE); priarr(x,SIZE); getave(x,w,SIZE);

printf(“Output 5 sum numbers :\\n”); priarr(w,SIZE/N); }

void getrand(int *a,int n) {

int i;

for(i=0;ivoid getave(int *a,int *b,int n) {

int i,j,sum;

for(sum=0,i=0,j=0;i<=n;i++) {

sum+=a[i];

if((i+1)%3==0) {

b[j]=sum; sum=0 j++; } } }

void priarr(int *a,int n) {

int I;

for(i=0;iprintf(“%5d”,a[i]); if((i+1)%5==0) printf(“\\n”); }

printf(“\\n”); } 例:将数组中的数按颠倒的顺序重新存放。在操作时,只能借助一个临时存储单元,不得另外开辟数组。

注意:不是按颠倒的顺序打印数据,而是要求按逆序重新放置数组中的内容。 #include #define NUM 8

void invert (int *,int); void priout(int *,int); main() {

int a[num]={10,20,30,40,50,60,70,80}; printf(“输出数组中的内容:”); priout(a,NUM); invert(a,NUM);

printf(“输出数组中调换后的内容:”) priout(a,NUM); }

void priout(int s[],int n) {

int i;

for(i=0;iprintf(“%4d”,s[i]); printf(“\\n”); }

void invert(int *a,int n) {

int i,j,t; i=0;j=n-1; while(i{t=a[i];a[i]=a[j];a[j]=t; i++;j--; } }、

9.5二维数组的定义和二维数组元素的引用 9.5.1二维数组的定义

当数组中的每个元素带有两个下标时,称这样的数组为二维数组。(在逻辑是可以把二维数组看成一个具有行和列的表格或一个矩阵) 定义语句形式如下:

类型名 数组名[常量表达式1][常量表达式2]

二维数组说明符中必须有用两个方括号括起来的常量表达式,常量表达式的值只能是正整数。如果将二维数组当做矩形来看,那么常量表达式1就是代表行数,常量表达式2就代表列数。

如int a[3][4] a[1][2]

1. 定义了一个名为a的二维数组。 2. 数组中的每个元素都是整形

3. a数组有3*4个元素。

4. a数组的逻辑结构是一个具有3行4列的矩阵。 第0列 第1列 第2列 第3列 第0行 a[0][0] a[0][1] a[0][2] a[0][3] 第1行 a[1][0] a[1][1] a[1][2] a[1][3] 第2行 a[2][0] a[2][1] a[2][2] a[2][3]

其实对于二维数组来说,我们还可以理解为一个特殊的一维数组。如上,将此二维数组中的第0行可以看为一个名为a[0]的一维数组的几个成员。同理对另外几行也成立。 9.5.2二维数组元素的引用

引用二维数组元素时必须带有两个下标,引用形式如下:

数组名[下标表达式1][下标表达式2] int a[3][4]在这样定义的二维数组中, 有 a[0][1] a[i][j] a[i+k][j+k] 注意:引用二维数组元素时,一定要把两个下标分别放在两个方括号肉。不可以定成a[0,1] a[I,j] a[i+k,j+k] 9.5.3二维数组的初始化

1.所赋值个数与数组元素的个数相同

int a[4][3]={{1,2,3},{4,5,6},{7,8,9},{10,11,12}}; 2.每行所赋值个数与数组中元素的个数不同。 int a[4][3]={{1,2},{4,5},{7},{10}}; 3.所赋值行数少于数组行数 int a[4][3]={{1,2},{4,5}}; 5. 赋值时省略行花括号对

int a[4][3]={1,2,3,4,5}; 9.5.4通过赋值定义二维数组的大小 int a[]={1,3,3,3,3,34}

对于二维数组,只可以省略第一个方括号中的常量表达式,而不能省略第二个方括号中的常量表达式

int a[][3]={{1,2},{4,5},{7},{10}}; 当用以下形式赋值时:

int a[][3]={1,4,6,7,23,25,17,18}; 一维大小按以下规则决定:

1,当初值的个数能被第二维的常量表达式的值除尽时,所得商数就是第一维的大小。 2,当初值的个数不能被第二维的常量表达式的值除尽时。则第一维的大小=所得的商+1 9.5.5 二维数组的定义和数组元素引用举例

通过键盘给2*3的二维数组输入数据,第一行赋值1,2,3,第二行赋值10,20,30然后按行输出此二维数组 #include main() {

int a[2][3],i,j;

printf(“Enter data by line :\\n”); for(i=0;i<2;i++) for(j=0;j<3;j++)

scanf(“%d”,&a[i][j]);

printf(“Output a 2-dimension array :\\n”); for(j=0;j<2;j++) {

for(i=0;i<3;i++)

printf(“%4d”,a[i][j]); printf(“\\n”); } }

9.6二维数组和指针

9.6.1二维数组和数组元素的地址 先给出以下定义: int *p,a[3][4];

1. 二维数组a由若干个一维数组组成

像上面定义的数组a,我们可以理解为由a[0]、a[1]、a[2]三个元素组成,而他们又分别是一个一维数组

通过前面我们学过的知识可以知道,数组名是一个地址,其值是第一个元素的地址,此地址的基类型就是数组元素的类型。而在二维数组中同样a[0]、a[1]、a[2]都是一维数组名,同样也代表了一个不可变的地址常量。由于它是一个常量,所以这样就错了:a[0]++。而a[0]+1这就是代表向后移动一个单位长度。 对于有一个指针变量P的基类型与a[i]相同,则p=a[i]这是正确的。 2. 二维数组名也是一个地址常量

二维数组名同样也是一个存放地址常量的指针,其值为二维数组中第一个元素的地址。以上a的值与a[0]的值是相同的。 a[0] a+0 第0行的首地址 a[1] a+1 第1行的首地址 „„„

像他们这样的,还有一个另外的名称----行地址。所以二维数组名应理解为一个行指针。

inta[3][4] a[0]=a 3. 二维数组元素的地址

用以下的五种方式表示: &a[i][j] a[i]+j *(a+i)+j

&a[0][0]+4*i+j a[0]+4*i+j

9.6.2通过地址引用二维数组元素 若有以下定义: int a[3][4]

则a数组元素可以用一下五种表达式来引用: a[i][j] *(a[i]+j) *(*(a+i)+j)

(*(a+i))[j]

*(&a[0][0]+4*i+j)

9.6.3通过建立一个指针数组引用二维数组元素 int *p[3],a[3][2],i,j;

说明符*p[3]中,也遵照运算符的优先级,一对[]的优先级高于*号,因此p首先与[]结合,构成p[3],说明了P是一个数组名,系统将为它开辟3个连续的存储单元,在它前面的*号则说明了数组p是批针类型,它的每个元素都是基类型为int的指针。 如有:

for(i=0;i<3;i++) p[i]=a[i]

这就意味着每一个指针都指向了a数组中的每行的开头。

所以对于数组a中的元素,我们也可以通过这样的指针来表示了 0 1 2 00 01 10 11 20 21

9.6.4通过建立一个行指针引用二维数组元素 若有以下定义:

int a[3][2] ,(*prt)[2]

为什么要先加一个()?这是因为想要*先与prt结合,说明prt是一个指针变量。然后再与[2]结合,说明指针变量prt的基类型是一个包含有两个int元素的数组。 因为prt与a的类型相同,所以prt=a就是一个合法表达式。当prt指向a数组的开头时,可以通过以下形式来引用a[i][j] *(prt[i]+j) *(*(prt+i)+j) (*(prt+i))[j] prt[i][j]

9.7二维数组名和指针数组作为实参

9.7.1二维数组名作为实参时实参和形参之间的数据传递

当二维数组名作为实参时,对应的形参必须是一个行指针变量。 假设有这样的一个二维数组名作为实参 double a[M][N] fun(a)

这个时候对应的函数首部应写成以下几种形式 fun(double (*a)[N]) fun(double a[][N]) fun(double a[M][N]) 一定要注意列下标不能丢。

9.7.2指针数组作为实参时,实参和形参之间的数据传递

当指针数组名作为实参时,对应的形参应当是一个指向指针的指针 如:

double *ps[M] fun(ps)

则fun函数的首部应写成以下几种形式 fun(double *a[M]) fun(double *a[ ]) fun(double **a)

9.8二维数组程序举例

编写程序,通过调用随机函数给5*6的二维数组元素赋值10-40内的整数,并求出每行元素的平均值。

#include #include #define M 6 #define N 5

void getdata(int (*)[M]);

void lineave(int[][M],float *); void outdata(int[N][M],float *); main() {

int r[N][M]; float ave[N]; getdata(r);

lineave(r,ave); outdata(r,ave); }

void gaetdata(int(*sp)[M]) {

int i,j,x;

for(i=0;iwhile(jx=rand()%41; if(x>10) {

sp[i][j]=x; j++; } } }

void lineave(int s[][M],float *a)

{

int i,j;

for(i=0;iave=0.0;

for(j=0;jvoid outdata(int sp[N][M],float a[]) {

int i,j;

printf(“output the result:\\n”); for(i=0;ifor(j=0;jprintf(“%4d”,sp[i][j]); printf(“:%6.2\\n”,a[i]); }

putchar(“\\n”) } }

第九章 数组 一、选择题

[9.1] 若已定义:

int a[]={0,1,2,3,4,5,6,7,8,9},*p=a,i;

其中0<=i<=9,则对a数组元素的引用不正确的是 A) a[p-a] B) *(&a[i]) C) p[i] D) *(*(a+i))

[9.2] 以下程序段数组所有元素输入数据,应在下划线填入的是 A) a+(i++) B) &a[i+1] C) a+i D) &a[++i] main()

{ int a[10],i=0;

while(i<10) scanf(\"%d\_); }

[9.3] 以下程序的输出结果是

A) 3 B) 4 C) 1 D) 2 main()

{ int a[10]={1,2,3,4,5,6,7,8,9,10},*p=a; printf(\"%d\\n\

[9.4] 以下程序的输出结果是

A) 不确定的值 B) 3 C) 2 D) 1 main()

{ int n[2]={0},i,j,k=2; for(i=0;ifor(j=0;iprintf(\"%d\\n\}

[9.5] 以下程序的输出结果是

A)17 B)18 C)19 D)20 main()

{ int a[]={2,4,6,8,10},y=1,x,*p; p=&a[1];

for(x=0;x<3;x++) y+=*(p+x); printf(\"%d\\n\}

[9.6] 以下程序的输出结果是

A) 6 B) 8 C) 4 D) 2 main()

{ int a[]={2,4,6,8},*p=a,i; for(i=0;i<4;i++) a[i]=*p++; printf(\"%d\\n\}

[9.7] 以下程序的输出结果是

A) 720 B) 120 C) 24 D) 6 f(int b[],int n) { int i,r=1;

for(i=0;i<=n;i++) r=r*b[i]; return r; }

main()

{ int x,a[]={2,3,4,5,6,7,8,9}; x=f(a,3);

printf(\"%d\\n\}

[9.8] 以下程序中若第一个printf语句输出的是194,则第二个printf语句的输出结果是

A) 212 B) 204 C) 1a4 D) 1a6 12 main()

{ int a[]={1,2,3,4,5,6,7,8,9,0},*p; p=a;

printf(\"%x\\n\

printf(\"%x\\n\ 2*9=18 12 }

[9.9] 以下程序的输出结果是

A) 09876321 B) 4321098765 C) 56701234 D) 0987651234 fun(int *s,int n1,int n2) { int i,j,t; i=n1; j=n2; while(i{ t=*(s+i); *(s+i)=*(s+j); *(s+j)=t; i++; j--; } }

main()

{ int a[10]={1,2,3,4,5,6,7,8,9,0},i,*p=a; fun(p,0,3); fun(p,4,9); fun(p,0,9); for(i=0;i<10;i++) printf(\"%d\}

[9.10] 以下程序的输出结果是

A) 4 4 B) 2 2 C) 2 4 D) 4 6 main()

{ int a[5]={2,4,6,8,10},*p,**k; p=a; k=&p;

printf(\"%d\printf(\"%d\\n\}

[9.11] 当运行以下程序时输入三行,每行都是在第一列上开始,<CR>代表Enter键; a b cdef

则程序的输出结果是

A)abcdef B)a C)a D)a

b b b c cd cdef

d f #include \"stdio.h\" #define N 6 main()

{ char c[N]; int i=0;

for(i=0;i[9.12] 若有定义和语句: int c[4][5],(*cp)[5]; cp=c; 则对C数组元素的引用正确的是

A) cp+1 B) *(cp+3) C) *(cp+1)+3 D) *(*cp+2) [9.13] 若已定义:

int a[4][3]={1,2,3,4,5,6,7,8,9,10,11,12},(*prt)[3]=a,*p=a[0]; 则能够正确表示数组元素a[1][2]的表达式是

A) *((*prt+1)[2]) B) *(*(p+5)) C) (*prt+1)+2 D) *(*(a+1)+2) [9.14] 若有定义和语句:

int a[4][3]={1,2,3,4,5,6,7,8,9,10,11,12},(*prt)[3]=a,*p[4],i; for(i=0;i<4;i++) p[i]=a[i];

则下能够正确表示a数组元素的表达式是

A) a[4][3] B) p[0][0] C) prt[2][2] D)(*(p+1))[1] [9.15] 以下程序的输出结果是

A) 23 B) 26 C) 33 D) 36 main()

{ int aa[3][3]={{2},{4},{6}},i,*p=&aa[0][0]; for(i=0;i<2;i++)

{ if(i==0) aa[i][i+1]=*P+1;

else ++p;

printf(\"%d\ } printf(\"\\n\"); }

[9.16] 以下程序的输出结果是

A) 60 B) 68 C) 99 D) 108 main()

{ int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23}; int (*p)[4]=a,i,j,k=0; for(i=0;i<3;i++) for(j=0;j<2;j++)

k+=*(*(p+i)+j); printf(\"%d\\n\}

[9.17] 以下程序的输出结果是

A) 1,5,9, B) 1,4,7, C) 3,5,7, D) 3,6,9, main()

{ int i,x[3][3]={1,2,3,4,5,6,7,8,9};

for(i=0;i<3;i++) printf(\"%d,\}

[9.18] 若有定义语句int (*p)[M]; 其中的标识符是 A)M个指向整型变量的指针

B)指向M个整型变量的函数指针

C)一个指向具有M个整型元素的一维数组指针

D)具有M个指针元素的一维指针数组,每个元素都只能指向整型量 二、填空题

[9.19] 若有以下定义: double w[10];

则数组元素下标的上限是 9 ,下限是 0 。 [9.20] 以下程序的输出结果是6 。 main()

{ int a[]={2,4,6},*ptr=&a[0],x=8,y,z; for(y=0;y<3;y++)

z=(*(prt+y)[9.21] 以下程序的输出结果是 12 。 main()

{ int arr[10],i,k=0;

for(i=0;i<10;i++) arr[i]=i;

for(i=0;i<4;i++) k+=arr[i]+i; printf(\"%d\\n\}

[9.22] 以下程序的输出结果是 3 . #define N 5

fun(char *s,char a,int n) { int j; *s=a;j=n;

while(a{ char s[N+1]; int k,p;

for(k=1;k<=N;k++) s[k]='A'+k+1; printf(\"%d\\n\"9; }

[9.23] 若输入3个整数3、2、1,则以下程序的输出结果是 2721 。 void sub(int n,int uu[]) { int t;

t=uu[n--]; t+=3*uu[n]; n++; if(t>=10)

{ uu[n++]=t/10; uu[n]=t%10; } else uu[n]=t; } main()

{ int i,n,aa[10]={0};

scanf(\"%d%d%d\for(i=1;ifor(i=0;i<=n;i++) printf(\"%d\printf(\"\\n\"); }

[9.24] 以下程序的输出结果是 -850,2,0 . main()

{ int i,j,row,col,m;

int arr[3][3]={{100,200,300},{28,72,-30},{-850,2,6}}; m=arr[0][0]; for(i=0;i<3;i++) for(j=0;j<3;j++) if(arr[i][j]{m=arr[i][j]; row=i; col=j;} printf(\"%d,%d,%d\\n\}

[9.25] 以下findmax返回数组s中最大元素的下标,数组中元素的个数由t传入,请填空。

findmax(int s[],int t) { int k,p;

for(p=0,k=p;ps[k]) k=p ; return p; }

[9.26] 以下程序统计从终端入的字符中每个大写字母的个数,中统计字母的个数,其它依次类推。用#号结束输入,请填空。 #include \"stdip.h\" #include \"ctype.h\" main()

{ int num[26]={0},i; char c; while((c=getchar())!=\"#\")

if(isupper(c)) num[_]+=1; for(i=0;i<26;i++)

if(num[i]) printf(\"%c:%d\\n\}

三、编程题

[9.27] 输入一行数字字符,请用数组元素作为计数器来统计每个数字字符的个数。用下标为0元素统计字符“1”的个数,下标为1的元素统计字符“2”的个数,...。

[9.28] 编写函数,对具有效期0个整数的数组进行如下操作:从第n个元素开始直到最后一个元素,依次向前移动一个位置。输出移动后的结果。 [9.29] 编写函数把数组中所有奇数放在另一个数组中返回。

[9.30] 编写函数对字符数组中的输入字母,按由大到小的字母顺序进行排序。

[9.31] 输入若干有序数放在数组中。然后输入一个数,插入到此有序数列中,插入后,数组中的数仍然有序。请对以下三种情况运行你的程序,以便验证你的程序是否下确。 (1)插在最前 (2)插在最后 (3)插在中间

[9.32] 编写函数把任意十进制下整数转换成二进制数。提示:把十进制数不断被2除余数放在一个一维数组中,直到商数为零。在主函数中进行输出,要求不得按逆序输出。 [9.33] 编写函数调用随机函数产生0到19之间的随机数,在数组中存入15个互不重复的整数。要求在主函数中输出结果。若已定义为类型,调用随机函数步骤如下: #include \"stdlib.h\"

x=rand()%20 /*产生0到19的随机数*/

[9.34] 编写程序求任意方阵每行、每列、两对角线一元素之和。 [9.35] 编写程序求两个矩阵的和。

[9.36] 编写程序打印出以下形式的乘法九九表。 ** A MULTIPCATION TABLE ** (1) (2) (3) (4) (5) (6) (7) (8) (9)

(1) 1 2 3 4 5 6 7 8 9 (2) 2 4 6 8 10 12 14 16 18 (3) 3 6 9 12 15 18 21 24 27 (4) 4 8 12 16 20 24 28 32 36 (5) 5 10 15 20 25 30 35 40 45 (6) 6 12 18 24 30 36 42 48 (7) 7 14 21 28 35 42 49 56 (8) 8 16 24 32 40 48 56 72 (9) 9 18 27 36 45 63 72 81

[9.37] 调用随机函数为5*4的矩阵置100以内的整数,输出该矩阵,求出每行元素之和,并把和值最大的那一行与第一行上的元素对调。若已定义x为int类型,调用随机函数步骤如下:

#include \"stdlib.h\"

x=rand()%100 /*产生0到100的随机数*/

[9.38] 调用随机函数为55的矩阵置100以内的整数,输出该矩阵,然后逆置该矩阵。

即将第一列的元素放在第一行上、第二列的元素放在第二行上、其它依次类推。

第10章 字符串

字符串的存储完全依赖于字符数组,但字符数组又不等于字符串变量 10.1用一维字符数组存放字符串 1.C语言对字符串的约定

字符串是借助于字符型一维数组来存放的,并规定以字符‘\\0’作为字符串的结束标志。‘\\0’作为标志占用存储空间,但不计入串的实际长度。 2.C语言中表示字符串常量的约定

随让C语言中没有字符串数据类型,但却允许是哟会更‘字符串常量’在第6章中已经介绍过字符串常量是由双引号括起来的一串字符,在表示字符串常量时,不需要人为在其末尾加入‘\\0’。

3.C语言中字符串常量给出的是地址值

每个字符串在内存中占用一串连续的存储空间,这些连续的存储空间实际上就是字符型一维数组。不同的字符串在内存中占有不同的存储空间。也就是说在C语言中,字符串常量被隐含处理成一个以‘\\0’结尾的无名字符型一维数组。

若有以下定义: char *sp ,s[10];

则以下赋值是不合法的 s=”hello”;

因为S相当是一维数组的首地址,是一个不可重新赋值的数组名。因此赋值不合法。而以下赋值是合法的。

Sp=”hello”;

这个语句并不是把字符串的内容放入sp中,而只是把字符串中在内存中所占的首地址赋予了char类型的指针变量sp,使指针变量sp指向该字符串。

4.字符数组与字符串的区别

字符数组的每个元素中可存放一个字符,但它并不限定最后一个字符应该是什么。而字符串则要求最后一个必须是‟\\0‟做为结束标识。在字符数组中可以存放字符串,但不能通过赋值语句将字符串常量或其它字符数组中的字符串直接赋给字符串变量。 10.1.1通过赋初值的方式给一维字符数组赋字符串

1.用给一般数组赋初值的相同方式给一维字符数组赋初值 Char str[10]={„s‟,‟t‟, ‟r‟,‟i‟,‟n‟,‟g‟,‟! ‟, ‟\\0‟};

字符数组str共有10个元素,但str作为字符串,其长度为7.虽然最后一个字符是\\0但它并不是结束标识,因为系统会自动的给其分配一个结束标识。 2.在赋值时直接赋字符串常量 char str[10]={“string”}; 习惯上省略花括号:

char str[10]=”string!”(这种方式会自动给字符串的末尾添加结束标识,但需要注意的是字符串数组的长度一定要比赋值的长度多一个)

10.1.2在C程序执行过程中给一维字符数组赋字符串 1.不可以用赋值语句给字符数组整体赋一串字符

当作字符串变量使用的字符数组,不能由赋值语句直接赋字符串常量 如:char mark[10];

mark=”C Program”; 以上的赋值是不允许的。

再如:char str1[10]=”computer” ,str2[10]; Str2=str1;

2.给数组元素逐个赋字符值,最后为加入串结束标志 思考一下如何用for语句赋值 char str[10] for(i=0;i<9;i++)

scanf(“%c”, &str[i]); str[i]=‟\\0‟;

10.2使指针指向一个字符串

10.2.1通过赋初值的方式使指针指向一个字符串

char *ps1=”form one”;(后面的这个字符串代表的是一个地址)

这里的意思是将把存放字符串常量的无名存储区首地址赋给指针变量ps1,(不要误以为是将字符串赋给了ps1)

10.2.2 通过赋值运算使指针指向一个字符串 char *ps1; ps1=”form one”;

10.2.3 用字符数组作为字符串和用指针指向的字符串之间的区别 char mak[]=”program”; char *pmark=”program”; 区别:

Mark代表的是一个固定的存储空间

但指针变量pmark中的地址可以改变而指向另外一个长度不同的字符串,一旦pmark指向新的字符串而没有另一个指针指向原来的字符串,则此字符串将“丢失”,其所占存储空间也将无法引用。 10.3字符串的输入和输出

10.3.1输入和输出字符串时的必要条件

当对字符串进行办出时,输出项既可以是字符串常量或学符数组名,也可以是已指向字符串的字符指针变量。

当对字符串进行输入时,输入项可以是字符数组名,也可以是字符指针变量 10.3.2用格式说明%s进行整串输入和输出 (1)scanf函数

scanf(“%s”,str_adr)

这里str_adr是地址值,它可以是字符数组名,字 符数组元素的地址或字符指针变量。 注意:

1. 用%s格式符输入字符串时,空格和回车符都作为输入数据的分隔符而不能被读入。 2. 若输入字符串的长度超过数组所能容纳的字符个数时,系统并不报错

3. 当输入项是数组元素的地址时,输入的字符将从这一元素开始依次存放在该数组中 4. 当输入项是字符指针变量时,该指针变量必须已指向确定的有足够空间的连续存储

单元

(2)在printf函数中使用格式说明%s可以实现字符串的整体输出、 Printf(“%s”,str_adr)

10.3.3调用gets \\puts函数在终端输入或输出一行字符串 printf(“%s”,str_adr) 10.4字符串数组

所谓字符串数组就是数组中的每个元素又都是一个存放字符串的一维数组

二维字符数组的第一个下标决定了字符串的个数,第二个下标决定了字符串的最大长度 2.字符串数组也可以在字义的同时赋初值 char ca[3][5]={“A”,”BB”,”CCC”}; 也可以写成

Char[][5]={“A”,”BB”,”CCC”};

3.可以定义字符型数组并通过赋初值来构成一个类似的字符串数组 char *pa[3]={“a”,”bb”,”ccc”};

指针数组pa的每个元素指向一个字符串,也就是说,数组pa的每个元素中存方放着一个字符串首地址

10.5用于字符串处理的函数 1.字符串复制函数strcpy strcpy(s1,s2)

这是用来把S2中的字符串的内容复制到S1所指存储空间中,返回S1的值,即目的的首地址。注意:为保证复制的合法性,S1必须指向下足够容纳S2串的存储空间。 2.字符串连接函数strcat Strcat(s1,s2);

该函数将s2所指字符串的内容边接到s1所指的字符串后面,并自动覆盖S1串末尾的\\0,注意:S1所指的字符串应有足够的空间容纳两中合并后的内容。 3.求字符串长度strlen strlen(s)

求字符串s的长度,这个长度不包括串尾的结束标志\\0 5. 字符串比较函数strcmp strcmp(s1,s2)

用来比较两个字符串的大小,若串要s1>s2函数值大于0(正数),若串s1=s2函数值等于0,若s1例1,编写函数slength(char *s),函数返回指针s所指字符串的长度,即相当于库函数strlen的功能。

按要求已知:形参s是指向字符串首地址的指针,计算字符串的长度,只需要逐个统计串中的字符个数,直到遇到串结束标志\\0为止。 include slength(char *s) {

int n=0;

while(*(s+n)!=‟\\0‟) n++; return(n); } main() {

char str[]=”ABCDEF”;int len1,len2; len1=length(“ ”);len2=length(str);

printf(“len1=%d,len2=%d\\n”,len1,len2); }

例2,编写函数scopy(char *s,char *t),将指针t所指的字符串复制到指针s所指的存储空间中。

#include

void scopy(char *s,char *t) { int i; i=0;

while((s[i]=t[i])!=‟\\0‟) i++; }

main() {

char str1[20],str2[]=”ABCDEFGH”; scopy(str1,str2); puts(str1); }

课后习题

第十章 字符串 一.选择题

[10.1] 以下能正确进行字符串赋值、赋初值的语句组是

A) char s[5]={'a','e','i','o','u'}; B) char *s; s=\"good!\"; C) char s[5]=\"good!\"; D) char s[5]; s=\"good\"; [10.2] 以下程序的输出结果是

A) 68 B) 0 C) 字符D的地址 D)不能确定的值 char str[ ]=\"ABCD\printf (\"%d\\n\

[10.3] 以下程序段的输出结果是

A) 11 B) 10 C) 9 D) 8 printf (\"%d\\n\

[10.4] 当运行以下程序时输入OPEN THE DOOR(此处代表Enter 键), 则输出的结果是

A) opEN tHE dOOR B) open the door C) OPEN THE DOOR D) Open The Door #include \"stdio.h\" char fun ( char *c )

{ if ( *c < = 'Z' & & *c > = 'A') *c - ='A'-'a'; return *c; } main( )

{ char s[81] , *p=s; gets(s); while(*p)

{ *p=fun(p); putchar(*p); p++ } putchar ( “ \\n “ ); }

[10.5] 以下程序的输出结果是

A) GFEDCBA B) AGADAGA C) AGAAGAG D) GAGGAGA #include \" stdio.h\" #include \"string.h\"

void fun ( char *w, int m ) { char s, *p1 , *p2 ; p1=w; p2=w+m-1; while(p1{ s=*p1++; *p1=*p2-- *p2=s; } main( )

{ char a[ ]=\"ABCDEFG\"; fun ( a , strlen(a) );

puts(a); }

[10.6] 以下程序的输出结果是

A) ABCD B) A C) D D) ABCD

BCD B C ABC

CD C B AB

D D A A main ( )

{ char s[ ]=\"ABCD\ *p;

for( p=s; p[10.7] 设有如下定义:

char *aa[2] = { \"abcd\" , \"ABCD\" } ; 则以下说法正确的是

A) aa数组元素的值分别是\"abcd\" 和 \"ABCD\"

B) aa是指针变量,它指向含有两个数组元素的字符型一维数组

C) aa数组的两个元素分别存放的是含有四个字符的一维数组的首地址 D) aa数组的两个元素中各自存放了字符 'a' 和 'A' 的首地址 [10.8] 以下程序的输出结果是

A) 6385 B) 69825 C) 63825 D) 693825 main( )

{ char ch[2][5] = {\"6937\ *p[2]; int i , j , s = 0 ;

for ( i=0 ; i <2 ; i++ ) p[i]=ch[i];

for ( i=0 ; i<2 ; i++ )

for( j=0 ; p[i][j]>'\\0' &&p[i][j]<='9';j+=2) s=10*s+p[i][j]-'0'; printf(\"%d\\n\}

[10.9] 以下程序的输出结果是

A) ABCDEFGHIJKL B) ABCD C) ABCDEFGHIJKLMNOP D) AEIM main( )

{ char *alpha[6]= {\"ABCD\char **P; int i; p=alpha;

for( i=0; i<4; i++ ) printf(\"%s\printf(\"\\n\"); }

[10.10] 库函数strcpy用以复制字符串。若有以下定义和语句:

char str1[ ]=\"string\ 则对库函数strcpy的不正确调用是

A) strcpy(str1,\"HELLO1\"); B) strcpy(str2,\"HELLO2\"); C) strcpy(str3,\"HELLO3\"); D) strcpy(str4,\"HELLO4\"); 二.填空题

[10.11] 以下程序的输出结果是___GFEDCB_________。 #include \"stdio.h\"

main( )

{ char b[ ]=\"ABCDEFG\ *chp=&b[7]; while (--chp>&b[0]) putchar(*chp); putchar('\\n'); }

[10.12] 以下程序的输出结果是____XYZA________。 #include \"stdio.h\" void fun(char *a1, char *a2, int n) { int k;

for (k=0;ka2[k]=(a1[k]-'A'-3+26)%26+'A'; a2[n]='\\n'; } main( )

{ char s1[5]=\"ABCD\ fun ( s1 , s2 , 4 ); puts(s2); }

[10.13] 以下程序的输出结果是____SO________。 main( )

{ char *p[ ]={\"BOOL\ int i;

for (i=3;i>=0;i--,I--) printf(\"%c\ printf(\"\\n\"); }

[10.4] 当运行以下程序时从键盘输入字符串qwerty和abcd,则程序的输出结果是____10________。 #include \"stdio.h\" #include \"string.h\" strle (char a[ ], char b[ ] ) { int num=0,n=0;

while (*(a+num)!='\\0') num++;

while (b[n]) {*(a+num)=b[n]; num++;n++} return(num); }

main( )

{ char str1[81],str2[81],*p1=str1,*p2=str2; gets(p1); gets(p2);

printf(\"%d\\n\ }

[10.15] 以下程序的输出结果是___Itis_________。 #include \"string.h\" #include \"ctype.h\" void fun(char str[ ]) { int i , j ; for(i=0,j=0; str[i]; i++)

if ( isalpha (str[i]) ) str[j++]=str[i];

str[i]='\\0'; } main( )

{ char ss[80]=\"It is!\"; fun(ss);

printf(\"%s\\n\ }

[10.16] 以下fun函数的功能是将一个字符串的内容颠倒过来,请填空。 #include \"string.h\" void fun(char str[ ] ) { int i , j , k ;

for ( i=0 , j=___strlen(str)-1_____ ; i < j ; i++ , _____j--_______ ) { k=str[i]; str[i]=str[j]; str[j]=k; } }

[10.17] 以下程序的输出结果是______3______。 printf(\"%d\\n\

[10.18] 以下程序的输出结果是____goodgood!________。 char s[20]=\"goodgood!\

sp=sp+2;

sp=\"to\";

puts(s);

第十一章 对函数的进一步讨论

11.1传给main函数的参数

在之前我们编写的main函数,其后的一对圆括号中是空的,其实在支持c的环境中,可以在运行c程序时,通过运行c程序的命令行吧参数传给c程序。如 main(int argc, char **argv)

其中argc和argv是两个参数名,可由用户自己命名,但是他们的类型是固定。第一参数argc必须是整形,第二个参数argv是一个指向字符型的指针数组的指针,这个字符型指针数组的每个指针都指向一个字符串。

当我们对包含以上主函数的,名为myc的文件进行编译连接,生成名为myc.exe 的可执行文件后,即可在操做系统提示符下输入以下命令执行该程序。 如: myc ok! good

这个时候会在屏幕上出现整数3。这也就是argc的值,他里面存放的是字符串的个数包括了myc这个文件名。

例题:若以下程序放在myc.c文件中,在编译连接后,生成一个myc.exe文件,输出arge和argv中的数据。 #include

main(int argc,char *argv[ ]) { int i;

printf(“argc=%d\\n”,argc); for(i=1;i若在命令行中输入

myc A COMMAND LINE 程序输出: argc=4

A COMMAND LINE

这样的程序的功能就是输出刚才输入的字符串的个数,然后把刚才输入的字符串输出。(注意:输出的个数是我们输入的字符串的个数再加上文件名。) 11.2通过实参向函数传递函数名或指向函数的指针变量 1.指向函数指针变量的定义

在C语言中函数名代表该函数的入口地址。 区分指向函数的指针和返回值是指针 类型的函数

double (*fp)(int ,int *)

这说明fp是一个指向函数的指针变量,这个函数必须是double类型。只有同种类型的指针才能指向这个函数。

double *fp(int ,int *)

这说明fp就不是指针变量,而是说明fp是一个函数,该函数的返回值类型是基类型为double的指针类型。

2.函数名或指向函数的指针变量作为实参

函数名或指向函数的指针变量可以作为实参传给函数,这时,对应的形参应当是类型相同的指针变量。

#include #include

double tran(double (*) (double),double(*)(double),double); main() {

double y,v;

v=60*3.1416/180.0; y=tran(sin,cos,v);

printf(“tan(60)=%10.6\\n”,y); y=tran(cos,sin,v);

printf(“cot(60)=%10.6f\\n”,y); }

double tran(double (*f1)(double),double(*f2)(double),double x) {return (*f1)(x)/(*f2)(x);} 11.3函数的递归调用。 如何求阶乘? f(n)=n*f(n-1)

8!=8*7*6*5*4*3*2*1 int f(int a) {int t;

if(a==0||a==1) return 1; else

{t=a*f(a-1); return t;} }

main() { int i,j;

scanf(“%d”,&i); j=f(i);

printf(“%d”,j); }

第十一章 对函数的进一步讨论 一.选择题

[11.1] 以下叙述不正确的是

A) C程序的main函数可以没有参数。 B) C程序的main函数可以有参数。

C) C程序的main函数可若有参数时,第一个参数的值最少是1。

D) main函数的第一个参数必须是整型,其名字必须是argv;第二个参数可以定义成: char*argv[ ],名字必须是argv。

[11.2] 若有以下说明和定义,则对fun函数的正确调用语句是 A) a=fun; a(w); B) a=fun; (*a)(&c); C) b=fun; *b(w); D) fun(b); main()

{ int (*a)(int*),*b( ),w[10],c; : : }

fun(int *c) {...}

[11.3] 以下叙述正确的是

A)C语言中各函数之间既允许直接递归调用也允许间接递归调用 B) C语言中各函数之间既不允许直接递归调用也不允许间接递归调用 C) C语言中各函数之间既允许直接递归调用不允许间接递归调用 D) C语言中各函数之间既不允许直接递归调用允许间接递归调用 [11.4] 以下程序的输出结果是

A) 8 B) 30 C) 16 D) 2 long fib (int n)

{ if (n>2) return (fib(n-1)+fib(n-2)); else erturn(2); }

main()

{ printf(“%ld\\n”,fit(6) ); } 二.填空题

[11.5] 假定以下程序经过编译和连接后生成可执行文件PROG.EXE,如果在DOS提示符下键入: PROG ABCD EFGH IJKL (表示Enter键) 则输出结果是:__IJKLEFGHABCD__________. main( )(int atgc,char *argv[])

{ while(--argc>0) printf(\"%s\printf(\"\\n\"); }

[11.6] 以下程序的输出结果是___7___. fun(int x)

{int p;

if(x==0||x==1) return(3); p=x-fun(x-2); return p; }

main( )

{ printf(\"%d\\n\ }

[11.7] 以下程序的输出结果是_8____. fun (int n,int *s) { int f1,f2;

if (n==1||n==2) *s=1; else

{ fun(n-1,&fi); fun(n-2,&f2); *s=f1+f2; } }

main( )

{ int x; fun(6,&x);

pirntf(\"%d\\n\}

[11.8] 以下程序调用invert函数按逆序重新放置a数组中元素的值,a数组中的值在main函数中读入. 请填空. #define n 10

void invert (int *s, int i , int j) { int t; if(i{ t=*(s+i); *(s+i)=_*(s+j)____; *(s+j)=t; invert (s,_i+1___,j-1); } }

main( )

{ int a[N],i;

for(i=0;ifor(i=0;i[11.9] 以下程序的输出结果是___17__. funa(int a, int b) { return a+b;} funb(int a, int b) { return a-b;}

sub (int(*t)( ), int x, int y) { return(*t)(x,y); } main( )

{ int x,(*p)(int,int); p=funa;

x=sub(p,9,3); x+=sub(funb,8,3);

printf(“%d\\n”,x); }

第12章 C语言中用户标识符的作用域与存储类

12.1局部变量、全局变量和存储分类

局部变量:在函数内部或复合语句内部定义的变量。函数的形参也属于局部变量。 全局变量;在函数外部定义的变量称为全局变量。

有时局部变量也称内部变量,全局变量称外部变量。 局部变量和全局变量的区别就在于他们的作用域不同,

C语言中,有两种存储类别:一种是自动类,一种是静态类。局部变量可以说是自动类,也可以说是静态类。而全局变量只能是静态类。 有几种说明符玉两种存储类别相关:

auto 自动

regisert 寄存器 (这种变量的利用率很高,一般把这样的变量就存放在了CPU中了。)

static 静态 (这种变量占据着永久性的存储单元) extern 外部

#include int f(int n); main() {

int a=3,s; s=f(a); s=s+f(a); s=s+f(a);

printf(“%d\\n”,s); }

int f(int n) {

static int a=1; n+=3++; return n; }

12.2局部变量及其作用域和生存期

局部变量的作用域是从定义的位置期,到函数体结束为止。 局部变量的生存期是整个程序的运行期间。

若全局变量和某个函数中的局部变量同名,则在该函数中,此全局变量被屏蔽,在该函数内,访问的是局部变量,与同名的全局变量不发生任何关系。

第十三章 编译预处理和动态存储分配

13.1 凡是以“#”号开头的行都称为“编译预处理”命令行。 13.1.1 宏替换

不带参数的宏定义

#define 宏名 替换文本 如 #define SIZE 100

上面提到的SIZE就是宏名,它一般情况下都是大写的。

#define PI 3.14

#define ADDPI (PI+1)

#define TWO_ADDPI(2*ADDPI)

程序中如有表达式 x=TWO_ADDPI 则替换后,表达式将成为:X=(2*(3.14+1)/2) 注意:当宏定义在一行中写不下,需要在下一行继续是,只需要在最后一个字符后紧接着加一个反斜线 “\\”

如果在\\前或在下一行的开头留有许多空格,则在宏替换时也将加入这些空格。 同一个宏名不能重复定义

替换文本不能替换双引号中与宏名相同的字符串 替换文本并不替换用户表示符中的成分 2.带参数的宏定义 格式;

#define 宏名(形参表) 替换文本 #define MU(x,y) ((x)*(y)) A=MU(5,2)=((5)*(2))

B=6/MU(a+3,a)=6/((a+3)*(a))

第十四章 结构体、共用体和用户定义类型

结构体式一种较为复杂但却非常灵活的构造型数据类型。

其实他们是这样发展的,最初我们学习了定义变量,但是一次只能定义一个。后来为了定义一次而是用多次,就出现了数组,但是它里面所能存存放的都是同种类型的。怎么样才能定义一次使用多次,同时他们还不受类型的呢。这就出现了结构体。

结构体类型的说明 struct 结构体标识名 {

类型名1 结构成员名表1; 类型名2 结构成员名表2; …

类型名n 结构成员名表n; };

struct 是关键字,是结构体类型的标志。 注意:结构体说明同样要以分号结尾。 如;

struct date {

int year,month,day; };

当结构体中有包含结构体式,称为结构体嵌套。 struct student {

char name[12]; char sex;

struct date birthday; float sc[4]; };

其中struct date 是一个已说明过的结构体类型。birthday就是这个结构体中的一个成员。

按照上面定义的结构体: 则给成员std复制如下

Std={“Li Ming”,‟M‟,1962,5,10,88,76,85.5,90}

对结构体变量赋值是,C编译程序按每个成员在结构体中的顺序一一对应赋值,不允跳过前面的成员给后面的成员赋值。但可以只给前面的若干个成员赋值,后面没有赋值的成员,系统将自动为数值型和字符型数据赋值0。 14.2.4引用结构体变量中的数据 1.对结构体成员变量的引用 1)结构体变量名.成员名 2)指针变量名->成员名 3)(*指针变量名).成员名 则有:

Std.sex=‟M‟

Std->name[0]=‟L‟ 14.3共用体

1.共用体类型的说明

union 共用体标识名 {

类型名1 共用体成员名1; 类型名2 共用体成员名2; 。。。

类型名n 共用体成员名n; }

Union是关键字,是共用体类型的标志,

结构体与共用体的区别:结构体变量中中每个成员分别占有的存储空间,因此结构体变量所占内存字节数是其成员所占字节数的总和。而共用体变量中的所有成员共享一段公共存储区,所以共用体变量所占内存字节数与其成员中占字节数最多的那个成员相等。

由于共用体变量中所有成员共享存储空间,因此变量中的所有成员的首地址相同,而且变量的地址也就是该变量成员的地址。

14.3.2共用体变量的引用

1、共用体变量中成员的引用 共用体变量名.成员名 指针变量名->成员名 (*指针变量名).成员名 本章例14.10大家要看一下。

第十五章 位运算

位运算的对象只能是整形或字符型数据。在VC6.0中int型数据占4个字节 1. 位运算符

运算符 作用 ~ 按位求反 << 左移 >> 右移

& 按位与 ^ 按位异或 | 按位或 它们的优先级是从高到低的 2. 位运算符的运算功能

1) 按位取反

~01001101=10110010 2)左移运算

A=00000110(a=6)

B=a<<2=00011000(在最低位添上2个00,从最高位去掉前两位) 3)右移运算

负数:就是从最高位添上两个1,从最低位去掉两位 正数:就是从最高位添上两个0,从最低位去掉两位 4)按位与

把参加运算的两个运算数按对应的二进制位分别进行“与”运算,当两个相应的位都为1时,该位的结果为1,否则为0.

1101010 0100100 5)按位异或

参与运算的两个运算数中相对应的二进制位上,若数相同,则该位的结果为0,若数不同,则该位的结果为1.

001101010 101010010 6)按位或

参加运算的两个运算数中,只要两个相应的二进制位中有一个为1,该位的运算结果即为1;只有当两个相应位的数都为0时,该位的运算结果才为0.

0010101 1101010

第16章 文件

16.2文件指针

文件指针实际上是批向一个结构体类型的指针。 定义:

FILE *指针变量名; 16.3打开文件

fopen(文件名,文件使用方式); fopen(“file_a”,”r”); 文件使用方式:

1.r ,为读而打开文本文件。只读,不能写 2.rb ,为读而打开二进制文件。只读,不写

3.w,为写而打开的文本文件,如果指定的文件存在,则从文件的起始位置开始写,文件中原有内容将全部消失。如果指定的文件不存在,则建立一个同名的文件。 4.wb,为写而打开的一个二进制文件。其余功能与w相似

5.a,为在文件后面添加数据而打开文本文件。如果指定的文件存在,则文件中原有内容将保存,新的数据写在原有内容之后。如果指定的文件不存在,则建立一个同名的文件。 6.ab,为在文件后面添加数据而打开一个二进制文件,其余功能与a相同。

7.r+,为读和写而打开文本文件,用这各方式 时,指定的文件 应当已经存在,既可以对该文件进行读,也可对该文件进行写,在读和写操作之间不必关闭文件。只是对文本文件来说,读和写总是从文件的起始位置开始。在写新的数据时,只覆盖新数据所占的空间,其后的老数据并不丢失。

8.rb+,为读和写而打开一个二进制文件。功能与“r+”相同,只是在读和写时,可以由位置函数设置读和 写的起始位置,也就是说不一定从文件的起始位置开始读和写。

9.w+,首先建立一个新文件,进行写操作,随后可以从头开始读。如果指定的文件已存在,则原有的内容将全部消失。

10wb+功能与w+相同,只是在随后读和写时,可以由位置函数设置读和写的起始位置。 11a+。功能与a相同,只是在文件尾部添加新的数据后,可以从头开始读。

12 ab+,功能与a+相同,只是在文件尾部添加新的数据之后,可以由位置函数设置开始读的起始位置。 16.4关闭文件

fclose(文件指针)

将一个文件中的内容输出到屏幕 判断文件结束函数feof

feof(fp)的返回值是1代表文件结束,否则为0. #include #include main() {

FILE *fpout; char ch;

fpout=fopen(\"file_a.dat\ch=fgetc(fpout); while(ch!=EOF) {putchar(ch); ch=getc(fpout); }

fclose(fpout); }

16.1题

把从键盘输入的文本按原样输出到名为file_a.dat文件中,用字符@作为键盘输入结束标志。

以上操作的算法步骤十分简单: 1. 打开文件。

2. 从键盘输入一个字符。

3. 判断输入的字符是否是@,若是,结束循环,执行步骤(7)。 4. 把刚输入的字符输出到指定的文件中。 5. 从键盘输入一个字符。 6. 重复步骤(3)和(5)。 7. 关闭文件 8. 程序结束。 程序如下;

#include #include

main() {

FILE *fpout; char ch;

if((fpout=fopen(“file_a.dat”,”w”))==NULL) {

printf(“Can‟t open this file!\\n”);exit(0);} ch=getchar(); while(ch!=‟@‟) {

fputc(ch ,fpout); ch=getchar(); }

fclose(fpout); } }

2010年考题

25、下列选项中,能正确定义数组的语句是 A. int num[0..2008] B.int num[]

C.int N=2008; D.#define N 2008 int num[N] int num[N] 35.#include #define SUB(a) (a)-(a) main() {

int a=2,b=3,c=5,d; d=sub(a+b)*c; 5-5*5 printf(“%d\\n”,d); }

程序运行后的输出结果是 A 0 B-12 C-20 D10 36.设有定义: struct complex

{int real,unreal;}datal={1,8},data2; 则以下赋值语句中错误的是

A.data2=data1; B.data2=(2,6);

Cdata2.real=data1.real; D.data2.real=data1.unreal; 37.有以下程序 #include #include strict A {int a; char b[10]; double c; };

void f(struct A t); main()

{

struct A a={1001,”ZhangDa”,1098.0}; f(a);

printf(“%d,%s,%6.1f\\n”,a.a,a.b,a.c);} void f(struct A t)

{t.a=1002;strcpy(t.b,”ChangRong”);t.c=1202.0;} 程序运行后的输出结果是

A1001,ZhangDa,1098.0 B1002,ChangRong,1202.0 C1001,ChangRong,1098.0 D1002,ZhangDa.1202.0 38.有以下定义和语句 strruct workers {

int num;char name[20];char c; struct

{int day ;int month;int year;}s; };

struct workers w,*pw; pw=&w;

能给W中year成员赋1980的语句是 A*pw.year=1980; Bw.year=1980; Cpw->year=1980; Dw.s.year=1980; 40.有以下程序 #include main() {

FILE *fp;char str[10];

fp=fopen(“myfile.dat”,”w”); fputs(“abc”,fp);fclose(fp); fp=fopen(“myfile.dat”,”a+”); fprintff(fp,”%d”,28); rewind(fp);

fscanf(fp,”%s”,str); puts(str); fclose(fp); }

程序运行后的输出结果是 Aabc B28c

C)abc28 D因类型不一致而出错 2009年9月 33设有以下函数 Viod fun(int n,char *s) {…….}

则下面对函数指针的定义和赋值均正确的是 A void (*fp)(); pf=fun; Bvoid *pf(); pf=fun; Cvoid *pf(); *pf=fun;

Dvoid(*pf)(int,char);pf=&fun; 35有以下程序 #include

#define f(x) x*x*x 3+1*3+1*3+1 main() {

int a=3,s,t;

s=f(a+1);t=f((a+1)); printf(“%d,%d\\n”,s,t); }

程序运行后的输出结果是 A10, B10,10 C,10 D,

36下面结构体的定义语句中,错误的是 Astruct ord{int x;int y;int z;};struct ord a; Bstruct ord{int x;int y;int z;} struct ord a; Cstruct ord{int x;int y;int z;} a; Dstruct {int x;int y;int z;}a; 39若有以下程序段 int r=8;

printf(“%d\\n”,r>>1); 输出结果是

A 16 B8 C4 D2 11.有以下程序 #include int a=5;

void sun(int b) {

int a=10; a+=b;

printf(“%d”,a); }

main() {

int c=20; fun(c); a+=c;

printf(“%d\\n”,a); }

程序运行后的输出结果是________3025_ 12设有定义: struct person

{int ID;char name[12];}p;

请将scanf(“%d”,_&p.ID__);语句补充完整,使其能够为结构体变量p的成员ID正确读入数据。

14.有以下程序、 #include typedef struct

{int num;double s;}REC; void sunl(REC x)

{x.num=23;x.s=88.5;} main()

{REC a={16,90.0}; sunl(a);

printf(\"%d\\n\

}程序运行后的输出结果是__16__ 其它相关题目 34.#define PT 5.5

#define S(x) PT*x*x #include main() {

int a=1,b=2;

printf(“%4.1f\\n”,S(a+b)); }

5.5*1+2*1+2

A 49.5 B9.5 C22 D45.0 35.下面程序输出为 #include “stdio.h” main() {

printf(“%d\\n”,12<<2);}

A 0 B47 C48 D24

36.在C语言中,只有在使用时才占用内存单元的变量,其存储类型是

A auto 和register B.extern和register C auto 和static D static和tegister 38若有以下定义的语句 struct student {

int age; int num; };

struct student stu[3]={{1001,20},{1002,19},{1003,21}}; main() {

struct student *p; p=stu; …}

则以下不正确的引用是

A(p++)->num B p++ C(*p).num Dp=&stu.age

40如果需要打开一个已经存在的非空文件“Demo”进行修改,下面选项中正确的是 A fp=fopen(“Demo”,”r”); Bfp=fopen(“Demo”,”ab+”); Cfp=fopen(“Demo”,”w+”); Dfp=fopen(“Demo”,”r+”);

14.以下程序的功能是从名为filea.dat的文本中逐个读入字符并显示在屏幕上,请填空。 #include main() {

FILE *fp; char ch;

vp=fopen(__”filea.dat”,”r”___); ch=fgetc(fp); while(!feof(fp))

{

putchar(ch); ch=fgetc(fp); }

putchar(„\\n‟); fclose(fp); }

34以下程序的运行结果是

#define MAX(A,B) (A)>(B)?(A):(B) #define PRINT(Y) printf(“Y=%d\”,Y) main() {

int a=1,b=2,c=3,d=4,t; t=MAX(a+b,c+d); PRINT(t); }

A :Y=3 B:存在语法错误 C: Y=7 D:Y=0 35以下程序的功能是进行位运算 main() {

unsigned char a,b; a=7^3;b=~4&3; printf(“%d%d\\n”,a,b); }

程序运行后的输出结果是

A 4 3 B 7 3 C 7 0 D 4 0

38.以下scanf函数调用 语句中对结构体变量成员的引用不正确的是 struct pupil {

char name[20]; int age; int sex; }pup[5],*p; p=pup;

A scanf(“%s”,pup[0].name); Bscanf(“%d”,&pup[0].age); Cscanf(“%d”,&(p->sex)); Dscanf(“%d”,p->age);

10.以下程序用来输出结构体变量ex所占存储单元的字节数,请填空。 struct st {

char name[20];double score; }; main() {

struct st ex;

printf(“ex size:%d\\n”,sizeof(___struct st__)) }

38.在C语言中,变量的隐含存储类别是

A auto B static C extern D 无存储类别

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- stra.cn 版权所有 赣ICP备2024042791号-4

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务