C语言中数组与指针

2024-08-13

C语言中数组与指针(共9篇)

C语言中数组与指针 篇1

0 引言

C语言是计算机程序设计语言中专业性较强的语言之一,以其功能丰富,表达能力强、使用方便灵活、目标代码运行效率高、可移植性好而受到青睐。数组和指针是C语言教学中的重点也是难点,多维数组与指针的关系更是让学生迷惑不解。如何使学生轻松理解并掌握数组与指针的对应关系成为教学中的难题。下面通过对一维﹑二维数组与指针的关系详细的探讨,总结C语言中多维数组与多级指针的对应关系。

1 一维数组与指针

数组是一组类型完全相同的有序数据的集合。用一个统一的数组名和下标来唯一确定数组中的元素。通过对数组一章的学习,定义一个一维数组并不难。例如:

即表示定义了一个整型的一维数组。数组名为a,数组长度为5。

数组一旦定义,其数组名代表的不是变量,而是一个描述该数组起始地址的常量,也就是该数组第0个元素的地址&a[0]。在C语言中,地址又称为指针,如果常量或变量描述的是另一个变量的地址,我们称该常量或变量指向另一个变量。所以a作为第0个元素的指针,可称a指向a[0]。通过数组名加地址偏移量的方式可以描述数组中其它元素的指针。a+1指向a[1],a+2指向a[2],以此类推。引用数组元素时可以采用下标法,也可以采用指针法。例如:

这种方式不能用于数组名,因为数组名是常量,不能使用自加自减运算。

2 二维数组与指针

二维数组是由行和列所组成的平面结构的数组。例如:

上例中,若把每一行看成一个大的元素,那么可以把x看成是一个特殊的一维数组,它有3个大的元素:x[0],x[1],x[2],每个大的元素又是一个包含4个具体的元素。如下表。

相当于定义了三个一维数组x[0],x[1],x[2]。x[0],x[1],x[2]看成了一维数组的数组名。

二维数组的数组名代表的是其特殊元素的指针,x指向的是其特殊元素x[0]。那么x+1指向x[1],x+2指向x[2],以此类推。要描述具体元素,则可以通过前述一维数组的方法,一维数组的数组名加下标描述的是其元素。那么第0行的元素即可为x[0][0],x[0][1]等。x[i]相当于一维数组的数组名。也可以采用指针法,因为x指向x[0],则x+i指向x[i],所以*(x+i)即表示x[i]。x[i]作为一维数组的数组名指向其内的第0个元素x[i][0],那么x[i]+j即指向第i行的第j个元素x[i][j],*(x[i]+j)表示的为x[i][j],将x[i]换成*(x+i),所以*(*(x+i)+j)表示的也是x[i][j]。从以上的分析可以看到,通过二维数组的数组名对元素的引用并非通过一次间接应用完成的,而是通过了两级指向。这说明二维数组的数组名代表的不是具体元素的地址,而是特殊元素的地址,即行地址。所以二维数组的数组名也升级成了二级指针常量。而每一个特殊元素则相当于一维数组的数组名来使用。

引用二维数组的元素可以用下列语句描述:

在第一个输出语句就会出现差错。因为p1=a将该数组的首地址给p1。p1指向*p1。*p1是一级指针。所以在该数组首地址取1个指针类型(4字节)的值,在32位环境下是第0列元素a[0][0]的值**p1指向*p1,数据类型是该指针的基本类型int,所以在第0行第0列元素指向的内存位置处取一个整型值,访问了不可以访问的内存区域。所以会出现‘xxxxxx指令引用的xxxxxx内存该内存不能为read’的错误。这就说明指针变量p1虽然也是二级指针变量,但并非与二级指针常量a的使用方式等价。p1只是一般的二级指针,不能正确描述二维数组中的行列值。指针变量p2的定义是C语言中行指针的定义方式。p2先后*相结合说明p2是指针变量,再与后面的[5]相结合,说明它指向的是具有5个元素的行。二维数组的每行都包含5个元素所以p2可以指向a中的行。a作为二维数组的数组名指向的是第0行。p2=a;使p2与a具有相同的指向。在引用数值元素时,p2就可以代替a来使用了。那么数组元素a[i][j]也可描述成*((*p2+i)+j)。在此还需说明的是虽然在定义p2时只用了一个*符号,但却将p2定义成了特殊的二级指针——行指针。从上面的分析可以看到,二维数组的数组名和行指针变量指向的并不是整个二维数组,而是二维数组中的行。

3 三维及多维数组与指针

二维数组可以看成由一维数组所组成,把一维数组当成了特殊元素。二维数组同样可以作为一个整体。

类型和长度完全相同的若干一维数组可以组成二维数组。那么同样可以把类型和长度相同的二维数组作为一个特殊的元素放于一个数组中,这就构成了三维数组。因为它的每一个特殊元素都是平面结构,那么三维数组则是由若干平面组成的立体结构。例如:

int m[3][5][10];

则定义了一个三维数组,其中包含了3个5行10列的二维数组。要想指向每一个平面,则可以定义指向平面的指针,int(*p3)[5][10]。由此可以推及n维数组与指针,定义一个n维数组的格式为:

类型标识符数组名[N1][N2][……][Nn];(其中N1,N2,……,Nn均为常量表达式)可以把n维数组看成由N1个n-1维数组组成的一维数组,要指向其中的n-1维数组,则应定义指向n-1维数组的指针,方式为:

类型标识符(*变量名)[N2][N3][……][Nn];

这里的指针变量和n维数组的数组名都是n级指针,都可以指向的是n-1维数组。

4 结束语

