第6章 指针 学习目的与要求: 了解指针的概念和相关术语 熟练掌握指向变量、数组和字符串的指针变量的使用方法 了解指向函数的指针变量

Slides:



Advertisements
Similar presentations
第九章 指针 西安工程大学.
Advertisements

第七章 指针 计算机公共教学部.
第六章 指针 指针的概念 指针变量 指针与数组 指针与函数 返回指针值的函数.
第十章 指针 分析C程序的变量所存放的数据:  数值型数据:整数、实数  字符型数据:字符、字符串 这些变量具有以下性质:
第7章 指针 存储地址的变量的类型就是指针类型 能直接对内存地址操作, 实现动态存储管理 容易产生副作用, 初学者常会出错
第七章 指针 教 材: C程序设计导论 主 讲: 谭 成 予 武汉大学计算机学院.
二级指针与二维数组.
C语言程序设计基础 第10章 指针进阶 刘新国.
10.1 二级指针 10.2 指针与二维数组 10.3 指针的动态存储分配 10.4 函数指针 10.5 main函数的参数
C语言程序设计教程 单位:德州学院计算机系.
第8章 指针 21世纪高等学校精品规划教材.
第 6 章 第 6 章 指 针 指 针 1.
C语言程序设计.
C语言基础——指针的高级应用 Week 05.
第6章 指针 6.1 指针的概念 6.2 变量与指针 6.3 数组与指针 6.4 字符串与指针 6.5 函数与指针 6.6 返回指针值的函数
6.4 字符串与指针 1. 用字符数组存放一个字符串.
第六节 二维数组和指针 二维数组的地址 对于一维数组: (1)数组名array表示数组的首地址, 即array[0]的地址;
8.1 指针的概念 8.2 指针变量 8.3 指针变量的基础类型 8.4 指针的运算 8.5 指针与一维数组 8.6 指针应用实例
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
第九章 指针 目录 指针与指针变量的概念 变量的指针和指向变量的指针变量 数组的指针和指向数组的指针变量
第5章 函数与模块化设计 学习目的与要求: 掌握函数的定义及调用方法 理解并掌握参数的传递方法 理解函数的嵌套与递归调用
4.3函数 4.3.1函数的概念及定义 1、函数的概念: 可以被其它程序调用具有 特定功能的一段相对独立的 程序(模块),称函数。
指 针 为什么要使用指针 指针变量 指针与数组 返回指针值的函数 动态内存分配 通过指针引用字符串 指向函数的指针 小 结 习 题.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
目录 10.1 指针的基本概念 10.2 指向变量的指针变量 10.3 指向数组的指针变量 10.4 指向函数的指针变量和指针型函数
第八章 指 针 8.1 指针的概念与定义 8.2 指针作函数参数 8.3 指针与数组 8.4 指针与函数 8.5 复杂指针.
第 十 章 指 针.
项目六 用指针优化学生成绩排名 项目要求 项目分析
第7章 间接访问—指针 指针的概念 指针运算与数组 动态内存分配 字符串再讨论 指针作为函数参数和返回值 指针数组与多级指针
Chap 8 指针 8.1 寻找保险箱密码 8.2 角色互换 8.3 冒泡排序 8.4 电码加密 8.5 任意个整数求和*
C语言程序设计 李祥.
辅导课程六.
第8章 善于利用指针 8.1 指针是什么 8.2 指针变量 8.3 通过指针引用数组 8.4 通过指针引用字符串 8.5 指向函数的指针
第8章 善于利用指针 8.1 指针是什么 8.2 指针变量 8.3 通过指针引用数组 8.4 通过指针引用字符串 8.5 指向函数的指针
二维数组的指针表示 与复杂的指针例子 专题研讨课之三.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
C语言程序设计基础 第8章 指针 刘新国.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
第8章 指针.
第六章 指针 指针的概念 指针的运算 指向变量的指针 指向数组的指针 指向函数的指针 二级指针 主讲:李祥 时间:2015年10月.
第八章 使用指针.
第十章 指针.
欲穷千里,更上层楼 第十章 指 针 指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构; 能很方便地使用数组和字符串; 并能象汇编语言一样处理内存地址,从而编出精练而高效的程序。指针极大地丰富了C语言的功能。 学习指针是学习C语言中最重要的一环,
第五章 习题课 电子信息与计算机科学系 曾庆尚.
9.1 地址、指针和变量 9.2 指针运算 9.3 指针与数组 9.4 函数与指针 9.5 程序综合举例 9.6 上机实训.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
C语言大学实用教程 第7章 指针 西南财经大学经济信息工程学院 刘家芬
函数 概述 模块化程序设计 基本思想:将一个大的程序按功能分割成一些小模块, 特点: 开发方法: 自上向下,逐步分解,分而治之
指针 几个概念:  指针也是一种数据类型,具有指针类型的变量,称为指针变量。
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
第6讲 指针与引用 6.1 指针 6.2 引用.
<编程达人入门课程> 本节内容 内存的使用 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群: ,
C语言程序设计 第一章 数据类型, 运算符与表达式 第二章 顺序程序设计 第三章 选择结构程序设计 第四章 循环控制 第五章 数组.
第六章 指针 C++程序设计中使用指针可以: 使程序简洁、紧凑、高效 有效地表示复杂的数据结构 动态分配内存 得到多于一个的函数返回值.
第6章 指针 6.1 指针的概念 6.2 变量与指针 6.3 数组与指针 6.4 字符串与指针 6.5 函数与指针 6.6 返回指针值的函数
成绩是怎么算出来的? 16级第一学期半期考试成绩 班级 姓名 语文 数学 英语 政治 历史 地理 物理 化学 生物 总分 1 张三1 115
第十章 指针 指针是C语言的重要概念,是C语言的特色,是C语言的精华。 10.1 地址和指针的概念 内存中的每一个字节都有一个地址。
第4章 Excel电子表格制作软件 4.4 函数(一).
第九节 赋值运算符和赋值表达式.
第8章 善于利用指针 8.1 指针是什么 8.2 指针变量 8.3 通过指针引用数组 8.4 通过指针引用字符串 8.5 指向函数的指针
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
C程序设计.
本节内容 C语言的汇编表示 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
C语言程序设计 第8章 指针.
第九章 指针 C程序设计中使用指针可以: 使程序简洁、紧凑、高效 有效地表示复杂的数据结构 动态分配内存 得到多于一个的函数返回值.
第八章 指 针 北京邮电大学出版社.
第7章 地址和指针 7.1 地址和指针的概念 7.2 指针变量的定义和指针变量的基类型 7.3 给指针变量赋值 7.4 对指针变量的操作
Presentation transcript:

