第五章 指针 5.1 指针的概念和定义 5.2 指针运算 5.3 指针和数组 5.4 字符串指针 5.5 指针数组 5.6 指向指针的指针

Slides:



Advertisements
Similar presentations
王 子 坊 《洛陽伽藍記》 主講教師:張其昀.
Advertisements

电子成绩单项目实现.
第一章 C语言概述 计算机公共教学部.
補充: Input from a text file
第九章 指针 目录 指针与指针变量的概念 变量的指针和指向变量的指针变量 数组的指针和指向数组的指针变量
第九章 系 统 安 全 性 9.1 结构体 9.2 结构体型数组  9.3 结构体型指针 9.4 内存的动态分配 9.5 共用体
第7章 结构体、联合体和枚举类型 本章导读 本章主要知识点 《 C语言程序设计》 (Visual C++ 6.0环境)
C语言程序设计 第十二章 位运算.
程序设计基础.
高级语言程序设计 主讲人:陈玉华.
C程序设计 第9章 自定义数据类型 主讲教师: 鲁 萍 西安建筑科技大学 理学院.
补充内容 结构体 概述 定义结构体类型和定义结构体变量 结构体变量的引用 结构体变量的初始化 指针与结构体 用typedef定义类型的别名.
编译原理与技术 类型检查 2018/11/21 《编译原理与技术》-类型检查.
项目六 用指针优化学生成绩排名 项目要求 项目分析
C程序设计.
结构体和共用体 2 梁春燕 华电信息管理教研室.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
Chap 9 结构 9.1 构建手机通讯录 9.2 结构变量 9.3 结构数组 9.4 结构指针.
STRUCTURE 授課:ANT 日期:2010/5/12.
C++语言程序设计 C++语言程序设计 第四章 数组及自定义数据类型 C++语言程序设计.
第九章 结构体和共用体 结构体的定义 结构体的使用 共用体的定义 共用体的使用 主讲:李祥 时间:2015年10月.
计算概论 第十八讲 C语言高级编程 结构与习题课 北京大学信息学院.
Object-Oriented Programming in C++ 第一章 C++的初步知识
第12章 從C到C++語言 12-1 C++語言的基礎 12-2 C++語言的輸出與輸入 12-3 C++語言的動態記憶體配置
C语言程序设计 李祥.
THE C PROGRAMMING LANGUAGE
第13章 结构体的应用 13.1 了解由用户构造的数据类型 13.2 结构体类型说明及结构体变量 13.3 结构体数组
Ch02-基礎語法.
第八章 使用指针.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
第十章 指针.
第4章 顺序程序设计.
Struct結構 迴圈
第1章 概述 本章要点: C语言程序结构和特点 C语言程序的基本符号与关键字 C语言程序的编辑及运行 学习方法建议:
第十章 用户自定义数据类型 目录 学生信息管理系统的开发 结构体数据类型的概述 结构体变量的使用 结构体数组
OOP6 結構Struct 黃兆武.
目录 9.1 结构体类型 9.2 共用体类型 9.3 枚举类型 9.4 类型声明符typedef 1.
第十章 结构体与链表 西安工程大学.
C语言复习3----指针.
第八章 指標 (Pointer).
Chap 5 函数 5.1 计算圆柱体积 5.2 使用函数编写程序 5.3 变量与函数.
7.1 C程序的结构 7.2 作用域和作用域规则 7.3 存储属性和生存期 7.4 变量的初始化
第11章 從C到C++語言 11-1 C++語言的基礎 11-2 C++語言的資料型態與運算子 11-3 C++語言的輸出與輸入
第十章 指针 指针是C语言的重要概念,是C语言的特色,是C语言的精华。 10.1 地址和指针的概念 内存中的每一个字节都有一个地址。
C程序设计.
<编程达人入门课程> 本节内容 字符与字符串 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群: ,
C语言程序设计 李祥 QQ:
C程序设计.
<编程达人入门课程> 本节内容 为什么要使用变量? 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
C++程式設計入門 變數與運算子 作者:黃建庭.
第九章 指针.
第2章 基本数据及其运算 本章学习的目标: 1、掌握基本数据的各种表示,基本数据常数的书写方法;
第二章 类型、对象、运算符和表达式.
第二章 基本数据类型 ——数据的表示.
C程序设计.
本节内容 指针类型.
結構、檔案處理(Structure, File)
第十二章 位运算.
本章主題 C++的程式結構 資料型態與宣告 算術運算 簡易的輸入輸出指令 程式編譯(Compile)的過程與原理.
第18讲 从C到C++ 计算机与通信工程学院.
C/C++基礎程式設計班 C語言入門、變數、基本處理與輸入輸出 講師:林業峻 CSIE, NTU 3/7, 2015.
基本資料型態 變數與常數 運算子 基本的資料處理 授課:ANT 日期:2014/03/03.
第九章 指针 C程序设计中使用指针可以: 使程序简洁、紧凑、高效 有效地表示复杂的数据结构 动态分配内存 得到多于一个的函数返回值.
變數與資料型態  綠園.
第六章 复合数据类型 指针的声明与使用 数组的声明与使用 指针与数组的相互引用 字符串及相关库函数 new与delete
本节内容 指针类型 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
安排座位.
C++语言程序设计 C++语言程序设计 第二章 基本数据类型与表达式 第十一组 C++语言程序设计.
Presentation transcript:

第五章 指针 5.1 指针的概念和定义 5.2 指针运算 5.3 指针和数组 5.4 字符串指针 5.5 指针数组 5.6 指向指针的指针 5.7 应用举例

5.1指针的概念和定义 5.1.1 指针的概念: 如果我们将抽屉看作计算机的内存单元,那么,抽屉的编号就是内存单元的地址,存放地址的内存单元就对应程序中的变量,这类特殊的变量在C中称指针变量。可见,pointer是指针变量,2000是pointer指针变量的值

5.1指针的概念和定义 5.1.2 指针的定义及初始化: 指针:就是地址,一个变量的指针就是该变量的地址。 指针变量:专门存放地址的一类特殊的变量。 下面的语句定义了一个名为pointer的指针,且被初始化为0,该指针“指向”的目标类型为整型。 int *pointer = 0 ;

指针变量的常见类型 简单的指针变量分为: 名称 定义 指向具体变量 含义 整型指针变量 int i; long a; 存放整型变量的地址 int *p1=0; long *p2=0; int i; long a; p1=&i; ( p1指向i ) p2=&a; ( p2指向a ) 存放整型变量的地址 字符型指针变量 char *p3=0; char ch; P3=&ch; ( p3指向ch ) 存放字符型变量的地址 实型指针变量 float *p4=0; double *p5=0; float x;double y; p4=&x;p5=&y; ( p4指向x, p5指向y ) 存放实型变量的地址 通用指针 void *p=0; p=0; (初始化为空指针) 存放任何类型变量的地址

5.1指针的概念和定义 5.1.3 指针的赋值: 例:有如下变量定义语句: int i, j; int *i_pointer = 0; 指针的赋值就是让指针变量指向某个具体的内存单元。一般有2种方式给指针变量赋值: 1、使用地址运算符(&)将变量的地址取出赋给指针变量,这样,就让指针变量指向了某一具体的变量。 例:有如下变量定义语句: int i, j; int *i_pointer = 0; 2000 以上语句经过编译后(编译后,每个变量名对应一个地址,在内存中不再出现变量名而只有地址) ,内存分配如左图所示: i_pointer = &i ; 执行以上变量赋值语句后, i_pointer 就指向了变量 i 代表的内存单元。