数组与指针在C语言教学中很容易引起学生的误解,希望能通过本文的探讨对读者理解数组与指针的关系带来方便。不当之处敬请同行不吝赐正。

参考文献

[1]谭浩强.C程序设计[M].北京:清华大学出版社,1997.

[2]谭浩强,张基温,唐永炎.C语言程序设计教程(第二版)[M].北京:高等教育出版社,1998.

[3]谭浩强.C程序设计题解与上机指导(第二版)[M].北京:清华大学出版社,2002.

[4]杨立影,高爱华,李晖.C语言程序设计教学方法的探索与实践[J].中国科技信息,2010,(15).

[5]彭召意,朱艳辉,周玉.C++面向对象程序设计课程的实践教学研究[J].计算机教育,2010,(05).

[6]夏承遗,李文杰,孙世温.问题驱动的“C++程序设计”教学方法研究[J].计算机教育,2010,(01).

[7]马晓亭.“C++高级编程”教学方法探索与实践[J].计算机教育,2010,(04).

[8]张明川,孙士保.面向工程实训的“C++程序设计”教学改革研究与实践[J].计算机教育,2010,(03).

[9]张波.C++程序设计案例遴选[J].计算机教育,2010,(18).

C语言中数组与指针 篇2

现在我定义了一个数组:int cc[10];

围绕这个数组有好几种指针:cc, cc+1, &cc[0], &cc, &cc+1等等。你知道它们都是什么含义吗?试试运行以下带代码:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

#include

int main

{

int cc[10];

printf(“%x ”, cc);

printf(“%x ”, cc+1);

printf(“%x ”, &cc[0]);

printf(“%x ”, &cc);

printf(“%x ”, &cc+1);

getchar();

return 0;

}

cc,这是学数组时第一个接触的“指针”,最为熟悉,它是数组的首个元素。

cc+1,这是指向数字第二个位置的指针。

&cc[0],这个其实就是cc,指向数组的首个元素。

&cc,这是什么玩意儿?指向指针的指针?

&cc+1,如果上面的意思是指向指针的指针,那这个岂不是指向野地址了?

假设运行环境是32位机,并且数组首地址为0x28ff00,那么:

cc的结果为0x28ff00,这点毫无疑问。

cc+1的地址是0x28ff04而不是0x28ff01,因为一个int占用了4个字节的空间。cc+1其实是当成cc+1*sizeof(int)来看待。

&cc[0]的结果是0x28ff00,cc[0]表示的是数组的首个元素,那么&cc[0]自然就是首个元素的地址了。&cc[0] == cc。

&cc,这个就难说了,指针cc的值是0x28ff00,&cc表示这个指针本身的地址,我们怎么可能会知道这个地址?输出是个随机地址吗?随机数的话这个输出完全没有意义啊。如果不是随机地址的话,难不成还是0x28ff00?这样的话a不就等于&a了?明显不对吧,

。。

对于基本类型的指针,如int *tt; 那么*tt是其值,&tt是指针的地址,&tt != tt

但是上述的cc是个数组,实际上,&cc被编译成了&cc[0],但是其含义不同,&cc指向的是整个数组的开头。&cc与cc的指向可以用下图来形象表示:

上图可以看出,&cc其实代表的是int(*)[10],那么&cc+1就可以理解为cc + sizeof(cc)/4,之所以除以4是因为int型指针++其实是移动了4个字节。

又或者说%cc == cc + sizeof(cc)/4 == cc + 10,所以&cc+1的值为0x28ff28。

可见我们平常使用的数组名,并不能单纯的当成指针看待。数组名的本质是代表数组对象的变量名,是一个左值,是一个不能被改变的左值。但是由于在程序中不保存数组的大小,所以通过数组名只能访问数组的左值,不能访问数组的右值。由于这个原因,数组名在作为右值使用的时候被赋予另外一个新的意义——指向数组第一个元素的指针,这就是array-to-pointer转换规则。根据标准规定,只有当数组名作为sizeof、&运算符的操作数的时候,它是一个左值,其类型为数组类型。除此之外的所有情况,数组名都是一个右值,被编译器自动转换为指针类型,这种情况下我们就说数组名是一个指针,并且是一个指针常量。

接下来是另外一些有趣的东西,我们结合sizeof与数组输出各类值。以下程序的输出结果是什么?建议思考后再运行程序来验证答案。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

#include

int main()

{

int cc[10];

printf(“%d ”, sizeof(cc[0]));

printf(“%d ”, sizeof(cc));

printf(“%d ”, sizeof(&cc));

printf(“%d ”, sizeof(int(*)[10]));

getchar();

return 0;

}

sizeof(cc[0]),一个int的大小,输出4,没问题。

sizeof(cc),注意不要和上面搞混,这不是数组首地址的指针,cc在这里是左值,其为数组类型,所以结果为40。

sizeof(&cc),这个的答案应该是多少呢?注意了,cc在这里还是左值,其为数组类型,但&cc不同于cc,不管数组怎么复杂它始终是个指针,32位机上指针大小始终是4个字节,所以结果为4。

论C语言中指针和数组关系 篇3

1 预备概念和结论

本文把指向具体元素的指针称为点指针;把指向包含n个具体元素一维数组的指针称为行指针。

int*p表示声明p是指向具体元素的指针, 为点的指针。

int (*pointer) [4]表示声明pointer是一个含4个具体元素一维数组的指针, 为行指针。

在C语言中, 地址可以认为是一个指针, 见下例:

运行结果如下:

&a是a的地址, aPtr是指向a变量的指针, 两者输出结果一致;&a+1和aPtr+1输出结果一致;*&a和*aPtr输出结果一致。

