C语言复习冲刺资料

更新时间:2023-11-05 11:33:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

第一章C语言基础知识

该章内容:本章是整个C语言最基础的部分;表达式是C语言的核心,本章会学习到不同的表达式。

学习方法:对关键的知识点一定要多背,把最基础的习题多做几遍,在以后的学习中要多次反回来复习,加深印象。

第一节 C语言的基本构成

知识点:C语言的注释;关键字;书写风格;常量和变量 重要程度:★★★★

1、C语言的良好风格

用C语言编写的程序,称为C语言源程序,简称C程序。

本节将通过一个简单的C程序例子,向大家介绍C语言的一些基本构成和如何写出风格良好的程序,使读者对C语言有一个初步的认识。

例1:计算两个整数之和的C程序 #include \

main( ) /*求两数之和*/ {

int a,b,sum; /*变量说明*/

a=10; /*把整数10赋值给变量a */ b=20; /*把整数20赋值给变量b */ sum=a+b; /*把两数之和赋值给变量sum */ printf(\ /*把计算结果输出到用户屏幕上*/

}

好的风格: 1. 花括号独占一行,有对应关系的花括号在同一列; 2. 有层次关系的代码有必要的缩进; 3. 一条语句独占一行 4. 有适当的注释

2、关于注释的说明(考点一)

? ? ? ?

程序中以―/*‖开头并且以―*/‖结尾的部分表示程序的注释部分。 注释可以加在程序的任何位置。

注释是为了提高程序的可读性而增加的,不属于C语言。

/*/*ddddddd*/*/ 这样的注释不是合法的。注释是从“/*“开始到”*/“结束的。以该例为准,属于注释的就是/* */两个之间的/*ddddddd,所以最后剩下的*/就是多余了。 例1: 阅读以下程序,想一想结果是多少?

main( )

{ int a=0,b=0;

a =10; /*给a赋值 b=20; 给b赋值 */

printf(\ /*输出计算结果*/ }

这是2006年9月全国计算机等级考试二级考试的第19题。需要特别注意的是,程序第三行―/*‖开始的注释部分,直到第四行末尾才结束。因此上面的程序等价于以下的程序:

1

main( )

{ int a=0,b=0;

a =10;

printf(\}

3、标识符(考试重点)

在C语言中用于标识名字的有效字符序列称为标识符。标识符可以用作常量名、变量名、符号名、函数名和后面要学到的指针名、数组名等。C语言中标识符的命名规则如下:

1)标识符只能由字母、数字和下划线组成; 2)标识符的第一个字符必须是字母或下划线。

3)标识符区分大小写字母。如int与Int是两个完全不同的标识符。 合法的标识符:

a x sum spels program ab1 _to file_5 a1b2c3 _2 B3 非法的标识符:

ab12# (含有不合法的字符“#”) a1-c (含有不合法的字符“-”) ab c (空格不是合法标识符) ?r (“?”不是字母,为不合法标识符字符) 23ab (第一个字符不能为数字) C语言的标识符分为如下三类: 1)关键字

关键字是具有特定含义的、专门用来说明C语言特定成分的一类标识符。关键字均由小写字母构成。Int 就不是关键字。

2)预定义标识符

预定义标识符(如printf,scanf,sin,isalum等)和编译预处理命令名(如define,include等)。注意,预定义标识符可以作为“用户标识符”使用。

3)用户标识符(考试重点)

不能是关键字;只能由字母、数字和下划线组成;第一个字符必须是字母或下划线。 Int可以作为用户标识符,int就不可以作为用户标识符。 考点:1. 识别哪些是(或不是)标识符 2. 识别哪些是(或不是)用户标识符 例2: 以下不能定义为用户标识符的是

A) scanf B) Void C) _3com_ D) int

分析:本题答案选D。因为int是关键字,关键字不能作为用户标识符。答案(A)的scanf虽然是预定义标识符,但是预定义标识符可以作为用户标识符使用。(B)中Void的第一个字符V大写,它与关键字void是两个不同的标识符,故它可以作为用户标识符。(C)中的_3com_符合标识符的命名规则,且不是关键字,故可以定义为用户标识符。

例3:以下不合法的用户标识符是

A) j2_KEY B) Double C) 4d D)_8_

分析:本题答案选C。答案(A)是一个用户标识符,符合标识符的命名规则。答案(B)也是用户标识符,需要注意的是,它与关键字double是两个不同的标识符。答案(D)是用户标识符,由数字和下划线组成,且第一个字符为下划线。只有答案(C)是不合法的用户标识符,因为它的第一个字符是数字,不符合标识符的命名规则。

2

? 标识符的常见错误:

1. 数字开头

2. 包含减号“-”

3. 用户标识符使用的是关键字 4、常量。

C语言中,还有另外一种常量是用标识符命名的,称为符号常量。下面程序的PI就是符号常量。 例4: 计算圆面积的C语言程序 #define PI 3.14159 main( )

{ float r,area;

r=12.5;

area=PI*r*r;

printf(\}

程序的第一行是宏定义,以后遇到PI就用其后的内容——3.14159来原样替换。这里的PI就是一个符号常量。通常,符号常量用大写字母表示,但这并不是语法上的要求,只不过用大写字母书写符号常量,便于辨认。当进行宏定义后,程序中只要用到相应的数值常量都可以用符号常量代替,这就给程序的修改提供了方便。例如,如果需要进一步提高圆周率的精度,可以直接修改宏定义中的数值常量:

#define PI 3.1415926

这样,程序中只要用到PI的地方,其值都自动变为3.1415926。

5、变量

与常量对应的是变量。顾名思义,变量就是在程序的运行过程中其值可以改变的量。例1中的a,b都是变量,它们是由用户定义的标识符,变量的命名必须遵循标识符的命名规则。

用盒子的理论来描述:

1) 变量就是盒子,里面装的内容可以改变。 2) 通过赋值语句就可以改变盒子里的内容。

3) 每次使用盒子时,盒子里都应该有确切的内容而不能是不确定的值。

4) 每次使用盒子时,都是用的现在盒子里装的内容。以前装过什么内容没有任何影响。

第二节 整型数据

知识点:进制的转换;整型的定义和使用; 重要程度:★★★★

在C语言中,有三种基本的数据类型,它们是整型、实型和字符型。

1、数制转换

二进制的数,基为二,某位出现的最大数字是2-1=1; 八进制的数,基为八,某位出现的最大数字是8-1=7;

十六进制的数,基为十六,某位出现的最大数字是f(相当与十进制的15)。在十六进制中,数字由十六个代码组成,分别是0~9和A~F(或者是a~f)这十六个代码。

表1列举出十进制数字从0~15时,相应的二进制、八进制和十六进制数字。(同列的为一组,表示相同的值)

3

表1 十进制、二进制、八进制和十六进制对照表

十进制 二进制 八进制 十六进制 十进制 二进制 八进制 十六进制

0 0 0 0 8 1000 10 8

1 1 1 1 9 1001 11 9

2 10 2 2 10 1010 12 A

3 11 3 3 11 1011 13 B

4 100 4 4 12 1100 14 C

5 101 5 5 13 1101 15 D

6 110 6 6 14 1110 16 E

7 111 7 7 15 1111 17 F

十进制的数字在我们日常生活中普遍使用,然而在计算机内部,数字均以二进制形式表示和存放。

引例:

(1)将任意进制的数转换为十进制数:

将这个数按照引例中的方法展开。注意底数使用的是该进制的基。 使用以上的方法,我们再来看两个例子:

(23E)16 = 2×162 + 3×161 + 14×160 =(574)10 (111)2 = 1×22+1×21+1×20 = 23-1 = (7)10 (2)将十进制数转换成任意进制数 十进制数转换成二进制数的规则为:将十进制的数字除以2,得到的商数继续除以2,直到商为0,然后将各次相除所得的余数从后往前排列,就得到该十进制数转换成的对应的二进制数。例如,将十进制数13转换成二进制数的过程如下:

2 | 1 3

2 | 6 …………1 2 | 3 …………0 2 | 1 …………1

0 …………1

所得的余数从后往前排列,得到二进制数1101,与表1中的一致。

同理,可以得出将十进制数转换为任意进制数的规则。例如,将十进制数13转换成八进制数的过程如下:

8 | 1 3

8 | 1 …………5 0 …………1

所得的余数从后往前排列,得到二进制数15,与表1中的一致。 (3)二进制与八进制、十六进制之间的转换

从表1中可以看出,每个八进制数的单个数字都可以用三位二进制数来表示,最大的八进制单个数字7等于最大的三位二进制111,最小的八进制单个数字0等于最小的三位二进制000。因此,每个八进制数的单个数字都可以用三位二进制数字来表示,即23=8。同样,每个十六进制数的单个数字都可以用四位二进制数来表示,即24=16。

例如,将八进制数13转换成二进制数的过程如下:

(1 3)8 = (001 011)2

从以上的转换过程看出,将每个八进制数字转换成了三位二进制数字,1转换成001,3转换成011,因此八进制13对应的二进制数字为1011。

现举例说明将十六进制数数E3转换成二进制数的过程:

(E 3)16 = (1110 0011)2

从表1可以看出,十六进制数字E等于二进制的1110,3等于二进制的0011,于是十六进制数字

4

E3等于二进制数字11100011。

反过来,将二进制转换成八进制、十六进制,只需将从右边起的每三位或者每四位二进制数转换成对应的八进制数或十六进制数。

进制的常见错误:

1. 八进制数据中出现8,甚至是9.

2. 十六进制中,把15当成一个字符(实际上应该是f)。

2、整型常量

? 在C语言中,整型常量分为十进制整型常量、八进制整型常量和十六进制整型常量三种表示形式。

注意,在C语言中没有直接表示二进制的整型常量。(常考)

(1)十进制整型常量由一串连续的0~9数字组成。如:0、120、365、-12等。 (2)八进制整型常量以数字0开头,其中的数字为0~7。如:0112(十进制74)、0123(十进制83)、077(十进制63)等。

(3)十六进制整型常量以0x(数字0和字母x)或0X开头,其中的数字可以是0~9、a~f或A~F中的数字或英文字母。如:0x11(十进制17)、0xa5(十进制165)、0X5a(十进制90)等。

整型常量又分为短整型(short int)、基本整型(int)、长整型(long int)和无符号整型(unsigned)等几类。

例1: 以下选项中可作为C语言合法整数的是

A) 10110B B) 0386 C) 0Xffa D) x2a2 分析:本题答案为C。

选项(A)不是C语言中三种整型常量之一。

选项(B)不是合法的八进制整型常量,因为八进制整型常量中不可能出现“8”字符。 选项(D)中x2a2前加上“0”就是一个合法的十六进制整型常量。

3、整型变量

整型变量是用于存放整型值的变量。对应于整型常量,整型变量也可分为短整型(short int)、基本整型(int)、长整型(long int)和无符号整型(unsigned)四种。

定义基本整型变量用关键字int,形式如下:

int i;

int类型所占据的字节长度因不同类型的机器或编译器而有所不同:

如果使用VC++6.0,则会为int型变量分配4个字节长度的存储单元。我们使用的将是这种情况。 如图1所示。图中表示对定义的int型整型变量i分配了四个字节的存储单元,这个存储单元的名字为i,里面的内容不确定。

图1 计算机系统为整型变量i分配的内存空间

当对变量i赋值时,这个值就存储在这个存储单元中。

例如,执行了赋值语句:

i=6;

则变量i的存储单元变为如图2所示的情况。

00000000 00000000 00000000 00000110

图2 十进制整数6存放在变量i的内存空间中的形式

正如读者所知,在计算机中实际上是以二进制形式存储数据的,所以在变量i的存储单元中存放的是四个字节的二进制数00000000 00000000 00000000 00000110(十进制6)。

C语言中规定,在定义变量的同时给变量赋初值,称为变量初始化。例如:

5

main( )

{ int a=2,b=3,c=4; ?? }

表2 不同类型的整型数在内存中所占用的字节数和数值范围

数据类型 短整型 无符号短整型 基本整型 无符号整型 长整型 无符号长整型

关键字 [signed] short [int] unsigned short [int] [signed] int unsigned [int] [signed] long [int] unsigned long [int]

占用的字节数

2 2 4 4 4 4

数值范围

-32768~32767 0~65535

-2147483648~2147483647 0~4294967295

-2147483648~2147483647 0~4294967295

说明:

1) 如果要表示一个长整型常量,则应该在对应的整型常量后面加上一个字母后缀l(L的小写)或者是L。如0L、110L、123L等。这是因为如果不加上L(或l),则表明这个整型常量为基本整型常量,在内存中占两个字节的存储单元,而加上之后,则表明为长整型常量,在内存中占四个字节存储单元。

2)无论是短整型还是长整型常量,C语言系统都默认为是有符号整数。无符号整数在数字的后面加上一个字母后缀u或者是U。若是长整型无符号整型常量,则应该加后缀lu或者是LU。

例2: 以下选项中不属于C语言的类型的是 A) signed short int B) unsigned long int C) unsigned int D) long short 分析:根据表2可知,正确答案为D。

4、整数在内存中的存储形式

在计算机内存中最小存储单位称为“位(bit)”。每一个位中或者存放0,或者存放1,因此称为二进制位。一个字节(Byte)有8个二进制位。沿用惯例,把最右边一位称为最低位,把最左边一位称为最高位。在C语言中,对于有符号型整数,将最高位作为符号位,当最高位为0时表示正整数,当最高位为1时表示负整数。

下面介绍整数的存储形式。

注意:计算机中(或者说内存中)的数据都以它对应的补码形式存在。

第三节 实型数据

知识点:实型的定义方法和实型常量的表达方法; 重要程度:★★★★

1、实型常量

在C语言中,实型常量有两种表示形式:小数形式和指数形式。 (1)小数形式

规则如下:1. 有且仅有一个小数点。

2. 左边和右边可以有一边没有数据,但是不能同时没有数据。 如:3.14159 0.158 12. .36 0.0 -18.0

(2)指数形式(E前E后都有数,E后必为整数) 规则如下:1. 有且仅有一个字母e(或者E)。

6

2. 左右两边都必须有数据。

3. 左边可以是整数也可以是小数。 4. 右边只能是整数。 以下列举出几个正确的指数形式:

1e5 (表示数值1?105) 1.25E+4 (表示数值1.25?104) 2.0E-3 (表示数值2.0?10-3) 实型常量的常见错误:

12 (缺少小数点,12其实为一个整型的常量而不是实型常量) e5 (缺少小数部分) 1.25E (缺少指数部分) 2.0E1.3 (指数部分不是整数)

例1: 以下选项中合法的实型常数是 A)5E2.0 B)E-3 C).2E0 D)1.3E 分析:本题的答案是C。

选项(A)的指数部分不是整数。 选项(B)缺少小数部分。 选项(D)缺少指数部分。

例2: 以下选项中,不能作为合法常量的是 A)1.234e04 B)1.234e0.4 C)1.234e+4 D)1.234e0

分析:选项(B)的指数部分不是整数,所以答案为B,其它选项均为正确的常量。

2、实型变量

C语言中,实型变量分为单精度实型(float)变量与双精度实型(double)变量两种。它们定义的形式分别如下:

float x,y,z; /*定义单精度实型变量x,y,z */ double a,b,c; /*定义双精度实型变量a,b,c*/ double的精度比float好!

第四节 字符型数据

知识点:字符型常量;字符型变量;转义字符; 重要程度:★★★★★(字符可当作整型使用)

1、字符常量 字符常量是由一对单引号括起来的。

1)由一对单引号括起来的单个字符:

单引号中只有一个字符: '0'、'A'、'a'、' '、'#'。

2)由一对单引号括起来的,里面是由斜杠“\\”引起的若干字符:

