2023年全国计算机等级考试上机考试题库二级C语言
上QQ阅读APP看书,第一时间看更新

2.3 二级C语言程序设计操作题高频考点

2.3.1 C程序设计基础

【考点1】 C程序结构特点

(1)一个C源程序有且仅有一个main()函数,程序执行总是从main()函数开始。

(2)函数体必须用花括号标识。

(3)每个执行语句都必须以分号结尾,预处理命令、函数头和花括号之后不加分号。

(4)区分大小写。

题型剖析: 该知识点常在程序修改题中考查。如句末缺少分号、括号不匹配、运算符或关键字书写错误等。做题前先运行程序,可以很快找到语法错误。

【考点2】 常量与变量
1.整型数据

(1)整型常量:即整型常数,包括十进制整数,如123、-456、0;八进制整数(以0开头),如0123,即(123)8;十六进制整数(以0x开头),如0x123,即(123)16

(2)整型变量:可分为有符号基本整型([signed] int)、无符号基本整型(unsigned [int])、有符号短整型([signed] short [int])、无符号短整型(unsigned short [int])、有符号长整型([signed] long [int])、无符号长整型(unsigned long [int])。

2.实型数据

(1)实型常量:实型常量也称浮点型常量,有两种表示形式,即十进制小数形式(如.123、123.、123.0)和指数形式(如123.456e3,表示123.456×103)。

(2)实型变量:可分为单精度型(float)、双精度型(double)和长双精度型(long double)。

3.字符型数据

(1)字符常量:用单撇号标识的一个字符,如’a’、’+’、’\0’。

(2)字符变量:用来存储单个字符。

(3)字符串常量:用双撇号标识的字符序列,如”hello”、”123456”。字符串常量占用的内存字节数等于字符串中字符数加1,最后一个字节存放字符“\0”(ASCII值为0),即字符串结束标志。

4.变量的初始化

定义的变量在使用之前,需要赋给一个确定的初值来初始化它。初始化有两种方法:先定义后初始化(如int a; a=5;);在定义时直接初始化(如int a=5;)。当遇到循环时,循环变量需要先定义,然后才能在循环结构中应用。

题型剖析: 字符串和字符串结束标志(\0)是常考查的知识点,在程序填空题和程序修改题中都时有出现,并且程序设计题中经常要对字符串进行操作,因此在程序设计题中出现的概率也很高。

常见的考查形式有两种。

(1)判断是否到达字符串的结尾,即判断当前字符是否为字符串结束标志。

如要遍历字符串s,使用整型变量n存放下标,那么判断当前字符是否为字符串结束标志,可表示为while(s[n]!=’\0’){…}。

注:也可以使用指针实现,若指针p指向某一个字符,则可表示为while(*p!=’\0’){…}。

(2)对字符串操作结束后,添加字符串结束标志。

如下标n为字符串中最后一个字符的下标,要添加字符串结束标志,可表示为s[++n]=’\0’。

注:也可以用指针实现,若指针p指向最后一个字符,则可表示为*(++p)=’\0’。

【考点3】 运算符与表达式

(1)算术运算符:圆括号(())、求正(+)、求负(-)、乘(*)、除(/)、求余(%)、加(+)、减(-)。

(2)复合赋值运算符:+=、-=、*=、/=、%=。

(3)自增自减运算符:i++表示i参加运算后再增1,++i表示i增1后参加运算,i--和--i同理。

(4)逻辑运算符:逻辑与(&&)、逻辑或(‖)、逻辑非(!)。

优先级的大小是:!>&&>‖。

应用逻辑运算符可以组成复杂的逻辑关系表达式。判断一个量是否为真的依据是其值是否为非0,若为0,则为假,否则为真。

题型剖析: 这一部分知识常在程序设计题中考查。表达式的应用是否正确直接决定了一个算法是否有效。程序填空题和程序修改题中也经常要求根据上下文的算法来补全特定位置的一个表达式。

(1)应该强调的是部分运算符的优先级问题。若涉及逻辑关系表达式的语句,如果想表达两个或关系进行与运算,就应该严格地应用圆括号(exp1‖exp2)&&(exp3‖exp4),而exp1‖exp2&&exp3‖exp4表示的是3个表达式的多元或关系。