从结果看, 如果把&a视为一个指针, 一个指向变量a的指针, 那么很好解释&a和aPtr等价, &a+1和aPtr+1等价, *&a和a P t r等价, 因此他们输出结果分别一致。

地址就是指针, 该结论是理解数组和指针关系的基础。

2 一维数组

假设有:

(1) 数组名称就是地址和指针。

一维数组名称a r r a y代表数组中首元素 (array[0]) 的地址, p=array是把首元素地址赋给p。根据“地址就是指针”, array实际上就是一个指针, 一个指向首元素的指针, p=array也可以认为是把一个指针赋给另一个指针, 使得p跟array一样指向首元素。

p=array和p=&array[0]等价。&array[0]表示array[0]的地址, p=&array[0]是把首元素array[0]的地址赋给指针p, 使得p指向首元素。根据“地址就是指针”, &array[0]实际就是一个指针, 一个指向首元素的指针, 因此, p=&array[0]也可以认为是把一个指针赋给另一个指针, 使得p跟&array[0]一样指向首元素。因此两者是等价的。

(2) 一维数组名称是点指针。

一维数组名称a r r a y表示一个指针常量, 该指针指向首元素 (第0号元素, 为具体的元素) , 因此一维数组名称a r r a y是点指针。因为array为点指针, 那么array+1指向的是数组中第1号元素。

(3) *array跟array[0]等价, * (array+1) 和array[1]等价。

由于a r r a y为指向首元素的点指针, 那么*array表示该指针指向的元素 (首元素) , 而在一维数组中, array[0]表示首元素, 因此*array跟array[0]等价。

由于a r r a y表示指向首元素的点指针, 那么array+1指向下一个点 (即下一个具体元素) 。因此, * (array+1) 和array[1]等价, 其他依次类推。

3 二维数组

假设定义一个二维数组如下:

int a[3][4]={{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 16}}。

(1) 把二维数组a视为一维数组, 其元素为a[0], a[1]和a[2], 其中a[0], a[1]和a[2]分别是包含4个具体元素的一维数组 (见图1) 。这里面包含两个信息。

(1) 把a作为一维数组来理解, 那么名称a就是一个指针, 指针a指向的是a[0], a+1指向的是a[1], a+2指向的是a[2]。由于a[0], a[1]和a[2]并不是具体的元素, 而是包含4个具体元素的一维数组。因此a和a+1, a+2分别是行指针。

(2) a[0], a[1]和a[2]并不是具体的元素, 而是包含4个具体元素的一维数组。因此把a[0], a[1]和a[2]作为一维数组名称来使用。

一维数组名称就是一个指针, 其指向该数组的首元素。本文把指向具体元素的指针称为点的指针, 因此a[0], a[1], a[2]就是指向该数组中首元素的指针, 为点的指针。

(2) a[0]+1指向的是第0行第1列元素, a[1]+2指向的是第1行第2列元素。

由于a[0]表示指向第0行数组的首元素 (第0列元素) , 为点的指针, a[0]+1表示把该指针移动1个位置, 即指向该数组中的第1列元素, 即指向的是第0行第1列元素;同样, 由于a[1]表示指向第1行数组的首元素 (第0列元素) , 为点的指针, a[1]+2表示把该指针移动2个位置, 即指向该数组中的第2列元素, 即指向的是第1行第2列元素;

点指针为具体指向某个元素的指针, * (a[0]+2) 表示第0行第2列元素。

(3) a[1]+2和* (a+1) +2等价。

把a看成是一个含有3个元素的一维数组。采用下标法访问元素, 即a[0], a[1]和a[2];采用指针法访问元素, 如*a, * (a+1) 和* (a+2) 等。因此a[1]和* (a+1) 等价, 所以a[1]+2和* (a+1) +2等价。

a[1]+2和* (a+1) +2都表示指向第1行第2列元素的指针, 因此* (a[1]+2) 和* (* (a+1) +2) 均表示该指针指向的元素。

(4) *a和a输出值一样, 类型不一样。

测试如下的程序, 观察*a和a的输出值:

测试表明*a和a输出的值一样。a代表0行首地址, *a其代表第0行第0列的地址, 因此两者的输出值是一样的, 但是两者的类型不一样。

a是行指针, 其代表0行首地址。a[0]和*a是点的指针 (a[0]和*a等价) , 其代表第0行第0列的地址。因此a和*a输出的值一样, 但是前者是行指针, 后者是点指针。

进一步测试如下程序, 该例的目的是输入二维数组a的行和列的下标, 把相应位置的元素输出:

发现以上程序通不过编译, 错误在于指针类型不匹配。p是点指针, 而a是二维数组名, 表示一个行指针常量, 显然把个行指针常量赋给一个点指针, 类型上不一致。因此, 修改如下:

发现以上程序通过编译, 功能满足要求。int (*p) [4]表示p为一个指针变量, 它指向包含4个整型元素的一维数组, 为行指针, 因此p和a类型一致。

如果采用点指针来完成上述程序的功能, 可以把程序修改为:

*a其代表第0行第0列的地址, 根据地址就是指针, *a就是第0行第0列的元素的指针, 为点指针。p=*a实现把p指向第0行第0列的元素, 亦为点指针。本例子是采用点移动的方法, 找到相应行和列的元素。

同样, 函数调用就是把实参赋给形参。如果指针作为函数参数, 必须分清形参和实参的类型并判别两者类型是否一致。数组名的本质就是指针, 因此数组名作函数参数, 实质就是指针作为函数参数, 同样遵守以上的规则。

4 结语

综上所述, 在数组和指针关系中, 有如下三个主要结论。

(1) 地址就是指针。