在单引号中,都由“\\”开头: '\\n '、'\\t '、'\\\\'、'\\''、'\\\'、'\\0 '、'\\377 '、'\\xff '。这个“\\”称为转义字符。转义字符后面的内容失去了原来的意义,如'\\n'表示换行符,而不是字母n了。

每个字符都有一个ASCII码与之对应。(字符可以看成整形)

如字符'0'的ASCII码值为48,我们简称字符'0'的值为48。同样,'A'的值为65,'a'的值为97。 字符型数据进行运算,使用的其实都是这个字符对应的ASCII码值。

C语言中一共有三种转义字符:一般转义字符、八进制转义字符、十六进制转义字符。

7

表3 C语言中常用的转义字符

字符形式 意义 字符形式 意义 \\n 换行 \\\\ 一个反斜杠字符 \\ \\t 横向跳格(Tab) \\' 一个单引号 ' \\v 竖向跳格 \\\一个双引号 \ \\b 退格符(backspace) \\ooo 1~3位八进制数代表的字符 \\r 回车符 \\xhh 1~2位十六进制数代表的字符 \\f 换页符 \\0 空值 (1)一般转义字符

'\\n'、'\\\\'、'\\\等,由一个“\\”开头加一个普通字符组成。请牢记表3中粗体的转义字符。