第6章 指针 学习目的与要求: 了解指针的概念和相关术语 熟练掌握指向变量、数组和字符串的指针变量的使用方法 了解指向函数的指针变量 第6章 指针 学习目的与要求: 了解指针的概念和相关术语 熟练掌握指向变量、数组和字符串的指针变量的使用方法 了解指向函数的指针变量 掌握返回指针值的函数 熟练掌握指针数组 了解二级指针的定义与使用

基本内容 指针简介 指针与数组 指针与字符串 指向函数的指针 返回指针值的函数 指针数组和多重指针 动态内存分配 本章小结

指针简介 指针是C语言里最强大的工具之一,正确灵活地运用指针,可以有效地表示和使用复杂的数据结构;并可动态分配存储空间,更好地利用内存资源 直接访问:按变量地址存取变量的值的方式。 间接访问:通过存放地址的变量的值(即地址)来存取最 终要访问的变量的值的方式。 指 针:即地址,反映访问变量的指向关系。

变量访问示例 2004 2000 2008 3010 int i,j,k,*p ; i=3; j=6; k=i+j; i 3 j 6 k 9 直接访问 2004 2000 2008 3010 int i,j,k,*p ; i=3; j=6; k=i+j; i 3 j 6 k 9 p=&i p 2000 间接访问

指针变量的定义 在C语言中,地址被称作指针。因此,变量的地址即称变量的指针。可以存储地址的变量称为指针变量 。 定义指针变量的一般形式为: 类型名 *指针变量名[=初始值]; 例如:int a=5,*p; p=&a;

指针变量说明 在定义指针变量时必须指定基类型。例如:int *p; 指针变量名前面的“*”号,表示该变量pointer是一个指针变量。 指针变量中只能存放地址。不要试图将一个整数赋给一个指针变量。 例如:int a=5; int *p=&a; 一般情况下,p作为指针变量名的第一个字母,以便于区分普通变量和指针变量。 例如:int *p=1000; × 注意区分“指针”和“指针变量”两个概念。

指针变量的引用 指针变量定义之后,必须将其与某个变量的地址相关联才能使用。可以通过指针运算符(*)访问指针变量所指的变量的值。 输入一个整数赋给某个变量,输出该变量的值和地址,并用指针变量完成对变量的操作。 #include <stdio.h> int main() { int x,*pointer=NULL; printf("输入一个整数:"); scanf("%d",&x); printf("x的值为:%d\n",x); //输出变量x的值 printf("x的地址为:%x\n",&x); //十六进制形式输出地址

指针变量的引用 通过上面的例子可以看出,对指针变量的引用主要有以下三种方式: pointer=&x; printf("指针变量pointer所指存储单元的值为:%d\n",*pointer); printf("指针变量pointer的值为:%x\n",pointer); printf("指针变量pointer的地址为:%x\n",&pointer); printf("指针变量pointer所占的字节数为:%d\n",sizeof(pointer)); return 0; } 通过上面的例子可以看出,对指针变量的引用主要有以下三种方式: (1)给指针变量赋值。如:pointer=&x; (2)引用指针变量指向的变量。如:printf("%d\n",*pointer); (3)引用指针变量的值。如:printf("%x\n",pointer);

