1 / 42

第 7 章 指针

第 7 章 指针. 指针的概念; 指针变量的定义及初始化; 指针变量的运算; 指针作为函数参数; 数组与指针; 多级指针; 函数指针。. 7.1 指针和指针变量的概念. 7.1.1 指针的概念. 1 .地址和指针. 计算机的内存是由连续的存储单元组成的,每个存储单元都有唯一确定的编号,这个编号就是内存单元的“地址”。如同教室的编号。 每个存储单元中可存储一个字节的数据,是这个存储单元的“内容”,如同教室里的学生。 内存中的地址是连续的。

sancha
Download Presentation

第 7 章 指针

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第7章 指针 • 指针的概念; • 指针变量的定义及初始化; • 指针变量的运算; • 指针作为函数参数; • 数组与指针; • 多级指针; • 函数指针。

  2. 7.1 指针和指针变量的概念 7.1.1 指针的概念 1.地址和指针 • 计算机的内存是由连续的存储单元组成的,每个存储单元都有唯一确定的编号,这个编号就是内存单元的“地址”。如同教室的编号。 • 每个存储单元中可存储一个字节的数据,是这个存储单元的“内容”,如同教室里的学生。 • 内存中的地址是连续的。 • C编译系统对程序中定义的变量,会根据变量的数据类型为其分配一定字节数并且连续的存储空间。分配的存储单元大小以及存储的数据格式由该变量的数据类型决定。

  3. 7.1.1 指针的概念 • 下面分别定义了3个变量,并进行了初始化: • short int i=1;char ch='A'; float f=2.5; 系统为变量i分配了1000和1001这两个内存单元,1000是变量i的地址。变量ch分配1002这个内存单元,1002是变量ch的地址。变量f分配了1003、1004、1005和1006这4个内存单元,1003是变量f的地址。如果要输出变量i的值,则先要找到i在内存中的地址, • 每个变量的地址是指该变量所占内存单元的第一个字节的地址。 • 对内存单元的访问要先获得内存单元地址。 • 内存单元地址称为指针。 • 一个变量的地址称为该变量的指针 。

  4. 7.1.1 指针的概念 2.直接访问和间接访问 • 直接访问:直接根据变量名存取变量的值。 • 间接访问:将变量的地址存放在另一个内存单元中,当要对变量进行存取时先读取另一个内存单元的值,得到要存取变量的地址,再对该变量进行访问。 • 用来存放另一个变量的地址(指针)的变量称为指针变量。 i_ptr是指针变量, 存放的是变量i的地址。

  5. 7.1 指针和指针变量的概念 7.1.2 指针变量的概念 • C语言中可以定义整型变量、浮点型变量、字符型变量等,也可以定义一种专门用来存放内存单元地址的特殊变量:指针变量。 • 指针变量中存放的是另一个有值变量的地址。 • 变量的指针就是变量的地址。一个指针变量一旦存放了某个变量的地址,该指针变量就指向了这个变量。 • 区分指针和指针变量这两个概念 。

  6. 7.2 指针变量的定义和初始化 7.2.1 指针变量的定义 数据类型 *指针变量名; *表示随后的变量是指针变量 指针变量指向的变量的数据类型 • int *ptr1,*ptr2; /* 定义指针变量ptr1和ptr2,ptr1和ptr2是指向整型变量的指针变量 */ • char *ptr3; /* 定义指针变量ptr3,ptr3是指向字符型变量的指针变量 */ • 指针变量中只能存放地址(指针),不要把它和整型变量混淆。如果某个指针变量取值为NULL,表示它不指向任何变量。 • —个指针变量只能指向与它定义的数据类型相同的变量。

  7. 7.2 指针变量的定义和初始化 7.2.2 有关指针的运算符 • C语言中有两个特殊的有关指针的运算符:取地址运算符&和间接访问运算符*,它们是一对互逆的运算符。 1.取地址运算符(&) &内存变量 • 运算符&是一个一元运算符,其含义是取指定变量的地址。 • 该运算返回的结果是内存变量的地址值。这个地址值是变量在内存中的位置,与变量的内容无关。 int i=3, *ptr1; char ch='a', *ptr2; ptr1=&i ; /* 将变量i的地址赋给指针变量ptr1 */ ptr2=&ch; /* 将变量ch的地址赋给指针变量ptr2,*/

  8. 7.2.2 有关指针的运算符 2.间接访问运算符(*) • 间接访问运算符(也称为指针运算符)是一个一元运算符。 • 该运算返回的结果是它的操作对象(即一个指针)指向的对象。表示间接存取指针变量所指向变量的值。 int i=3, *ptr1; char ch='a', *ptr2; ptr1=&i; /*ptr1指向i */ *ptr1=10; /* 把10存入ptr1所指向的变量中, 等同于i=10; */ ptr2=&ch; /*ptr2指向ch */ *ptr2+=32; /* 把ptr2所指向的变量的值加32, 相当于ch+=32; */ • 间接访问运算符必须出现在运算对象的左边,其运算对象或者是指针变量或者是地址。 int i=3,j, *ptr1;ptr1=&i; j=*ptr1; j=*(&i); /* 或j=*&i; */ • 区分指针变量定义中的“*” 和间接访问运算符“*” 。

  9. 7.2.2 有关指针的运算符 #include <stdio.h> int main(void) { int a, *a_ptr; /*定义整型变量a和指向整型变量的指针变量a_ptr*/ a=50; a_ptr=&a; /* 将变量a的地址赋给指针变量a_ptr */ printf("变量a的地址是:%p, 变量a_ptr的值是:%p\n ",&a, a_ptr); printf("变量a_ptr的的地址是:%p\n ",&a_ptr); printf("变量a的值是:%d, 变量*a_ptr的值是:%d\n ",a, *a_ptr); printf("&*a_ptr的值是:%p\n *&a_ptr的值是:%p\n ",&*a_ptr ,*&a_ptr); return 0; }

  10. 7.2 指针变量的定义和初始化 7.2.3 给指针变量赋空值 • 指针变量已定义但没有赋值前,其值是不确定的。即该指针变量指向的对象不确定,可能是任意一个不合法的内存单元。此时试图使用该指针,不仅可能造成程序崩溃,也可能造成操作系统垮掉,这是非常严重的错误。系统会让指针变量随机地指向一个内存地址,如果该地址正好被系统程序所使用,有可能导致系统的崩溃。 • 对于当前没有指向合法的内存位置的指针,为其赋值为NULL,以确保该指针不指向任何对象。 int *ptr=NULL;/*等价于ptr='\0'; 等价于ptr=0; */

  11. 7.2 指针变量的定义和初始化 7.2.4 指针变量的初始化 数据类型 *指针变量名=初始地址值; • 任何指针变量在使用之前要指向一个确定的内存单元,这可以通过初始化来实现,也可以在定义后通过赋值语句实现。 • 必须使用同类型变量的地址进行指针变量的初始化。如,赋给整型指针变量的必须是整型变量的地址,赋给字符型指针变量的必须是字符型变量的地址。 char c='A'; /* 变量c的初始值为'A' */ char *p=&c; /* 变量c的地址作为指针变量p的初始值 */ printf("%c%c\n", c, *p); c='B'; /* 将变量c赋值为'B' */ printf("%c%c\n", c, *p); *p='C'; /* 指针变量p所指向变量的值改为'C' */ printf("%c%c\n", c, *p);

  12. 7.3 指针变量的运算 • 指针变量的运算有:指针变量赋值、指针变量加(减)一个整数、两个指针变量比较和两个指针变量相减等。 7.3.1 指针变量赋值 ptr1=ptr2; /*ptr1是指针变量,ptr2是指针变量或地址表达式*/ int i=1; int *ptr1=&i, *ptr2; ptr2=ptr1; /* 将ptr1所指向变量的地址赋给ptr2 */ printf("*ptr2=%d\n", *ptr2); /* 结果:*ptr2=1*/ • 可以将变量地址、数组元素地址、指针变量等的值赋给一个指针变量。 • 指针变量的赋值运算只能在相同数据类型的变量之间进行。

  13. 7.3 指针变量的运算 7.3.2 指针变量的算术运算 p±n 1.指针变量加(减)一个整数 表达式的值为p当前执行对象的后面(或前面)第n个对象。 • 指针变量加(减)一个整数的含义是,使指针变量由当前位置进行移动,从而指向另一个存储单元。 • 指针变量的移动是以它所指向的变量的数据类型在系统中所占的字节数为移动单位,因此,p+n的值等于p+sizeof(*p)×n。 short int *a_ptr,a[5]={76,89,65,90,84 a_ptr=&a[0]; };/*设数组在内存中的首地址为3000 */ a_ptr+=3; /*指针向后移动6个字节指向a[3] 3006(3000+2*3) */

  14. 7.3.2 指针变量的算术运算 2.自增、自减运算 p±1 • 对指针变量进行自增(自减)运算,实质上是p+1(p-1)是,即向后(向前)移动指针变量,使其指向后一个(前一个)同类型变量。 不同的是自增、自减运算有前置后置、先用后用之分。 【例7-4】 移动指针变量访问数组元素。 int a[10]={1, 3, 5, 7, 9, 11, 13, 15, 17, 19}; int n=6, *p1, *p2; p1=p2=&a[0]; printf("(1) *p1=%d, *p2=%d\n", *p1, *p2); p1=p1+n; /*指针变量加一个整数*/ p2++; /*指针变量自增1*/ printf("(2) *p1=%d, *p2=%d\n", *p1, *p2); ++p1; /*指针变量自增1*/ p1=p1-3; /*指针变量减一个整数*/ p2=p2+7; printf("(3) *p1=%d, *p2=%d\n", *p1, *p2);

  15. 7.3.2 指针变量的算术运算 3.两个指针变量相减 • 两个指针变量相减一般用于数组,当两个指针变量指向同一数组时,两个指针变量相减的差值即为两个指针指向对象之间相隔的元素个数。 short int *p1,*p2,a[10]= {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; p1=&a[8]; p2=&a[2]; 表达式p1-p2的结果是6,表示p1和p2指向的对象之间相差6个数组元素。

  16. 7.3 指针变量的运算 7.3.3 指针变量比较 • 两个指向相同类型变量的指针变量可以使用关系运算符进行比较运算,对两个指针变量中存放的地址进行比较。参与比较的两个指针类型必须相同,且指向同一对象。 • 若p1和p2指向同一数组,则: • p1<p2 表示判断是否p1所指向的元素在p2所指向的元素之前; • p1>p2 表示判断是否p1所指向的元素在p2所指向的元素之后; • p1= =p2 表示判断p1和p2是否指向同一元素; • p1!=p2 表示判断p1和p2是否不指向同一元素。 【例7-5】 将一个整型数组逆序存储并输出。 • 算法分析:要将整型数组的数组元素逆序存储,则要对其中的位置进行移动:数组的第一个数组元素与最后一个元素的值互换,数组的第二个数组元素与倒数第二个元素的值互换,以此类推,直到全部逆序存储为止。

  17. 7.3.3 指针变量比较 #include <stdio.h> int main(void) { int a[10]={1, 3, 5, 7, 9, 11, 13, 15, 17, 19}; int *p1=&a[0], *p2=&a[9]; /*p1指向数组的头部, p2指向数组的尾部*/ int t; while(p1<p2) /*两个指针变量比较*/ { t=*p1; *p1=*p2; *p2=t; /*交换两个指针变量所指向的数组元素的值*/ p1++; /*指向头部的指针变量向后移动1个位置*/ p2--; /*指向尾部的指针变量向前移动1个位置*/ } /*当p1>=p2时,表示全部交换完毕,循环结束*/ for(t=0; t<10; t++) printf("a[%d]=%d ", t, a[t]); return 0;}

  18. 7.4 指针变量作为函数参数 • 当函数的参数是整型、字符型等普通变量时,函数调用仅仅把实参数据传递给形参,形参值的改变不会影响实参变量的值,传递是单向的。 【例7-6】 交换两个整数值的例子:int型形参无法改变实参值。 void swap(int x,int y) /*交换函数*/ {int temp=0 ; temp=x; x=y; y=temp; } /*交换形参x和y的值*/ int main(void) { int a, b; scanf("%d%d",&a,&b); printf("a=%d\tb=%d\n",a,b); swap(a,b); /*调用交换函数*/ printf("两个整数互换的结果是:\n"); printf("a=%d\tb=%d\n",a,b); return 0; } 请输入两个整数:10 20↙ a=10 b=20 两个整数互换的结果是: a=10 b=20

  19. 7.4 指针变量作为函数参数 • 当函数的参数是指针变量,即用变量的地址作为参数,可以达到交换的目的。 【例7-7】 交换两个整数值的例子:形参为int型指针变量。 #include <stdio.h> void swap(int *p1,int *p2); int main(void) { int a, b; scanf("%d%d",&a,&b); printf("a=%d\tb=%d\n",a,b); swap(&a,&b); /*调用交换函数*/ printf("两个整数互换的结果是:\n"); printf("a=%d\tb=%d\n",a,b); return 0; } void swap(int *p1,int *p2) /*交换函数*/ { int temp=0 ; temp=*p1;*p1=*p2;*p2=temp;} /*交换指针变量所指向的变量的值*/ 请输入两个整数:10 20↙ a=10 b=20 两个整数互换的结果是: a=20 b=10

  20. 7.4 指针变量作为函数参数 • 指针变量作为函数参数,实参将地址传给了形参,属于地址传递。实参和形参是同一地址,指向的是同一内存空间,因此实现了通过函数调用改变主调函数中指针变量所指向变量的值。但应注意的是这种方式的本质仍然是值传递,只不过这个值是地址值。 将例题7-7中的swap函数改为: swap(int *p1,int *p2) { int *p; p=p1; p1=p2; p2=p; } • 交换了p1和p2的值,但没有交换指针变量所指向的变量的值。

  21. 7.5 数组与指针 7.5.1 数组元素的指针 • 数组元素的指针就是数组元素的地址。 int a[10]; /*定义数组a为包含10个整型数据的数组*/ int *ptr; /*定义ptr为指向整型变量的指针变量*/ ptr=&a[2] ; /将a[2]的地址赋给指针变量*/ • 数组名代表数组的首地址。ptr=a;等价ptr=&a[0] ;都是将数组a的首地址(即第一个数组元素的地址)赋给指针变量ptr,使ptr指向数组a的开始。 • 数组在内存中是一片连续的存储空间,即数组元素的地址是连续递增的,所以通过指向数组的指针变量进行加(减)一个整数的算术运算来移动,就可以访问数组中的其他数组元素。

  22. 7.5 数组与指针 7.5.2 通过指针引用数组元素 • 两种访问数组元素的方法:下标法和指针法。 1.下标运算符 • a[i] ,[]是下标运算符。 • 下标运算符的一般形式: exp1和exp2是操作数表达式,其中一个是地址类型,表示首地址,另一个必须是整数,表示偏移量。 exp1[exp2] *((exp1)+(exp2)) int a[10]; 表达式a[2] *(a+2) 2.通过数组的首地址访问数组元素 • 通过数组的首地址加上偏移量就可得到其他数组元素的地址。

  23. 7.5.2 通过指针引用数组元素 • a(a+0)的值等于&a[0],a+1的值等于&a[1]……a+i的值等于&a[i]。 • 对于a[0],可以用表达式*&a[0]或*(a+0)或*a来引用;对于a[1],可以用表达式*&a[1]或*(a+1)来引用……对于a[i],可以用表达式*&a[i]或*(a+i)来引用。 【例7-8】使用下标法和通过数组的首地址访问数组元素的例子。 int a[4]={1, 2, 3, 4}, i; printf("下标法.以a[i]形式输出数组元素\n"); for(i=0;i<4;i++) printf("a[%d]=%d ", i, a[i]); printf("\n以*(a+i)的形式输出数组元素\n"); for(i=0;i<4;i++) printf("*(a+%d)=%d ", i, *(a+i));

  24. 7.5.2 通过指针引用数组元素 3.通过指向数组的指针变量访问数组元素 • 通过指向数组元素的指针找到所需的元素。 int a[4]={1, 2, 3, 4}; int *p=a; int i; printf("指针法。使用指针变量访问数组元素:\n"); for (i=0;i<4;i++) printf("*(p+%d)=%d ", i,*(p+i)); • 设有:int a[10];int *p=a; • 在p指向数组a的首个数据元素的前提下,有: • 对于数组元素a[0],等价于*(a+0),也等价于*(p+0);a和a+0和p+0均表示数组的首地址&a[0],即指向a[0]。 • 对于数组元素a[i](0<i<10),等价于*(a+i),也等价于*(p+i);a+i和p+i均表示a[i]的地址&a[i],即均指向a[i]。

  25. 7.5.2 通过指针引用数组元素 • 数组名是常量,不能进行诸如++等运算。而指针变量是变量,可以实现其值的改变。 • 指向数组元素的指针变量,也可以表示成数组的形式。允许指针变量带下标。 • int a[10],p,i; /* 0≤i<10 */ • p=a; • *(p+i)也可以用p[i]来表示。当 p指向数组a的首地址时,显示数组元素a[i]的表达式有:a[i]、*(a+i)、*(p+i)和p[i]。 • 如果p不指向a[0],则p[i]和a[i]是不一样的。设:p=a+1;则p[2]相当于*(p+2),由于p指向a[1],所以p[2]就相当于a[3]。而p[-1]就相当于*(p-1),表示a[0]。

  26. 7.5 数组与指针 7.5.3 指向二维数组的指针和指针变量 • C语言中定义的二维数组实际上是一个一维数组,这个一维数组的每个元素又是一个一维数组。 • 二维数组的每个数组元素既可以视为二维数组的成员,也可将二维数组的行视为一个独立的一维数组,二维数组元素是所在行的一维数组的成员。 1.二维数组的地址 • 二维数组存储结构是按行顺序存放的。二维数组的地址有两种: • 行地址,即每行都有一个确定的地址, • 列地址(数组元素的地址),即每个数组元素都有一个确定的地址。

  27. 7.5.3 指向二维数组的指针和指针变量 定义并初始化二维数组a: short int a[3][4]={{0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11}}; • 数组a由a[0]、a[1]和a[2]三个元素组成,而它们中的每个数组元素又是一个一维数组,且都含有4个数组元素(相当于4列),其中,a[0]所代表的一维数组包含的4个元素为a[0][0]、a[0][1]、a[0][2]和a[0][3]。 • a代表二维数组的首地址,也是数组中行下标为0的地址。a+1代表二维数组中行下标为1的地址,a+2行代表下标为2的地址。

  28. 7.5.3 指向二维数组的指针和指针变量 • a[0]代表第0行中第0列元素的地址,即&a[0][0],a[1]是第1行中第0列元素的地址,即&a[1][0]。 a[i]是第i行中第0列元素的地址,即&a[i][0]。 • 根据地址运算规则,a[0]+1即代表第0行第1列元素的地址,即&a[0][1],a[i]+j即代表第i行第j列元素的地址,即&a[i][j]。 • a[i]与*(a+i)等价,因此,a[i]+j就与*(a+i)+j等价,它表示二维数组元素a[i][j]的地址。 • 对于定义的数组a,若0≤i<3,0≤j<4,则表示a[i][j]的地址有以下5种形式: • &a[i][j] • a[i]+j • *(a+i)+j • &a[0][0]+4*i+j • a[0]+4*i+j

  29. 7.5.3 指向二维数组的指针和指针变量 • a+i和*(a+i)的含义是不同的。a+i代表二维数组第i行的地址,是行地址;而*(a+i)代表二维数组第i行第0列元素的地址,是列地址。行地址以行的位移量为单位进行控制,列地址以数组元素的位移量为单位进行控制。对于数组a,数组元素的位移量是2个字节,而行的位移量是8个字节(因为a的每个数组元素是包含4个短整型数组元素的一维数组)。 • 对于定义的数组a,若0≤i<3,0≤j<4,则表示a[i][j]有以下5种形式: • a[i][j] • *(a[i]+j) • *(*(a+i)+j) • (*(a+i))[j] • *(&a[0][0]+4*i+j)

  30. 7.5.3 指向二维数组的指针和指针变量 2.指向二维数组的指针变量 • 对应二维数组的行地址和列地址。指向二维数组的指针变量也有两种。 (1)指向二维数组元素的指针变量。 • 指向二维数组元素的指针变量的定义方法与指向一维数组元素的指针变量相同。 • 指向二维数组元素的指针变量不能指向二维数组的行,只能指向数组元素。 int a[3][4],*ptr; int i,j; ptr=&a[0][0]; /*ptr指向a数组的第0行第0列元素*/ printf("请输入12个整型数据:\n"); for(i=0;i<3;i++) for(j=0;j<4;j++) scanf("%d", ptr++);

  31. 7.5.3 指向二维数组的指针和指针变量 (2)指向具有m个元素的一维数组的指针变量。 数据类型 (*指针变量名)[常量表达式]; 为指针变量指向的一维数组中的数组元素个数 (*指针变量名)中的圆括号不能少 short int (*p)[3]; • 指针p为指向一个由3个元素组成的短整型一维数组的指针变量,指针变量p所指向的对象的数据类型是一个包含有3个short int元素的数组。 • 这种数组指针变量不同于短整型指针变量。当短整型指针变量指向一个短整型数组元素时,进行地址加1运算,表示指针指向数组的下一个元素,此时地址值增加了2。而对于上面定义的指向一个由3个元素组成的数组指针变量,进行地址加1运算时,其地址值增加了6(3*2=6)。

  32. 7.5.3 指向二维数组的指针和指针变量 【例7-12】 建立一个行指针引用二维数组元素的例子。 #include <stdio.h> int main(void) { int a[3][4]={{1, 3, 5, 7}, {9, 11, 13, 15}, {17, 19, 21, 23}}; int i, (*ptr)[4]; float sum,average; for(ptr=a;ptr<a+3;ptr++) { sum=0; for(i=0;i<4;i++) sum+=*(*ptr+i); /* 求每行的总和 */ average=sum/4; /* 求每行的平均值 */ printf("average=%.2f\n", average);} return 0;}

  33. 7.5 数组与指针 7.5.4 数组名形参 • 数组名代表数组的首地址,当形参是数组名时,标准C将数组名形参直接转换为指针类型的形参。 【例7-13】写一个函数,用选择法对10个整数从大到小进行排序。 void sort(int x[],int n) /* 作为形参的数组名x实质上是一个指针变量 */ { int *x_end,*y,*p,temp; x_end=x+n; /*x实质上是一个指针变量 */ for(;x<x_end-1;x++) { p=x; for(y=x+1;y<x_end;y++) if(*y>*p) p=y; if(p!=x) { temp=*x; *x=*p; *p=temp; } }

  34. 7.5 数组与指针 7.5.5 指针数组 1.指针数组的定义 • 如果数组中的每个元素都是指向同类对象的指针数据,则这种数组称为指针数组。 • 指针数组中的每一个数组元素都是指针变量。 数据类型 *数组名[常量表达式]; • int *ptr[5]; • 定义了一个由5个指针变量构成的指针数组ptr,数组中的每个数组元素(指针变量)都指向一个整型数据。

  35. 7.5.5 指针数组 2.指针数组的初始化 数据类型 *数组名[常量表达式]={初值表}; • int b[2][4], *bptr[2]={b[0],b[1]}; • bptr是一维指针数组。bptr[0]指向b[0],bptr[1]指向b[1]。 3.指针数组的应用 • 通过建立指针数组可以来引用二维数组元素。 int a[3][2], *aptr[3],i,j; for(i=0; i<3; i++) aptr[i]=a[i]; • a[i]为常量,表示a数组每行的首地址。循环中的赋值语句使aptr[0]、aptr [1]和aptr [2]分别指向a数组每行的开头。这时,指针数组aptr和数组a建立了关系。 *(a[i]+j)和*(p[i]+j)等价 。

  36. 7.6 多级指针 • 指向指针数据的指针变量称为指向指针的指针,也就是二级指针 。 数据类型 **指针变量名; int i, *ptr, **pptr; ptr=&i; pptr=&ptr; **pptr=2; • 定义了一级指针变量ptr和二级指针变量pptr。 • pptr指向ptr,ptr指向变量i。 • * pptr是pptr直接指向的对象。 • ** pptr是pptr间接指向的对象。 • int *是指针变量pptr直接指向的对象的数据类型,int是*pptr指向的数据对象的数据类型。 • 二级指针变量只能指向一级指针变量,不能越级指向int类型变量i。pptr=&i; 是错误的。

  37. 7.6 多级指针 【例7-14】 利用二级指针输出二维数组。 #include <stdio.h> int main(void) { int **p,*q; int a[3][4]={{15,9,23,0},{8,45,6,17},{25,64,14,50}},i,j; for (i=0;i<3;i++) { q=a[i]; p=&q; for(j=0;j<4;j++) printf("%-4d",*(*p+j)); printf("\n"); } return 0; }

  38. 7.7 函数指针 7.7.1 函数的指针 • 函数的指针是该函数的入口地址。 • 定义一个指针变量,让它指向某个函数,这个变量就称为指向函数的指针变量,即函数指针。 • 指向函数的指针变量既可以作为函数实参传递给函数,也可以作为函数的返回值从函数中返回。 7.7.2 函数指针的定义与引用 形参表列表示指针变量指向的函数所带的参数列表。 1.函数指针的定义 函数类型 (*指针变量名) (形参表列); 2.函数指针的初始化 函数类型 (*指针变量名) (形参表列)=函数名;

  39. 7.7.2 函数指针的定义与引用 3.函数指针的赋值 • 利用函数名给相应的指针变量赋值,就使得该指针变量指向这个函数。 int func(int x); /* 一个函数原型声明 */ int (*f)(int x); /* 定义一个指向函数的指针变量 */ f=func; /* 将func函数的入口地址赋给指针变量f */ • 赋值时函数func不带括号,也不带参数,由于func代表函数的入口地址,因此经过赋值以后,指针变量f就指向函数func。 4.通过函数指针来调用函数 • 指向函数的指针变量是通过函数名及有关参数对函数进行调用。 (*指针变量名) (实参表);

  40. 7.7.2 函数指针的定义与引用 • 指向函数的指针变量指向存储区中的某个函数,因此可以使用它调用相应的函数。调用过程主要有3个步骤。 • 定义指向函数的指针变量。例如,int (*f)(int x);。 • 对指向函数的指针变量赋值。例如,f=func;(函数func已经定义)。 • 用(*指针变量名) (实参表);形式调用函数。例如,(*f)(x);(x已经有确定的值)。

  41. 7.7.3 函数指针作为函数参数 • 整个函数不能作为参数在函数间进行传递。但在某个情况下,需要把一个函数传给另一个函数,这就必须使用指向函数的指针变量作参数。 • 函数的参数不仅可以是变量、指向变量的指针变量、数组名和指向数组的指针变量等,而且还可以是指向函数的指针变量。当函数指针作为函数的参数时,可以实现函数地址的传递。函数名代表的是函数的入口地址,因此,也就是将函数名传递给形参 。

  42. 7.7.4 返回指针的函数 • 一个函数不仅可以返回一个整型值、字符值、浮点型值等,也可以返回指针型的数据。如果一个函数的返回值是一个指针,即某个对象的地址,那么这个函数就是返回指针的函数。 数据类型 *函数名(参数表){函数体}

More Related