版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第九章,指针,9.1地址和指针的概念,为了说清楚什么是指针,必须弄清楚数据在内存中是如何存储的,又是如何读取的。,计算机中,所有的数据都是存放在存储器的内存单元中的。一般把存储器中一个字节称为一个内存单元,不同数据类型所占用的内存单元数不等,如整型变量占2个字节,字符变量占1个字节等。 为了正确地访问这些内存单元,必须为每个内存单元编上号,根据一个内存单元的编号即可准确地找到该内存单元。 内存单元的编号,称为“地址” 。,内存单元的地址和内存单元的内容是两个不同的概念: 假设程序中定义了整型变量i,并赋值为3。编译时系统分配2000和2001两个字节给变量i,此时两个内存单元的编号为单元的地址
2、,其中存放的数据即是该单元的内容。,两种访问方式:,直接访问方式: 在程序中一般是通过变量名来对内存单元进行存取操作的,其实程序在编译后,已经将变量名转换成变量的地址,对变量值的存取都是通过地址进行的。,间接访问方式: 将变量i的地址存放在另一个变量中,C语言规定,可以在程序中定义一种特殊的变量,用来存放地址。 假设定义一个变量p,用来存放整型变量的地址,它被分配为3010、3011两个字节。,可以通过下面语句将i的地址(2000)存放到p:p= 对变量i是访问,可直接访问,已知变量i的地址,根据此地址直接对变量i的存储单元进行存取访问; 也可间接访问,先找到存放变量i的地址的变量p,从其中得
3、到变量i的地址,然后找到变量i的存储单元,对它进行存取范围。,一个变量的地址称为该变量的“指针”。如,地址2000是变量i的指针。 C语言中,用一个变量存放指针(地址),此变量称为指针变量,上述的变量p是指针变量,指针变量的值是某个内存单元 的地址(指针)。 严格地说,一个指针是一个地址,是一个常量;而一个指针变量却可以被赋予不同的指针值,是变量。但通常把指针变量简称指针。,指针变量的值不仅可以是变量的地址,也可以是其他数据结构的地址。 例如:在一个指针变量中可存放一个数组或一个函数的首地址。,9.2 变量的指针和指向变量的指针变量,区别:变量的指针和指针变量 1.变量的指针就是变量的地址。
4、2.存放变量地址的变量是指针变量,它用来指向另一个变量。,为了表示指针变量和它所指向的变量之间的联系,在程序中用“ * ”符号表示“指向”。 若已定义i_pointer为指针变量,则* i_pointer是i_pointer所指向的变量,因此* i_pointer也代表一个变量,它和变量i是同一回事。,下面两个语句作用相同: (1)i=3; (2) * i_pointer=3; 第二个语句含义是将3赋给指针变量i_pointer所指向的变量i.,一、 指针变量的定义,指针变量在使用前必须先定义,一般形式为: 类型说明符 *指针变量名; 其中,*表示这是一个指针变量,类型说明符 表示该指针变量所
5、指变量的数据类型。 例如:int *p1; (其中p1(而不是 *p1)是一个指向整型变量的指针变量,它的值是某个整型变量的地址。) float *p2; (其中p2是指向浮点型变量的指针变量),说明:,(1)指针变量名的构成原则是标识符,前面必须有“ * ” , 表示该变量的类型是指针型变量。 (2)在一个定义语句中,可以同时定义普通变量、数组、 指针变量。 (3)类型说明符说明的数据类型不是指针变量中存放的数据的数据类型,而是它将要指向的变量或数组的数据类型。因此,一个指针变量只能用来指向同种数据类型的其他变量或数组,不能时而指向一个浮点型变量,时而指向一个整型变量。,二、 指针变量的引用
6、,指针变量中只能存放变量的地址,绝不能存放任何其他数据。 例如:int *p; p=2000; /*2000是一个整数而不是一个地址*/,C语言提供两种有关的运算符: (1) int *p= (2)指针运算符*和指针变量说明中的指针说明符*不是一回事。后者表示其后的变量是指针类型,前者则是一个运算符用以表示指针变量所指的变量。,说明:,(3)如果已执行了语句p= ,则: int *p1,*p2; a=100; b=10; p1= ,例: 通过指针变量访问整型变量。,运行结果: 100,10 100,10,#include void main( ) int a=5,b,c,*p; p= ,例:
7、通过指针变量进行运算。,运行结果: 5,10,说明:,(1) 指针变量的运算种类也是有限的,它只能进行赋值运算和部分算术运算及关系运算。 (2) 指针变量还可以赋空值,其赋空值后,则可以使用,只是它不指向具体的变量而已。 例如:#define NULL 0 int *p=NULL;,三、 指针变量作函数参数,#include swap(int x,int y) int t; t=x; x=y; y=t; void main( ) int a=3,b=5; if(ab) swap(a,b); printf(“a=%d,b=%d n”,a,b); ,C语言是通过传值将参数传递给函数的,对被调函数来
8、说,没有直接的方法来改变主调函数内的变量的值。 例:对两个整数按大小顺序输出。,运行结果: a=3,b=5,#include swap(int *x,int *y) int t; t=*x; *x=*y; *y=t; void main( ) int a=3,b=5; if(ab) swap( ,使主调函数传递指向要被改变量的指针,即可使被调函数能改变主调函数的参数值。 例:对两个整数按大小顺序输出。,运行结果: a=5,b=3,数组与指针,(苏小红版第11章的11.1和11.2),一个数组是由连续的一块内存单元组成的,数组名即是这块连续内存单元的首地址。 一个变量有地址,一个数组包含若干元素
9、,每个数组元素都在内存中占用存储单元,它们都有相应的地址。指针变量既然可以指向变量,当然也可以指向数组元素(把某一元素的地址放到一个指针变量中)。所谓数组元素的指针就是数组元素的地址。,指向数组的指针变量称为数组指针变量。 其一般形式为: 类型说明符 *指针变量名; 其中,类型说明符表示所指数组的类型。从中可以看出指向数组的指针变量和指向普通变量的指针变量的说明是相同的。,一、指向数组元素的指针,说明:,设有实型数组a,指向a的指针变量为pa,则有以下关系: pa,a, (2)int a; 初始化赋值 int *p=,按C语言的规定:如果指针p已指向数组中的一个元素,则p+1指向同一数组中的下
10、一个元素,而不是将p的值(地址值)简单地加1。 例如: 数组元素是float型,每个元素占4个字节,则p+1意味着使p的值(地址值)加4个字节,以使它指向下一个元素,此时,p+1所代表的地址实际上是p+1 d,d是一个数组元素所占的字节数。,二、通过指针引用数组元素,(1)下标法 #include void main( ) int a10,i; for(i=0;i10;i+) scanf(“%d”, ,例:输出数组中的全部元素。 (设一个a数组,整型,有10个元素,要输出各元素的值有3种方法),(2)通过数组名计算数组元素 的地址,找出元素的值 for(i=0;i10;i+) printf(“
11、%d”,*(a+i); (3)用指针变量指向数组元素 for(p=a;p(a+10);p+) printf(“%d”,*p);,#include void main( ) int a10,i,*p; p=a; for(i=0;i10;i+) scanf(“%d”,p+); printf(“n”); for(i=0;i10;i+,p+) printf(“%d”,*p); printf(“n”); ,例:(改错题)通过指针变量输出a数组中的10个元素。,运行结果:1 2 3 4 5 6 7 8 9 0 22153 234 0 0 30036 25202 11631 8529 8237 28483,
12、1.算术运算 只能进行加减运算,数组指针变量加或减一个整数n的意义是把指针指向的当前位置(指某数组元素)向前或向后移动n个位置。 例如:int a5,*pa; pa=a; /*pa指向a0,pa的值为 /*pa指向a2,pa的值为 pa=qa=a; for(i=0;i5;i+) *qa=i; qa+; /*将指针qa指向a数组中的下一元素 */ for(i=0;paqa;i+) printf(“a%d=%-2d”,i,*pa); pa+; ,例:通过指针变量的运算输出a数组中的5个元素。,运行结果:a0=0 a1=1 a2=2 a3=3 a4=4,2.指针变量的自增自减运算 如果先使p指向数组
13、a的首元素(即p=a),请分析: (1)p+:使p指向数组a的下一元素,即a1。 (2)*p+:由于元素符+和*同优先级,结合方向为自 右向左,因此它等价于*(p+)。 (3)*(p+) 与*(+p)作用不同。 (4)(*p)+:表示p所指向的元素值加1,它等价于 (a0)+。若a0=3,则(*p)+的值为4。 注意:是元素值加1,而不是指针值加1。,前面已介绍过可以用数组名作函数的参数,例如: void f(int arr ,int n) void main( ) int array10; f(array,10); f (int arr , int n) 但在编译时是将arr按指针变量处理的
14、,相当于将函数f的首部写成 f (int *arr, int n) 以上两种写法是等价的。,三、用数组名和数组指针变量作函数参数,以变量名和数组名、数组指针变量作为函数参数的比较:,归纳起来,如果有一个实参数组,想在函数中改变此数组中的元素的值,实参与形参的对应关系有以下种情况:,(1) 形参和实参都用数组名,如: void main() void (int ,int ) int ; (,); ,(2) 实参用数组名,形参用指针变量。如: void () void (int *,int ) int ; (,); ,(3)实参形参都用指针变量。例如: void main() void (int
15、*,int ) int , *p=a; (p,); ,(4) 实参为指针变量,形参为数组名。如: void main() void (int x ,int ) ,*p=a; (p,); ,#include void main( ) void inv(int *x,int n); int i,a10=3,7,9,11,0,6,7,5,4,2; printf(“The original array:n”); for(i=0;i10;i+) printf(“%d”,ai); printf(“n”); inv(a,10); printf(“The array has been inverted:n”)
16、; for(i=0;i10;i+) printf(“%d”,ai); printf(“n”); ,例:将a数组中n个整数按相反顺序存放。,void inv(int *x,int n) int *p,temp,*i,*j,m=(n-1)/2; i=x; j=x+n-1; p=x+m; for(;i=p;i+,j-) temp=*i; *i=*j; *j=temp; return; ,运行结果: The original array: 3,7,9,11,0,6,7,5,4,2 The array has been inverted: 2,4,5,7,6,0,11,9,7,3,四、 多维数组与指针,
17、用指针变量可以指向一维数组中的元素, 也可以指向多维数组中的元素。 下面以二维数组为例。,1. 多维数组元素的地址的表示方法,定义int a34=1,2,3,4,5,6,7,8,9,10,11,12; C语言允许把一个二维数组分解为多个一维数组来处理。 a是一个数组名, a数组包含3个元素:a0,a1,a2,而每一个元素又是一个一维数组,包含4个元素(即4个列元素)。如行元素a0所代表的一维数组包含4个元素: a00,a01,a02,a03。 故可以认为二维数组是“数组的数组”,即二维数组a是由3个一维数组所组成的。,从二维数组的角度看,a代表二维数组首元素的地址。现在的首元素不是一个简单的整
18、型元素,而是由4个整型列元素所组成的一维数组, 因此a代表的是首行(0行)的首地址; a+1代表1行的首地址; a+2代表2行的首地址。 如果二维数组首行的首地址是2000,则a+1的首地址为a+4*2=2008。,a0,a1,a2是一维数组名,而C语言规定了数组名代表数组首元素地址, 因此a0代表一维数组a0中第0列元素的地址,即二维数组0行0列元素的地址,即 int *p; for(p=a0;pa0+12;p+) if(p-a0)%4=0) printf(“n”); printf(“%4d”,*p); printf(“n”); ,分析: 指针变量p是用“int *p;”定义的,它是指向整型
19、数据的,p+1所指向的元素是p所指向的元素的下一元素。,(2) 指向由m个元素组成的一维数组的指针变量,此时p不是指向整型变量,而是指向一个包含m个元素的一维数组。 如果p先指向a0,则p+1是指向a1,p的增值以一维数组的长度为单位。,二维数组指针变量说明的一般形式为: 类型说明符 (*指针变量名)长度; 其中,“类型说明符”是所指数组的数据类型; “*”表示其后的变量是指针类型; “长度”表示二维数组分解为多个一维数组时,一维数组的长度,即是二维数组的列数。 注意:(*指针变量名)两边的括号不能省,如缺少括号则表示指针数组。,#include void main( ) int a34=1,
20、3,5,7,9,11,13,15,17,19,21,23; int (*p)4,i,j; p=a; scanf(“i=%d,j=%d”, ,例:输出二维数组任一行任一列元素的值。,运行结果: i=1,j=2 a1,2=13,字符串与指针,(苏小红版第10章的10.3和10.7),一、字符串的表示形式,对指向字符变量的指针变量应赋予该字符变量的地址 例如:char ch,*pch= 其中pch是一个指向字符变量ch的指针变量。,在C语言中,可以用两种方法访问一个字符串: 1.用字符数组存放一个字符串; 2.用字符指针指向一个字符串。 (可以不定义字符数组,而只定义一个字符指针, 用字符指针指向字
21、符串中的字符),例:#include void main( ) char *string=“I love China!”; printf(“%s n”, string); ,注意: 1.其中string是一个指向字符串的指针变量,把字符串的首地址赋予string。 2.定义string部分:char *string=“I love China!”; 等价于:char *string; string=“I love China!”; 但对字符数组使用方式char *str =“I love China!”; 不能写为:char *str80; str=“I love China!”;,二、字符指
22、针作函数参数,将一个字符串从一个函数传递到另一个函数,可以用地址传递的办法,即用字符数组名作参数,也可以用指向字符的指针变量作参数。 在被调函数中可以改变字符串的内容,在主调函数中可以得到改变了的字符串。,(1)实参用指针变量,形参用数组名 #include void main( ) void copy_string(char str1 ,char str2 ); char s1 =“I am a teacher.”; char s2 =“You are a student.”; char *a=s1,*b=s2; printf(“string a=%snstring b=%sn”,a,b);
23、 printf(“copy string a to string b:n”); copy_string(a,b); printf(“string a=%snstring b=%sn”,a,b); ,例:用函数调用实现字符串的复制。,void copy_string(char str1 ,char str2 ) int i=0; while(str1 !=0) str2i=str1i; i+; str2i= 0; ,例:用函数调用实现字符串的复制。,运行结果: string a= I am a teacher. string b= You are a student. copy string a
24、 to string b: string a= I am a teacher. string b= I am a teacher.,(2)实参、形参都用字符指针变量 #include void main( ) void copy_string(char *str1,char *str2); char s1 =“I am a teacher.”; char s2 =“You are a student.”; char *a=s1,*b=s2; printf(“string a=%snstring b=%sn”,a,b); printf(“copy string a to string b:n”)
25、; copy_string(a,b); printf(“string a=%snstring b=%sn”,a,b); ,void copy_string(char *str1,char *str2) int i=0; for(;*str1!=0;str1+,str2+) *str2=*str1; *str2= 0; ,运行结果: string a= I am a teacher. string b= You are a student. copy string a to string b: string a= I am a teacher. string b= I am a teacher.
26、,指向函数的指针,通过用函数指针变量调用函数 (苏小红版第9章的9.6),可以用指针变量指向整型变量、字符串、数组,也可以指向一个函数。 C语言中规定,一个函数占用一段连续的内存单元,函数名即是函数所占内存单元的首地址(或称函数的入口地址,函数的指针)。 可以把函数的首地址(即入口地址)赋予一个指针变量,使该指针变量指向该函数,然后通过该指针变量可以找到并调用此函数。,把指向函数的指针变量称为“函数指针变量”。 函数指针变量定义的一般形式为: 类型说明符 (*指针变量名)(函数参数表列); 其中,“类型说明符”表示被指函数的返回值的类型。 例:int (*p)(int,int); 其中p是一个
27、指向函数的指针变量,该函数有两个整型参数,函数值为整型。,#include int max(int a,int b) return(ab)?a:b); void main( ) int (*pmax)(int,int),x,y,z; pmax=max; printf(“Input two numbers:n”); scanf(“%d%d”, ,例:求a和b中的最大者。(通过指针变量调用函数),说明:,(1)定义“int (*pmax)(int,int);”中的*pmax两侧的括号不可省略,表示pmax先与*结合,是指针变量,然后再与后面的( )结合,表示此指针变量指向函数,这个函数值(即函数返
28、回值)是整型的。 若写成“int *pmax(int,int);”,则由( )优先级高于*,它就成了声明一个pmax函数了,此函数的返回值是指向整型变量的指针。,说明:,(2)函数指针变量不能进行算术运算,如p+、p-、p+n等运算是无意义的。 因为函数指针变量p只能指向函数的入口处,而不能指向函数中的某一条指令处,因此不能用(*p+1)来表示函数的下一条指令。,指针型函数,(返回指针值的函数) (苏小红版第9章的9.6),一个函数可以返回一个整型值、字符值、实型值等,也可以返回指针型是数据,即地址。 这种返回指针值的函数,称为指针型函数。 一般定义形式为: 类型说明符 *函数名(形参表列);
29、 其中,“*”在函数名之前,表示此函数是指针型函数; “类型说明符”表示被指函数的返回值的类型。,#include float *search(float (*pointer)4,int n) float *pt; pt=*(pointer+n); return(pt); ,例:有若干个学生的成绩(每个学生有4门课程),要求在用户输入学生序号以后,能输出该学生的全部成绩。 用指针函数来实现。,void main( ) float score 4=60,70,80,90,56,89,67,88, 34,78,90,66; float *p; int i,m; printf(“enter the
30、number of student:”); scanf(“%d”, ,运行结果: enter the number of student:1 The scores of No.1 are: 56.00 89.00 67.00 88.00,指针数组和,(苏小红版第11章的11.3),指向指针的指针变量,一、 指针数组,一个数组,若其元素均为指针类型数据,称为指针数组。 即指针数组中的每一个元素都相当于一个指针变量。 指针数组说明的一般形式为: 类型说明符 *数组名数组长度; 其中,“类型说明符”为指针值所指向的变量的类型。 例:int *p4; 由于 比*优先级高,因此p先与4结合,说明p是一个
31、数组,有4个元素。 *表示其后的数组为指针类型的,每个数组元素(即指针变量)都可指向整型变量。,说明:,(1)通常可用一个指针数组来指向一个二维数组,指针数组中的每个元素被赋予二维数组每一行的首地址,因此也可理解为指向一个一维数组。 (2)指针数组也常用来表示一组字符串,此时指针数组的每个元素被赋予一个字符串的首地址。,注意:,指针数组和二维数组指针变量的区别: 两者虽然都可用来表示二维数组,但是其表示方法和意义是不同的。二维数组指针变量是单个变量,而指针数组表示的是多个指针变量。 例:int (*p)4;表示p是一个指向二维数组的指针变量,该二维数组的列数为4或分解为一维数组的长度为4。 i
32、nt *p4;表示p是一个指针数组,有4个元素p0,p1,p2,p3都为指针变量。,#include char *day_name(char *name,int n) char *p1,*p2; p1=*name; p2=*(name+n); return(n7)?p1:p2); ,例:用指针数组作函数参数,编写输入一个17之间的整数,输出对应的星期名。,void main() char *name=Illegal day,Monday,Tuesday, Wednesday,Thursday,Friday, Saturday,Sunday; char *ps; int i; printf(In
33、put Day No:); scanf(%d, ,分析: 主函数中,定义了一个指针数组name,并对name作了初始化赋值,其每个指针变量元素都指向一个字符串。 在day_name函数中,指针变量p1被赋予name0的值,p2被赋予namen的值。,二、 指向指针的指针变量,如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量。 其一般形式为: 类型说明符 *指针变量名;,例:#include void main() int x,*p,*pp; x=10; p= ,分析: p是一个指针变量,指向整型变量x;pp也是一个指针变量,它是指向指针变量p。 通过pp指针
34、变量访问x的写法是*pp。,说明:,通过指针变量访问变量称为间接访问,简称间访。 这种指针变量直接指向变量,所以称为单级间访。 通过指向指针的指针变量来访问变量则构成二级间访。 从理论上说,间访方法可以延伸到更多的级数;但在实际上一般程序很少超过二级,因为级数太多,不易理解,易出错。,例:#include void main( ) int a5=1,3,5,7,9; int *num5= ,运行结果: 1 3 5 7 9,例:#include void main( ) char *name =“Folloew me”,“BASIC”,“Great Wall”,“Fortran”,“Computer design”; char *p;
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 磁性声音的课件
- 短文六则课件
- 盗窃罪培训教学课件
- 2026年心理健康自我测试题库
- 2026年教育行业遴选教师笔试模拟题
- 2026年会计中级职称考试复习题集
- 2026年职业发展与创新思维实践题库
- 2026年商场服装陈列规范与6S管理结合的货位设置题集
- 2026年汽车维修技师职业技能鉴定模拟试题集
- 2026年生物技术与工程基因工程原理应用技术题集
- 初中地理八年级《中国的气候特征及其影响》教学设计
- 广州大学《电磁场与电磁波》2023-2024学年第二学期期末试卷
- 中国家居照明行业健康光环境与智能控制研究报告
- 主动防护网系统验收方案
- 医学人文关怀培训课件
- 基于BIM的ZN花园14号住宅楼工程清单与招标控制价编制
- 压缩机操作工岗位操作技能评估
- 2025年小学三年级语文单元测试模拟卷(含答案)
- 河北省石家庄第二中学2025-2026学年高一上数学期末联考试题含解析
- 【必会】自考《管理学原理》13683备考题库宝典-2025核心题版
- 土方施工环保措施方案
评论
0/150
提交评论