1 / 114

第 7 章 指针

C 语言程序设计. 第 7 章 指针. 内容提要. 指针的概念 难点:理解指针数据类型 用指针做函数参数,向函数传递变量值、数组元素和字符串 用指针数组处理多个字符串 指向数组的指针与指针数组的区别 带参数的 main 函数; 动态内存分配函数及其应用 一维、二维动态数组的实现 Skill 用指针做函数参数编程. 为什么引入指针的概念. 指针 为函数提供修改变量值的手段 为 C 的动态内存分配系统提供支持 为动态数据结构(如链表、队列、二叉树等)提供支持 改善某些子程序的执行效率. 内存:计算机内的存储部件 所有指令和数据都保存在内存里

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. C语言程序设计 第7章 指针

  2. 内容提要 • 指针的概念 • 难点:理解指针数据类型 • 用指针做函数参数,向函数传递变量值、数组元素和字符串 • 用指针数组处理多个字符串 • 指向数组的指针与指针数组的区别 • 带参数的main函数; • 动态内存分配函数及其应用 • 一维、二维动态数组的实现 • Skill • 用指针做函数参数编程

  3. 为什么引入指针的概念 • 指针 • 为函数提供修改变量值的手段 • 为C的动态内存分配系统提供支持 • 为动态数据结构(如链表、队列、二叉树等)提供支持 • 改善某些子程序的执行效率

  4. 内存:计算机内的存储部件 所有指令和数据都保存在内存里 速度快,可随机访问,但掉电即失 编译或函数调用时为变量分配内存单元 变量的地址 0 0 0 0 变量名 Contents Contents Contents Contents Contents Contents Contents 变量的值 变量 (Variables)与变量的地址 (Address) int a=0; a 0x0037b000 变量是对程序中数据存储空间的抽象 某存储区域

  5. 内存中的每个字节都有唯一的一个编号(地址)内存中的每个字节都有唯一的一个编号(地址) 地址是一个无符号整数,其字长一般与主机相同 地址按字节编号,按类型分配空间 变量的地址 0 0 0 0 Contents Contents Contents Contents Contents Contents Contents the Address Operator 变量 (Variables)与变量的地址 (Address) int a=0; a &a 0x0037b000 0x0037b001 0x0037b002 0x0037b003 某存储区域

  6. 如何读写内存中的数据? 只要指明要访问的变量的内存单元地址 就可以立即访问到变量所在的存储单元 0 0 0 0 Contents Contents Contents Contents Contents Contents Contents scanf("%d", &a); 变量 (Variables)与变量的地址 (Address) int a=0; a &a 0x0037b000 0x0037b001 0x0037b002 0x0037b003 某存储区域

  7. 如何读写内存中的数据? 直接访问:按变量地址存取变量值 0 0 0 0 Contents Contents Contents Contents Contents Contents Contents scanf("%d", &a); 变量 (Variables)与变量的地址 (Address) int a=0; a &a 0x0037b000 0x0037b001 0x0037b002 0x0037b003 某存储区域

  8. 如何读写内存中的数据? 0 0 0 0 Contents Contents Contents Contents Contents Contents 0x0037b000 变量 (Variables)与变量的地址 (Address) 间接访问:通过存放变量地址的变量去访问变量 int a=0; a &a 0x0037b000 0x0037b001 0x0037b002 0x0037b003 某存储区域

  9. 指针变量 指向 变量 变量的地址(指针) 变量地址存入 指针变量 变量值 指针(Pointer)的概念 • 什么类型的变量可以存放变量的地址? • 指针类型——存放地址型数据的特殊数据类型 • 指针变量——专门用于存放地址型数据的变量 • 变量的指针←→变量的地址

  10. 指针变量 如何定义指针变量? Declaring pointers int a=10; …... &a 0x0037b000 整型变量 a 10 0x0037b004 0x0037b008 0x0037b000 0x0037b00B …...

  11. 指针变量指向的数据类型称为基类型 指针变量 用指针变量要指向的数据类型 作为指针变量的基类型 Declaring pointers int a=10; …... &a 0x0037b000 整型变量 a 10 0x0037b004 0x0037b008 pa 0x0037b000 int*pa; 0x0037b00B …...

  12. 指针变量 仅仅是定义了可以指向int型数据 的指针变量,但并未指向a 使其指向a需对指针变量初始化 Pointer Assignments int a=10; …... &a 0x0037b000 整型变量 a 10 0x0037b004 0x0037b008 int*pa=&a; pa 0x0037b000 int*pa; 0x0037b00B pa = &a; …...

  13. 指针变量 Pointers have names, types and values Pointer Assignments int a=10; …... &a 0x0037b000 整型变量 a 10 0x0037b004 0x0037b008 int*pa=&a; pa 0x0037b000 int*pa; 0x0037b00B pa = &a; …...

  14. 指针变量 • 只能指向同一基类型的变量,否则将引起warning • floata; • int *pa = &a; • warning C4133: '=' : incompatible types - from 'float *' to 'int *' Pointer Assignments int a=10; …... &a 0x0037b000 整型变量 a 10 0x0037b004 0x0037b008 int*pa=&a; pa 0x0037b000 int*pa; 0x0037b00B pa = &a; …...

  15. 判断:正确的? 应在类型相同的指针变量之间赋值 一个指针变量不能指向与其类型不同的变量! int i,*p; p=&i; int i; float *p; p=&i; int *p; float *q; p=q; int *p; p=100; 指针变量只 存放地址! 我是正确的, 你猜对了吗?

  16. 24 &i i Dereferencing Pointers and the Address Operator • int i = 24; • i is an int variable • &i is like an int pointer, pointing to the variable i the Address Operator

  17. 24 p *p Dereferencing Pointers and the Address Operator • int *p; • p = &i; • p is an int pointer • *p 像普通变量一样使用*p ,*取指针p指向内存的内容 the pointer Operator

  18. Dereferencing Pointers and the Address Operator int a=10; …... *(&a) /*该表达式引用的是 变量a的内容*/ &(*pa) /*该表达式的值 代表的是变量a的地址*/ &a 0x0037b000 a 20 0x0037b004 0x0037b008 pa 0x0037b000 0x0037b00B …... int*pa=&a;

  19. 指针变量 间接访问(寻址) Using Pointers int a=10; …... &a 0x0037b000 整型变量 a 10 20 0x0037b004 0x0037b008 int*pa=&a; pa 0x0037b000 int*pa; 0x0037b00B pa = &a; …... *pa = 20;

  20. 指针变量 如果指针指向一个非你控制的内存空间 并对该空间进行访问,将可能造成危险 Never use uninitialized pointers. Using Pointers int a=10; …... &a 0x0037b000 整型变量 a 20 0x0037b004 0x0037b008 int*pa=&a; pa 0x0037b000 int*pa; 0x0037b00B pa = &a; …... *pa = 20;

  21. int i;scanf("%d", i); /* 这样会如何?*/ char c;scanf("%d", &c); /* 这样呢?*/ i的值被当作地址。如i==100,那么输入的整数就会从地址100开始写入内存 输入以int的二进制形式写到c所在的内存空间。c所占内存不足以放下一个int,其后的空间也被覆盖

  22. ? 3 iPtr jPtr i j Using Pointers int i; int *iPtr = &i; int j = 3; int *jPtr = &j; • Consider: *jPtr = *iPtr; i = 4; *jPtr = i; iPtr = j;

  23. p p+1 pointer manipulation ——算术运算 short *p, a[10]; p = a; p++; • p值增加多少? a[0]

  24. p p+1 pointer manipulation ——算术运算 short *p, a[10]; p = a; p++; • p值增加多少? • 如果short改成long,p值增加多少呢? • 指针的加减运算是以其基类型的字节长度为单位的 a[0]

  25. pointer manipulation ——算术运算 • 指针运算不能乱算 • 指针和整数的加减运算 • 同类型指针之间的减法运算 • 其它运算,比如乘法、除法、浮点运算、指针之间的加法等,并无意义,所以也不支持

  26. *p *p = *p + 1; *p p = p + 1; Pointers and Errors • To increment a dereferenced pointer, use (*p)++ • rather than *p++ /* correct but means … */

  27. pointer manipulation ——关系运算 • 指向同一种数据类型的两个指针才能进行关系运算 • 值为1或0 p > q p < q p == q • 不能与非指针类型变量进行比较

  28. pointer manipulation——赋值运算 • 指针在使用前一定要赋值 • 确定指针指向哪里 • 为指针变量赋的值必须是一个地址 main() { int a,*p=&a; scanf("%d",p); … } main() { int *p; scanf("%d",p); … } TC下不报错 VC下报错

  29. argument a &a a x parameter pointer parameter Pointers and Functions • 简单变量做函数参数——Call by Value • Can not modify the argument 形参(parameter)←实参变量(variable) • 指针做函数参数——Call by Reference • In order to modify the argument use: 指针形参(Pointer parameter) ← &(variable)

  30. 例7.1~7.2 两数互换 • void Swap(int *x, int *y) { int temp; temp = *x; *x = *y; *y = temp; } /* call by reference: int a = 15, b = 8; swap(&a, &b); */

  31. 例7.1~7.2 两数互换 • void Swap(int *x, int *y) { int temp; temp = *x; *x = *y; *y = temp; } /* call by reference: int a = 15, b = 8; int *pa = &a, *pb = &b; swap(pa, pb); */

  32. 主调函数 被调 函数 例7.1~7.2:编写函数实现两数的互换 程序 2 程序 1 Trace the execution main() { int a, b; a = 5; b = 9; Swap( &a, &b ); printf("a=%d,b=%d",a,b); } main() { int a, b; a = 5; b = 9; Swap(a, b); printf("a=%d,b=%d",a,b); } void Swap(int x,int y) { int temp; temp = x; x = y; y = temp; } 实 参 void Swap(int *x,int *y) { int temp; temp = *x; *x = *y; *y = temp; } 形 参 Not Work!Why? 结果有何不同?

  33. x y a b 程序 1 主调函数 被调函数 void Swap(int x, int y) { int temp; temp = x; x = y; y = temp; } main() { int a, b; a = 5; b = 9; Swap(a, b); printf("a=%d,b=%d",a,b); } temp 5 y x b a 9 9 5 5 9 形 参 5 实 参 x和 y是内部变量 单向值传递

  34. x y a b 程序 2 形 参 实 参 主调函数 被调函数 void Swap(int *x, int *y) { int temp; temp = *x; *x = *y; *y = temp; } main() { int a, b; a = 5; b = 9; Swap(&a, &b); printf("a=%d,b=%d",a,b); } temp 5 x y a b 5 9 &a &b 9 5 &a &b *x *y 交换的是x和 y 指向的单元内容

  35. void Swap(int *x, int *y) { int*pTemp; *pTemp = *x; *x = *y; *y = *pTemp; } void Swap(int *x, int *y) { int temp; temp = *x; *x = *y; *y = temp; } 指针pTemp未初始化 指针pTemp指向哪里未知 对未知单元写操作是危险的

  36. void Swap(int *x, int *y) { int*pTemp; pTemp = x; x = y; y = pTemp; } void Swap(int *x, int *y) { int temp; temp = *x; *x = *y; *y = temp; } 非危险操作 但是交换的是地址值 不是指针指向单元的内容

  37. 指针变量与其它类型变量的对比 • 共性 • 在内存中占据一定大小的存储单元 • 先定义,后使用 • 特殊性 • 它的内容只能是地址,而不能是数据 • 必须初始化后才能使用,否则指向不确定的存储单元 • 只能指向同一基类型的变量 • 可参与的运算:加、减整数,自增、自减、关系、赋值 • 使用原则 • 明确指针指向了哪里 • 明确指针指向单元的内容是什么

  38. 作业 • 习题 • 7.5~7.6

  39. H e l l o C h i n a \0 字符数组与字符指针 • C语言并没有为字符串提供任何专门的表示法,完全使用字符数组和字符指针来处理 字符串就是一串以用''引起来的字符 "Hello China" 数组最后一个元素必须是'\0'才表示字符串 pStr 字符数组就是每个元素都是字符型的数组 字符指针就是指向字符类型数据的指针

  40. H e l l o C h i n a \0 字符数组与字符指针 "Hello China" str • 定义和初始化方法不同 pStr char str[12] = {"Hello China"}; char *pStr = "Hello China"; char *pStr; pStr = "Hello China"; pStr = &str[0];

  41. H e l l o C h i n a \0 字符数组与字符指针 "Hello China" str • 定义和初始化方法不同 pStr char str[12] = {"Hello China"}; str = "Hello China"; 数组名str是地址常量 Why? char *pStr; pStr = "Hello China"; 字符指针pStr是变量

  42. H e l l o C h i n a \0 例7.5 :字符串拷贝——用字符数组编程 void MyStrcpy(char dstStr[], char srcStr[]) { int i = 0; while (srcStr[i] != '\0') { dstStr[i] = srcStr[i]; i++; } dstStr[i] = '\0'; } srcStr[i]=='\0 srcStr[i] i=6 i=7 i=0 i=1 i=3 i=4 i=5 i=8 i=9 i=10 i=2 C h \0 H e l o i n a l dstStr[i]

  43. H e l l o C h i n a \0 srcStr srcStr dstStr dstStr srcStr dstStr srcStr dstStr srcStr dstStr srcStr dstStr srcStr dstStr srcStr dstStr srcStr dstStr srcStr dstStr dstStr srcStr dstStr srcStr 例7.5 :字符串拷贝——用字符指针编程 void MyStrcpy(char *dstStr, char *srcStr) { while (*srcStr != '\0') { *dstStr = *srcStr; srcStr++; dstStr++; } *dstStr = '\0'; } dstStr++ srcStr++ *srcStr=='\0 *srcStr C h H e l o i n a l \0 *dstStr

  44. H e l l o C h i n a \0 srcStr dstStr 例7.5 :字符串拷贝——用字符指针编程 void MyStrcpy(char *dstStr, const char *srcStr) { while (*srcStr != '\0') { *dstStr = *srcStr; srcStr++; dstStr++; } *dstStr = '\0'; } 当只允许访问指针指向的地址中的内容时,把函数的指针形参定义为const ,试图修改内容时编译器会报错 Protecting Parameter Values *srcStr C h H e l o i n a l \0 *dstStr

  45. Aconstqualifier qualify pointers使用const修饰指针变量 const int *p; • pointer to a constant integer • p是一个指针变量,可以指向一个整型常量 • the value of p may change, but the value of *p can not • 执行*p = 10这样的赋值操作,VC下编译会提示如下错误信息: error C2166: l-value specifies const object int *const p; • constant pointer to integer • p是一个常量指针,可以指向一个整数 • the value of *pcan change, but the value of p can not

  46. 例7.6 :计算实际字符个数 • 方法1:用字符数组实现 unsigned int MyStrlen(char str[]) { int i; unsigned int len = 0; for (i=0; str[i]!='\0'; i++) { len++; } return (len); } • 方法2:用字符指针实现 unsigned int MyStrlen(const char *pStr) { unsigned int len = 0; for (; *pStr!='\0'; pStr++) { len++; } return (len); }

  47. 指针与数组 int a[4]={1,2,3,4}; int*pa=a; a …. int*pa=&a[0]; 0x0037b000 1 a[0] pa 数组名是一个常量指针 不能修改该指针的指向 0x0037b004 2 a[1] 0x0037b008 3 a[2] 指针可当数组名使用 0x0037b00B 4 a[3] …...

  48. 指针与数组 int a[4]={1,2,3,4}; int*pa=a; a …. int*pa=&a[0]; 0x0037b000 1 a[0] pa pa[0] 0x0037b004 2 a[1] • 数组元素的等价引用形式 • a[i] • *(a+i) • pa[i] • *(pa+i) a+1 *(a+1) 0x0037b008 3 a[2] pa+2 *(pa+2) 0x0037b00B 4 a[3] *pa …...

  49. 指针与数组 for (i=0; i<4; i++) scanf("%d", &a[i]); for (i=0; i<4; i++) printf("%d ", a[i]); int a[4]={1,2,3,4}; a …. 0x0037b000 1 a[0] p *p 0x0037b004 2 a[1] *p 0x0037b008 for (p=a; p<(a+4); p++) scanf("%d", p); for (p=a; p<(a+4); p++) printf("%d ", *p); 3 a[2] 0x0037b00B 4 a[3] …... a+4

  50. 1 9 7 5 3 a[0] a[1] a[2] a[3] a[4] a[5] 例7.7 :插入排序 • 算法的关键是: • 找到待插入的位置 • 依次移动插入位置及其后的所有元素 • 腾出这一位置放入待插入的元素 待插入元素x=4 5 9 4 7 插入元素 x=4

More Related