(2)整数除法的问题。一个整数除以另外一个整数,那么得到的结果是一个整数,这个整数是结果的整数部分,小数部分会被忽略掉,而不是按照四舍五入的规则。如3/2结果是1.5,但是如果返回一个整数的时候,则结果是1。这类情况通常在比较长的综合计算表达式中会被忽视,造成整体运算的错误,所以在特定的时候需要注意整数除法。相应的解决方法是将数据类型设置为浮点型。

(3)除法运算符(/)和求余运算符(%)的区别。典型题目是求一个多位整数各个位上的数值。

例如,求三位数456的个位、十位和百位数值。

个位数:456%10=6。

十位数:456/10%10=45%10=5。

百位数:456/100=4。

(4)自增自减运算符的特点及区别。

f(i++):表示i在参与f运算之后自增1。

f(++i):表示i在参与f运算之前自增1。

(5) 赋值运算符(=)与等于运算符(==)的区别,容易在语句中由于疏忽而混淆。

【考点4】 强制类型转换

利用强制类型转换运算符,可以将一个表达式转换成所需类型,其一般形式如下:

(类型名)(表达式);

例如,(char)(x+y)表示将表达式(x+y)的值强制转换为字符型。

题型剖析: 该知识点常在程序填空题和程序修改题中出现,典型题目是求两个整数相除的值。

例如,“int i;double f;”,需要将整数i的倒数赋值给f,这里直接使用f=1/i是错误的,因为两个整数相除的结果也是一个整数,f中存放的是1与i相除结果的整数部分。解决的方法有以下两种。

强制类型转换,f=(double)1/i;。

在赋值运算中进行类型转换,将运算符左侧的整数变为浮点数,f=1.0/i;。

2.3.2 C语言的基本结构

【考点1】 格式化输入/输出
1.printf()函数

printf()函数用于格式化输出数据,其语法格式如下:

printf(格式控制字符串,输出列表);

其中,格式控制字符串是用双撇号标识的部分,它包括两种信息:格式说明和原样输出的字符。输出列表是需要输出的一些数据,可以是常量、变量或表达式。

printf(“Hello World!!”);

原样输出字符串Hello World!!。

printf(“%5d”,123);

输出□□123,即123前面还有两个空格,5表示格式输出长度。

printf(“%2d”,123);

输出123,即如果格式长度不足,则按实际长度输出。

printf(“%c”,c);

输出字符型变量c,其中c一定被赋值过。

printf(“%s”,”string”);

输出字符串string。

printf(“%f”,a);

输出单精度变量a。

printf(“%2.2f”,1.2);

输出1.20,小数点后有两位有效数字。

2.scanf()函数

scanf()函数用于格式化输入数据,其语法格式如下:

scanf(格式控制字符串,地址列表);

其中,格式控制字符串与printf()函数相同,只是没有小数位数的设置。

值得注意的是,格式化输入字符的时候,空格也会被当作一个有效字符输入,所以连续输入多个字符的时候,中间一定不能添加空格,例如:

#include<stdio.h>

void main(){

 char a,b,c;

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

/*容易忽略的地方是输入时的空格和这里的取地址运算符*/

  }

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

可以看到,如果在格式控制字符串之间添加空格,那么连续输入字符的时候添加空格就是合法的。即地址列表中,非格式字符需要按原样输入。

3.putchar()函数

putchar()函数用于向终端输出一个字符,其语法格式如下:

putchar(字符型变量);

putchar(‘a’);

  /*将字符a输出在屏幕上*/

putchar(65);

  /*将ASCII值为65的字符输出在屏幕上*/

char a=’c’;putchar(a);

  /*将字符型变量a的值输出在屏幕上*/

4.getchar()函数

getchar()函数用于从终端获得一个字符,其语法格式如下:

getchar();

题型剖析: 输入/输出是基本知识点,其他的功能往往通过输入/输出来体现。主要考查以下3个方面。

(1)格式控制,根据输出列表判断格式控制的形式。

(2)输出列表,根据题目要求输出不同的结果。

(3)地址列表,根据题目要求输入不同的数据。

该知识点通常会在程序填空题和程序修改题中出现。程序填空题中会要求根据格式控制、输出列表或地址列表的部分内容补充另外部分的内容,从而符合语法要求。而程序修改题则是要求判断格式控制、输出列表、地址列表之间的对应关系是否正确,如小数点后有效位数的保留情况,小数点之前整数位数预留情况,输入/输出格式中空格的作用等。