(2)八进制转义字符

它是由“\\”与其后的1~3位八进制数字构成的字符序列。 反斜杠后面的十六进制数不需要以0开头。?\\061?就错了

'\\61'首先把61这个八进制化成十进制,得到49,ASCII为49的字符就是‘1‘。. '\\101'首先把101这个八进制化成十进制,得到65,ASCII为65的字符就是‘A‘。.

(3)十六进制转义字符

它是由“\\x”与其后的1~2位十六进制数字构成的字符序列。 反斜杠后面的十六进制数不需要以0x开头。?\\0x77?错了!

但是反斜杠之后的必须是小写字母x,而不能是大写字母X,也不能是其它形式。?\\0X77?错了! '\\x42'表示字符常量'B'

'\\x6e'分别表示字符常量和'n'。

字符型常量的常见错误:

(1)把\看作字符常量。字符常量的标志是一对单引号' ',而不是双引号\。 (2)一对单引号中有多个字符。'65'是非法的字符常量。(常考) (4)′\\ooo′中出现数字8。′\\ooo′中只能出现字符0~7。 (5)'\\xhh'中,忘记书写字符x。

例1: 以下不合法的字符常量是

A ′\\018′ B ′\\′″ C ′\\\\′ D ′\\xcc′

分析:本题是2006年4月考题,考察点在字符常量的概念。此题答案为A。 A中为八进制转义字符,但是八进制数不能出现8,因此错误。 B中是一般转义字符,表示一个双引号字符,正确。 C中是一般转义字符,表示一个反斜杠字符,正确。

D中匹配十六进制转义字符,cc是合法的十六进制数,正确。

2、字符变量(考试重点)

char a: 等价于 char a a='A'; a = 65;

变量a中存放了'A'的ASCII码值65。前面已经知道,字符型数据都是被处理为整型量,因此,可以直接对字符变量赋字符常量对应的ASCII码值。如赋值语句a=65;与赋值语句a='A';等价。

例2: 已定义c为字符型变量,则下列语句中正确的是

8

A) c=?97‘; B) c=\ C) c=97; D) c=\分析:答案选择C。

A中'97'为非法的字符常量。单引号内不能出现多个字符。

B中\为字符串,字符常量的标志的一对单引号,而不是双引号。

C将整型量97赋给字符变量c,即将ASCII码值为97的字符常量'a'赋给变量c,正确。 D中\不是字符常量,而是字符串。

3、对字符型数据的运算

1、对字符进行算术运算就是将字符对应的ASCII码值进行运算。

如:'D'-'C'的值为1。因为我们用'D'和'C'的ASCII码68、67分别替换'D'、'C'之后,等价于求68-67的值。又例如,'C'+1的值为'D'。

2、大写字母的ASCII码与对应的小写字母的ASCII码相差32。 大写字母 转换成 小写字母

'A' 加上32 'a'

如'A'与'a'的ASCII码分别为65和97。这样我们经过简单的算术运算就可以进行大小写字母字符的转换。如'A' +32即为,'a'-32即为'A'。

3、字符数字的ASCII码与对应的数字的ASCII码相差了48. 字符数字 转换成 数字 ?1‘ 减去48 1

第五节 算术表达式

知识点:运算符号的优先级别;强制类型转换的使用; 重要程度:★★★★

1、算术运算符与算术表达式

1、在C语言中,有下列五个基本的算术运算符:+、-、*、/和%,依次表示加、减、乘、除、求 余运算。(考得最多的是/ 和%符号!!!)

2、求余运算符%的运算对象只能是整型,即%左侧的被除数与右侧的除数都只能为整型值。

求余得到的运算结果的符号与被除数相同。(3%1.2错了) 如:12%9运算结果为3,12%-9的运算结果也为3。

-12%9运算结果为-3,-12%-9的运算结果也为-3。

3、求余就是求余数,而不是求商,这点总是容易被弄混淆。 ? 想一想:3%9运算结果为多少??(结果为3而不是0)

4、1/2得到的数据是为0的,这个原则是当除号“/“左右两边都为整数的时候,我们遵守取整丢小数的原则。那么如果希望1和2相除得到0.5,我们就可以用1.0/2,或者1/2.0,或者1.0/2.0都可以实现。

先面通过一个具体例子的分析,我们来彻底搞清楚算术运算符的运算规则。 例1:试求 1.6+3/2*1.2-3/2.0 的值

步骤:

计算过程: 说明:

9

根据运算优先级和结合的顺序,先算3/2,注意到它们为整型数据相运算,因此结果应为整数1,而不是1.5。

