全国计算机等级考试二级C语言考点(完整版) 联系客服

发布时间 : 星期一 文章全国计算机等级考试二级C语言考点(完整版)更新完毕开始阅读0e6f883a7d1cfad6195f312b3169a4517623e502

以上定义语句中,p和t都是合法用户标识符,在每个变量前的星号(*)是一个类型说明符,用来标识该变量是指针变量。

变量前的星号不可省略,若省略了星号说明符,就变成了把p和t定义为整型变量(int是类型名)。在这里,说明了p和t是两个指向整型(int 类型)变量的指针,也就是说变量p和t中只能存放int类型变量的地址,这时我们称int是指针变量p和t的“基类型“。基类型用来指定该指针变量可以指向的变量的类型。 例如: int *p1;

表示p1是一个指针变量,它的值是某个整型变量的地址。或者说p1指向一个整型变量。至于p1究竟指向哪一个整型变量,应由向p1赋予的地址来决定。 再如:

int *p2; /*p2是指向整型变量的指针变量*/ float *p3; /*p3是指向浮点变量的指针变量*/ char *p4; /*p4是指向字符变量的指针变量*/

应该注意的是,一个指针变量只能指向同类型的变量,如P3 只能指向浮点变量,不能时而指向一个浮点变量,时而又指向一个字符变量。

2.2 指针变量的引用

指针变量中只能存放地址(指针),将一个整型变量(或任何其他非地址类型的数据)赋给一个指针变量是不允许的。 如:

int *p; /*定义一个指向整型变量的指针*/ p=300 ; /*300为整数*/ 是不合法的赋值。

与指针相关的两个运算符是“&“(取地址运算)和“*“(指针运算符)。 1) &:取地址运算符。

2) *:指针运算符(或称“间接访问” 运算符)。 C语言中提供了地址运算符&来表示变量的地址。 其一般形式为: &变量名; 如:

int i,*p; P=&i;

2.3 指针变量作为函数参数

前面的章节中介绍过,函数参数可以是整型、实型、字符型等数据,指针类型数据同样也可以作为函数参数来进行传递。它的作用是将一个变量的地址传送到另一个函数中,参与该函数的运算。 如果想通过函数调用从而得到n个要改变的值,可以采用如下方法: (1)在主调函数中设n个变量,分别用n个指针变量指向它们。

(2)然后将各个指针变量作为实参,即将这n个变量的地址传给所调用的函数的形参。 (3)通过形参指针变量的改变,从而改变这n个变量的值。 (4)主调函数中就可以使用这些改变了值的变量。

形参指针变量的值的改变不能使实参指针变量的值发生改变。

考点3. 数组与指针

一个数组包含若干个元素(变量),在定义时被分配了一段连续的内存单元。因此,可以用一个指针变量来指向数组的首地址,通过该首地址就可以依次找到其他数组元素,同样指针变量也可以指向数组中的某一个元素。所谓数组的指针是指数组的起始地址,数组元素的指针是各个数组元素的地址。

3.1 指向数组元素的指针

C语言规定数组名代表数组的首地址,也就是数组中第0号元素的地址。有如下语句: int c[10]={0};

int *p; p=c;

则语句p=c;与语句p=&c[0];是等价的。 数组c不代表整个数组。上述“p=c;“的作用是把数组c的首地址赋值给指针变量p,而不是把数组c中各元素的值赋给p。

定义指向数组元素的指针变量的方法,与定义指向变量的指针变量相同。例如: int c[10],*p; p=&c[5];

指针变量p指向了数组c中下标为5的那个元素,即p用来保存c[5]的地址。

3.2 通过指针引用数组元素

按C语言的规定:如果指针变量p已指向数组中的一个元素,则p+1指向同一数组中的下一个元素(而不是将p的值简单加1),这里的加1是指增加一个长度单位(与数组基类型所占存储单元相同)。例如,数组元素是浮点型,每个元素占4个字节,则p+1意味着使p的值(是一个地址)加4个字节,以使它指向下一个元素。

将++和--运算符用于指针变量是十分有效的,可以使用指针变量自动向前或向后移动,指向下一个或上一个数组元素。不过要小心利用,否则会导致内存错误。

3.3 用数组名作为函数参数

数组名可以用做函数的形参和实参。当数组名作为参数被传递时,若形参数组中各元素发生了变化,则原实参数组各元素的值也随之变化。因为数组名作为实参时,在调用函数时是把数组的首地址传送给形参,因此实参数组与形参数组共占一段内存单元。而如果用数组元素作为实参的情况就与用变量作为实参时一样,是“值传递“方式,单向传递,即使形参数组元素值发生了变化,原实参的数组元素值也不会受影响。