另外,应用scanf()函数接收终端输入的时候,待赋值变量一定要加上取地址运算符(&),否则可能出现未初始化或者计算错误等问题。

【考点2】 条件与分支(if,switch)
1.if语句

if语句可以有两种形式:if(表达式){}或者if(表达式){} else{}。在嵌套结构中,else只与其前面最近的且未匹配的if匹配,或者在嵌套结构中直接应用{}将if-else匹配关系表示清楚。

例如:

int a=0;

if(1) a=3;

if(0) a=4;

else a=5;

得到的答案是a=5。而下面的代码:

int a = 0;

if(1){

  a=3;

  if(0) a=4;

}

else a = 5;

得到的答案是a=3。

三目运算符也可表示分支语句,即(表达式1)?表达式2∶表达式3;等价于if(表达式1)表达式2;else 表达式3;。同样,三目表达式也可以嵌套。

2.switch语句

switch语句是多分支选择语句,用来实现多分支选择结构。其语法格式如下:

  switch(表达式){

    case 常量表达式1: 表达式1;

    case 常量表达式2:表达式2;

    …

    default: 表达式n;

  }

如果想在执行某条case语句后直接跳出分支判断,则在case语句后面添加break语句即可。每个case的标号的值应该不同,否则会出现冲突。

题型剖析: if语句是一个很重要的考点,考查广泛分布在程序填空题、程序修改题、程序设计题中,尤以程序设计题中居多。考查方式主要有如下几种。

(1)if语句的条件表达式。一般根据题目要求填入判断的条件,如if(   )。语句的表达式有很多种,可以是简单的算术表达式、逻辑表达式,也可以是带有指针、数组等变量的表达式。

(2)if语句体。根据题目要求填入判断后应执行的语句,如if(a == 0){   }。

(3)if的嵌套形式。注意if语句的配对,在程序填空题中可以考查根据嵌套形式写出结果,也可以在程序修改题中判断所在的嵌套形式中某个条件是否正确,是否满足算法的判断要求。

而switch语句的考查主要涉及程序填空题中语句的书写形式。一般根据题目要求填入表达式,如switch(  ),或者选择条件及执行语句,如case  :   ;,或者考查break语句。

【考点3】 循环
1.常用的循环语句

while(表达式) {循环体}  

/*当表达式为真时,执行循环体*/

do{循环体}while(表达式); /*先执行循环体,然后判断表达式是否为真,若为真,则继续执行*/

for(表达式1;表达式2;表达式3){循环体} /*应用表达式1初始化,满足条件则执行表达式2,变化量为表达式3*/

循环是可以嵌套的,其实质是对应语句块的嵌套,也就是花括号的配对。

考试中,循环的考查方式往往是给出一段程序,然后让考生填写循环表达式。循环表达式包括循环变量的初始化、循环变量的取值范围以及循环的结束条件等。

2.跳出循环的语句

continue语句:表示跳过本次循环,而继续执行下一次循环。

break语句:表示跳出整个循环体,直接执行该循环的后继语句。

题型剖析:

1.while语句

(1)while语句中条件表达式的考查。一般根据题目要求填入循环条件,如while(   )。与if语句的条件表达式一样,while语句的条件表达式的表达也有很多种,可以是简单的算术表达式、逻辑表达式,也可以是带有指针、数组等变量的表达式。

(2)while循环体的考查,根据题目要求填入循环体语句,如while(a>5&&a<10){   }。

2.do-while语句

(1)循环条件,即while语句后表达式的考查,与while语句考查形式基本相同。

(2)循环体,根据题目要求填写,基本与while循环体语句的考查形式相同。但是要注意do-while循环是先执行循环体,再进行循环判断,而while循环是先进行循环判断,再执行循环体。

(3)与迭代算法一起考查,如求级数或者求阶乘。

3.for语句

(1)考查循环起始条件、循环条件、循环变量,如for(   ;   ;   )。

(2)for循环体的考查,根据题目要求写出循环体语句,如for(i=0;i<100;i++){   ;   }。

4.循环嵌套

(1)循环嵌套的形式:6种基本嵌套形式。