(2) 数组名称是既表示地址, 又表示指针。一维数组名称是点指针, 二维数组名称是行指针。

(3) 假设有array[n][m], 二维数组array认为是包含array[0], array[1], array[2]…array[n-1]等n个元素的一维数组, 而这n个元素分别是包含了m个具体元素的一维数组, array[0], array[1], array[2]…array[n-1]等可以视为一维数组名称。

参考文献

[1] (美) 阿霍, 赵建华[译].编译原理 (第2版) [M].机械工业出版社, 2009, 1.

[2]张素琴.编译原理 (第2版) [M].清华大学出版社, 2005, 2.

[3]严蔚敏, 吴伟民.数据结构 (C语言版) [M].清华大学出版社, 1997, 4.

C语言中数组与指针 篇4

如果在程序中定义一个变量,在对程序进行编译,系统会自动给这个变量分配内存单元,根据不同的类型,分配不同长度的空间,如int占用4个字节,char占用1个字节,内存单元中每个字节都有编号,这就是地址。由于可通过地址能够找到所需的变量单元,可以说地址指向该变量单元。打个比方,一个房间的门口挂了一个房间号301,这个301就是房间的地址,将该地址形象化为指针。对于一个内存单元来说,单元的地址(编号)即为指针,其中存放的数据才是该单元的内容。

严格地说,一个指针是一个地址,是一个常量,

而一个指针变量却可以被赋予不同的指针值,是变量。但常把指针变量简称为指针。为了避免混淆,约定:“指针”是指地址,是常量,“指针变量”是指取值为地址的变量。定义指针的目的是为了通过指针去访问内存单元。

例如:

int a=12;

int *p=&a;

二、指针的指针(二级指针)

简单来说,二级指针变量就是一级指针变量的地址。

例如:

int a=12;

int *p=&a;

int **=&p;

C语言的指针运用和数组的关系 篇5

指针是C语言使用比较广泛的数据类型之一, 是C语言的一个重要特色。指针可以有效地表示复杂的数据结构、方便引用数据和字符串、动态分配内存、直接访问物理地址等等。正确而灵活地使用指针, 能够使程序精练, 高效运行。指针即是重点又是难点, 能否正确掌握和运用指针是是否掌握C语言的重要体现。有些学生在学习指针这部分时, 甚至学完C语言后仍然不明白指针是怎么回事, 为什么要用指针, 怎样用指针, 在什么情况下用指针, 复杂指针类型之间的区别和联系, 搞的不是很清楚。本文以指针和数组的关系为线索, 加以阐述。

2. 数组和指针的相关概念

数组是C语言的构造类型之一, 是同类数据的有序集合。数组元素可以是基本数据类型或是构造类型。C语言中规定, 数组只能静态定义, 定义时必须指定所占空间的大小。数组名表示数组在内存中的首地址。

指针这里是指指针变量。指针变量的值就是某个内存单元的地址。指针的实质就是通过对内存地址的操作来实现对数据的操作。

指针有指向简单变量的指针, 指向字符串的指针, 指向数组的指针即数组指针, 指向指针的指针等。本文将重点放到指针和数组的关系上。把上面的概念搞清楚, 在学习指向函数、结构体、文件等的指针就容易理解和掌握。

3. 数组与指针的关系

3.1 简单指针变量与数组的关系

例题1:输出一维整形数组a[4]的全部元素

方法一:用数组名访问数组元素

用下标法或者通过数组名计算数组元素地址, 找到数组元素。

for (i=0;i<4;i++) printf ("%3d", a[i]) ;或者for (i=0;i<4;i++) printf ("%3d", * (a+i) ) ;

方法二:用指针变量来访问数组元素

针对例题, 先定义一个指向整形变量的指针p并被赋初值p=a.。然后for (i=0;i<4;i++) printf ("%3d", *p++) ;

例题2:输出二维整形数组a[4][6]的全部元素

方法一:用数组名访问数组元素

方法二:用指针变量来访问数组元素

定义一个指向整形变量的指针p, 并被赋初值p=&a[0][0], 使用循环语句for (i=0;i<24;i++) printf ("%3d", *p++) ;来输出全部元素。

二维以上数组均可使用这两种方法。

分析:在对数组元素顺序访问时, 使用指针变量直接访问数组元素, 由于不用象使用数组名那样每次都要计算元素地址, 而是有规律地改变地址值, 大大提高了程序的执行效率。但在对数组元素进行随机访问时, 两者访问速度一样, 由于下标法更易理解, 不容易出错, 使用下标法更好。

3.2 数组指针、指针数组和指向指针的指针与二维数组的关系

例题1:对5个字符串进行排序

方法一:使用数组指针

在主函数中:

定义二维字符数组和指向由N个元素组成的一维数组的指针:char str[M][N];char (*p) [N];经输入语句输入各个字符串:for (i=0;i<M;i++) scanf ("%s", str[i]) ;再将指针p指向二维数组的首地址:p=str;执行调用语句:sort (p) ;最后输出结果:

在主函数中:

定义由M个指针类型元素组成的数组p:char*p[M];将各字符串的首地址赋给指针数组p的各元素:for (i=0;i<M;i++) p[i]=str[i];执行调用语句sort (p) ;通过循环语句for (i=0;i<M;i++) print ("%sn", p[i]) ;输出排序好的字符串。

方法三:使用指向指针的指针

在主函数中:

定义:char**p, *pstr[M], str[M][N];将第i个字符串的首地址赋给指针数组pstr的第i个元素:for (i=0;i<M;i++) pstr[i]=str[i];指针p指向指针数组pstr:p=pstr;执行调用语句:sort (p) ;通过循环语句:for (i=0;i<M;i++) printf ("%sn", pstr[i]) ;输出排序好的字符串。