第二步: 1.6+1.0*1.2-3.0/2.0 1*1.2为整型和实型数据相运算,因此,会把整型数据1转换

为对应的实型数据1.0,再与1.2进行运算。同理,3变成3.0

第三步: 1.6+1.2-1.5 分别计算出 1.0*1.2 和 3.0/2.0 的结果 第四步: 2.8-1.5 同一优先级的运算,从左到右依次进行 第五步: 1.3 结果为1.3,而不是1.9

下面,大家自己算算,表达式3.6-5/2+1.2+5%2的值应该是多少? A)4.3 B)4.8 C)3.3 D)3.8

分析:根据表3列出的算术运算符优先级,本题目应先计算5/2与5%2得到2和1,然后再计算3.6-2+1.2+1,得到答案D。

第一步: 1.6+1*1.2-3/2.0

2、强制类型转换

在进行算术运算时,如果希望将某一运算量转换成指定的类型,则可以利用强制类型转换符。 强制类型转换表达式为:(类型名)表达式 其中,“(类型名)”是强制类型转换符,它将右边表达式的类型转换为括号中的类型。 强制类型转换并不会改变右边表达式的值,(类型名)表达式 这个整体产生了一个临时值。 例:有如下代码:

float a=3.8; int b; b=(int)a;

这段代码把a强制转化为整型数据3(注意C语言里的强制转换都是截取,而不是四舍五入),并把这个值3赋给整型变量b。注意,此时a的值仍然是3.8。

强制转换只控制其后的一个数据 例:(int ) a+b和(int ) (a+b)不同:

前者是把a强制转换为整型,再把这个临时的整型值和b作运算。 后者是先计算a+b,之后把它们的值做整体的强制转换。 强制转换需要注意的几点: 1) 类型名外的()必不可少

2) 强制转换控制其后的一个数据

3) 强制类型转换并不会改变右边表达式的值

第六节 赋值表达式

知识点:赋值表达式的运算;复合赋值表达式的运算;自加和自减; 重要程度:★★★★★

1、赋值运算符和赋值表达式 int a = 12;

它的含义是将赋值运算符右边的表达式的运算结果赋值给左边的变量。 说明:

1)赋值运算符左边必须是单个变量。例如x+1=3在数学上虽然是正确的,可是在C语言中却 是错误的,不能将一个常量赋值给一个表达式。

2)赋值运算会将左边变量的值用右边表达式的值来代替,右边的值不会改变。

例如,int x=3,y=5;

10

x=y+1;

以上代码先将x初始化为3,将y初始化为5。执行完赋值语句x=y+1;后,变量x的值被y+1覆盖掉,即x的值变成了6,变量y的值不会改变。

用盒子理论来说就是,先定义了两个盒子,分别叫做x盒子和y盒子,x盒子装的是整数3,y盒子装的是整数5。之后把x盒子所装的内容改成y盒子的内容加1,也就是6。这样,x盒子中装的就是6了,以后再要使用x,都是用的新值6。而以前x装过什么值现在再也不知道了。

3)赋值表达式的值是赋值号左边变量被赋值后的值。

例如:x=0整个赋值表达式的值是变量x被赋值之后的值,也就是说这个表达式的值为0。

4)可以将赋值表达式的值再赋值给变量,形成连续赋值运算。(学会分析过程)

例如,x=(y=25)是一个连续赋值表达式。由于赋值表达式的结合形式是从右到左,因此可以简写为x=y=25,它表达的含义是将25赋值给变量y,然后将表达式y=25的值赋值,即变量y的值赋给变量x,结果使变量x和y的值都变为25。

5)虽然可以连续赋值,但是不能连续初始化。(考试重点) 例如:int x=y=25; 就是错误的。

对于int x=y=25;我们会先计算y=25,此时,y并没有定义,而是在直接使用,所以就会报错。 如果我们把上面的连续初始化改成:int y; int x=y=25; 这样就没有错了。

6)赋值运算符不同于数学上的“等号”。(C语言中“=”表示赋值,“= =”表示等号)

因为赋值运算符的操作是将赋值号右边的表达式的值赋给左边的变量。它是单方向的操作。例如在数学中,i=i+1不成立,但在赋值表达式中却是成立的,它表示将变量i的值增加1之后得到的结果赋值给变量i,因此,该表达式的含义是使变量i的值增加1。

7)如果赋值号两边的运算对象类型不一致,则系统会自动进行类型转换。

8)自动类型转换的实例:int a=3.6;

赋值号左边的变量类型是整数,右边的值是实数,因此将右边的值转换成整数。3.6转换成整数后是3,因此a的值被赋为了3。

注意:实数转换成整数的方法是截取而不是四舍五入,因此直接把小数点后的数据去掉就行了。

2、复合赋值表达式(掌握如何计算即可)

在C语言中,可以将算术运算符与赋值运算符组合在一起组成复合赋值运算符。它们是:+=,-=,*=,/=,其使用方法及具体的运算规则如下:

表达式n+=100等价的表达式为:n=n+100 表达式n-=2*n等价的表达式为:n=n-2*n 表达式n*=m+1等价的表达式为:n=n*(m+1) 表达式n/=m+1等价的表达式为:n=n/(m+1)

上述四种复合赋值运算符的运算优先级与赋值运算符的优先级相同(优先级都非常低),运算方向均为自右向左。

想一想:n+=10和n+10有什么区别?区别在于前者n本身的值改变了,而后者n的值没有改变。

例1: 已知变量n的初始值为8,计算表达式n+=n*=n-2的值。(经典考题)

分析:表达式中有两个复合赋值运算符:+=和*=。它们优先级相同,运算方向均为自右向左。因

11

此,运算的步骤如下:

(1)先计算最右边表达式n-2的值为6;

(2)再计算n*=6,该表达式等价n=n*6,将n中的值8乘以6,得到48,并赋值给n,因此变量n的值为48,表达式n*=n-2的值为48;

(3)最后计算n+=48,该表达式相当于n=n+48。因为上一步计算出n的值为48,所以n+48的值为96,即n的值最终为96。

通过计算,表达式n+=n*=n-2的值为96。

例2:int a=5,b=6,c=2; c *=a+b;

请问:c的值最终是多少?

错误的算法: c=c*a+b;得到的是16。 正确的算法: c=c*(a+b);得到的是22。

第七节 自加表达式

1、自加与自减运算符(超级重点)

如何让一个变量自身的值加1?通过之前的学习,我们知道a=a+1; 和 a+=1; 都可以实现。而我们将要讨论的a++和++a同样可以实现这样的效果。

自加、自减运算是一种赋值运算。

既然a++和++a写法上有区别,那么它们应该有所不同。这里仅就++运算符进行说明,--运算符有类似的结论:

a++和++a的相同处:对于变量a而言,它们都是让a的值加1。

a++和++a的不同处:( ++a)、(a++)是两个自加表达式,所以这两个表达式本身就有数值,只是++a,a++两个的表达式的数值不同。

自加表达式的核心理解

++a是先把a加1,再作为(++a)这个表达式的数值。 a++是先把a的数值作为(a++)这个表达式的数值,再使a自加1。