(2)循环的嵌套、执行的过程,内层循环的执行以及循环语句的结束条件。

2.3.3 函数

【考点1】 函数的定义、调用及参数传递
1.函数的定义

函数定义的语法格式如下。

类型标识符 函数名([形参列表]){

      声明部分

      语句部分

      }

2.函数的参数和返回值

函数的参数分为形式参数和实际参数。在定义函数时,函数名后面圆括号中的变量称为形式参数(简称形参);在主调函数中,函数名后面圆括号中的参数(可以是一个表达式)称为实际参数(简称实参)。形参与实参应该类型相同且个数相等。

函数的返回值是通过函数调用,使主调函数得到的一个确定的值。返回值的类型应与函数类型标识符指定的类型相同。

3.函数的调用

函数调用的语法格式如下。

函数名(实参列表)

函数调用的方式有如下几种。

(1)把函数调用作为一条语句,此时该函数不要求有返回值,只需要执行一定的操作。

(2)函数出现在一个表达式中,因为要参与表达式的计算,所以要求函数有对应数据类型的返回值。

(3)函数参数,把函数调用作为一个函数的实参。

4.函数的参数传递

形参与实参的值传递:

函数名(实参列表)

形参与实参的地址传递:

函数名(& 参数,…)

它们的区别是:在值传递时,参数在函数执行过程中所产生的变化不被记录,即形参中值的变化不会影响实参的值;而在地址传递时,形参的值变化,对应实参的值可能也会改变。

题型剖析:

1.函数的定义

(1)函数类型的考查。要求根据主调函数的调用形式,写出被调用函数的类型标识符,如:  fun(int a)。其类型可以是基本类型,也可以是用户自定义类型。要确定函数的类型,只需要确定函数应返回值的类型即可,如果函数不返回值,则为void。

(2)参数类型的考查,要求根据实参类型填写被调用函数的形参类型,如int fun(int a,  c)。这里要记住,形参与实参一一对应。

2.函数的参数和返回值

(1)函数的形参和实参,该考点考查形式比较灵活,除了定义时两者的个数和类型要一一对应外,还要根据具体程序确定变量的名称。

(2)函数返回值,根据函数调用后要返回主调函数的值填写返回值变量名,如return  

【考点2】 迭代算法和递归算法

迭代算法:使用计算机解决问题的一种基本方法,它利用计算机运算速度快、适合做重复性操作的特点,让计算机对一组指令(或一定的步骤)进行重复执行,在每次执行这组指令(或这些步骤)时,都从变量的原值推出一个新值。迭代算法常用来求方程的近似根。

递归算法:在调用一个函数的过程中直接或间接调用其函数本身的方法,称为函数的递归调用。常用的递归调用有:求n!、遍历树等。

题型剖析: 求n!、Fibonacci数列、递归输出回文数等是递归算法的典型应用,在程序填空题、程序修改题、程序设计题中均有出现,具体考查形式不固定,多是对算法中关键步骤的考查。

例如,求10!。

#include<stdio.h>

long fun(int n)

{ if(n>1) return(n*fun(n-1));

 return 1;

}

main()

{printf(“10!=%ld\n”,fun(10));}

2.3.4 指针

【考点1】 指针变量的定义

如果有一个变量专门用来存放地址,那么这个变量是指针变量,即存放变量地址的变量是指针变量。

指针的定义格式如下:

  基类型 * 指针变量名

例如:

 float *a; /*a是指向float型变量的指针变量*/

 char *b; /*b是指向char型变量的指针变量*/

变量的前面加上符号“&”(如&a),表示变量的地址,所以可以将&a赋值给一个指针。例如:

#include<stdio.h>

void main(){

  int a = 0;

  int *i = &a;

}

注意:int *i定义了一个指向int型变量的指针,该指针的变量名为i;定义指针时要在*前面声明指针的类型;对指针赋值时,指针的类型应与其指向的值的类型一致;对*p=a来说,p和&a表示变量a的地址,*p和a表示变量a的值;p++表示指针p移动1个存储单元,(*p)++表示指针指向的数据加1。

题型剖析: 指针是C语言的重要工具,也是考查的重点,其考查形式如下。

(1)指针变量的声明,特别要注意声明时的“*”。

(2)指针变量的赋值,指针变量存储的是地址,因此在考试时要注意变量的值与地址的区别。