分析:数组指针是指向含有多个元素组成的一维数组的指针变量, 即指向数组的指针, 而不是指向某个数组元素。因此可以理解为是一个行指针。使用数组指针时, 调用排序函数sort, 传递的参数是原字符数组的首地址。对原字符数组进行排序, 最后直接输出已经排序好的字符数组;

指针数组是其元素类型均为指针类型数据的数组。使用指针数组时, 由于数组的元素类型是指针型, 是各字符串的首地址, 调用sort函数后, 传递的参数是指针数组的首地址, sort函数是对指针数组排序, 原字符数组并无直接参与排序。通过输出已经排序好的指针数组来达到对原字符串的排序;

指向指针的指针是指指向指针数据的指针变量。使用指向指针的指针变量时, 又使用了一个指向指针数组的指针变量, 函数调用后传的参数也是指针数组的首地址, 但是sort函数是将存储各字符串地址的指针数组进行了排序, 通过使用指向指针的指针变量来对指针数组排序的。而不是象使用指针数组那样直接对指针数组排序。因此也必须通过输出指针数组的内容来达到排序的目的, 原字符串无变化。

3.3 数组指针、指针数组和指向指针的指针与数组的区别与联系

(1) 当数组的各维大小确定时, 多用静态数组, 但浪费严重, 适合对空间需求不大的场合;当数组的低维确定, 高维需要动态生成的场合, 例如a[x][16], 使用数组指针。体现指针里的一个进步, 指向整个数组而不是某个元素;当数组高维确定, 低维许动态生成时, 例如a[20][x], 使用指针数组。好处在于, 指针的内容可以根据需要动态生成, 避免浪费空间, 并且由于指针呈数组形式排列, 方便索引。当处理对象是多个字符串时, 使用指针数组可以节省空间, 提高程序的执行效率;当数组的高低维均需动态生成时, 使用指向指针的指针。

(2) 二维数组名、数组指针和指向指针的指针是同类型的, 同一级指针。但是二维数组名是指针常量, 而数组指针和指向指针的指针是指针变量。

(3) 数组在生命期内, 地址和容量保持不变, 内容可以变;使用数组初始空间大, 但索引方便。指针初始空间小, 动态分配空间, 使用灵活方便。常用指针来操作动态内存, 但如果使用不谨慎, 容易出错。

谈到指针的应用, 与数组有关的还有利用动态分配函数malloc () 或calloc () 为指针变量分配内存, 建立动态数组。

4. 结束语

指针是C语言的重要特色, 但指针及相关概念不容易理解, 使用也易出错。对于初学者来说, 只有勤于实践, 多上机调试程序, 才能真正掌握, 才能充分利用指针灵活多变的特点, 编写出有特色、高效和精练的程序。

参考文献

[1].谭浩强.C语言程序设计 (第三版) 北京:清华大学出版社, 2005、7

C语言中的函数与指针 篇6

随着计算机技术的飞速发展及应用领域的扩大, 熟练掌握一门语言已变的尤为关键。C语言这门课程在计算机的基础教学中一直占有比较重要的地位, 然而要想突破C语言的学习, 对函数和指针的掌握是非常重要的, 本文将具体针对函数和指针的关系做详尽的介绍。

一、函数的有关概念

为了使程序的编写更加清晰、直观且易于修改, C语言中引用了函数。所谓函数, 就是一个程序模块, 该模块用来完成一个特定的程序功能。引用一个函数时, 需要包括对函数的定义、声明, 继而调用。在掌握函数相关概念的同时, 有以下几点需要注意:

(1) 调用函数和被调用函数

由上例可以看出, 函数A在执行的过程中包括了对函数B的调用, 则函数A称为调用函数 (调用函数B) , 而函数B被函数A调用, 称为被调用函数。

(2) 实参和形参

调用函数中定义的变量是实参, 被调用函数中定义的变量是形参。如上例, 函数A中的变量a是实参, 函数B中的变量b是形参。

(3) 实参变量和形参变量之间的独立性

实参变量和形参变量之间只存在值的传递过程, 实参变量的存储空间在调用函数中分配, 而形参变量的存储空间在被调用函数中分配, 被调用函数执行完毕后, 其所分配的存储空间被释放, 即形参变量的存储空间被释放, 它不会返回值给实参变量, 也不会参与调用函数的继续执行。例如 (实现两个数的交换) :

显然, 函数main是调用函数 (调用函数swap) , 函数swap是被调用函数。main函数中的a, b由main函数分配存储空间, 而swap函数中的a, b由swap函数分配存储空间。main函数执行到swap函数时, 调用swap函数, swap函数为其变量分配存储空间, 然后实现了swap函数中变量a, b的值交换, 执行完毕后即释放其分配变量的存储空间。继而, main函数继续执行, 但其变量a, b没有做任何改变, 即main函数不能实现a, b的交换。由上例可以看出, 若单纯的使用变量, 则被调用函数无法改变调用函数中的变量值, 即swap函数无法实现main函数中变量a, b的交换。

二、指针的有关概念

指针是C语言中功能最强大, 使用最广泛的一种数据类型, 主要用于描述存储单元的地址。通过使用指针, 可以在函数中进行传址调用。

(1) 指针变量的定义

定义指针变量的一般形式:类型标识符*变量名;其中, 变量名前的符号“*”表示将要定义的变量, 类型说明符表示该指针变量所指向数据的类型。例如:int*p1;char*p2;float*p3;

(2) 指针变量的引用

&为取地址运算符, 其一般形式为:&变量名, 例如:

int x=3, *p;p=&x;指针变量p指向变量x。