? 遇到a++,就看成a,等这部分执行结束后,再让a的值加一。(加号在后,则先使用后自加)

? 遇到++a,则把a的值先加一,之后再使用加过一后的值。(加号在前,则先自加后使用)。

例如有以下代码(通过以下代码,学会分析a++和++a的执行过程):

int a=3,b; b=a++;

这段代码执行完后,b的值为3,a的值为4。

对于语句b=a++; 按照以上所说,我们就看成b=a; 此时a值为3,因此赋值后b的值也为3。等这部分执行结束后,再让a的值加一。因此,整个这段代码结束后,b的值为3,a的值为4。

----------------------------------------------------------------------------------------------------------------------------------

int a=3, b;

b=++a,代码发生了变化,那么执行完后,a和b的值分别为多少呢?

对于语句b= ++a; 按照以上所说,我们把a值先加一,得到a的值为4。之后赋值给b。因此,整个这段代码结束后,a、b的值都为4。

通过以上的简单例子,我们看到,a++和++a都会让a本身的值加一。 12 不同在于对别人的影响。 语句b=a++; 等价于以下两条语句:b=a;a++;(先使用(赋值),后自加) 语句b=++a; 等价于以下两条语句:a++;b=a;(先自加,后使用(赋值))

说明:

补充考点:

1)增量运算符的运算对象只能为单个变量,不能是常量或是表达式。例如:++3、++(i+1) 都是不合法的增量表达式。

2)不论“++”在变量的前面还是在变量的后面,对于变量本身都具有“增加1”的相同效果。 例如i++、++i两个增量表达式运算后变量i的值都是增加1。

3)自加、自减运算符的结合方向是“从右到左”。 例如有如下代码: int y,x=3; y=-x++;

负号“-”与自加运算符“++”具有相同的运算优先级,但是根据“从右到左”的结合方向,那么应该先计算x++,而x++可以先看成就是x。取其负值3赋给y,那么y的值就为-3,这部分执行结束了,x的值再加一,所以这段代码结束后,x的值为4,y的值为-3。

4)在使用“++”运算符时,变量应该有个确定的值。例如:int a; a++; 就是错误的。因为刚定 义好的a值不确定。让一个垃圾值自加一没有任何意义。

经典考题:

例1: 有以下定义语句:double a,b; int w; long c;

若各变量已正确赋值,则下列选项中正确的表达式是

A)a=a+b=b++ B)w%((int)a+b) C)(c+w)%(int)a D)w=a%b; 分析:答案C正确。

选项A是一个连续赋值表达式,先将表达式b++的值赋值给表达式a+b,因为赋值语句的左边只能是变量名称,因此这时会出错。

选项B是一个求余运算符连接起来的两个运算对象,除数((int)a+b)看起来比较复杂,它先将双精度类型变量a的值强制转换为整型,然后再与双精度类型变量b求和,得到的值的类型仍为双精度类型,也就是说除数是一个实数而不是整数,因此不能使用%运算符,所以答案B错误。

选项C的被除数是两个整型数相加,运算结果为整型,除数为(int)a,也为整型,答案C正确。 选项D中a%b错误。

例2 有以下程序 main()

{ int m=12,n=34;

printf(\

printf(\}

程序运行后的输出结果是

A)12353514 B)12353513 C)12343514 D)12343513

分析:在第一个printf输出语句中,计算表达式m++时,其值为变量m的初始值,即12,因为执行了表达式m++,变量m的值增加1,因此m的值变为13。计算表达式++n 时,其值为变量n的

13

初始值增加1,即35,因为计算了表达式++n,因此变量n的值增加1,为35。在第二个printf中,计算n++时,其值为n的初始值,即上一次计算得到的35,因为计算了n++,变量n的值增加1。计算++m时,其值为变量m的初始值增加1,即使上一次计算得到的m的值加上1,为14。因此本题答案为A。

第八节 逗号表达式

5、逗号运算符和逗号表达式

1、在C语言中,逗号除了做分隔符,还可以作一种运算符——逗号运算符。用逗号运算符把两个或两个以上的表达式连接起来,可以构成一个新的表达式,即逗号表达式。例如:

x=5,y=6,z=7 整个(x=5,y=6,z=7)是逗号表达式,他的数值等于7,

2、逗号运算符是级别最低的运算符号,比赋值还要低。

3、逗号运算符具有从左到右的结合性,即先计算第一个表达式,然后计算第二个表达式,直到最后一个表达式。最后一个表达式的值就是整个逗号表达式的值。上述的逗号表达式的值就是表达式z=7的值7。

x=5,y=6,z=7 是个逗号表达式,它的数值为7。x的数值为5。 x=(5,y=6,z=7) 是个逗号表达式,它的数值为7,x的数值为7。 .

例1: 有以下程序 main( )

{ int a1=3,a2=9;

printf(\ }

以下叙述中正确的是

A)程序输出3 B)程序输出9 C)格式说明符不足,编译出错 D)程序运行时产生出错信息

分析:函数体中首先变量初始化,变量a1、a2的值分别为3和9,接下来的printf输出语句中,要输出的项是(a1,a2),在此要明白输出项是一个逗号表达式就不会选错答案。逗号表达式a1,a2的值就是a2的值,因此本题的答案为B。

请注意它与printf(\的区别。

例2: 有以下程序(经典考题) main( )

{ int x,y,z;

x=y=1;

z=x++,y++,++y;

printf(―%d,%d,%d\\n‖,x,y,z); }

程序运行后的输出结果是

A)2,3,3 B)2,3,2 C)2,3,1 D)2,2,1

分析:函数体中首先定义了三个整型变量x,y和z,接下来,对变量x和y赋值为1。然后,仔细分析语句z=x++,y++,++y;,因为逗号运算符在所有运算符中的优先级最低,因此赋值表达式应该先于逗号表达式计算,所以上述逗号表达式语句由三个赋值表达式组成:z=x++、y++和++y。按逗号表达式

14

的计算规则,从左至右依次计算每个表达式,故应先计算x++,并将其值赋给变量z,z的值为1,因为计算了x++,x的值增加1,变为2;计算了y++和++y,变量y的值应增加2,变为3。最后,程序 输出x,y,z的值应为2,3,1。本题答案为C。

补充:

int a=1,x;

x= (a++,a++,++a)后,x的数值为多少? x为3.

int a=1,x;

x= a++,a++,++a后,x的数值为多少? x为1

15

第二章 顺序结构

该章内容:这章我们学习三大结构之一:顺序结构,它是程序从上往下顺序执行,是程序运行最简单的方式。printf和scanf

函数使用和特例是必考知识。本章是考试的重点章节。

学习方法:从简单的顺序结构题目入手,逐步把难度加大,对比记忆printf和scanf函数。

第一节 表达式与语句

知识点:语句和表达式之间的联系;分号的使用;复合语句 重要程度:★★★

1、表达式与语句

“ 表达式 “ + ” ;“ = ”语句 ”。例如:

赋值表达式

x=9

赋值语句

X=9;

算术表达式

x+y

算术语句

x+y;

自加表达式

i++

自加语句

i++;

从图中可以很清楚的看见,表达式和语句的区别就是一个有分号,一个没有分号。这个分号是考试的重点,尤其是在上机考试的改错题目,最喜欢不写分号,我们要加一个分号!