【考点2】 函数之间的地址传递

在2.3.3小节已经讲过,传递值不修改原参数的值,但是如果参数是一个指针,就可以修改指针指向的内存地址中所存放的数据。例如:

#include<stdio.h>

void change(int *);

void main(){

  int a = 0;

  int *p = &a;

  change(p);

  printf(“%d\n”,a);

}

void change(int *p){

  (*p)++;

}

输出结果为1。

题型剖析: 函数之间的地址传递在程序填空题和程序修改题中均有出现,考查形式如下。

(1)根据函数的实参,确定指针形参的类型。例如:

int *p3,*p4;

swap(p3,p4);

void swap(int *p1,*p2)

        /*实参与形参的类型要一致*/

(2)根据函数的形参,确定实参的变量名。

2.3.5 数组

【考点1】 一维数组
1.定义方法

类型说明符 数组名 [常量表达式];

其中,类型说明符是指数组元素的数据类型;常量表达式是一个整型值,指定数组元素的个数,即数组的长度,数组的长度必须用“[]”标识;常量表达式可以是常量或符号常量,不能包含变量。

例如:

int array[5];

  /*定义了一个数组元素类型为整型、长度为5的数组*/

注意:数组的元素下标从0开始,即该数组元素分别为a[0]、a[1]、a[2]、a[3]、a[4],这也是数组元素的访问方法。

2.一维数组的初始化

一般在定义的时候为数组赋值。

例如:

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

    /*分别赋值0、1、2、3、4*/

int array[5]={0,1,2};

    /*前面3个元素赋值0、1、2,后面两个元素默认为0*/

int array[5]={0};

    /*给所有5个元素均赋值为0*/

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

    /*定义并初始化了一个长度为5的整型数组*/

3.一维数组元素的输入/输出

如果需要逐个输入或输出数组元素,可以使用循环语句实现,以int array[5]为例:

#include<stdio.h>

void main(){

  int array[5],i;

  for(i = 0 ; i < 5 ; i ++){

    /*输入*/

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

  }

  for(i = 0 ; i < 5 ; i ++){

    /*输出*/

    printf(“%d”,array[i]);

  }

}

输入:0 1 2 3 4

输出:0 1 2 3 4

注意:数组名a本身就是一个指向数组内存区域首地址的指针,其类型与数组元素类型相同。也就是说,数组元素a[i]可以写成*(a+i)。

题型剖析: 一维数组的考查比较频繁,其考查形式如下。

(1)数组元素的引用,可以使用数组下标和指针两种形式实现,其中常见的方法是使用数组下标。

如引用整型数组a的第3个元素,使用数组下标的方式为a[2],使用指针的方式为*(a+2)。

(2)数组的遍历,常使用循环语句实现,此时要注意数组的上界和下界。

如遍历数组a,则该数组的下界为0,上界为4,用程序实现为:

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

...

【考点2】 排序算法
1.冒泡排序算法

以升序为例,冒泡排序算法的基本思想是:将元素两两比较,把较大的数向后移动,经过一轮比较,使最大的数移动到数组的最后一位;经过第2轮比较,使第2大的数移动到数组的倒数第2位。以此类推,最终得到一个升序序列。排序过程如下。

(1) 比较第1个数和第2个数,若为逆序即a[0]>a[1],则交换;然后比较第2个数和第3个数;以此类推,直到第n-1个数和第n个数比较完成,完成第一轮冒泡排序。结果使最大的数放到了最后的位置。

(2) 下面需要排序前n-1个元素,按照步骤(1),将这n-1个元素中最大的元素放到前面n-1个元素的最后位置,也就是整体的倒数第2个位置。

(3) 重复上述步骤,经过n-1轮排序后,整体冒泡排序算法结束。

程序如下:

#include<stdio.h>

void main(){

  int a[10],i,j,t;

  printf(“Input 10 numbers:\n”);

  for(i = 0 ; i < 10 ; i++){

   /*由终端接收10个整数,一般情况下是无序的*/

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

  }

  printf(“\n”);

  for ( i= 0 ; i < 9 ; i++){

   /*代表的是执行冒泡排序的次数,统一从0开始*/

   for( j = 0 ; j < 9-i ; j++){

   /*从0开始两两比较,不用比较已经确定位置的数*/

      if(a[j]>a[j+1]){

         t = a[j];

         a[j] = a[j+1];

         a[j+1] = t;

      }

     }

   }

   for(i = 0 ; i < 10 ; i++){

     printf(“%d”,a[i]);

   }

}