指针变量作为函数参数 函数的参数不仅可以是整型、实型和字符型等基本数据类型,还可以是指针类型。它的作用是将一个变量的地址传送到另一个函数中。 输入两个整数,调用交换函数实现两数的交换。 #include <stdio.h> void swap1(int x, int y); void swap2(int *x, int *y); void swap3(int *x, int *y); int main() { int a,b; int *pt1,*pt2; printf("输入两个整数:\n"); scanf("%d%d",&a,&b); printf("交换前:a=%d, b=%d\n",a,b);

指针变量作为函数参数 swap1(a,b); printf("执行swap1后:a=%d, b=%d\n",a,b); pt1=&a; pt2=&b; swap2(pt1,pt2); printf("执行swap2后:a=%d, b=%d\n",a,b); swap3(pt1,pt2); printf("执行swap3后:a=%d, b=%d\n",a,b); return 0; }

指针变量作为函数参数 值传递 void swap1(int x,int y) { int temp; temp=x; x=y; y=temp; } 特点:被调函数的值发生变化,但主调函数的值没变。 地址传递 void swap2(int *x,int *y) { int temp; temp=*x; *x=*y; *y=temp; } 特点:被调函数的值发生变化,主调函数的值也发生变化。 地址传递 void swap3(int *x,int *y) { int *temp; temp=x; x=y; y=temp; } 特点:虽然是地址传递,但在被调函数中交换的是地址,主调函数的值没有变化。

指针变量作为函数参数变量变化示意图 调用swap1函数,进行的是值传递,变量在函数调用之前、调用时的参数传递、调用中和调用后值的变化如下图所示。

指针变量作为函数参数变量变化示意图 调用swap2函数,进行的是地址传递,变量在函数调用之前、调用时的参数传递、调用中和调用后值的变化如下图所示。

指针变量作为函数参数变量变化示意图 调用swap3函数,进行的是地址传递,变量在函数调用之前、调用时的参数传递、调用中和调用后值的变化如下图所示。

基本内容 指针简介 指针与数组 指针与字符串 指向函数的指针 返回指针值的函数 指针数组和多重指针 动态内存分配 本章小结

指针与数组的关系 不同类型的变量在内存中都有一个具体的地址,数组也是一样,并且数组中的元素在内存中是连续存放的,数组名代表数组的首地址。而指针存放地址的值,因此,既然指针可以指向普通变量,当然也可以指向数组或数组元素,指向数组的指针称为数组指针。事实上,在C语言中,把指针和数组当作同一个概念看待,数组名是指针,指针也是数组,可以认为数组名是常量指针。

指向一维数组的指针 C语言规定,数组名就是数组的首地址,例如: int a[10]={1,2,3,4,5,6,7,8,9,10}; int *pa; //数组名是数组的首地址,指针pa指向数组的首地址 pa=a; //把a[0]元素的地址赋给指针变量pa,指向数组的首地址 pa=&a[0];

指向一维数组的指针 下面的操作是等价的: int a[10],*p=a; 等价于:int a[10],*p; p=a;

指向数组的指针举例 输入10个整数存入一维数组a中,要求输出该数组中所有元素的值。 #include <stdio.h> int main() { int i,a[10],*p; printf("输入十个整数:\n"); for(i=0; i<10; i++) scanf("%d", &a[i]); printf("使用下标法输出数组元素\n"); for(i=0;i<10;i++) printf("%5d",*(a+i)); printf("\n");

指向数组的指针举例 p=a; //将数组的首地址赋给指针变量 printf("使用指针法输出数组元素\n"); for(;p<a+10; p++) printf("%5d",*p); printf("\n"); return 0; }

指向数组的指针说明 数组名不代表整个数组,而是数组第1个元素的地址,即数组的首地址。 “p=a;”不是把整个数组a全部送入p中,而是把数组a的首地址送入p中。 若指针变量p指向数组a的首地址,则一维数组a的地址用p、a和&a[0]来表示是等价的,数组a中下标为i的元素可以分别用*(a+i)、*(p+i)、a[i]和p[i]来引用。

指向数组的指针说明 当指针变量指向数组元素时,可以对指针变量进行一些加减运算或自增、自减运算。 int a[10]={1,2,3,4,5,6,7,8,9,10}; int *p,*q,*r; p=a+3; //p指向数组a中第4个元素a[3]的首地址 q=a+9; //q指向数组a中最后一个元素a[9]的首地址