在使用x的值时, 可以直接使用x, 也可以用*p来代替使用x。此外, 指针变量一定是和它所对应的变量相互引用, 即指针变量在使用时一定要有明确的指向, 必须赋予具体的值, 否则将可能导致错误。

三、指针与函数的关系

在函数的编写过程中, 若单纯的只用变量参数, 则无法实现被调用函数改变调用函数中变量值的目的。而为了实现这一目的, 就需要函数和指针之间的结合使用。

(1) 引用指针, 可以实现调用函数和被调用函数中的指针变量共同指向调用函数中的存储单元, 从而实现被调用函数改变调用函数中变量值的目的。例如:

由上例可以看出, 在调用函数 (main函数) 中定义了变量a和指针变量p1, 被调用函数 (change函数) 中定义了指针变量p2。程序首先从main函数开始执行, 分配变量a和指针变量p1的存储单元, 此时指针变量p1指向变量a (p1=&a) 。当程序执行到change函数时, 程序跳转到change函数执行其函数体, change函数为其指针变量p2分配存储单元, 同时p2也得到了p1传过来的值 (变量a的地址) , 此时p2也指向了调用函数中的变量a, 即实现了p1和p2共同指向了调用函数中的存储单元 (变量a的存储单元) , change函数执行其函数体 (*p2=3) , 即使a的值变为3。change函数执行完毕后, 释放其变量的存储空间, 转而继续执行main函数, 此时a的值已经发生改变 (由2变为3) , 实现了被调用函数改变调用函数中变量值的目的。

(2) 调用函数和被调用函数中实参和形参之间的关系图

被调用函数执行完毕后, 释放它所分配的存储单元, 而调用函数分配的存储单元仍继续使用。此外, 只有当调用函数中传指针值 (即实参是指针值) , 而被调用函数中引用变量 (即形参收到指针值后, 在函数体内引用变量值) , 才能达到改变的目的。

例如, 实现变量a和b的交换, 程序如下:

例1虽然传的是指针值, 但在函数体的执行过程中引用的仍然是指针值 (引用x和y) , 所以不能实现a和b的交换;例2程序传指针值后, 引用变量 (*x和*y, 即a和b) , 所以能实现a和b的交换。

四、结束语

在以后的编程过程中, 若遇到想通过被调用函数改变调用函数中变量值的目的, 则可以把该变量的地址值传给被调用函数, 从而达到改变的目的。鉴于文章篇幅及个人能力有限, 本文肯定还存在许多不足之处, 仅供大家学习和参考。

参考文献

[1]谭浩强.C程序设计[M].二版.清华大学出版社, 2004.

[2]杜友福.C语言程序设计[M].二版.科学出版社, 2007.

C语言中指针的教、学与高效编程 篇7

1 指针

1.1 指针的特点

1.1.1 概念多,易混淆

指针这部分内容最突出的特点就是概念多,并且容易混淆。如变量的指针和指针变量,指针数组和数组指针,指针函数和函数指针等。

变量的指针是指基本变量的地址,而指针变量是专门存放地址的变量;指针数组是指数组中的每个元素均为指针变量的数组,而数组指针是指向数组的指针,教学内容中重点讲述了一维数组和二维数组中隐含或存在的指针以及用法;指针函数是指函数的返回值为指针,而函数指针是指函数的首地址。这些概念字面差别不大,含义却不同。

1.1.2 由指针引出的数据类型多

引入指针概念后,可以定义出许多新的数据类型。如:整型指针变量、字符型指针变量、实型指针变量;整型指针数组、字符型指针数组、实型指针数组;指向一维整型数组的数组指针、指向一维字符型数组的数组指针、指向二维整型数组的数组指针、指向二维字符型数组的数组指针等;除此之外,还有指针函数类型和函数指针类型等。众多的数据类型使用相互之间有差别,使用时应特别小心。

1.1.3 指针语法要求严格

指针内容的语法细节要求严格,如:(*p)++和*(p++),p为指针变量,仅括号位置不同,表示的含义就不同。前者表示p所指向变量的值加1,后者是“先使用后自加”,即先对p的原值进行*运算,然后使p的值自加。

指针的这些特点决定了指针的应用非常灵活。熟练的编程人员,利用它可以编写出颇具特色、高质量的程序,实现其它高级语言难以实现的功能。

1.2 指针的教与学

1.2.1 指针的课堂教学

目前,大多数高校采用先进的多媒体设备辅助教学,增强了课堂教学的新颖性和生动性,但是教学方式仍局限于传统方式———从语法角度按部就班地罗列语法知识,并且多媒体教学过多追求情节和画面,分散了学生的注意力,使学生对指针的理解过于肤浅,作题时不知所措。通过笔者多年的C语言教学实践证明:对于抽象复杂的指针概念,采用板书的教学方式,教学效果明显高于多媒体。一方面:教师在黑板上书写过程中,学生有充分时间理解和思考;另一方面:教师可以根据学生的反应,灵活调整授课内容或者改变教学方法。

针对指针概念多、数据类型多,易混淆的特点,在教学过程中,如果善于发现规律,对所学知识进行“罗列和总结”,那么将增强知识结构的系统性和完善性,同时将零碎的知识点串联起来,提高学生的记忆能力和辨别能力,进一步改善教学效果。以数组与指针为例,学习了指针之后,运用指针法同样可以表示数组元素,且该方法使目标程序占内存少,运行速度更快。

1.2.2 指针的学习