5.1指针的概念和定义 5.1.3 指针的赋值(续): 例:有如下变量定义语句: int i = 123; 指针的赋值就是让指针变量指向某个具体的内存单元。一般有2种方式给指针变量赋值: 5.1.3 指针的赋值(续): 2、将一个已有具体指向的指针变量赋值给另一个指针变量。 例:有如下变量定义语句: int i = 123; int *p1 = 0 , *p2 = 0; p1 = &i ; 执行以上变量赋值语句后, p1 就指向了变量 i 代表的内存单元。 p2 = p1 ; 执行以上变量赋值语句后, p1、p2 就指向了相同的内存单元。

5.1指针的概念和定义 5.1.3 指针的赋值(续): ①直接访问:通过变量名或变量的地址访问。 有了指针的概念后,程序中对变量(内存)的访问就有两种方式: ①直接访问:通过变量名或变量的地址访问。 例:printf(“%d”,i); scanf(“%d”,&i); ②间接访问:通过指针变量(i_pointer)中存放的值,找到最终要访问的变量。 例: scanf(“%d”, i_pointer); 在现有的微机系统中指针变量一般占4个字节。 指针变量在使用前必须指向某个具体的内存单元,没有具体指向的指针变量叫悬空指针,使用是非法的。 定义指针并将其初始化为0是一个值得提倡的好习惯。

5.2 指针运算 关于指针的两个运算符 含义:取变量x的地址。 *p: ( p 只能是指针变量 ) 含义:p所指向的变量。 取地址运算符:& 指向运算符: * &x: ( x 可以是任何类型的变量 ) 含义:取变量x的地址。 *p: ( p 只能是指针变量 ) 含义:p所指向的变量。 应当注意的是,在变量说明语句中的“*”号意味着“指向……的指针”,而在表达式语句中的“*”号是表示“间接”存取变量的值。 例: int x = 1, y = 2, z[10]; int *ip = 0; ip = &x; //ip is now points to x y = *ip; // y = x; *ip = 0; // x = 0; ip = &z[0]; // ip is now points to z[0]

5.2 指针运算(续) 关于指针运算的注意事项 例:int i = 0 , a[3] = {0}; -&i ,&a[0]合法。 地址运算符&可用于取变量或数组元素的地址,但&不能用于非左值表达式 和常数,因为它们没有地址的概念。 例:int i = 0 , a[3] = {0}; -&i ,&a[0]合法。 -&a非法(因为数组名a本身就代表数组的首地址,是一个常数)。 -&(i + 5)非法(因为i + 5不是一个左值表达式,它不能代表存储域)。 -&i = 123也是非法的赋值表达式,因为&i表示的是一个常数(i的地址)。

5.2 指针运算(续) 关于指针使用的示例 *&i和i等价; (*p)++和i++等价; *p++等价于*(p++); 原则:先定义后使用。 例5.1 原则:先定义后使用。 关于指针使用的示例 //* 程 序 名:5_1.cpp //* 主要功能:通过指针间接访问内存单元 //*************************************** int main() { …… int i = 0; int *p = 0; p = &i; …… } 说明: 如果已执行了程序第12行的语句:“p=&i;”,则&*p和&i等价; *&i和i等价; (*p)++和i++等价; *p++等价于*(p++);

5.2 指针运算(续) 关于指针使用的示例 原则:先定义后使用。 //* 程 序 名:5_2.cpp 例5.2 原则:先定义后使用。 关于指针使用的示例 //* 程 序 名:5_2.cpp //* 主要功能:测试交换两个指针变量的指向//*************************************** int main() { …… p_max = &C_score; p_min = &math_score; if(math_score > C_score) { 16 p = p_max, p_max = p_min, p_min = p; } ……