2.选择排序算法

仍然以升序排序为例,选择排序算法的基本思想是:当进行第1轮排序时,从所有的元素中找到最小的元素,与第1个元素交换。当进行第2轮排序时,从剩下的n-1个元素中找到最小的元素,与第2个元素交换。以此类推,完成排序。 排序过程如下。

(1) 首先通过n-1次比较,从n个数中找到最小的数,将它与第1个数交换,使最小的数被放到第1个元素的位置上。

(2) 再通过n-2次比较,从剩余的n-1个数中找出次小的数,将它与第2个数交换,使次小的数被放到第2个元素的位置上。

(3) 重复上述过程,经过n-1轮排序后,得到一个升序序列。

程序如下:

#include<stdio.h>

void main(){

  int a[10],i,j,k,x;

  printf(“Input 10 numbers:\n”);

     /*从终端接收10个整数*/

  for(i = 0 ; i < 10 ; i++){

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

  }

  printf(“\n”);

  for(i=0;i<9;i++){/*开始进行选择排序算法*/

    k = i;

    for( j = i+1 ; j < 10 ; j ++){

       if(a[j] < a[k]){k=j;}

    }

    if(i!=k)

    { x = a[i];

     a[i] = a[k];

     a[k] = x;

    }

 }

 printf(“the sorted numbers:\n”);

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

   {printf(“%d”,a[i]);}

}

题型剖析: 将这两个算法的完整代码写在这里,是为了强调这两个算法的基础性和重要性。这两种排序方法在操作题中经常考查,要学会灵活运用。着重理解两重循环中内层循环和外层循环在算法中各自起到的作用,以及它们的联系和区别。

【考点3】 二维数组
1.定义方法

类型说明符 数组名[常量表达式1][常量表达式2];

例如:

int array[3][4];  /*定义了一个3×4 = 12个元素的数组,元素类型为整型*/

注意:二维数组的定义不能写成int array[3,4];二维数组中元素是按行排列的,即存放完第1行的元素之后接着存放第2行的元素,数组名array代表二维数组首地址,a[0]代表数组第0行的首地址,a[i]代表数组第i行的首地址;允许定义多维数组。

2.二维数组的初始化

例如:

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

/*为3行数组元素分别赋值*/

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

/*为12个元素赋值*/

int a[3][4] = {{0},{4},{8}}

/*与一维数组一样,没有赋值的元素默认为0*/

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

/*为全部元素赋值的时候可以省去第1个常量*/

3.二维数组的输入/输出

如果需逐个输入/输出数组元素,则需要使用一个两层循环实现,以array[3][3]为例:

#include<stdio.h>

void main(){

  int array[3][3],i,j;

  for(i=0;i<3;i++) /*输入*/

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

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

   for(i=0;i<3;i++)/*输出*/

    {for(j=0;j<3;j++)

      printf(“%d “,array[i][j]);

      printf(“\n”);

   }

  }

输入:1 2 3 4 5 6 7 8 9

输出:1 2 3

   4 5 6

   7 8 9

题型剖析:

二维数组的考查形式如下。

(1)二维数组元素的引用多使用数组下标实现,常用于矩阵的运算。

例如,用二维数组a[3][3]存放三阶矩阵A,则该矩阵的对角线元素为a[0][0]、a[1][1]、a[2][2]。

(2)二维数组的遍历,常使用嵌套循环语句实现,此时要注意内外两层循环分别表示的意义。

例如,遍历二维数组a[3][3],用程序实现如下:

for(i=0;i<3;i++)  /*i表示行坐标*/

for(j=0;j<3;j++)  /*j表示列坐标*/

2.3.6 字符串

【考点1】 字符串的表示

由于没有字符串变量,在C语言中,用一维字符数组存储字符串,其定义、初始化均与一般的数组相仿。

如果在声明字符数组的同时初始化数组,则可以不规定数组的长度,系统在存储字符串常量时,会在串尾自动加上一个字符串结束标志“\0”。字符串结束标志在字符数组中也要占用一个元素的存储空间,因此在声明字符数组的长度时,要预留出该字符的位置。