学习C语言时,学生对C语言基础知识掌握的熟练程度,直接影响指针的教学质量。以学习“指针变量”为例,首先应该清楚“指针变量”也是“变量”,因此具有“变量”的共同特点,即:变量值可以改变;任何变量名必须先定义,后使用等。其次,要明白“指针变量”与以前学过的“变量”的区别:指针变量的值一旦改变,表示指向不同的存储单元;在引用指针变量之前定义指针变量时,标识符即为指针变量名,与一般变量的定义不同的是:变量名前需加“*”;此外,在引用之前,还必须做到“先指向,后使用”,即将相应类型变量的地址先赋给指针变量,以确保指针变量有确切指向,这样才不至于造成指针变量的任意指向有可能破坏内存中的系统数据的严重后果。

另外,指针应用灵活,值得注意的语法细节也很多,如:p为一个指针变量,p++的含义,已不是简单的将p值加1,而是p+1*d,d=sizeof(p所指向的数据的数据类型)。这些细微之处直接影响学生实际分析程序,理解程序和编写程序的能力。为了能够正确掌握语法知识,培养实际的编程能力,在学习C语言的过程中,上机实践是必不可少的。学生根据教师指定的上机题目,在课前设计算法、编写程序,上机时对编写的程序进行调试、修改。总之,C语言是一门实践性很强的课程,只有不断上机摸索,才能熟练掌握并灵活应用。

2 C语言的高效编程

同一个问题解决的方法多种多样,因此,编写的程序就会多种多样,众多的解决方案中选择一个高效的解决方法,是编程人员必须具备的素质。

2.1 使用数学方法

数学是计算机之母,也是计算机的主要用途之一。没有数学的依据和基础,就没有计算机的发展,所以,在编写程序时,采用一些数学方法会对程序的执行效率有数量级的提高。

例如,用C语言编程求1~100之内的所有素数。我们通常的编程方法是:

该方法解决这个问题至少循环100次,最少用了100次判断。但是如果我们找出解决这个问题的规律,采用下面的算法就可以大大提高程序效率。算法如下:

这个简单的例子说明,在使用C语言编写程序时,可以更多的使用数学知识,最大限度的发挥数学的威力提高程序运行的效率。

2.2 使用位操作

数据的位是计算机程序中可以操作的最小数据单位。灵活的位操作可以有效的提高程序的运行效率。位操作一般应用在对一些整数的乘除运算上。

例如,如下的程序段:

对于数值8,即为2的3次方,所以语句i=257/8;可以写成i=257>>3;,前一语句调用了基本的除法函数,这个过程既有函数调用,还有很多汇编代码和寄存器参与运算,而后一语句仅仅是相关的汇编代码,因此更简洁、效率更高[2]。

2.3 嵌入汇编程序

汇编语言是执行效率最高的语言,在嵌入式软件的开发中,尤其在进行操作系统移植、驱动程序的开发时,程序员往往需要利用汇编语言来编写程序。这是因为某些和架构相关的代码必须使用汇编语言,另外一个就是为了优化代码性能,提高程序的运行效率。所以,为了获得程序的高效率,可以采用混合编程方法,即在C语言程序中嵌入汇编程序。

GCC为内嵌汇编提供了一个专门的关键词:asm(或者_asm_),其格式如下[3]:

上面的“汇编程序指令”就是实际的汇编语言指令;“输出操作数”建立汇编指令的输出清单;“输入操作数”是作为输入到汇编指令的操作数的C语言中的变量或表达式;“内嵌汇编指令使用的寄存器”是告诉C编译器,这段内嵌的汇编指令代码使用到的一些寄存器,以便于在C编译器编译C程序时避开这些寄存器。

下面的例子说明了上述汇编模板的用法:

这个例子是C语言语句”b=a”;的内嵌汇编语言语言。C程序中内嵌汇编是优化程序代码,提高程序效率的一个有效的手段。

2.4 使用指针

在解决数组问题的众多编程方案中,使用指针可以说是效率最高的一种。例如,有如下的实现给一个整形数组a赋值并输出数组中全部元素的程序段[1]:

1)下标法:

2)指针法:

对于上面的方法一,C编译系统是将a[i]转换为*(a+i)处理的,即先计算元素地址,因此用这种方法找数组元素费时较多。对于方法二,用指针变量p直接指向数组元素,不必每次都重新计算地址,像p++这样的自加操作是很快的,这种有规律的改变地址值的(p++)运算能大大提高执行效率。

3 总结

C语言是目前各高校计算机专业和相关专业所开设的一门重要基础课程,学好这门语言课是后续课程比如操作系统、数据结构等的基础。指针是C语言的重点和难点,其概念复杂、使用灵活的特点,使得大多数学生在学习过程中感觉难以掌握。在实际教学过程中,教师不仅要对C语言中的指针有深刻理解,而且要有丰富的教学经验,激发学生的学习兴趣。与此同时,教师更应该引导学生在C语言的学习过程中注重C程序的高效性,在日常编写程序时,自觉选择一种相对高校的编程方法。本文列举的提高程序效率的几种方法可供参考。

参考文献

[1]谭浩强.C程序设计教程[M].北京:清华大学出版社,2007:199-121.

[2]孙承爱,赵卫东.程序设计基础基于C语言[M].北京:清华大学出版社,2008:85-87.

C语言教学中指针浅析 篇8

一、使用电子教室配合多媒体教学

C语言程序设计是一门实践性极强的课程, 传统的课堂教学往往使学生在听课的过程中感到极为吃力, 几乎完全不能理解教师所讲解的内容。而C语言中的指针又是C程序设计中的一个重点也是一个难点, 概念抽象, 学生更是难以理解。在我们的教学中采用将学生分组带进实验室进行实际的多媒体配合电子教室进行和教师同步教与学的方法。让教师一边演示一边讲解, 使指针的教学由枯燥、晦涩变得生动活泼起来, 加深学生对指针的理解和掌握, 比如说针对以下两个问题的教学。