2、空语句与复合语句

;

1、这个分号也是一个语句,称为“空语句”。“空语句”表示程序执行时不产生任何动作。注意:随意使用空语句会导致逻辑上出现错误,需要慎用。

2、所谓复合语句,就是把好几个语句复合到一起,那么用什么符号把多个语句复合到一起来?我们要记住是用花括号“{”把多个语句括起来组成了一个复合语句。

复合语句具体形式:{语句1;语句2;?? 语句n;}

3、顺序结构

程序中的多个语句按照语句从上往下出现的先后次序顺序逐条执行,这种执行方式是最基本的执行方式,称为顺序结构,是三大基本结构之一。

记住一句话:看到顺序结构就想到从上往下。

16

第二节 数据输出

考 点:pirntf函数的使用;printf两个参数的使用方法;格式说明符号对应的意思; 重要程度:★★★★(每年必考)

printf函数和scanf函数都是库函数,printf和scanf都不是关键字,他们只是预定义标识符。

1、printf函数第一个参数讲解

例1:printf(\

第一个部分是用双引号括起来!第二部分是两个数据“1,2”,数据之间是用逗号隔开的。

第一部分的双引号中就有两种信息:一种是原样输出,一种是格式说明。其中原样输出的说明信息是“x= ,y= ”,包括第一个%d之后的逗号也是原样输出。双引号中还有两个%d,这两个%d就是格式转换说明,用于指定第二部分数据“1,2”的输出格式为整型。这里第一个“%d”对应第一个数字1,第二个“%d”对应第二个数字2,因此我们可以在屏幕上看到:x=1,y=2。

例2:printf(―the result is %d‖,123);

这个程序中运行结果是可以在屏幕上看到:the result is 123。那么原样输出的说明信息是“the result is”,第一个部分的%d是要把输出数据列表的123以整型的格式输出。

例3:printf(\

这个程序运行的结果是可以在屏幕上看到:x=1,y2。那么我们可以看到比例一中的第一部分,我们少了个等号“=”,所以我们在输出时候,原样输出的信息就没有等号“=”。

2、printf函数第二个参数讲解

printf函数第二个参数可以是常量数据,也可以是变量,也可以是表达式。 例4:printf(\ 输出数据列表是常量 屏幕显示:x=1

printf(\ 输出数据列表是变量 若x为9,屏幕显示:x=9

printf(\ 输出数据列表是表达式 若x+y为12,屏幕显示:x=12

第二个要记住的:各个数据之间用逗号分隔开。

第三个要记住:输出数据的个数与输出控制中的格式转换说明的个数相等,并且在顺序上要一一对应且类型匹配。注意一点:如果类型不匹配,这时系统并不报错,但不能得到正确的结果。

例5:printf(\,9.87,2);

这里是不会报错的,但是得不到正确的结果,因为,第一个格式说明“%d”表示要把输出数据按整数形式输出,而它对应要输出数据却是实数9.87,对应出错了。第二个格式说明“%f”是要把输出数据按实数形式输出,而第二个要输出的数据却是整数2,显然不匹配。

在输出控制中,格式说明的个数(也就是第一部分%d的个数)应与第二部分输出项的输出数据个数相同。

情况一:格式说明的个数 < 输出项的个数。处理方式:多于的输出项不予输出;

情况一的例子:printf(\,2,3,4);的输出结果为2,3。数据4不会被输出。 情况二:格式说明的个数 > 输出项的个数,处理方式:对多于的格式说明将输出不定值。

情况二的例子:printf(\,2);的输出结果为2,772。第二个数据是不定值。

17

例6:有以下程序(常考题型) main( )

{ int a=888,b=999; printf(\}

程序运行后的输出结果是

A)错误信息 B)999 C)888 D)888,999 分析:在printf语句中,格式控制的格式说明只有一个“%d”,但是而输出列表项有两项“888,999”,即a和b。由于只有一个%d,输出的结果只有一个,即printf函数的第二部分中第一个出现的变量a的值。则正确的答案是:C。

3、printf函数中的格式说明

前面的例子中多次出现了由“%”加上一个字符的组成的格式转换说明,它是作为printf的输出控制的。这个是一定要牢记的,是考试的重点!

表1 格式说明对应的输出数据格式

格式说明 %d或%i %f %c %o %x或%X %#o %#x或%#X %u %e或%E

输出有符号的十进制整型数

输出数据格式

输出单精度或双精度数且小数点后有6位小数数位 输出一个字符

输出八进制无符号形式整型数(不带前导0)

输出十六进制无符号形式整型数(不带前导0x或0X) 输出八进制无符号形式整型数(带前导0)

输出十六进制无符号形式整型数(带前导0x或0X) 输出无符号的十进制整数

以[-]m.ddddde?xx或[-]m.ddddde?XX的形式输出单精度或双精度数。d的个数由精度决定。系统隐含的精度为6, d的个数隐含为5。

说明:

1) 对于长整型数据的输出,一定要在%和d之间加上英文小写字母l,即格式%ld。

2) 对于双精度数据的输出,一定要在%和f或e之间加上英文小写字母l, 即格式%lf或%le。 3) 用表1所列出的格式说明时,系统自动决定输出数据所占的宽度,并采用右对齐的方式。

常考题型:

例7: 若有以下程序段(注意:n所赋的是八进制数) int x=32767,y=032767; printf(\; 执行后输出结果是

A) 32767,032767 B) 32767,32767 C) 32767,77777 D) 32767,077777

分析:整型变量x和y分别存放的是十进制整数32767和八进制整数32767。在printf语句中,把x和y两个变量分别按%d(十进制有符号的形式)和%o(八进制无符号形式)形式输出。那么得到的结果应该是32767,32767,即答案B正确。

例8:同例7相似,只是在printf函数中的%o之间加上#,变为%#o。 int x=32767,y=032767;

18

printf(\#o\\n\;

那么该例子得到的结果为:32767,032767, 可以看到%o与%#o之间的区别。就是一个不要输出八进制中前导的0,而另外一个是要输出前导的0。

例9:若有以下程序段 int i=0xabc,j=0xabc; i-=j;

printf(\printf(\执行后输出结果是 A) 0X0 B) 0x0 C) 0 D) 0XABC

0 0 0x0 0xABC

分析:第一行:整型变量i和j里面存放的都是十六进制整数abc。第二行:执行i-=j;语句,i值变为0。第三行:在printf语句中,把i存放的整数0以%X(十六进制无符号形式)形式输出,得到的结果是0,第四行:把i存放的整数0以%#X形式输出,得到的结果是0x0。所以正确答案是C。

例10:若变量a,b已定义为int类型并赋值22和66,要求用printf函数以a=22,b=66的形式输出,请写出完整的输出语句______。

分析:根据题目要求,变量a、b要求以int类型输出,从表1中可知:输出时应使用格式说明%d来对应整型,同时输出的形式为a=21,b=55,那么也就是有一部分的内容要原样输出。这些内容是“a= ,b=”,所以在输出控制的双引号内,我们写上代码“a=%d,b=%d”。最后,整个需要输出语句为:printf(\

重要说明:(考得很少)

1) 在%和格式字符之间加入一个整数来控制输出数据所占的宽度,如%5d,