3.4 指向多维数组的指针和指针变量

有如下定义: int c[3][4],*p;

c是该二维数组的数组名,它代表了整个数组的首地址,也就是第0行的首地址,c+1代表第1行的首地址,即c+1是[c1]的地址。c[0]、c[1]、c[2]既然是一维数组名,而C语言又规定了数组名代表数组的首地址,因此c[0]代表第0行的一维数组中第0列元素的地址,即&c[0][0]。同样地,c[1]的值是&c[1][0]。

第0行第1列元素的地址怎么表示呢?可以用c[0]+1来表示。此时“c[0]+1“中的1代表1个列元素的字节数,即两个字节。如c[0]的值是2020,则c[0]+1的值是2022。

根据上面的介绍,c[i]和*(c+i)等价,因此,c[0]+1和*(c+0)+1的值都是&c[0][1],都是用来表示第0行第1列的元素的地址。c[i]从形式上看是数组c中第i个元素。如果c是二维数组名,则c[i]代表一维数组名,c[i]本身并不占实际的内存单元,它也不存放数组中各个元素的值,它只是一个地址。c、c+i、c[i]、*(c+i)+j、c[i]+j都是地址,*(c[i]+j)、*(*(c+i)+j)是元素的值。

考点4. 字符串与指针

4.1 字符串的表示形式

(1)用字符数组存放一个字符串,然后输出该字符串。 例如:

char str[]=“I am a student??“; printf(“%s\\n“,str);

(2)用字符指针指向一个字符串。

可以不定义数组,而定义一个字符指针,用字符指针指向字符串中的字符。 例如:

char *str=“I am a student??“;

/*定义str为指针变量,并指向字符串的首地址*/ printf(“%s\\n“,str);

在这里没有使用字符数组,而是在程序中定义了一个字符指针变量str,并使该指针变量指向一个字符串的首地址。C语言对字符串常量是按字符数组进行处理的,在内存中开辟了一个字符数组来存放字符串常量。程序在定义字符指针变量str时,把字符串的首地址赋给str。str只能指向一个字符变量或其他字符类型数据,不能同时指向多个字符数

据,更不能理解为把字符串中的全部字符存放到str中(指针变量只能存放地址)。在输出时,利用字符型指针str的移动来控制输出,直到遇到字符串结束标志'\\0'为止。

通过字符数组名或字符指针变量可以一次性输出的只有字符数组(即字符串),而对一个数值型的数组,是不能企图用数组名输出它的全部元素的,只能借助于循环逐个输出元素。

显然,用%s可以控制对一个字符串进行整体的输入输出。对字符串中字符的存取,与操作其他数组的方法相同,既可以用下标方法,又可以用指针方法。

4.2 字符串指针作函数参数

将一个字符串从一个函数传递到另一个函数,可以用地址传递的办法,即用字符数组名作为参数或用指向字符串的指针变量作为参数,进行传递。

字符串指针变量作为函数实参,形参可以是字符指针变量,同样也可以是字符数组名。当字符数组名作为函数实参时,形参可以是字符数组名,同样也可以是字符指针变量。

4.3 字符指针变量和字符数组的区别

虽然字符数组和字符指针变量都能实现对字符的存储和运算,但它们两者之间有如下区别:

(1)字符数组是由若干个元素组成的,每个元素中存放一个字符,而字符指针变量中存放的是地址(字符串的首地址),绝不是将字符串的内容存放到字符指针变量中。

(2)赋值方式。只能对字符数组各个元素赋值,不能用以下方法对字符数组赋值: char str[20]; str=“I am happy“;

而对字符指针变量,可以采用以下方法赋值: char *s;

s=“I am happy??“;

(3)字符数组可以在定义时对其整体赋初值(即初始化),但在赋值语句中不能完成整体赋值。下面的做法是不允许的:

char s[30];

s[]=“I am so happy“;

而字符指针变量既可以在定义时赋初值,也可以出现在赋值语句中,相对来说要比字符数组使用起来灵活一点。 (4)如果定义了一个字符数组,在编译时,系统会为它分配一段连续的内存单元,它的地址是确定的。而当定义了一个字符指针变量后,就要即时给该指针变量分配内存单元,该指针变量中可以存放一个地址值,也就是说,该指针变量可以指向一个字符型数据,但如果未对它赋以一个地址值,则它并未具体指向一个确定的字符数据。如: char s[10]; scanf(“%s“,s);