5.3 指针和数组 5.3.1 指针与一维数组 &a[0] + 偏移量 &a[1] 数组的首地址也就是数组中第1个元素的地址; 例5.3 5.3.1 指针与一维数组 数组的首地址也就是数组中第1个元素的地址; 在内存中数组a的元素的地址是连续递增的; 通过数组a的首地址,加上偏移量就可以依次得到其它元素的地址; &a[0] + 偏移量 &a[1] 这里的偏移量就是一个数组元素所占的字节数。编译程序会根据数组元素的类型,自动确定出不同的偏移量

5.3 指针和数组 5.3.1 指针与一维数组(续) 有了数组的地址,我们现在有另外一种引用一维数组元素的方法—— 地址引用法。 例5.4 5.3.1 指针与一维数组(续) 有了数组的地址,我们现在有另外一种引用一维数组元素的方法—— 地址引用法。 图5-3-2 数组地址和元素的关系 score[ 0] *score score[ 1] *(score +1) score[ 2] *(score +2) score +2 内存数据区 地址 score score +1 元素 90 80 70 … 例5.4

5.3 指针和数组 指向一维数组元素的指针: 例:int score[3] = {0} , *p = score; 例5.5 指向一维数组元素的指针: 例:int score[3] = {0} , *p = score; 以上定义还可以写成: 例:int score[3] = {0} , *p = &score[0]; 由于p是一个指针变量,因此可以修改它,使之指向其他地方。与数组名(score)不同,p不必被固定为指向数组score的第一个元素。在需要时,可以修改它,使之指向score数组的其他元素。 例:int score[3] = {0} , *p = &score[1];

5.3 指针和数组 指向一维数组元素的指针(续): int a[10]; int* p; p=a;或 p=&a[0]; …… a[i]=0; 数组元素的下标访问方式 int a[10]; int* p; p=a;或 p=&a[0]; …… a[i]=0; for(int k=3;k<10;k++) scanf(“%d”,a+k); 数组名作地址值的直接地址访问 *(a+i)=0; p[i]=0; *(p+i)=0; scanf(“%d”,p+k); 将指针变量看作数组名以后的下标变量方式 指针加偏移量的访问方式

5.3 指针和数组 指向一维数组元素的指针(续): 可以对指向数组元素的指针变量进行自增(或自减)运算,表示指针向后(向前)移动一个数组元素。例如,假设p的当前指向为a[k],则p++指向a[k+1]. *p++ 和*( p++) 等价于 *p, p++ (先引用p当前指向的元素a[k] ,再使p指向下一个元素a[k+1] ) *(++ p)等价于 p++, *p (先使p指向a[k+1] ,再引用p指向的元素a[k+1] ) (*p)++表示p当前指向的元素的值加1,即a[k]++ 例5.6

5.3 指针和数组 指向同一数组的两个指针之间可以进行的运算: 应该避免如下几种错误 : (1)比较运算,即比较它们所存储的地址,可以反映出它们在数组中的前后顺序。 (2)数值加减运算,加上某个整型量表示指针向后移动相应个数组元素。同样地,减去某个整型量表示指针向前移动相应个数组元素。这种运算用的最多的是自增和自减运算。 (3)指针的减法运算的结果为它们之间的数组元素的个数。 应该避免如下几种错误 : (1)对不指向数组的指针进行算术运算。 (2)把不指向同—数组的两个指针相减或比较。 (3)指针算术运算的结果超出了数组的范围。 例5.7

考虑:1.能否用scanf(“%c”,str++)代替 scanf(“%c”,p++)? 例: char str[10]; char* p; p=str; for(int k=0;k<10;k++) scanf(“%c”,p++); × scanf(“%c”,str++); p str[0] str[9] p++ 考虑:1.能否用scanf(“%c”,str++)代替 scanf(“%c”,p++)? 不行!! 2.循环结束后p指向哪儿?