情况一:整数指定的宽度大于实际输出数据的宽度。处理方式:数据的输出采用右对齐的方式,左边自动补空格;

情况二:整数指定的宽度小于实际输出数据的宽度。处理方式:以输出数据的实际宽度输出。 表2举例说明了未指定宽度和指定宽度时的对比结果。

表2 未指定宽度和指定宽度时的输出数据对比结果(―?‖代表空格)

输出语句

printf(\printf(\printf(\printf(\printf(\printf(\

625 625

输出结果

??625 1.250000 1.250000 ????1.250000

说明:在输出时,小数点占一位,对于float和double类型一定要保证小数后是六位,不足的补0。

2) 在%和格式字符f之间加入“整数1.整数2”来控制输出数据的格式时,如%3.2f。

“整数1”指定整个输出数据占的总宽度。“整数2”指定输出实数的小数部分的个数。

情况一:当实际输出数据的小数个数 > “整数2”指定的个数时。处理方式:截去多余的数据,并对截去的第一位小数做四舍五入处理。

情况二:当实际输出数据的小数个数 <“整数2”指定的个数时。处理方式:在小数的右边添0 补足。

19

重要的一句话:碰到“整数1.整数2”形式,首先用“整数2”处理小数部分,处理完后,在用“整数1”处理整个数据,包括已经处理好的小数部分。

表3 ―%整数1.整数2f‖的输出格式(―?‖代表空格)

输出语句 printf(\printf(\printf(\printf(\输出结果 3.142 3.14150 ??3.14150 ??3

3)%o和%#o之间及%x和%#x之间的区别。有#号的时候,八进制要输出前导0,十六进制要输出前导0x,但是有一点:输出前一定要把十进制转换成需要输出的十六进制或者八进制。(注意:#号对其它格式字符通常不起作用)。

表4 输出的八进制数、十六进制数前分别添加0、0x

输出语句

printf(\printf(\printf(\printf(\输出结果 376 0376 fe 0xfe

其它使用说明:

1) 输出“%”字符的方法,应该在格式控制中用两个连续的“%”,即“%%”来表示,也就是要 在格式控制中出现两个连续的“%”。

例11:printf(\不会输出整数255。因为“%%”的意图是要输出一个“%”,这个时候“d”会当作一个字符按原样输出。同时,由于这时因为没有格式说明,整数254无法输出到屏幕上。输出到屏幕上的结果为“%d”。

例12:printf(\“%%”意图输出一个“%”,后面的“%d”是格式说明,对应后面的255。那么这个时候输出的结果是为%255。

2) 注意格式说明会导致结果不同。

printf(―%d‖,65); 把65以整型输出,得到结果是65。

printf(―%c‖,65); 把65以字符形式输出,得到结果是小写字母a。

3) int的输出的格式说明:%d float输出的格式说明:%f char 输出的格式说明:%c 字符串输出的格式说明:%s double 输出的格式说明:%lf long int 输出的格式说明:%ld

第三节 数据输入

考 点:scanf函数的使用;scanf两个参数的使用方法;格式说明符号对应的意思; 重要程度:★★★★ 20

所指的元素a[1]赋值为5。如果想要通过指针引用数组其他元素,可以指针移动。如执行*(p+3)=6表示对a[4]赋值为6,执行*(p-1)=8表示对a[0]赋值为8。

一般地,如果p的初值为&a[0],则:

(1) p+i和a+i就是a[i]的地址,或者说它们指向数组a的第i个元素。 (2) *(p+i)或*(a+i)表示p+i或a+i所指向的数组元素,即a[i]。例如,*(p+4)和*(a+4)都表示a[4]。 (3) 指向数组的指针变量也可以用下标形式。例如,我们可以使用p[0]来表示p指针指向的内

存单元,使用p[1]表示p指针指向的内存单元的下一个内存单元。

注意:当指针p指向数组a的首地址后,我们使用p[0]来表示a[0],p[1]来表示a[1]??

a和p具有相同的引用方法。但是,a和p有着本质的区别:a是数组名而p是指针,a不能重新赋值而p可以随意的重新赋值。

例4:以下程序运行的输出结果是 (经典考题,多练习几次!!!)

main() {

int a[10]={1,2,3,4,5,6,7,8,9,10},*p=&a[3],*q=p+4; printf(\}

A) 9 2 8 B) 8 1 7 C) 8 2 9 D) 程序有错

分析:不同于前面,本题中指针p指向了数组元素a[3],q指向了p后四个单元的内存单元,即指向了a[7]。因此p[5]表示p指针指向内存单元的后面第5个内存单元即a[8],其值为9;同理p[-2]表示a[1],其值为2;*q的值为a[7]的值,即为8。本题答案选A。

第三节 二维数组

知识点:二维数组的定义; 二维数组的赋值;二维数组元素的引用;二维数组和一维数组之间的差别; 重要程度:★★★★

1、二维数组的定义

int a[2][3];

1、一定记住是前行后列,这里就是2行3列。 2、 二维数组的存放的规则是按行存放。 3、 注意行和列都是从0开始标记的。

4、 以上定义了一个2×3(或2行3列)的数组a,共有6个元素,每个元素都是整型,做题目

时候我们要想象下面这个图

第0列 第1列 第2列 第0行 a[0][0] a[0][1] a[0][2] 第1行 a[1][0] a[1][1] a[1][2]

图1 二维数组示意图

5、二维数组和一维数组类似,在内存中占有连续的内存空间。如图2所示。

a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2]

1001 1002 1003 1004 1005 1006

图2 二维数组的存放

图2是数组实际存放在计算机中的图。

2、二维数组的初始化(考试重点)

二维数组的初始化可以有以下几种方法。

(1) 分行给二维数组赋初值,每对花括号内的数据对应一行元素。

46

int a[2][3]={{1,2,3},{4,5,6}};

1 2 3 4 5 6 int a[2][3]={{1},{4,5}};

1 0 0 4 5 0 int a[2][3]={{1,2,3}};

1 2 3 0 0 0

综上可以看到,二维数组初始化括号是关键!!

--------------------------------------------------------------------------------------------------------- (2) 将所有元素的初值写在一对花括号内,按数组元素储存顺序对各元素赋初值。 int a[2][3]={1,2,3,4,5,6};

1 2 3 4 5 6 int a[2][3]={1,2,3,4};

1 2 3 4 0 0

----------------------------------------------------------------------------------------------------------

(3) 初始化时,可以不指定第一维大小,系统自动根据初值数目与列数确定第一维大小,但是第二维大小必须指定。(考试超级重点)

int a[][3]={{1,2,3},{4,5,6}};

1 2 3 4 5 6

int a[][3]={1,2,3,4,5};

1 2 3

4 5 0

注意:

(1)每一行所赋初值的个数不能多于该行的元素数,即列数;行数也不能多于数组应有的行数。如:int a[2][3]={{1,2,3},{2,3,5},{1,2}};和int a[2][3]={{1,2,3,4},{2,3,5}};都是错误的。

(2)在单纯的定义二维数组的时候,不能缺少任何常量表达式,如int a[][3];是错误的。在初始化的过程中,不能缺省常量表达式2(列数),如int a[2][]={1,2,3};是错误的。

例1:以下数组定义中错误的是

A) int x[][3]={0}; B) int x[2][2]={{1,2},{3,4},{5,6}}; C) int x[][3]={{1,2,3},{4,5,6}}; D) int x[2][3]={1,2,3,4,5,6};

分析:B选项在初始化时,赋值的行数多于定义的行数,定义2行,赋值时有3行,所以错误。答案选择B。

3、二维数组的引用

int a[2][3]; 记住可以看成是六个变量来处理就可以了。 a[0][0]引用数组的第0个元素, a[0][1]引用数组的第1个元素。

a[i][j]和a[i+k][j+k](i ,j,k都是整型变量)都是合法的引用形式。 注意:

(1)引用二维数组元素时,行下标值的下限为0,上限为定义时的行数减1;列下标值的下限也为0,上限为定义时的列数减1。

47

(2)二维数组同样是一个构造类型,是集合的概念。但是不能整体引用数组里面的所有的元素。简单地通过数组名a整体代表其中的6个int类型的变量是不行的。

例1: 有以下程序 main()

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

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

printf(\

}

程序执行后的输出结果是:

A) 7 5 3 B) 3 5 7 C) 3 6 9 D) 7 5 1