当然,还可以采用循环语句进行输入/输出,程序如下:

#include<stdio.h>

void main(){

  char a[3];

  scanf(“%s”,a);

     /*或者用gets(a)进行输入操作*/

  printf(“%s\n”,a);

      /*或者用puts(a)进行输出操作*/

}

输入:ab

输出:ab

题型剖析:

字符串及其数组元素的引用在操作题中的考查形式如下。

(1)字符与字符常量的表示形式和输出形式。字符常量用ˈ ˈ表示,输入/输出时使用格式字符“%c”;字符串与字符串常量的表示形式和输出形式分别为” “和”%s”。

(2)字符串结束标志“\0”。根据“\0”来判断字符串是否结束。例如:

for(i =0;str[i]!=’\0’; i++)

【考点2】 指向字符串的指针

定义格式:

  char * 指针变量

初始化方法:

  char *p = “abc”;

使用方法:

  while(*p){}

注意:只有字符数组才可以应用数组名直接将整个数组中的元素输出,其他类型的数组不具备这种特征。

题型剖析:

(1)程序填空题中,常常要求根据函数的调用,写出参数中字符串指针的正确形式,如a、b是两个数组,对于函数void fun(char *a, char *b),其调用形式为fun(a,b)。

(2)使用指针对字符串进行操作。如字符串s=”hello”,指针p指向字符串s,要求将字符串中的字母l转换为字符a,程序如下:

while(p)

{ if(*p==’l’)

  *p=’a’;

  p++;

}

【考点3】 字符串处理函数
1.字符串复制函数——strcpy()

例如:

char a[] =”abc”;

char b[] =”b”;

strcpy(a,b);/*调用结束后,a = b*/

C语言中不可以应用赋值运算符(=)直接将一个字符串的值赋给另外一个字符串,但可以用库函数中的strcpy()函数来实现。

2.字符串连接函数——strcat()

例如:

char a[] =”abc”;

char b[] =”b”;

strcat(a,b);/*调用结束后,a =abcb*/

3.字符串长度函数(从起始指针到“\0”处为止的字符总数)——strlen()

例如:

char a[100] =”abc”;

int b = strlen(a);/*调用后b = 3*/

4.字符串比较函数——strcmp()

例如:

char a[] =”abc”;

char b[] =”b”;

int c = strcmp(a,b);/*调用结束后,c = -1 */

即按字典顺序排列,靠后的字符串比较大。若a<b为真,返回-1;若a>b为真,返回1;若a=b为真,返回0。

题型剖析: 这里主要是牢记各个函数的功能和调用方法。利用字符串处理函数可以方便地对字符串进行处理。在上机操作过程中,熟练使用字符串处理函数(除非题目要求不能使用),可以大大减少工作量。

2.3.7 结构体、共用体和用户定义类型

【考点1】 结构体变量的定义与表示方法
1.结构体的声明

struct  结构体名

{

 类型标识符  成员名;

 类型表示符  成员名;

 …

}

2.结构体变量的声明

(1)可以直接跟在结构体声明之后。例如:

struct{

}array[10];

(2)先声明结构体类型,再单独定义。例如:

struct student{

};

struct student array[10];

(3)先声明一个结构体类型名,再用新类型名来定义变量。例如:

typedef struct{

}ST;

ST array[10];

3.结构体变量的引用

结构体变量名.成员名

可以将一个结构体的变量直接赋给另外一个结构体变量,结构体嵌套时逐级引用。

题型剖析:主要考点是结构体的定义和结构体变量的几种声明形式。在程序填空题中考查,如根据上下文补全结构体中的成员等。

【考点2】 链表
1.指针指向结构体的引用方法

例如:

struct student *p = a;

若变量b为结构体student的一个成员,则下面3种引用成员的方式是一致的。

a.b;

(*p).b;

p->b;

2.链表的组成

(1)头指针,存放第1个数据节点的地址。

(2)节点,包括数据域和指针域。

链表的结构可以表示为图2.35所示的结构。

图2.35 链表的结构

3.链表的操作

链表是一种重要的数据结构,可以动态地进行数据的存储分配。对链表的操作包括链表的建立、链表节点的插入和删除等。