指向数组的指针说明 自增、自减运算说明,以自增(++)为例: ①p++和++p:表示p的值加1,运行后p指向数组元素a[4]的首地址。 ②*p++和*(p++):表示取出p所指数组元素a[3]的值4,然后p指向数组元素a[4]的首地址。 ③(*p)++:*p表示p所指变量的值,即a[3]的值4,“(*p)++”也是a[3]++,所以操作后a[3]的值变成5,指针变量p仍然指向数组元素a[3]的首地址。 ④*(++p)和*++p:表示p指向下一个数组元素的首地址,即a[4]的首地址,然后取其值5。*(++p)和*++p功能相同。

指向数组的指针说明 数组名是地址常量,在内存中的位置是不会改变的。 int a[10]={1,2,3,4,5,6,7,8,9,10}, *p=a; p++; √ a++; × 指向数组的指针和指向简单变量的指针是不同的。前者可以通过指针运算引用到数组中的每个元素,而后者却不能通过指针引用到其它变量。 由于对指向数组元素的指针变量可进行加减运算,使得其值在程序运行期间会改变,因此使用指针变量时要时刻注意指针变量的当前值,否则程序会出现意想不到的结果。 int a[10],b=3,*pt1,*pt2; pt1=a; //指针变量pt1指向数组a的首地址 pt1+=5; //指针变量pt1指向数组a的第5个元素的首地址 pt2=&b; //指针变量pt2指向变量b的首地址 pt2++; //该语句没有意义

指针变量错误使用的例子 #include <stdio.h> int main() { int a[10],i,*p; p=a; printf("输入十个整数:\n"); for(i=0;i<10;i++) scanf("%d",p++); printf("输出结果为:\n"); for(i=0;i<10;i++) { printf("%12d", *p++); if((i+1)%5==0) printf("\n"); } return 0; 使用前要重新赋值

指向多维数组的指针 用指针变量可以指向一维数组中的元素,也可以指向多维数组中的元素,在C语言中,对于二维数组而言是按行存储的。例如:int a[3][4],在内存中的存储形式如右图所示。 对于二维数组而言,数组名同样代表着数组的首地址。根据二维数组的特性,数组a可以看成是由3个一维数组a[0]、a[1]、a[2]构成的,而每个一维数组就是二维数组的一行(含有4个元素)。

指向多维数组的指针 对于二维数组a,不存在a、a[0]、a[1]、a[2]的存储空间,C系统不给它们分配内存,只分配12个整数的内存空间。事实上,a、a[0]、a[1]、a[2]都是指针常量。对于a[i],如果a是一维数组,则a[i]代表数组a的第i个元素,它是一个变量且有值,并且系统会给该元素分配存储空间。若a是二维数组,则a[i]代表一维数组,它是一个指针常量,系统不给它分配存储空间,它仅仅是一个地址。

指向多维数组的指针 对于二维数组而言,有行地址和列地址之分。二维数组a的首地址有三种表示:a、a[0]、&a[0][0],但它们之间存在着差异。假设指针变量p指向数组的首地址,若指向二维数组a的行地址,则p+1表示指向第1行元素的首地址(即a[1]的地址);若指向二维数组a的列地址,则p+1表示指向第0行第1列元素的首地址(即a[0][1]的地址)。

若改成“p<a+3*4;”,结果会怎样? 多维数组指针——指向数组元素的指针变量 用指向数组元素的指针变量输出二维数组的值。 #include <stdio.h> int main() { int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}, *p; for(p=a[0]; p<a[0]+3*4;p++) { printf("%5d",*p); if((p-a[0]+1)%4==0) printf("\n"); } return 0; 若改成“p<a+3*4;”,结果会怎样?

多维数组指针——指向一维数组的指针变量 C语言提供了一个指向一维数组的指针,它具有与数组名相同的特征,可以更方便地用指针来处理数组。 指向一维数组的指针变量的定义形式如下: 数据类型 (*指针变量名)[N]; 其中,N是整型常量,表示指针变量所指一维数组的元素个数。 例如: int a[3][4], (*p)[4], *ptr; ptr=a[0]; //ptr指向数组元素a[0][1]的首地址 p=a; //指向数组a的首地址,即a[0]的值

多维数组指针——指向一维数组的指针变量 #include <stdio.h> int main() { int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}, (*p)[4]; int i, j; p=a; for(i=0;i<3;i++) { for(j=0;j<4;j++) printf("%5d",*(*(p+i)+j)); //输出a[i][j]的值 printf("\n"); } return 0; 指针变量指向一维数组

指向数组元素的指针作函数参数 输入一组整数,使用直接插入排序法对其进行排序。 #include <stdio.h> #define N 10 void Input(int a[],int n) //输入n个整数,形参是数组名 { int i; for(i=0;i<n;i++) scanf("%d",&a[i]); } void Output(int *ptr,int n) //输出数组中的值,形参是指针变量 { int *ptr_end=ptr+n; for(;ptr<ptr_end;ptr++) printf("%5d",*ptr); printf("\n");