5.3 指针和数组 5.3.2 指针与结构数组: StudentInfo stu; StudentInfo *pStuInfo = 0; struct StudentInfo { char no[20]; int sexy; double height; Date birthday; }; 5.3.2 指针与结构数组: 让pStuInfo指向结构变量stu: pStuInfo = &stu; 声明一个该结构类型的变量: 例5.8 图5-3-6 指向结构的指针 … &stu.sexy 内存数据区 地址 结构成员 pStuInfo stu.no[0] stu.sexy &stu stu.no &stu.height &stu.birthday stu.birthday.year StudentInfo stu; 声明一个指向 StudentInfo结构的指针: StudentInfo *pStuInfo = 0; 三种方式引用结构变量stu的成员: stu.no = "1443011101"; (*pStuInfo).no = "1443011101"; pStuInfo -> no = "1443011101";

5.4 字符串指针 5.4.1 用字符数组存放字符串数据: char name[] = "王芳"; char name[20] =""; 无论哪种方式,编译器都自动在该字符串的末尾加上—个空字符。请记住,字符串必须以空字符结尾。操纵字符串时均需通过查找空字符来确定字符串的尾部。如果遗漏了空字符,程序会认为该字符串一直延续到内存中的下一个空字符。 5.4.1 用字符数组存放字符串数据: 在C中,没有为字符串数据提供专门变量来存放,而是用字符数组来处理字符串,字符数组就是用来存放和操作字符串数据的。常用的将字符串数据存放进字符数组的方式有两种: (1)定义字符数组时用字符串常量初始化: char name[] = "王芳"; (2)从键盘输入一个字符串给字符数组: char name[20] =""; cin >> name; //输入wangfang则该字符串进入name数组

5.4 字符串指针 字符串指的是在程序中经常要处理的一类数据。我们先了解C中提供的字符串的处理的几种基本技术 。 5.4.2 通过字符数组操作字符串: 字符串放入字符数组存放后,就可以通过操作字符数组来操作字符串了。 例5.9

5.4 字符串指针 5.4.3 使用指向字符数组的指针操作字符串: 字符串指的是在程序中经常要处理的一类数据。我们先了解C中提供的字符串的处理的几种基本技术 。 5.4.3 使用指向字符数组的指针操作字符串: 字符串是由字符数组的名称和字符'\0'定义的。字符数组的名称是一个char指针常量,它指向字符串的开头,而字符'\0'标记了字符串的末尾。由于标记了字符串的末尾,因此要操作某个字符串,可以指定一个指向该字符串开头的指针变量,通过操作该指针变量就可访问字符串中的每一个字符。 例5.10

5.4 字符串指针 5.4.4 指向字符串常量的指针: char *pStr = "Hello,World”; 当编译这条语句时,字符串“Hello,World”(包括一个结尾的空字符)将被存储在内存的某个地方,而指针pStr将被初始化为指向该字符串存放的内存的第一个单元。不用关心该字符串被存储在内存的什么地方,这是由编译器自动处理的。—旦被定义,pStr便是一个指向存储该字符串的内存空间的开头的指针。

5.4 字符串指针 字符串指的是在程序中经常要处理的一类数据。我们先了解C中提供的字符串的处理的几种基本技术 。 例5.11 5.4.4 指向字符串常量的指针(续): #include <stdio.h> /*程序5-11. cpp */ void main( ) { char *p = "abcdefg"; for(; *p != '\0'; p++) if(*p >='a' && *p <='z') printf("%c", *p-32); else printf("%c", *p); } putchar('\n'); if(*p >='a' && *p <= 'z') *p = *p - 32; printf("%c", *p);

5.5 指针数组 5.5.1 指针数组的概念: 指针数组也是数组; 其数组元素中存放的是内存单元的地址 。即:数组中的元素为指针; 而这些指针必须指向同一种数据类型; 指针数组的数据类型是其所有元素(指针)所指向的变量的数据类型。 实际上,指针数组存在的目的就是用来处理多个有关系的字符串数据。