是可以的。但用下面的方法是极其危险的: char *s;

scanf(“%s“,s);

因为编译时虽然给指针变量s分配了内存单元,s的地址(即&s)已经指定了,但s的值并未指定。在s单元中是一个不可预料的值,在执行scanf()函数时要求将一个字符串输入到s所指向的一段内存单元中,即以s的值(地址)开始的一段内存单元。而s的值如今却是不可预料的,它可能指向内存中空白的存储区(未用的用户存储区),这样固然可以,但它也有可能指向内存中已存放指令或数据的有用内存段。这就会破坏程序,甚至破坏系统,造成严重的后果。应当这样:

char *a,s[10]; a=s;

scanf(“%s“,a);

先使a有确定值,也就是使a指向一个数组的首地址,然后输入一个字符串,把它存放在以该地址开始的若干单元中。 (5)在程序中指针变量的值可以改变。例如: char *s=“china”; s=s+2;

指针变量s的值可以改变,当要输出字符串时,从s当前所指向的单元开始输出各个字符(本题中从字符i开始输出),直到遇到'\\0'为止。而数组名虽然代表了地址,但它的值是一个固定的值,是不能改变的。下面是错的: char str[]={“china”};

str=str+2;

考点5. 指向函数的指针

用函数指针变量调用函数

我们已经知道,可以用指针变量指向整型变量、字符型变量、字符串、数组,同样指针变量也可以指向一个函数。编译时,一个函数将被分配给一个入口地址,这个入口地址就称为该函数的指针。因此,可以通过使用一个指向函数的指针变量调用此函数。 说明:

(1)指向函数的指针变量的一般定义形式为: 数据类型 (*指针变量名)( );

如int(*s)();,“数据类型”指该函数返回值的类型。

(2)(*s)()表示定义了一个指向函数的指针变量,但目前它不是固定指向哪一个函数,而只是表示定义了这样一个类型的变量,它的作用是专门用来存放函数的入口地址。在程序中实现把某一个函数的地址赋给它,它就指向那一个函数,这样它的值也就确定了。在一个程序中,一个指针变量以先后指向不同的函数,也就是说指向函数的指针变量和普通指针变量一样,可以多次使用。

(3)在给函数指针变量赋值时,只需给出函数名而不必给出参数。如: s=fun; /* fun为已有定义的有参函数*/

因为是将函数入口地址赋给s,不涉及到参数的问题,不能写成: s=fun(a,b);

(4)用函数指针变量调用函数时,只需将(*s)代替函数名即可(s为已经定义过的指向函数的指针变量名),在(*s)之后的括号中根据需要写上实参。

(5)对指向函数的指针变量,有些运算,如++s、--s、s+3等都是没有意义的。

考点6. 返回指针的函数

返回指针值的函数

一个函数的返回值可以是一个整型值、字符型值、实型值等,同样地,函数的返回值也可以是指针类型的数据,即地址。这种返回指针值的函数,一般定义形式为: 类型名 *函数名(参数表); 例如:

int *fun(int a,int b);

fun是函数名,调用它可以得到一个指向整型数据的指针(地址)。a、b是两个整形变量,是函数fun()的形参。注意:*fun在两侧没有括弧,在fun的两侧分别为*运算符和()运算符。而()优先级高于*,因此fun先与()结合,显然这是函数形式。这个函数前面有一个*,表示此函数是指针型函数。

考点7. 指针数组和指向指针的指针

7.1 指针数组的概念

若在一个数组中,其元素均为指针类型数据,这样的数组称为指针数组,也就是说,指针数组中的每一个元素都相当于一个指针变量。一维指针数组的定义形式为: 类型名 *数组名[数组长度]; 例如:

int *a[10];

由于[]运算符的优先级比*运算符的优先级高,因此a先与[10]结合,形成a[10]形式,然后与前面的“*“结合,“*“表示此数组是指针类型的,每个数组元素都可指向一个整型变量。

指针数组的一个重要用途是可以用来指向若干个字符串。例如,在对库房物品进行管理时,想把物品名称放在一个数组中,然后对这些物品进行统计和查询,我们可以分别定义一些字符串来存放各物品名称,然后利用指针数组中的元素分别指向各字符串。如果还想对字符串排序,不必改动字符串的位置,只需改动指针数组中各元素的指向(即