指向数组元素的指针作函数参数 void InsertSort(int *ptr, int n) {//直接插入排序,形参是指针变量 int *p,*q,*p_end,temp; p_end=ptr+n; for(p=ptr+1;p<p_end;p++) //n个元素经过n-1趟排序 if(*p<*(p-1)) { temp=*p; *p=*(p-1); for(q=p-2;q>=ptr&&temp<*q;q--) *(q+1)=*q; *(q+1)=temp; }

指向数组元素的指针作函数参数 int main() { int a[N], *p; printf("输入%d个整数:\n",N); Input(a, N); //实参是数组名 printf("排序前数组元素的值:\n"); Output(a, N); //实参是数组名 p=a; InsertSort(a, N); //实参是指针变量 printf("排序后数组元素的值:\n"); Output(a, N); //实参是指针变量 return 0; }

指向数组元素的指针作函数参数 归纳起来,用指针变量作为函数参数时,实参与形参的类型有以下几种对应关系,如下表所示。

指向数组的指针作函数参数 一个班有n个学生,每个学生有4门课,设计函数计算总平均分以及查找有两门以上(包括两门)成绩在85分以上的学生,并输出满足条件的学生。 #include <stdio.h> #define N 40 float Average(float *ps,int n) {//计算总平均分 float sum=0,aver,*p_end=ps+n-1; while(ps<=p_end) sum+=*ps++; aver=sum/n; return aver; } 指向数组元素的指针变量

指向数组的指针作函数参数 void Search(float (*p)[4],int n,int s[],int *q) {//查找两门以上课程的成绩在85分以上的学生 int i,j,k=0,count; for(i=0;i<n;i++) { count=0; for(j=0;j<4;j++) if(*(*(p+i)+j)>85) count++; if(count>=2) s[k++]=i; } *q=k; //统计满足条件的学生人数 指向数组元素的指针变量

指向数组的指针作函数参数 void Output(float (*p)[4],int s[],int m) {//输出满足条件的学生的信息,其中m表示数组s的大小, //n表示所有学生 int i,j,k; for(k=0;k<m;k++) { i=s[k]; for(j=0;j<4;j++) printf("%7.0f",*(*(p+i)+j)); printf("\n"); } int main() { float score[N][4],*ps,aver; int i,j,m,n,s[N]={0}; //s数组统计成绩在85分以上学生数

指向数组的指针作函数参数 printf("输入学生人数(不超过40):\n"); scanf("%d",&n); for(i=0;i<n;i++) for(j=0;j<4;j++) scanf("%f",&score[i][j]); ps=score[0]; //ps为指向数组元素的指针变量 aver= Average(ps,4*n); printf("\n%d个学生的总平均分为:%5.1f\n",n,aver); m=0; Search(score,n,s,&m); printf("\n有两门以上的课程成绩在85分以上的学生:\n"); Output(score,s,m); return 0; }

基本内容 指针简介 指针与数组 指针与字符串 指向函数的指针 返回指针值的函数 指针数组和多重指针 动态内存分配 本章小结

指向字符串的指针 C语言中没有字符串变量,若要存储字符串,可以使用字符数组。除了用字符数组保存并标识字符串外,还可以使用字符类型指针指向一个字符串,从而使用指针访问它所指的字符串。 例如: char *sp="I am a student.", *sq; char str[]="I am a boy."; sq=str;

指针与数组的关系 指针变量和数组名存储字符串 执行完sq=str后的情况

指向字符串的指针应用举例 使用指针变量实现字符串的连接。 #include <stdio.h> int main() { char str1[80],str2[40]; char *ps1=str1,*ps2=str2; printf("输入第一个串:\n"); gets(str1); printf("输入第二个串:\n"); gets(str2); while(*ps1++!='\0'); ps1--; //将ps1指向第一个串的结束标志 while(*ps1++=*ps2++); //逐个字符进行拷贝 ps1=str1; //重新确定指针指向 printf("连接后的新字符串为:\n"); puts(ps1); return 0; }

指向字符串的指针变量说明 指向字符串的指针变量,它只存放字符串的首地址,而不是存放整个字符串,但它可以指向任何字符串。字符数组名是一个常量,不能将一个字符串赋给一个字符数组。 例如: char str1[20]="I am a teacher.",str2[20]; char *ps1="I am a student.",*ps2; ps="I love China."; × str1="I love China."; √ str2=str1; × ps2=ps1; √ 不论字符串指针还是字符数组,都可以访问其分量,但访问时要十分小心,要注意操作的正确性。

字符数组与字符指针变量的比较

基本内容 指针简介 指针与数组 指针与字符串 指向函数的指针 返回指针值的函数 指针数组和多重指针 动态内存分配 本章小结

指向函数的指针 指针可以作为函数参数,进行地址传递。由于函数名就是函数的入口地址,因此,指针还可以指向函数。 指向函数的指针变量的定义形式如下: 类型名 (*指针变量名)(函数参数表列); 注意:此处的括号一定不能省略,否则就成了返回指针的函数了。函数参数表列表示函数形参的类型。 例如:int (*pf)(int,int); 表示pf是一个指向函数入口的指针变量,该函数有两个整型类型的参数,其返回值是整型类型。

指向函数的指针应用举例 利用指向函数的指针求两个数的最大值和最小值 。 #include <stdio.h> int max(int x, int y) { return x>y?x:y; } int min(int x, int y) return x<y?x:y; int main() { int a,b,c; int (*pf)(int,int); printf("输入两个整数:\n");

指向函数的指针应用举例 scanf("%d%d",&a,&b); c=max(a,b); //通过函数名调用函数max printf("a=%d, b=%d, max=%d\n",a,b,c); pf=max; //将函数的入口地址赋给pf c=(*pf)(a,b); //通过指针变量调用函数max c=min(a,b); //通过函数名调用函数min printf("a=%d, b=%d, min=%d\n",a,b,c); pf=min; //将函数的入口地址赋给pf,pf重新赋值 c=(*pf)(a,b); //通过指针变量调用函数min return 0; }

指向函数的指针使用说明 定义指向函数的指针变量,并不意味着这个指针变量可以指向任何函数,它只能指向在定义时指定的类型的函数。 如果要用指针调用函数,必须先使指针指向该函数。 给函数指针变量赋值时,只需给出函数名而不必给出参数。 如上例中,“pf=max;”表示把函数max的入口地址赋给了指针变量pf。 用函数指针变量调用函数时,只需将(*指针变量)代替函数名即可,在(*指针变量)之后的括号中根据需要写上实参。 如上例中,“pf=max;”是将函数的入口地址赋给pf,与实参和形参的结合问题无关。 在一个程序中,一个指针变量可以先后指向同类型的不同函数,但函数的返回值类型必须相同。 如上例中,c=(*pf)(a,b);

指向函数的指针变量作为函数参数 利用指向函数的指针变量作函数参数,求两个整数的和、差以及乘积。 #include <stdio.h> int Sum(int x, int y); int Difference(int x, int y); int Product(int x, int y); int func(int x, int y, int (*pf)(int,int)); int main() { int a,b,c; printf("输入两个整数a和b:"); scanf("%d%d",&a,&b); printf("%d+%d=",a,b); c=func(a,b,Sum); printf("%d\n",c);

指向函数的指针变量作为函数参数 printf("%d-%d=",a,b); c=func(a,b, Difference); printf("%d\n",c); printf("%d*%d=",a,b); c=func(a,b, Product); return 0; } int Difference(int x, int y){ return x-y; } int Product(int x, int y){ return x*y; } int Sum(int x, int y){ return x+y; } int func(int x, int y, int (*pf)(int,int)){ return (*pf)(x,y); }

基本内容 指针简介 指针与数组 指针与字符串 指向函数的指针 返回指针值的函数 指针数组和多重指针 动态内存分配 本章小结

返回指针的函数 函数的返回值表示函数的计算结果,其类型除了可以是系统定义的简单数据类型外,还可以返回指针型的数据。 指针函数定义的一般形式为: 类型名 *函数名(参数表列); 例如:int *fun(int x,int y) { …… } 表示fun是一个返回指针值的指针型函数,它返回的指针指向一个整型数据。

指针函数的应用举例 从键盘输入一个字符,判断在给定的字符串中是否存在该字符,若存在,给出该字符在字符串中第一次出现的位置。 #include <stdio.h> char *search(char *ps, char ch); int main() { char str[80],*p,ch; printf("输入一个字符串:\n"); gets(str); printf("输入要查找的字符:"); ch=getchar(); p=search(str,ch);

指针函数的应用举例 if(p){ printf("字符串的首地址是%x\n",str); printf("字符%c的地址是%x\n",ch,p); } else printf("字符串中没有字符%c\n",ch); return 0; char *search(char *ps, char ch) { while(*ps!='\0') if(*ps==ch) return ps; else ps++;

基本内容 指针简介 指针与数组 指针与字符串 指向函数的指针 返回指针值的函数 指针数组和多重指针 动态内存分配 本章小结

指针数组 指针数组也是一种数组,数组中的每一个数组元素均为指针类型数据。即每个元素都存放一个地址,相当于一个指针变量。 定义一维指针数组的一般形式为: 类型名 *数组名[数组长度]; 例如,int *pi[10]; //定义一个大小为10的指针数组

指针数组应用举例 使用指针数组处理字符串。 #include <stdio.h> int main() { char str[3][10]={"I", "love", "China"}; char *ps[3]={str[0],str[1],str[2]}; int i,j; printf("通过数组元素输出字符串:\n"); for(i=0;i<3;i++) { for(j=0;str[i][j]!='\0'; j++) putchar(str[i][j]); printf(" "); } printf("\n");

指针数组应用举例 printf("通过一维数组输出字符串:\n"); for(i=0;i<3;i++) printf("%s ",str[i]); printf("\n"); printf("通过指针数组输出字符串:\n"); printf("%s ",*(ps+i)); return0; }

指针数组使用说明 指针数组中数组元素的值虽然是指针,但在使用前应该对其进行赋值,否则数组元素的值是随机地址,直接对其操作会产生错误。 如果用二维数组存放字符串,并且采用指针数组存放每个串的首地址(即每行的首地址),那么对字符串的排序有两种方法:一是交换指针数组的数组元素的值,一种是对字符串按字典序重新进行排列 。 例如下列程序段: int i; char *ps[4]; for(i=0;i<4;i++) gets(ps[i]); puts(ps[i]);

使用指针数组处理字符串应用举例 有n个字符串存储在二维数组中,对这n个字符串进行排序。 #include <stdio.h> #include <string.h> void Sort1(char *ps[], int n); void Sort2(char *ps[], int n); void Input(char *ps[], int n); void Output(char *ps[], int n); int main() { char str[10][80],*pc[10]; int n,i; printf("输入字符串的个数n(n<10):"); scanf("%d",&n); for(i=0;i<n;i++) pc[i]=str[i]; //指针数组pc初始化

使用指针数组处理字符串应用举例 printf("输入%d个字符串\n",n); Input(pc,n); Sort1(pc,n); printf("排序后字符串的顺序:\n"); Output(pc,n); printf("重新输入%d个字符串\n",n); Sort2(pc,n); return 0; }

使用指针数组处理字符串应用举例 void Input(char *ps[], int n) { int i; char ch; for(i=0;i<n;i++) scanf("%s",ps[i]); ch=getchar(); //屏蔽最后一个换行符 } void Output(char *ps[], int n) printf("%10s",ps[i]); printf("\n");

使用指针数组处理字符串应用举例 void Sort1(char *ps[], int n) {//采用冒泡排序法对字符串进行排序 //修改指针数组的值 int i,j; char *p; for(i=0;i<n-1;i++) for(j=0;j<n-i-1;j++) if(strcmp(ps[j],ps[j+1])>0) { p=ps[j]; ps[j]=ps[j+1]; ps[j+1]=p; }

使用指针数组处理字符串应用举例 void Sort2(char *ps[], int n) {//采用冒泡排序法对字符串进行排序 //将字符串按字典序重新排列 int i,j; char p[80]; for(i=0;i<n-1;i++) for(j=0;j<n-i-1;j++) if(strcmp(ps[j],ps[j+1])>0) { strcpy(p, ps[j]); strcpy(ps[j],ps[j+1]); strcpy(ps[j+1],p); }

字符串排序图示 调用Sort1函数排序前后数组元素值的变化情况 调用Sort2函数排序前后数组元素值的变化情况

多级指针 如果一个指针变量存放的是另一个指针变量的地址,则称这个指针变量为二级指针变量,也称为指向指针的指针。 二级指针定义的一般形式为: 类型名 **指针变量名; 例如: int a=3,*pa, **ppa; pa=&a; ppa=&pa; 三者之间的关系

多级指针应用举例 利用二级指针变量,访问字符串。 #include <stdio.h> int main() { char str[][20]={"Qingdao", "Yantai", "Jinan", "Weifang"}; char *ps[]={str[0],str[1],str[2],str[3]}; char **pps=ps; int i; for(i=0;i<4;i++) printf("%10s",*pps++); printf("\n"); return 0; }

main函数的参数 在C语言中,main函数也可以带参数,参数的个数最多3个,并且参数名(习惯上)、参数顺序和参数类型是固定的。带有main函数参数的程序,不适合在集成环境下运行,而要在命令行下执行,其参数就来自命令行下运行该程序时输入的相关信息。

main函数的参数 参数形式如下: void main(int argc, char *argv[], char *env[]) 命令行的一般格式为: 文件名 参数1 参数2 … 参数n 注意:各参数之间用空格隔开。

带参数 main函数举例 编写程序,输出命令行的参数内容。 #include <stdio.h> int main(int argc, char *argv[]) { int i; printf("argc=%d\n",argc); printf("command name: %s\n",argv[0]); for(i=1;i<argc;i++) printf("parameter %d: %s\n",i,argv[i]); return 0; }

基本内容 指针简介 指针与数组 指针与字符串 指向函数的指针 返回指针值的函数 指针数组和多重指针 动态内存分配 本章小结

计算机内存描述 在程序执行期间分配的内存,该内存区域称为堆(heap),堆中的内存是由程序员控制的,由程序员跟踪所分配的内存何时不再需要,并释放这些空间,以便以后再次使用。 对内存的动态分配是通过系统提供的库函数来实现的,主要有:malloc、calloc、free和realloc这4个函数,这4个函数都包含在头文件“stdlib.h”中。

动态申请内存——malloc() 函数 在运行时分配内存的最简单的标准库函数是malloc(),其函数原型为: void *malloc(unsigned int size); 作用:在内存的动态存储区中分配一个长度为size(非负数)的连续空间。 返回值:分配区域的第一个字节的地址。失败时,返回空指针(NULL)。 注意:指针的基类型为void,即不指向任何类型的数据,只提供一个地址。若要返回具体的数据类型,必须进行强制类型转换。 例如:int *p; p= (int*)malloc(32);

malloc() 函数应用举例 从键盘输入n个整数存入动态申请的一个连续存储空间中,并输出这n个整数。 #include <stdio.h> #include <stdlib.h> int main() { int i, n, *p; scanf("%d",&n); p=(int*)malloc(n*sizeof(int)); for(i=0;i<n;i++) scanf("%d",p+i); printf("输出这%d个整数:\n",n); printf("%5d",*(p+i)); printf("\n"); return 0; }

动态申请内存——calloc() 函数 calloc函数。该函数与malloc函数相比有两个优点。第一,它把内存分配为给定大小的数组;第二,它初始化了所分配的内存,所有的位都是0。其函数原型为: : void *calloc(unsigned n, unsigned size); 功能:在内存的动态存储区中分配n个长度为size的连续空间。 例如:int *p; p= (int*)calloc(10,sizeof(int));

释放动态分配的内存 在动态分配内存时,应在不需要该内存时释放它们。堆上分配的内存会在程序结束时自动释放,但最好在使用完这些内存后立即释放。 要释放用malloc函数或calloc函数分配的内存,可以使用free函数,其函数原型为: : void free(void *p); 功能:释放指针变量p所指向的动态空间,使这部分空间重新被其它变量使用。

重新分配内存——realloc() 函数 如果通过malloc和calloc动态分配大小为n的连续的存储空间,若要改变其大小,可以用realloc函数重新分配,其函数原型为: void *realloc(void *p, unsigned size); 功能:重新分配由malloc和calloc申请的存储空间的大小。

realloc() 函数应用举例 输入n个整数存入动态分配的存储空间中,再输入m个整数,将其追加到该组数中。 #include <stdio.h> #include <stdlib.h> int main() { int i, n,m, *p; printf("输入整数个数:"); scanf("%d",&n); p=(int*)calloc(n,sizeof(int)); printf("输入%d个整数:\n",n); for(i=0;i<n;i++) scanf("%d",p+i); printf("输出这%d个整数:\n",n); printf("%5d",*(p+i)); printf("\n");

realloc() 函数应用举例 printf("输入要插入整数个数:"); scanf("%d",&m); printf("再输入%d个整数:\n",m); p=(int*)realloc(p,(m+n)*sizeof(int)); for(;i<m+n;i++) scanf("%d", (p+i)); printf("输出新的一组数:\n"); for(i=0;i<m+n;i++) printf("%5d", *(p+i)); printf("\n"); free(p); return 0; }

使用动态分配的内存的基本规则 避免分配大量的小内存块,分配许多小的内存块比分配几个大的内存块的系统开销大。 仅在需要时分配内存,使用结束后就释放它。 在释放内存之前,确保不会无意中覆盖堆上分配的内存的地址,否则程序会出现内存泄露。

基本内容 指针简介 指针与数组 指针与字符串 指向函数的指针 返回指针值的函数 指针数组和多重指针 动态内存分配 本章小结

本章小结 指针是C语言的精华,其本质体现在对内存的操作。 指针有:指向变量的指针,指向数组的指针,指向字符串的指针,指向函数的指针,指向指针的指针,返回指针值的函数和指针数组。 对于指向任何数据类型的指针变量,要注意的是它也是一种变量,在未赋值前其值是一个不确定的地址,若要正确使用它,引用前首先给其赋值。 参数的传递有值传递和地址传递两种,而指针就是地址,通过指针变量作为函数参数,实参和形参共占同一段存储单元。即可对实参的值进行修改,又可节省存储空间,提高程序效率。

本章小结 指向数组的指针可以进行关系运算和加减运算。与整数进行运算时,每单位增量,所移动的是该指针类型所占的字节数。 函数名是函数的入口地址,函数调用时,除了可以通过函数名外,还可以通过指向函数的指针变量来实现。利用指向函数的指针变量调用函数,可以通过该变量调用具有相同返回类型的不同函数。