分析:程序首先定义并初始化了一个二维数组t。t数组在定义时只指定了列数为3,系统根据初值的个数9,自动计算出行数为3。程序接着使用for循环输出某些特定元素:i的值为0时,输出t[2][0]的值,即为第2行第0列的元素,值为3;i的值为1时,输出t[1][1]的值,即为第1行第1列的元素,值为5;i的值为2时,输出t[0][2]的值,即为第0行第2列的元素,值为7。答案选择B。

第四节 二维数组和指针

知识点:二维数组和指针之间的联系;二维数组和指针使用的方法;行指针; 重要程度:★★★★

1、二维数组的首地址和数组元素的地址

int a[3][2], *p,i; 数组a如图所示:

a[0] a[1] a[2]

a[0][0] a[1][0] a[2][0]

图1 数组a示意图

a[0][1] a[1][1] a[2][1]

二维数组a由三个元素组成,分别是a[0],a[1]和a[2]。

1、a[0],a[1]和a[2]都是一维数组名,它们是一个不可变的地址常量,其值代表每行的首地址。请大家记住:在二维数组中,a[i]表示第i行的第一个元素的地址,因此,a[0]代表了a[0][0]的地址,a[1]代表了a[1][0]的地址,a[2]代表了a[2][0]的地址。

指针的指针 指针 值

a→ a[0]→ a[0][0]

a[0]+1→ a[0][1]

a+1→ a[1]→ a[1][0]

a[1]+1→ a[1][1]

a+2→ a[2]→ a[2][0]

a[2]+1→ a[2][1]

图2

2、如果我们使用以下语句进行赋值:

int a[2][2]={1,2,3,4},*p;

p=a[0];

48

则是合法的。*p的数值等于a[0][0]的数值。

int a[2][2]={1,2,3,4},*p;

p=a[1];

则是合法的。*p的数值等于a[1][0]的数值。

*(p+1)的数值等于*(a[1]+1)的数值,也就是a[1][1]的数值。

在这里要把p和a[i]都看成是列指针。什么叫做列指针,也就是+1表示往后跳1列。 3、二维数组名也是一个地址常量

二维数组名同样也是一个地址常量,其值为二维数组中第一个元素的地址。同样,对于二维数组名a,也不可以进行a=a+i,a++之类的赋值运算。

a[2][2]这个二维数组的数组名为a,它表示第一个元素的地址,但是它是行指针。 所以a+1表示往下面跳一行!图2中可以看到。 常考的重点和难点:

1、行指针、列指针的概念。我们在C语言中一共学习了两个行指针。这里先介绍一个行指针。二维数组名是一个行指针。而a[i]表示的是列指针。因为a+1表示跳一行,a[i]+1表示跳一列。

int a[2][2]={1,2,3,4} int a[2][2]={1,2,3,4} int *p int *p

p=a就是非法的 p=a[1]就是合法的

因为a是行指针,p是列指针,单位不同 p和a[1]都是列指针,所以合法

2、指针数组与二维数组(考试重点)

(1)指针数组: int *p[3];

概念是重点:定义了一个具有三个元素的一维数组,并且每个元素都是一个指针变量。实际上是相当于定义了*p[0],*p[1],*p[2]三个指针变量。(地址是连续的,因为是数组)

1001 1002 1003

p[0] p[1] p[2]

(2)通过指针数组引用二维数组元素 若有以下程序:

int *p[3] a[3][2], i, j; for(i=0;i<3;i++) p[i]=a[i] 完成赋值以后是: a[0][0] p[0]指向了a[0] p[1]指向了a[1] p[2]指向了a[2] p[0]

p[1]

p[2]

图3

49

a[0][1] a[1][0] a[1][1] a[2][0] a[2][0]

它们的等价形式如下:

1)*(p[i]+j),与*(a[i]+j)对应

2)*(*(p+i)+j),与*(*(a+i)+j)对应 3)(*(p+i))[j],与 (*(a+i))[j]对应 4)p[i][j],与 a[i][j]对应

例1: 有以下程序(经典考题,多次练习) int a[3][2]={1,2,3,4,5,6},*p[3]; p[0]=a[1];

则*(p[0]+1)所代表的数组元素是

A) a[0][1] B) a[1][0] C) a[1][1] D) a[1][2]

分析:首先定义了一个二维数组a,一个指针数组p;然后将二维数组第1行的首地址a[1]赋给指针数组的第一个元素p[0],p[0]指向了a[1][0]元素的内存单元;p[0]+1代表的是p[0]中的内存地址移动一个数组元素后的地址,即a[1][1]的地址,因此,*(p[0]+1)代表的数组元素为a[1][1]。本题答案为C。

3、行指针(我们一共学习两个行指针)

(1)定义行指针: 类型名 (*指针数组名)[常量表达式];:

int (*p)[2];

在这里,我们定义了一个指针变量p,p只能存放含有两个整型元素的一维数组的首地址。值得注意的是,p并不是一个含有两个元素的一维数组。

对行指针(*p)[2]稍加说明:遵照C语言运算符的优先级,( )的优先级高于[ ]号,因此p首先与*结合,说明p是一个指针变量;在它后面的[2]则说明指针p的基类型为2个整型元素,所以p+1不是让指针p移动一个整型大小(2个字节),而是移动两个整型大小(4个字节)。

这里出现了C语言考试中,两个行指针,注意一个是数组名a,一个是int (*p)[2]定义的行指针。

如有定义:

int (*p)[2], a[3][2]; p=a;

如图4所示:

p+0→

p+1→

p+2→

a[0][0] a[1][0] a[2][0] a[0][1] a[1][1] a[2][1] 图4

在执行语句p=a后,p+i就等价于a[i],即二维数组第i行的首地址。

4、指针数组与行指针的区别(概念考题)

指针数组int *p[3]:表示一个数组,它含有三个元素p[0]、p[1]、p[2],且这三个元素只能存放整型元素的地址。

行指针int (*p)[2]:表示一个指针变量,它仅有一个存储空间,只能存放一个长度为2的一维数组的指针。

50

本文来源:https://www.bwwdw.com/article/kj82.html

Top