1、什么是指针

指针实质是代表某一个内存单元的地址, 是内存单元的编号;在C语言的译系统中, 对于变量的访问形式之一, 就是先求出变量的地址, 然后再过地址对它进行访问, 这就是指针, 变量的指针就是指该变量所占用的内存单元的首地址。

2、什么是指针变量

指针变量是存放内存单元编号的变量, 或者说指针变量就是存放地址的变量。比如说有这样的定义:

int*i_point;;

在这里point是变量的名字, int*代表i_point这个变量存放的是int型变量的地址。再作如下定义:

int i=10

i_point=&i;

为了让学生彻底理解指针变量和指针是两个不同的概念, 教师可以制作出有趣的PPT动画进行演示。

二、指针教学中学生容易犯的错误

1、指针变量未初始化

学生在学习的过程中定义好一个指针变量后, 常常会忘记对其进行初始化操作。在C语言中, C语言的变量, 都是先定义后使用, 而C中的指针变量却有所不同, 指针变量在使用前, 不仅要先定义, 还要进行初始化也就是要对对指针进行赋值。如果没有对指针变量进行初始化, 那定义的指针变量就不具有具体的指, 将会随机指向内存单元中的某个地址, 如果不幸指向系统区中, 就会造成灾难性的后果。所以必须对指针变量进行初始化。

在这个程序中, 指针变量*point没有经过赋值操作, 就很容易造成计算机系统的灾难性崩溃!

2、对指针变量直接进行赋整数值

运行结果为:10, 20

10, 20

本程序定义了两个指针变量g1和g2, “g1=&i;和g2=&j;”语句是将i与j的地址分别赋给g1和g2, 不能写成“*g 1=&i;和*g 2=

&j;”。

与指针相关的两个运符:

(1) &:取地址运算符。

(2) *:指针运算符或称间接访问运算符, 取指针所指向的目标值。

“&”与“*”运算符的优先级别相同, 按自右而左的方向结合, 如“g1=&i;”语句, 若&*g1, 先进行的是*g 1的运算, 再执行&运算。

如:*&i的含义是什么?当然先进行&i运算, 得到i的地址, 再进行*运算。

三、指针与数组的安全性

C语言指针的研究与运用 篇9

关键词:C语言,指针,数组,函数

指针是C语言中的精髓,它在C语言中被广泛的使用。理解和运用好指针可以灵活方便地处理程序中各种复杂问题,可以轻松完成其他高级程序设计语言不便完成的任务。

一、指针的概念

一个指针变量的值就是某个内存单元的地址或称为某内存单元的指针。

指针的引入为系统存取数据提供了一种“间接访问”方式。所谓间接访问,是先访问存放变量地址的存储单元,得到该变量的地址,再对变量内容进行访问。

指针变量是一种特殊变量。系统为指针变量分配一块连续存储单元不是供其存储数据,而是存储内存地址。因此,指针变量是存储内存地址的变量。

二、指针的类型

1、指向简单变量的指针。指针所知的数据类可以使简单的数据类型。

例:(1)int*p,i;p=&i;意思是指针变量指向整型变量i

(2)char*p,a;p=&a;意思是指针变量指向字符型变量a

(3)int*p,a[10];p=a;意思是指针变量指向数组a

2、指向数组的指针。指针所指的数组既可以是一维数组,也可以是多维数组。

分析:指针P指向了a数组的首地址,通过p++来访问a数组的每一元素。

3、指针数组。数组元素是由指针变量组成的一种指针。定义如:nt*p[2];指针数组p包含两个元素,每个元素指向一个整型数据。

分析:指针P是一个数组,通过for循环语句给指针数组中的每个指针变量赋值,p[1]的初值为数组a的第二行的首地址,*(p[1]+1)便是元素a[1][1],因此程序输出7。

4、指向指针的指针。指针变量指向的是指针的地址,定义如:int**p。

分析:指针数组p的各个指针变量指向数组a的各行首地址,q指向指针数组p的首地址,*(q+1)等同p[1],如此,*(*(q+1)+1)便等同*(p[1]+1)也就是a[1][1],因此程序输出7。

5、指向函数的指针。指针变量指向函数的首地址,然后通过该指针变量调用该函数。定义如:int(*p)()。

分析:int (*p)()表示定义了一个指向函数的指针变量,函数名max代表了函数的入口地址,执行p=max后,p指向了函数max,(*p)(a,b)便是通过p调用函数max。

6、指向文件的指针。C语言对文件的操作并不是直接通过文件名进行的,而是根据文件名生成一个文件指针,通过该指针来对文件进行操作.定义如:FILE*fP(fp为文件指针,此时fp不指向任何文件)。

三、指针应用中常见的错误

1、把数据赋给指针变量。指针在使用前必须进行初始化,赋予指针的值必须是地址。

正确语句:p=&i;“&”是一个取变量地址的运算符。

2、指针常量运算错误。程序中常量指针是不能被修改的。典型有数组名指针常量和指向字符串常量的指针。

3、指针赋值类型不一致

正确语句:p=a[0];或p=&a[0][0];如果一定把a赋值给p,必须先将a转换成整型指针类型,如:p=(int*)a;。特别是将多维数组赋值给指针变量时应注意类型匹配。

参考文献

[1]陈建辉,C语言指针探讨[M]·莆田高等专科学校学报,2001

[2]施冬梅,C语言指针教学中应注意的几个方面[M].镇江高专学报,2004

上一篇:绘本与作文教学下一篇:企业对员工履行责任

本站热搜