5.5 指针数组 5.5.2 指针数组的定义及初始化: 定义三个存放字符串数据的字符数组: char str1[ ] = "China"; 例5.12 5.5.2 指针数组的定义及初始化: 定义三个存放字符串数据的字符数组: char str1[ ] = "China"; char str2[ ] = "America"; char str3[ ] = "German"; 定义指针数组并初始化指向上面三个字符串数据: char *pStr[3] = { str1, str2, str3 }; 图5-5-1 指针数组 str1 str2 str3 pStr[0] pStr [1] pStr [2] 指针数组pStr 元素 C h i n a \0 A m e r c G 元素值

5.6 指向指针的指针 由于指针变量本身是—个变量,它被存储在计算机内存特定某处。因此可以创建指向指针的指针变量—— 双重指针变量,其值为一个指针变量的内存存放地址 int a = 123; int *p_a = &a; // p_a 现在指向了变量 a int **p = &p_a; // p 指向了变量 p_a 图5-6-1 双重指针 &p_a &a ... 123 ××× &p 声明和使用指向指针的指针被称为多重间接。图5-6-1说明了变量、指针和指向指针的指针之间的关系。对于多重间接的层数没有任何限制。但通常多于两层时无疑是自找麻烦

5.6 指向指针的指针 由于指针变量本身是—个变量,它被存储在计算机内存特定某处。因此可以创建指向指针的指针变量—— 双重指针变量,其值为一个指针变量的内存存放地址 二维数组和双重指针: 二维数组与一维数组一样,二维数组名也是一个首地址,指向该二维数组对应的内存空间的开始,即:指向二维数组的第一个元素。二维数组可以看做一个特殊的一维数组。其特殊性在于:该一维数组的每一个元素又是一个一维数组名(指向另外的一维数组)。实际上,这个特殊的一维数组就是一个指针数组。所以,二维数组名可以看作是一个双重指针。

5.6 指向指针的指针 二维数组和双重指针(续) : 由于指针变量本身是—个变量,它被存储在计算机内存特定某处。因此可以创建指向指针的指针变量—— 双重指针变量,其值为一个指针变量的内存存放地址 例5.13 二维数组和双重指针(续) : char name[3][20] = {"China", "America", "German"}; 上面语句定义了名为name的数组,它包含3个一维数组,name[0],name[1],name[2],每个一维数组又是存放字符串的字符数组。

5.6 指向指针的指针 二维数组和双重指针(续) : 数组名:name 例5.13 数组名:name 元素: name[0], name[1], name[2](每一个元素都是指向一个字符串的指针) name是一个地址,指向这个含3个元素的指针数组的第一个元素name[0]。 name[0]本身是一个指针,指向字符串”China” 所以,name是一个指向指针的指针,即:双重指针。既然name, name[0],&name[0],&name[0][0]都指向同一个内存单元,当然他们的值是一样的。只不过意义不一样。

5.8 本章小结 指针变量存储的是另一个变量的地址。给指针赋值变量就是将一个内存地址装入指针变量。如果这个内存地址是某变量的地址,则该指针就指向了该变量。 指针变量的类型是指针所指向的变量的类型。 在定义一个指针变量时,将其初始化为空(NULL)是一个好习惯。 对指针赋值是将它所指向的变量的地址赋给指针变量。这时要用到取地址运算符&。&a表示取变量a的地址。 在赋值语句中可使用间接访问运算符*

5.8 本章小结(续) 数组名可视为常量指针,将数组名赋给指针变量,则该指针就指向了该数组的首地址(即数组中的第一个元素所在地址)。 数组中的元素为指针的数组叫指针数组。这时数组中的元素不是普通的数值,而是内存中的地址。 字符数组就是字符串。字符数组只有在定义时才允许整体赋值。C库函数中有字符判断函数和字符串相关函数,在编程时可以选用。 如果对指针使用地址运算符,将得到指针的地址。指针也是—个变量,存储的是它指向的变量的地址。存放指针变量地址的变量叫双重指针。

本章作业 5.3题 5.4题 5.5题