(1)插入节点:如果在节点a、b之间插入节点c,则需要将指针指向a,然后将“c->next = a->next;a->next = c;”,便得到“a->c->b;”。

(2)删除节点:如在a、c、b这3个连续节点中删除c,则将指针指向a后,再将“a->next = c->next;,free(c);”。

题型剖析:

1.单个链表元素

相当于同时考查结构体和指针。

(1)结构体指针的定义,要注意先赋值再使用。

(2)结构体内的成员用指针的引用同直接用结构体变量名引用形式上的区别。结构体变量和结构体变量指针引用结构体成员赋值,尤其要注意字符数组的赋值。

2.链表

多考查于程序填空题和程序修改题,主要是对链表节点的插入、删除操作,往往还连带着前后元素的链接关系,所以需要特别注意指针指向的调整以及元素的先后顺序。

【考点3】 typedef说明一种新类型

typedef 类型名 标识符

例如:

typedef int INT

之后便可以使用INT来定义一个int型的变量,如INT a=0与int a=0等价。

题型剖析:该知识一般在程序填空题中考查,只要理解了别名和原定义体实际上是同一个类型即可。

【考点4】 宏定义
1.不带参数的宏定义

#define 宏名 替换文本

例如:

#define R 13

#define PI 3.14

2.带参数的宏定义

#define 宏名(参数列表) 字符串

例如:

#define MV(x,y) ((x)*(y))

题型剖析: 不带参数的宏替换比较简单,只需要将宏名替换成相应的常量即可。进行带参数的宏替换时要注意,程序不会将预定义字符串的运算结果进行替换,而是执行简单的字符替换,如#define MV(x,y) x*y与#define MV(x,y) (x)*(y)是不同的,当程序引用MV(a+3,5)时,该表达式被分别替换为MV(a+3*5)和MV((a+3)*5)。

2.3.8 文件

【考点1】 文件的打开与关闭
1.文件的定义

文件是存储在外部介质上数据的集合,是操作系统进行数据管理的基本单位。文件分为文本文件和二进制文件。C语言把文件看作一个字符(字节)的序列,即由一个个字符(字节)的数据顺序组成。一个输入/输出流就是一个字节流或二进制流。

2.文件的打开与关闭

(1)文件类型指针: FILE *fp;。

(2)打开文件:fp = fopen(文件名,文件使用方式);。

(3)关闭文件:fclose(fp);。

注意:文件打开函数和关闭函数的形式,其参数和返回值为文件指针。文件打开时,自动生成一个文件结构体;关闭后,结构体自动释放。

文件的打开方式如表2.24所示。

表2.24 文件的打开方式

题型剖析: 这部分是概念,考查考生对概念记忆的准确性,通常会以程序填空题和程序修改题的形式出现,如补全文件名称、文件使用方式、操作完成后文件是否被关闭等。

【考点2】 文件的读写

fputc(ch,fp);

功能:将字符(ch的值)输出到fp所指的文件中。

fgetc(fp);

功能:从fp所指向的文件中返回一个字符。

fgets(char *str, int n, FILE *fp);

功能:从指定的文件读入一个字符串。

fputs(const str, FILE *fp);

功能:向指定的文件输出一个字符串。

fprintf(文件指针,格式字符串,输出列表);

功能:将字符串输出到文件。

fscanf(文件指针,格式字符串,输入列表);

功能:从文件读入一个字符串。

fread(buffer,size,count,fp);

fwrite(buffer,size,count,fp);

功能:数据块读/写函数,用于向文件读/写一组数据,其中,buffer是一个指针,表示起始地址;size是要读/写的字节数;count表示要读/写多少个size字节的数据项。

题型剖析: 这部分内容在考试中以概念考查为主,因此要熟练掌握这些函数的功能、调用格式以及参数的含义。

【考点3】 文件检测函数

int feof(FILE *stream);

功能:检测文件是否结束,如果结束,返回1,否则返回0。

ferror(*fp);

功能:返回0表示文件未出错,否则表示出错。

fseek(文件类型指针,位移量,起始点);

起始点有:文件开头(SEEK_SET0)、文件当前位置(SEEK_CUR1)、文件结尾(SEEK_END2)。

题型剖析: 重点考查feof()函数的调用格式和参数的含义,例如:

  int a = 2; fseek(fp,0,a);