C语言程序设计 李祥.

Slides:



Advertisements
Similar presentations
电子成绩单项目实现.
Advertisements

第10章 结构体与链表 本章要点: 结构体类型与结构体变量的定义 结构体变量的引用与初始化 结构体数组 链表处理 共用体类型和枚举类型
第一章 C语言概述 计算机公共教学部.
C语言基础——指针的高级应用 Week 05.
第九章 指针 目录 指针与指针变量的概念 变量的指针和指向变量的指针变量 数组的指针和指向数组的指针变量
第九章 系 统 安 全 性 9.1 结构体 9.2 结构体型数组  9.3 结构体型指针 9.4 内存的动态分配 9.5 共用体
第7章 结构体、联合体和枚举类型 本章导读 本章主要知识点 《 C语言程序设计》 (Visual C++ 6.0环境)
C语言程序设计 第十二章 位运算.
第5章 函数与模块化设计 学习目的与要求: 掌握函数的定义及调用方法 理解并掌握参数的传递方法 理解函数的嵌套与递归调用
第六章 数 组 主讲教师 贾月乐 联系电话:
C程序设计 第9章 自定义数据类型 主讲教师: 鲁 萍 西安建筑科技大学 理学院.
選擇排序法 通訊一甲 B 楊穎穆.
补充内容 结构体 概述 定义结构体类型和定义结构体变量 结构体变量的引用 结构体变量的初始化 指针与结构体 用typedef定义类型的别名.
编译原理与技术 类型检查 2018/11/21 《编译原理与技术》-类型检查.
C 程式設計— 指標.
目录 10.1 指针的基本概念 10.2 指向变量的指针变量 10.3 指向数组的指针变量 10.4 指向函数的指针变量和指针型函数
项目六 用指针优化学生成绩排名 项目要求 项目分析
结构体和共用体 2 梁春燕 华电信息管理教研室.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
Chap 9 结构 9.1 构建手机通讯录 9.2 结构变量 9.3 结构数组 9.4 结构指针.
第9章 自訂資料型態 – 結構 9-1 結構資料型態 9-2 結構陣列 9-3 指標與結構 9-4 動態記憶體配置 9-5 聯合資料型態
STRUCTURE 授課:ANT 日期:2010/5/12.
C语言程序设计基础 第9章 结构 刘新国.
第七章 函数 目录 有参的加法函数的开发 函数定义的一般形式 函数参数和函数的值 函数的调用
C++语言程序设计 C++语言程序设计 第四章 数组及自定义数据类型 C++语言程序设计.
第九章 结构体和共用体 结构体的定义 结构体的使用 共用体的定义 共用体的使用 主讲:李祥 时间:2015年10月.
计算概论 第十八讲 C语言高级编程 结构与习题课 北京大学信息学院.
Object-Oriented Programming in C++ 第一章 C++的初步知识
第12章 從C到C++語言 12-1 C++語言的基礎 12-2 C++語言的輸出與輸入 12-3 C++語言的動態記憶體配置
程式撰寫流程.
Chap 8 指针 8.1 寻找保险箱密码 8.2 角色互换 8.3 冒泡排序 8.4 电码加密 8.5 任意个整数求和*
第8章 善于利用指针 8.1 指针是什么 8.2 指针变量 8.3 通过指针引用数组 8.4 通过指针引用字符串 8.5 指向函数的指针
第五章 指针 5.1 指针的概念和定义 5.2 指针运算 5.3 指针和数组 5.4 字符串指针 5.5 指针数组 5.6 指向指针的指针
第13章 结构体的应用 13.1 了解由用户构造的数据类型 13.2 结构体类型说明及结构体变量 13.3 结构体数组
第9章 文件操作 文件 使用文件的目的 操作系统管理数据的基本单位 存储在外存储器上的数据的集合
第八章 使用指针.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
第十章 指针.
第三章 数据类型、运算符与表达式.
Struct結構 迴圈
第十章 用户自定义数据类型 目录 学生信息管理系统的开发 结构体数据类型的概述 结构体变量的使用 结构体数组
目录 9.1 结构体类型 9.2 共用体类型 9.3 枚举类型 9.4 类型声明符typedef 1.
第十章 结构体与链表 西安工程大学.
C语言概述 第一章.
C语言大学实用教程 第5章 函数与程序结构 西南财经大学经济信息工程学院 刘家芬
C语言复习3----指针.
第一章 程序设计和C语言 主讲人:高晓娟 计算机学院.
Main() { Dfas Asdfasf fasdfa } #include <stdio.h> void main( ) {
Chap 5 函数 5.1 计算圆柱体积 5.2 使用函数编写程序 5.3 变量与函数.
第十章 指针 指针是C语言的重要概念,是C语言的特色,是C语言的精华。 10.1 地址和指针的概念 内存中的每一个字节都有一个地址。
第一章 C语言概述 教师:周芸.
C语言程序设计 李祥 QQ:
C程序设计.
第九章 指针.
第二章 类型、对象、运算符和表达式.
C程序设计.
本节内容 指针类型.
第七章  数 组.
第4章 鏈結串列(Linked Lists) 4-1 動態記憶體配置-(6) 4-2 鏈結串列的基礎-(7)
第18讲 从C到C++ 计算机与通信工程学院.
C/C++基礎程式設計班 C語言入門、變數、基本處理與輸入輸出 講師:林業峻 CSIE, NTU 3/7, 2015.
第九章 指针 C程序设计中使用指针可以: 使程序简洁、紧凑、高效 有效地表示复杂的数据结构 动态分配内存 得到多于一个的函数返回值.
C/C++基礎程式設計班 陣列 講師:林業峻 CSIE, NTU 3/14, 2015.
第9章 C++程序设计初步 9.1 C++的特点 9.2 最简单的C++程序 9.3 C++的输入输出 9.4 函数的重载
第三章 流程控制 程序的运行流程 选择结构语句 循环结构语句 主讲:李祥 时间:2015年10月.
本节内容 指针类型 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
安排座位.
C语言基础学习 从外行到入门.
隨機函數.
Presentation transcript:

C语言程序设计 李祥

第十一章 指针(二) 目录 1 2 3 4 5 指针数组和指向指针的指针 指向函数的旨针和指向函数的指针变量 返回指针的函数 指向结构体类型数据的指针 5 动态存储分配函数

知识点要求: 技能要求: 教学要求 指针数组的概念 1 指向结构体指针变量的使用 2 3 1 2 动态分配函数的使用 掌握指向结构体的指针变量的应用 2 掌握动态分配函数的使用

注意:它与前面介绍的指向二维数组行的行指针变量的定义形式上的区别。 11.1 指针数组和指向指针的指针 注意:它与前面介绍的指向二维数组行的行指针变量的定义形式上的区别。 11.1.1 指针数组的概念及应用 指针数组是指数组元素均为指针类型的数组,即指针数组中的每一个元素都是指针变量。 指针数组的定义形式为: 类型标识符 *数组名[数组长度]; 例如,语句: int *p[5]; 定义了一个指针数组,数组名为p,共有5个元素,每个元素都是一个可以指向int型变量的指针变量。

11.1 指针数组和指向指针的指针 指针数组特别适合于用来处理指向若干个字符串的问题,它将使字符串的处理更加方便灵活。 例如,某班有若干个人,每个人都有一个姓名,我们可以采用二维字符数组来处理全班同学的花名册问题。定义一维字符指针数组并初始化如下: char *name[5]={“ZHANG XIAOHUA","WANG JUN","LU SHENG","ZHAO YICHENG","ZHOU YUAN"};

11.1 指针数组和指向指针的指针 char *name[5]={“ZHANG XIAOHUA","WANG JUN","LU SHENG","ZHAO YICHENG","ZHOU YUAN"};

【例11.1】 对花名册按姓名字母升序排序后输出 #include <stdio.h> void sort(char *name[ ],int n) { int i,j,minpost; char *t; for(i=0;i<n-1;i++) { minpost=i; for(j=i+1;j<n;j++) if(strcmp(name[minpost],name[j])>0) minpost=j; if(minpost!=i) { t=name[i]; name[i]=name[minpost]; name[minpost]=t; } }

void prn(char *name[ ],int n) { int i; for(i=0;i<n;i++) printf("%s\n",name[i]); } void main( ) { char *name[]={"ZHANG XIAOHUA","WANG JUN", "LU SHENG", "ZHAO YICHENG ","ZHOU YUAN"}; int count=5; sort(name,count); prn(name,count); return; 输出结果:

11.1 指针数组和指向指针的指针 11.1.2 用指针数组作main函数的形参 其中,argc是int型参数,它接受的值是命令行参数的个数;argv是指向char型的指针数组,它的每个数组元素接受的值分别是命令行各字符串参数的指针。 有些情况下,当程序开始执行时,希望通过命令行将某些参数传递给程序,以控制程序的执行,这时main函数就需要带参数,以便来接受命令行的参数。命令行的一般形式为: 命令名 参数1 参数2 … 参数n 带参数的main函数的一般格式如下: main( int argc, char *argv[]) { … }

11.1 指针数组和指向指针的指针 11.1.3 指向一维数组的指针数组 11.1.3 指向一维数组的指针数组 指向一维数组的指针数组是指该数组的元素均为指向一维数组的指针变量。指向一维数组的指针数组的定义形式为: 类型标识符 (* 数组名[数组长度])[一维数组长度]; 例如: 语句: int ( *p[5])[6];

【例11.2】 某班有4个学生,学4门课程,每个学生4门课程的成绩及总成绩已经给出,要求将他们按总成绩由高到低排序后输出。 #include <stdio.h> void main( ) { int score[4][6]={{9601,80,82,88,93,343}, {9602,86,54,95,57,292}, {9603,80,56,88,93,317}, {9604,95,89,77,96,357}}; int i, j, post, (*t)[6], (*p[4])[6]; for (i=0; i<4; i++) p[i]=score+i; 初始化指向一维数组的指针数组,使得p[i]分别指向score的每一行

for (i=0; i<=2; i++) { post=i; for (j=i+1; j<=3; j++) if ( *(*p[j]+5)> *(*p[post]+5)) post=j; if(post!=i) { t=p[i]; p[i]=p[post]; p[post]=t; } } printf("No.\tscore1\tscore2\tscore3\tscore4\ttotal\n"); for (i=0; i<4;i++) { for (j=0; j<6; j++) printf("%4d\t", *(*p[i]+j)); printf("\n"); } return; 输出结果:

11.1 指针数组和指向指针的指针 11.1.4 指向指针的指针 1. 指向指针的指针和指向指针的指针变量 假设有一个指向int型变量i的指针变量p,p的值是指针,它是变量i的指针&i; 指针变量p本身又有指针,即&p; 再定义一个指针变量b来指向指针变量p,b的值也是指针,它是指针变量p的指针&p。 则称指针变量b是一个指向指针的指针变量。如下图所示:

11.1 指针数组和指向指针的指针 指向指针的指针变量定义形式如下: 类型标识符 ** 变量名; 例如, 语句:int **b;

for (i=0;i<5;i++,b++) 【例11.3】 指向指针的指针变量的应用。 #include <stdio.h> void main( ) { char *name[]={ "ZHANG XIAOHUA","WANG JUN", "LU SHENG","ZHAO YICHENG ","ZHOU YUAN"}; char **b=name; //定义指向指针的指针变量 int i; for (i=0;i<5;i++,b++) printf("%c ",**b); printf("\n"); b=name; printf("%s\n", *b); //*b指向每个字符串 printf("\n"); return; } 输出结果:

11.1 指针数组和指向指针的指针 2.指向指针的指针数组 指向指针的指针数组是指数组元素为指向指针的指针类型的数组,即数组中的每一个元素都是指向指针的指针变量。指向指针的指针数组的定义形式为: 类型标识符 ** 数组名[数组长度]; 例如,语句: int **p[5];

11.2 指向函数的指针和指向函数的指针变量 11.2.1 函数的指针和指向函数的指针变量 11.2.1 函数的指针和指向函数的指针变量 指针不仅可以指向一般变量,也可以指向数组,还可以指向函数。 每一个函数都分配了一个入口地址,这个入口地址就称为函数的指针。 指向函数的指针变量的一般定义形式如下: 类型标识符(* 变量名)(); 例如,语句: int (*p) ( );

11.2 指向函数的指针和指向函数的指针变量 11.2.2 使用指向函数的指针变量来调用函数 11.2.2 使用指向函数的指针变量来调用函数 将某个函数的指针赋给指向函数的指针变量后,该指针变量就指向该函数,以后就可以通过该指针变量来调用该函数。 通过指向函数的指针变量调用所指向函数的一般调用形式为: (* 指针变量名)(实参表列);

11.2 指向函数的指针和指向函数的指针变量 例如,有一返回int型值的函数 int max(int a,int b),则: int (*p)( ); //定义指向函数的指针变量p p=max; //使指针变量p指向函数max z=(*p)(a,b); //通过指针变量p调用函数max 等价于: z=max(a,b);

11.2 指向函数的指针和指向函数的指针变量 11.2.3 指向函数的指针数组 指向函数的指针数组是指数组元素为指向函数的指针类型的数组,即数组中的每一个元素都是指向函数的指针变量。 指向函数的指针数组的定义形式为: 类型标识符(* 数组名[数组长度])( ); 例如,语句 int (*p[5])( );

11.3 返回指针的函数 11.3.1返回指针的函数 一个函数不仅可以返回一个整型值、字符值、实型值等,也可以返回一个指针型的值。这种返回指针的函数的一般说明形式如下: 类型标识符 *函数名(参数表) 例如: int *fun (int x,int y) { int *p; … return p; }

11.3 返回指针的函数 11.3.2 指向返回指针的函数的指针变量 11.3.2 指向返回指针的函数的指针变量 前面已经介绍了指向函数的指针变量和返回指针的函数是如何定义的。将它们结合起来使用,就得到指向返回指针的函数的指针变量。 它的一般定义形式为 类型标识符 *(* 变量名)( ); 例如: int * ( *p) ( );

11.3 返回指针的函数 11.3.3 指向返回指针的函数的指针数组 11.3.3 指向返回指针的函数的指针数组 把指向返回指针的函数的指针变量和指向函数的指针数组结合起来使用,就可得到指向返回指针的函数的指针数组。 它的一般定义形式为: 类型标识符 *(* 变量名[数组长度])(); 例如: int * (*p[4]) ( );

11.3 返回指针的函数 11.3.4 返回行指针的函数 把返回指针的函数和二维数组行指针的概念结合起来使用,就可得到返回行指针的函数的一般说明形式: 类型标识符( * 函数名(参数表))[数组长度] 例如: int ( * fun())[4] { int (*p)[4]; … return p; }

11.3 返回指针的函数 11.3.5 指向返回行指针的函数的指针变量 把指向函数的指针变量和返回行指针的函数结合起来使用,就可得到指向返回行指针的函数的指针变量的一般定义形式: 类型标识符(*(*变量名)())[数组长度]; 例如: int ( *(*p) ( ) )[4]; 定义了一个指针变量p,它可以指向一个函数,该函数将返回包含4个元素的行指针。

11.4 指向结构体类型数据的指针 结构体变量也有自己的指针,一个结构体变量的指针就是该变量所占据的内存段的起始地址。 可以设一个指针变量,用来指向一个结构体变量,此时该指针变量的值是结构体变量的起始地址,通过该指针可以间接的访问该结构体变量。 指针变量也可以用来指向结构体数组中的元素。

11.4 指向结构体类型数据的指针 11.4.1 指向结构体变量的指针 【例11.4】 指向结构体变量的指针的应用。 11.4.1 指向结构体变量的指针 【例11.4】 指向结构体变量的指针的应用。 #include <stdio.h> void main( ) { struct student { long int num; char name[20]; char sex; float score; };

struct student stu_1; struct student *p; p=&stu_1; stu_1.num=89101; strcpy (stu_1.name, “Li Lin”); stu_1.sex=’M’; stu_1.score=89.5; printf(“No.:%ld\nname:%s\nsex:%c\nscore:%f\n”,stu_1.num,stu_1.name,stu_1.sex,stu_1.score); printf(“\nNo.:%ld\nname:%s\nsex:%c\nscore:%f\n”, ( *p).num,(*p).name,(*p).sex,(*p).score); return; } 输出结果:

11.4 指向结构体类型数据的指针 在C语言中,为了使用方便和使之直观,可以把(*p).num改用p->num来代替,即:p所指向的结构体变量中的num成员。同样,(*p).name等价于p->name。也就是说,以下三种形式等价: ①结构体变量. 成员名; ② (*p).成员名; ③ p->成员名。

11.4 指向结构体类型数据的指针 11.4.2 指向结构体数组的指针 【例11.5 】指向结构体数组的指针的应用 。 11.4.2 指向结构体数组的指针 【例11.5 】指向结构体数组的指针的应用 。 #include <stdio.h> struct student { int num; char name[20]; char sex; int age; }; struct student stu[3]={{10101, “Li Lin”, ’M’,18}, {10102, “Zhang Fun”,’M’,19}, {10104, “Wang Min”,’F’,20}};

void main( ) { struct student *p; printf(“ No. Name sex age\n”); for (p=stu;p<stu+3;p++) printf(“%5d %-20s %2c %4d\n”,p->num,p->name,p->sex,p->age); return; } 输出结果:

11.4 指向结构体类型数据的指针 注意以下两点: (1) 如果p的初值为stu,即指向第一个元素,则p+1后指向下一个元素的起始地址。 例如: (++p)->num 先使p自加1,然后得到它指向的元素中的num成员值 (p++)->num 先得到p->num的值,然后使p自加1,指向stu[1]。

11.4 指向结构体类型数据的指针 (2) 指针p已定义为指向struct student类型的数据,它只能指向一个结构体型数据,而不能指向一元素中的某一成员。 例如,下面是不对的: p=&stu[2].num 千万不要认为,反正p是存放地址的,可以将任何地址赋给它。如果地址类型不相同,可以用强制类型转换。 例如: p=(struct student *) &stu[2].num;

11.4 指向结构体类型数据的指针 11.4.3 用指向结构体的指针作函数参数 【例11.6】有一个结构体变量stu,内含学生学号、姓名和三门课的成绩。要求在main函数中赋以值,在另一函数printf中将它们打印输出。 #include <stdio.h> #define format “%d\n%s\n%f\n%f\n%f\n” struct student { int num; char name[20]; float score[3]; };

void print(struct student *p) { printf (format, p->num, p->name, p->score[0], p->score[1], p->score[2]); printf(“\n”); } void main( ) { struct student stu; stu.num=12345; strcpy(stu.name, “Li Li”); stu.score[0]=67.5; stu.score[1]=89; stu.score[2]=78.6; print(&stu); return; 输出结果:

11.4 指向结构体类型数据的指针 注意: ANSI C允许用整个结构体作为函数的参数传递,但是必须保证实参与形参的类型相同。 把一个完整的结构体变量作为参数传递,虽然合法,但要将全部成员值一个一个传递,费时间又费空间,开销大。如果结构体类型中的成员很多,或有一些成员是数组,则程序运行效率会大大降低。在这种情况下,用指针作函数参数比较好,能提高运行效率。

11.4 指向结构体类型数据的指针 11.4.4 应用举例 【例11.7】 有4个学生,每个学生包括学号、姓名、成绩。要求找出成绩最高者的姓名和成绩。 #include <stdio.h> void main( ) { struct student { int num; char name[20]; float score; }; struct student stu[4]; struct student *p; int i,temp=0; float max;

{ printf(”请输入第%d个学生的学号,姓名,成绩:\n”,i+1); for (i=0;i<4;i++) { printf(”请输入第%d个学生的学号,姓名,成绩:\n”,i+1); scanf (“%d %s %f”,&stu[i].num,stu[i].name,&stu[i].score); } for (max=stu[0].score, i=1;i<4;i++) if (stu[i].score>max) { max=stu[i].score; temp=i; } p=stu + temp; //将p指向成绩最高的学生记录 printf(“\nThe maximum score:\n”); printf(“No.:%d\nname:%s\nscore:%4.1f\n”, p->num,p->name,p->score); return;

11.5 动态存储分配函数 C语言新标准ANSI C要求各C编译版本提供的标准库函数中应包括动态存储分配的函数,它们是: malloc( ) calloc( ) free( ) realloc( )

11.5 动态存储分配函数 1. malloc函数 它的作用是在内存开辟指定大小的存储空间,并将此存储空间的起始地址作为函数值带回。 void * malloc(unsigned int size)

11.5 动态存储分配函数 malloc函数的模型(原型)为: void * malloc(unsigned int size) 注意: p=(long *) malloc(8); (2)如果内存缺乏足够大的空间进行分配,则malloc函数值为“空指针”,即地址为0。

11.5 动态存储分配函数 2. calloc函数 其函数模型为: void *calloc(unsigned int num, unsigned int size) 它有两个形参num和size。其作用是分配num个大小为size字节的空间。 例如用calloc(10,20)可以开辟10个(每个大小为20字节)的空间,即总长为200字节。此函数返回值为该空间的首地址。

11.5 动态存储分配函数 3. free函数 其模型为: void free(void *ptr) 注意: ptr值不能是任意的地址,而只能是由在程序中执行过的malloc或calloc函数所返回的地址。 下面这样用是可以的: p=(long *)malloc(8); … free(p);

11.5 动态存储分配函数 4. realloc函数 用来使已分配的空间改变大小,即重新分配。 其函数原型为: void *realloc(void *ptr, unsigned int size) 作用是将ptr指向的存储区(是原先用malloc函数分配的)的大小分配为size个字节。

11.5 动态存储分配函数 注意:以上4个函数的声明在stdlib.h头文件中,在用到这些函数时应当用“#include <stdlib.h>”指令把stdlib.h头文件包含到程序文件中。

本章小结 重点: 1 指向结构体类型数据的指针 2 动态存储分配函数 难点: 1 指向结构体类型数据的指针的应用 2 动态存储分配函数的应用

本章结束!