第8章 指针.

Slides:



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

第七章 指针 计算机公共教学部.
第六章 指针 指针的概念 指针变量 指针与数组 指针与函数 返回指针值的函数.
第十章 指针 分析C程序的变量所存放的数据:  数值型数据:整数、实数  字符型数据:字符、字符串 这些变量具有以下性质:
第7章 指针 存储地址的变量的类型就是指针类型 能直接对内存地址操作, 实现动态存储管理 容易产生副作用, 初学者常会出错
第七章 指针 教 材: C程序设计导论 主 讲: 谭 成 予 武汉大学计算机学院.
二级指针与二维数组.
C语言程序设计基础 第10章 指针进阶 刘新国.
10.1 二级指针 10.2 指针与二维数组 10.3 指针的动态存储分配 10.4 函数指针 10.5 main函数的参数
C语言程序设计教程 单位:德州学院计算机系.
第 6 章 第 6 章 指 针 指 针 1.
第8章 指针 ● 8.1 指针简介 ● 8.2 指针变量的操作 ● 8.3 数组与指针 ● 8.4 二维数组与指针 ●本章小结 ●本章练习.
一维数组 乾坤以有亲可久; 君子以厚德载物。.
C语言基础——指针的高级应用 Week 05.
第6章 指针 6.1 指针的概念 6.2 变量与指针 6.3 数组与指针 6.4 字符串与指针 6.5 函数与指针 6.6 返回指针值的函数
6.4 字符串与指针 1. 用字符数组存放一个字符串.
第六节 二维数组和指针 二维数组的地址 对于一维数组: (1)数组名array表示数组的首地址, 即array[0]的地址;
第九章 指针 目录 指针与指针变量的概念 变量的指针和指向变量的指针变量 数组的指针和指向数组的指针变量
第5章 函数与模块化设计 学习目的与要求: 掌握函数的定义及调用方法 理解并掌握参数的传递方法 理解函数的嵌套与递归调用
程序设计基础.
第6章 指针 学习目的与要求: 了解指针的概念和相关术语 熟练掌握指向变量、数组和字符串的指针变量的使用方法 了解指向函数的指针变量
第六章 数 组 主讲教师 贾月乐 联系电话:
指 针 为什么要使用指针 指针变量 指针与数组 返回指针值的函数 动态内存分配 通过指针引用字符串 指向函数的指针 小 结 习 题.
目录 10.1 指针的基本概念 10.2 指向变量的指针变量 10.3 指向数组的指针变量 10.4 指向函数的指针变量和指针型函数
第八章 指 针 8.1 指针的概念与定义 8.2 指针作函数参数 8.3 指针与数组 8.4 指针与函数 8.5 复杂指针.
第 十 章 指 针.
项目六 用指针优化学生成绩排名 项目要求 项目分析
第七章 函数 目录 有参的加法函数的开发 函数定义的一般形式 函数参数和函数的值 函数的调用
Chap 8 指针 8.1 寻找保险箱密码 8.2 角色互换 8.3 冒泡排序 8.4 电码加密 8.5 任意个整数求和*
C语言程序设计 李祥.
Chap 8 指针 8.1 寻找保险箱密码 8.2 狸猫换太子 8.3 冒泡排序 8.4 加密变换问题 8.5 任意个整数求和问题*
第八章 函数.
第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++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
第八章 使用指针.
第十章 指针.
欲穷千里,更上层楼 第十章 指 针 指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构; 能很方便地使用数组和字符串; 并能象汇编语言一样处理内存地址,从而编出精练而高效的程序。指针极大地丰富了C语言的功能。 学习指针是学习C语言中最重要的一环,
第五章 习题课 电子信息与计算机科学系 曾庆尚.
数组 梁春燕 华电信息管理教研室.
9.1 地址、指针和变量 9.2 指针运算 9.3 指针与数组 9.4 函数与指针 9.5 程序综合举例 9.6 上机实训.
第8章 函数 函数参数和函数的值 概述 函数定义的一般形式 函数的调用(嵌套调用、递归调用) 数组作为函数参数
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
C语言大学实用教程 第5章 函数与程序结构 西南财经大学经济信息工程学院 刘家芬
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
C语言复习3----指针.
第一章 程序设计和C语言 主讲人:高晓娟 计算机学院.
C语言大学实用教程 第6章 数组 西南财经大学经济信息工程学院 刘家芬
C语言大学实用教程 第7章 指针 西南财经大学经济信息工程学院 刘家芬
函数 概述 模块化程序设计 基本思想:将一个大的程序按功能分割成一些小模块, 特点: 开发方法: 自上向下,逐步分解,分而治之
指针 几个概念:  指针也是一种数据类型,具有指针类型的变量,称为指针变量。
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
第6讲 指针与引用 6.1 指针 6.2 引用.
第六章 指针 C++程序设计中使用指针可以: 使程序简洁、紧凑、高效 有效地表示复杂的数据结构 动态分配内存 得到多于一个的函数返回值.
第6章 指针 6.1 指针的概念 6.2 变量与指针 6.3 数组与指针 6.4 字符串与指针 6.5 函数与指针 6.6 返回指针值的函数
第十章 指针 指针是C语言的重要概念,是C语言的特色,是C语言的精华。 10.1 地址和指针的概念 内存中的每一个字节都有一个地址。
C程序设计.
第九章 指针.
第九节 赋值运算符和赋值表达式.
第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语言程序设计 第8章 指针.
第九章 指针 C程序设计中使用指针可以: 使程序简洁、紧凑、高效 有效地表示复杂的数据结构 动态分配内存 得到多于一个的函数返回值.
第八章 指 针 北京邮电大学出版社.
第六章 复合数据类型 指针的声明与使用 数组的声明与使用 指针与数组的相互引用 字符串及相关库函数 new与delete
第7章 地址和指针 7.1 地址和指针的概念 7.2 指针变量的定义和指针变量的基类型 7.3 给指针变量赋值 7.4 对指针变量的操作
Presentation transcript:

第8章 指针

主要内容 地址和指针的概念 变量的指针和指向变量的指针变量 数组与指针 字符串与指针 指向函数的指针 返回指针值的函数 指针数组和指向指针的指针 有关指针的数组类型和指针运算的小结

本章学习目标: 认识到用地址作为一种数据类型的重要性。 理解指针包括地址和类型两种属性。 掌握指针运算符&和*。 能够通过地址引用调用在被调函数与主调函数之间共享数据。 理解指针和数组的关系。 理解指向函数的指针的用法。

8.1 地址和指针的概念 指针:一个变量的地址。 指针变量:存放某一变量的地址(即指针)。 内存用户数据区 变量 i 变量 j 8.1 地址和指针的概念 内存用户数据区 变量 i 变量 j 变量 i_pointer 3 6 2000 2002 3010 指针:一个变量的地址。 指针变量:存放某一变量的地址(即指针)。

8.2 变量的指针和指向变量的指针变量 定义一个指针变量 定义的一般形式:基类型 *指针变量名; 例 int *p1,*p2; 8.2 变量的指针和指向变量的指针变量 定义一个指针变量 定义的一般形式:基类型 *指针变量名; 基类型:用来指定指针变量可以指向的变量的类型。 将决定指针移动和运算时的移动量。 * :表示该变量为指针类型 例 int *p1,*p2; float *q ; static char *name; 注意: 1、int *p1, *p2; 与 int *p1, p2; 2、指针变量名是p1,p2 ,不是*p1,*p2 3、指针变量只能指向定义时所规定类型的变量 4、指针变量定义后,变量值不确定,应用前必须先赋值

&与*运算符: 10 指针运算符(“间接访问”运算符) 取地址运算符 含义: 取指针所指向变量的内容 含义: 取变量的地址 …... 2000 2004 2006 2005 整型变量i 10 变量i_pointer 2001 2002 2003 指针变量 2000 10 i_pointer *i_pointer &i_pointer i i_pointer-----指针变量,它的内容是地址量 *i_pointer----指针的目标变量,它的内容是数据 &i_pointer---指针变量占用内存的地址

指针变量的初始化 一般形式:[存储类型] 数据类型 *指针名=初始地址值; 例 int i; int *p=&i; 赋给指针变量, 一般形式:[存储类型] 数据类型 *指针名=初始地址值; 例 int i; int *p=&i; 赋给指针变量, 不是赋给目标变量 变量必须已说明过 类型应一致 指针变量赋值: int i, j; int *p1, *p2; p1=&i; p2=&j ; i=3; *p1=5; j=6; *p2=8; 例 int i; int *p=&i; int *q=p; 例 int *p=&i; int i; 用已初始化指针变量作初值

指针变量的引用 例8.1 通过指针变量访问整型变量 #include <stdio.h> void main( ) 例8.1 通过指针变量访问整型变量 #include <stdio.h> void main( ) {int a, b, *p1, *p2 ; a=100; b=10; p1=&a; p2=&b; printf(“a=%d, b=%d\ n”,a, b); printf(“* p1=%d, * p2=%d\ n”, *p1, * p2); printf(“&a=%x,& b=%x\ n”,&a, &b); printf(“p1=%x, p2=%x\ n”, p1, p2); printf(“& p1=%x, &p2=%x\ n”, &p1, & p2); } 运行结果: a=100, b=10 *p1=100, *p2=10 &a=ffd4, &b=ffd6 p1=ffd4, p2=ffd6 &p1=ffd8, &p2=ffda 100 10 ffd4 ffd6 a b p1 p2 ffd8 ffda

关于 & 和 * 运算符的进一步说明: * 、&:优先级同为2级, 结合性:从右向左。 关于 & 和 * 运算符的进一步说明: * 、&:优先级同为2级, 结合性:从右向左。 1.若已执行: int a, b, * p1, * p2; p1=&a; p2=&b; a=100; b=10; 则 ① &* p1  &a (p1) &* p2  &b (p2) ②p2=&* p1  p2=&a 2. * & a:先进行&a得a的地址,再对a的地址进行* 运算 即指向a地址所指向的变量,就是a ,其值是100 3. 运算符 * ,++ :优先级为2, 结合性:从右到左 (* p1)++  a++ * p1++  * (p1++) 意即: p1原指向a , 现在指向下一个地址了。 &a p2 p1 10 100 b a &a &b p1 p2 10 100 b a

换后 换前 ffd0 ffd2 ffd4 ffd8 ffd6 p1 p2 p a b #include <stdio.h> void main( ) {int *p1, *p2, *p, a, b; scanf(“%d%d”,&a,&b); p1=&a;p2=&b; if(a<b) {p=p1; p1=p2; p2=p; } printf(“\na=%d, b=%d\n”, a, b); printf(“max=%d, min=%d\ n”, *p1, *p2); } 运行情况: 5,9  a=5, b=9 max=9,min=5 只交换了指针的值,没有交换变量的值 换后 换前 ffd8 ffd6 5 5 ffd0 ffd2 ffd4 ffd8 ffd6 ffd6 ffd8 20 ffd6 9 9 p1 p2 p a b

指针变量作为函数参数——地址传递 例8.3a 将数从大到小输出 #include <stdio.h> …... 2000 2008 200A 2002 2004 2006 例8.3a 将数从大到小输出 #include <stdio.h> void swap(int x,int y) { int temp; temp=x; x=y; y=temp; } void main() { int a,b; scanf("%d,%d",&a,&b); if(a<b) swap(a,b); printf("\n%d,%d\n",a,b); } 变量a 变量b (main) 5 5 9 9 变量temp 变量y 变量x (swap) COPY 9 5 5 运行结果: 5 , 9  5 , 9

#include <stdio.h> void swap(int *p1, int *p2) { int *p; p=p1; 例8.3b 将数从大到小输出 #include <stdio.h> void swap(int *p1, int *p2) { int *p; p=p1; p1=p2; p2=p;} void main() { int a,b; int *pointer_1,*pointer_2; scanf("%d,%d",&a,&b); pointer_1=&a; pointer_2=&b; if(a<b) swap(pointer_1,pointer_2); printf("%d,%d",*pointer_1,*pointer_2); } …... 2000 2008 200A 2002 2004 2006 200C 200E 2010 ... 整型a 整型b (main) pointer_1 pointer_2 5 9 2000 2000 2002 2002 (swap) 指针p1 指针p2 指针p **** 2002 2000 2000 运行结果:5,9

#include <stdio.h> void main() { void swap(int *p1, int *p2); 例8.3 将数从大到小输出 (使用指针变量作函数参数) #include <stdio.h> void main() { void swap(int *p1, int *p2); int a,b; int *pointer_1,*pointer_2; scanf("%d,%d",&a,&b); pointer_1=&a; pointer_2=&b; if(a<b)swap(pointer_1,pointer_2); printf("\n%d,%d\n",a,b);} void swap(int *p1, int *p2) { int temp; temp=*p1; *p1=*p2; *p2=temp;} …... 2000 2008 200A 2002 2004 2006 200C 200E 2010 ... 整型变量a 整型变量b (main) 指针pointer_1 指针pointer_2 9 5 地址传递 5 9 2000 2000 2002 2002 (swap) 指针p1 指针p2 整型temp 5 运行情况: 5,9  9,5 问题:函数调用结束后, 分配给p1,p2,temp单元释放否?

#include <stdio.h> void main( ) 例8.5 输入a,b,c3个整数,按从大到小输出 #include <stdio.h> void main( ) {void exchange(int *q1, int *q2, int *q3); int a,b,c,*p1,*p2,*p3; scanf(“%d,%d,%d”,&a,&b,&c); p1=&a; p2=&b; p3=&c; exchange(p1, p2, p3); printf(“\n%d, %d, %d\ n”,a, b, c);} 运行情况: 9 , 0 , 10  10 , 9 , 0 ffbc ffc2 ffc4 ffca ffcc ffce ffd0 ffd2 ffd4 ffd6 ffd8 ffda temp pt1 pt2 q2 q1 q3 a b c p1 p2 p3 9 10 10 9 0 ffd0 ffd2 ffd4 ffd4 0 0 9 10 9 0 void exchange(int *q1, int *q2, int *q3) {void swap(int *pt1, int *pt2); if(*q1 < *q2) swap(q1, q2); if(*q1 < *q3) swap(q1, q3); if(*q2 < *q3) swap(q2, q3);} void swap(int *pt1, int *pt2) {int temp; temp=*pt1; *pt1=*pt2; *pt2=temp;}

8.3 数组与指针 Q1:如何用指针指向数组? Q2:如何用指针访向数组元素?

回顾 数组名代表什么? 如何访向数组元素及地址? int a[5]; // a代表这组数的首地址 指针变量里存放的是什么? int *p; // p里存放的是内存单元地址

Q1:如何用指针指向数组? int a[5]={1,2,3,4,5}, *p; p= ; a &a[2]

P++;//指针移动 P--; *P=5; Q2:如何用指针访向数组元素? int a[5]={1,2,3,4,5}, *p=a;

a[i]  p[i]  *(p+i) *(a+i) [] 变址运算符 a[i]  *(a+i) 表示数组元素的两种方法: a[0] a[1] a[2] a[3] a[9] ... a a+9 a+1 a+2 地址 元素 下标法 a[0] a[1] a[2] a[3] a[9] ... p p+9 p+1 p+2 地址 元素 指针法 *p *(p+1) *(p+2) *(p+9) *a *(a+1) *(a+2) *(a+9) p[0] p[1] p[2] p[9] a[i]  p[i]  *(p+i) *(a+i)

例8.6 用三种方法输出数组中全部元素的值 ⑴ 下标法: #include <stdio.h> void main() 例8.6 用三种方法输出数组中全部元素的值 ⑴ 下标法: #include <stdio.h> void main() {int a[10]; int i; for(i=0; i<10; i++) scanf("%d",&a[i]); printf("\n"); printf("%d",a[i] );} ⑷ 指针法和指针下标: #include <stdio.h> void main() {int a[10]; int *p,i; for(i=0; i<10; i++) scanf("%d",&a[i]); printf("\n"); for(p=a,i=0; i<10; i++) printf("%d",*(p+i));} ⑵ 用数组名: #include <stdio.h> void main() {int a[10]; int i; for(i=0; i<10; i++) scanf("%d",&a[i]); printf("\n"); printf("%d",*(a+i));} ⑶ 指针法: #include <stdio.h> void main() {int a[10]; int *p,i; for(i=0; i<10; i++) scanf("%d",&a[i]); printf("\n"); for(p=a; p<(a+10); p++) printf("%d",*p );} 运行情况: 1 2 3 4 5 6 7 8 9 0  1 2 3 4 5 6 7 8 9 0

#include <stdio.h> void main() { int *p,i,a[10]; p=a; 例8.7 用指针变量输出元素 #include <stdio.h> void main() { int *p,i,a[10]; p=a; for(i=0;i<10;i++) scanf(“%d”,p++); printf(“\n”); for(i=0;i<10;i++,p++) printf(“%d”,*p); } 例8.7 用指针变量输出元素 #include <stdio.h> void main() { int *p,i,a[10]; p=a; for(i=0;i<10;i++) scanf(“%d”,p++); printf(“\n”); p=a; /*或者p=&a[0]*/ for(i=0;i<10;i++,p++) printf(“%d”,*p); } 原因? 能正确输出吗? 运行情况: 1 2 3 4 5 6 7 8 9 0  22153 234 0 0 30036 25202 11631 8259 8237 28483 运行情况: 1 2 3 4 5 6 7 8 9 0  1 2 3 4 5 6 7 8 9 0

编译时arr按指针变量处理,所以,此句与f(int *arr , int n)等价。 用数组名作函数参数 数组名作函数参数 void main( ) {f(int arr[ ], int n); int array[10]; ┆ f(array, 10); } void f(int arr[ ], int n) { arr[0] array[0] ┋ arr[1] array[1] arr[9] array[9] 编译时arr按指针变量处理,所以,此句与f(int *arr , int n)等价。

例8.8 将数组a中n个整数按相反顺序存放。 思路:数组元素头尾对调。四种调用方式。 m=4 ⑴ 实参与形参均用数组 #include <stdio.h> void main() {void inv(int x[ ], int n); int i,a[10]={3,7,9,11,0,6,7,5,4,2}; printf("The original array:\n"); for(i=0;i<10;i++) printf("%d,"a[i]); printf("\n"); inv(a,10); printf("The array has been inverted:\n"); for(i=0;i<10;i++) printf("%d,",a[i]); } void inv(int x[ ], int n) { int temp,i,j,m=(n-1)/2; for(i=0;i<=m;i++) { j=n-1-i; temp=x[i]; x[i]=x[j]; x[j]=temp; } return; 例8.8 将数组a中n个整数按相反顺序存放。 思路:数组元素头尾对调。四种调用方式。 m=4 i j i j i j i j j i 3 7 9 11 0 6 7 5 4 2 0 1 2 3 4 5 6 7 8 9 2 3 4 7 5 9 11 7 6

⑵ 实参用数组,形参用指针变量 #include <stdio.h> void main() {void inv(int *x, int n); int i,a[10]={3,7,9,11,0,6,7,5,4,2}; printf("The original array:\n"); for(i=0;i<10;i++) printf("%d,"a[i]); printf("\n"); inv(a,10); printf("The array has been inverted:\n"); for(i=0;i<10;i++) printf("%d,",a[i]); } void inv(int *x, int n) { int temp,*p,*i,*j,m=(n-1)/2; i=x; j=x+n-1; p=x+m; for(;i<=p;i++,j--) { temp=*i; *i=*j; *j=temp; } return; 3 7 9 11 6 5 4 2 a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] x p=x+m a数组 j i 2 3 i j 4 7 i j 5 9 i j 7 11 j i 6

此句用意? ⑶例8.8 实参与形参均用指针变量 #include <stdio.h> void main() {void inv(int *x, int n); int i,arr[10],*p=arr; printf("The original array:\n"); for(i=0;i<10;i++,p++) scanf("%d",p); p=arr; inv(p,10); printf("The array has been inverted:\n"); for(p=arr;p<arr+10;p++) printf("%d",*p); printf(“\n"); } void inv(int *x, int n) { int *p, m, temp,*i,*j; m=(n-1)/2; i=x; j=x+n-1; p=x+m; for(;i<=p;i++,j--) { temp=*i; *i=*j; *j=temp; } return;} 此句用意?

⑷ 实参用指针变量,形参用数组 #include <stdio.h> void main() {void inv(int x[ ], int n); int i,a[10],*p=a; for(i=0;i<10;i++,p++) scanf("%d",p); p=a; inv(p,10); printf("The array has been inverted:\n"); for(p=arr;p<arr+10;p++) printf("%d ",*p); printf(“\n "); } void inv(int x[ ], int n) { int t,i,j,m=(n-1)/2; for(i=0;i<=m;i++) { j=n-1-i; t=x[i]; x[i]=x[j]; x[j]=t; } return;

为了得到两个结果值,用两个全局变量max和min。 例 从10个数中找出其中最大值和最小值 为了得到两个结果值,用两个全局变量max和min。 ⑴ 实参和形参均用数组 int max, min; /* 全局变量*/ void max_min_value(int array[ ],int n) { int *p, *array_end; array_end=array+n; /*指向数组最后一个元素的后面 */ max=min=*array; /* 相当于max=min=array[0] */ for(p=array+1; p<array_end; p++) /* p指向array[1] */ if(*p > max) max=*p; else if(*p<min) min=*p; } main( ) { int i, number[10]; printf(“enter 10 integer numbers:\ n”); for(i=0;i<10;i++) scanf(“%d”,&number[i]); max_min_value(number,10); printf(“\nmax=%d, min=%d\n”, max, min); }

⑵ 实参和形参均用指针变量 int max, min; /* 全局变量*/ void max_min_value(int *array,int n) { int *p, *array_end; array_end=array+n; /*指向数组最后一个元素的后面 */ max=min=*array; /* 相当于max=min=array[0] */ for(p=array+1; p<array_end; p++) /* 使p指向array[1] */ if(*p > max) max=*p; else if(*p<min) min=*p; } main( ) { int i, number[10],*p; p=number; /* 使p指向number数组 */ printf(“enter 10 integer numbers:\ n”); for(i=0;i<10;i++,p++) scanf(“%d”,p); printf("the 10 integer numbers:\n"); for(p=number,i=0;i<10;i++,p++) printf("%d ",*p); p=number; max_min_value(p,10); printf(“\nmax=%d, min=%d\n”, max, min); }

归纳:用数组做函数参数有如下四种情况: 1、实参形参都用数组名: int a[10]; inv(int x[ ],int n) inv(a,10) { …... } 2、实参用数组名,形参用指针变量: int a[10]; inv(int *x,int n) 3、实参形参都用指针变量: int *p=a; {……} inv(p,10) 4、实参用指针变量,形参用数组名: int *p=a; {…...}

例8.9 用选择法对10个整数排序 ⑴ 实参用指针变量,形参用数组 #include <stdio.h> void main() {void sort(int x[ ], int n); int *p,i,a[10]; p=a; for(i=0;i<10;i++) scanf("%d",p++); p=a; sort(p,10); for(p=a,i=0;i<10;i++) {printf("%d ",*p); p++;} } void sort(int x[ ], int n) { int i,j,k,t; for(i=0;i<=n-1;i++) { k=i; for(j=i+1;j<n;j++) if(x[j]>x[k]) k=j; if(k!=i) {t=x[i];x[i]=x[k];x[k]=t;} } } 例8.9 用选择法对10个整数排序

列元素地址:a[1]+3  *(a+1)+3  &a[1][3] 多维数组与指针 int a[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}}; 列元素地址 a[2]+0 1 3 5 7 9 11 13 15 17 19 21 23 a[0]+0 a[0]+1 a[0]+2 a[0]+3 a+0 a+1 a+2 a[1]+3 行地址 列元素地址:a[1]+3  *(a+1)+3  &a[1][3]

*(a[1]+2),*(*(a+1)+2),a[1][2] 表示形式 含义 地址 a 二维数组名,数组首地址 a[0],*(a+0),*a 第0行第0列元素地址 a+1 第1行首地址 a[1],*(a+1) 第1行第0列元素地址 a[1]+2,*(a+1)+2,&a[1][2] 第1行第2列元素地址 *(a[1]+2),*(*(a+1)+2),a[1][2] 第1行第2列元素值 2000 2008 2012 13

指向多维数组的指针变量 指向数组元素的指针变量 例8.12 用指针变量输出数组元素的值 #include <stdio.h> void main() { static int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23}; int *p; for(p=a[0];p<a[0]+12;p++) { if((p-a[0])%4==0) printf("\n"); printf("%4d ",*p); }

a a+1 a+2 p p+1 p+2 p[0]+1或 *p+1 p[1]+2或 *(p+1)+2 *(*p+1)或 (*p)[1] 指向由m个元素组成的一维数组的指针变量 定义形式: 数据类型 (*指针名)[一维数组维数]; 例 int (*p)[4]; int a[3][4]; a[0][0] a[0][1] a[1][0] a[1][1] a[2][0] a[2][1] a[0][2] a[0][3] a[1][2] a[1][3] a[2][2] a[2][3] a a+1 a+2 p p+1 p+2 ( )不能少 int (*p)[4]与int *p[4]不同 可让p指向二维数组某一行 如 int a[3][4], (*p)[4]=a; p[0]+1或 *p+1 p[1]+2或 *(p+1)+2 p的值是一维数组的 首地址,p是行指针 *(*p+1)或 (*p)[1] *(*(p+1)+2) 一维数组指针变量维数和 二维数组列数必须相同

例8.13 输出二维数组任一行任一列元素的值 #include <stdio.h> void main() { static int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23}; int (*p)[4], i, j; p=a; scanf(“i=%d, j=%d”, &i, &j); printf(“a[%d][%d]=%d\ n”, i, j, *(*(p+i)+j)); } 1 3 5 7 9 11 13 15 17 19 21 23 a,a+0,p+0 a+1,p+1 a+2,p+2 运行结果: i=1, j=2 a[1][2]=13

8.4 字符串与指针 字符串的表示形式 char string[ ]=“I love China!”; 8.4 字符串与指针 字符串的表示形式 字符串: 用双引号括起的一串字符。 I l o v e C h i string[0] string[1] string[2] string[3] string[4] string[5] string[6] string[7] string[8] string[9] string string[10] string[11] string[12] string[13] n ! a \0 char string[ ]=“I love China!”; char *string="I love China!"; string+7

#include <stdio.h> void main( ) { char *string=“I love China!”; 改动后的例8.16 #include <stdio.h> void main( ) { char *string=“I love China!”; printf(“%s\n”,string); string+=7; while(*string) { putchar(*string); string++; } I l o v e C h i string n ! a \0 *string!=‘\0’ string 输出: I love China! China!

用下标法存取字符串中的字符 地址访问: a[ ]复制到b[ ] 例8.18 将字符串a复制为字符串b #include <stdio.h> void main( ) { char a[ ]="I am boy.",b[20]; int i; for(i=0;*(a+i)!='\0';i++) *(b+i)=*(a+i); *(b+i)='\0'; printf("string a is: %s\n",a); printf("string b is: "); for(i=0;b[i]!='\0';i++) printf("%c",b[i]); printf("\n"); }  b[i]=a[i] 下标法输出 运行结果: string a is: I am boy. string b is: I am boy.

运行结果: 运行结果: 例8.19 用指针变量实现例8.18 #include <stdio.h> void main( ) b y p1 . \0 p2 例8.19 用指针变量实现例8.18 #include <stdio.h> void main( ) { char a[ ]=“I am boy.”,b[20]; char *p1=a,*p2=b; int i; for( ; *p1!=‘\0’ ; p1++,p2++) {*p2=*p1;} *p2='\0'; printf(“string a is: %s\n”, a ); printf(“string b is: %s\n”, b ); } p1=a; p2=b; p1 p2 p1 p2 运行结果: string a is: I am boy. string b is: I am boy. 运行结果: string a is: string b is:

字符指针作函数参数 例8.20 用函数调用实现字符串的复制 a I m t e c h \0 r . from b y u a r s t n d e to o . \0 I a e c h \0 r . t m 例8.20 用函数调用实现字符串的复制 ⑴用字符数组作参数 #include <stdio.h> void main() {void copy_string(char from[],char to[]); char a[ ]="I am a teacher."; char b[ ]="You are a student."; printf("string_a=%s\n string_b=%s\n",a,b); printf(“copy string_a to string_b: \n"); copy_string(a,b); /* 数组名作参数是地址传递*/ printf(“\nstring_a=%s\nstring_b=%s\n",a,b); } void copy_string(char from[],char to[]) { int i=0; while(from[i]!='\0') { to[i]=from[i]; i++; } to[i]='\0';

⑵字符指针变量作形参 #include <stdio.h> void main() { void copy_string(char *from,char *to); char *a="I am a teacher."; char *b="You are a student."; printf("string_a=%s\n string_b=%s\n",a,b); printf(“copy string_a to string_b: \n"); copy_string(a,b); printf(“\nstring_a=%s\nstring_b=%s\n",a,b); } void copy_string(char *from,char *to) { for(;*from!='\0';from++,to++) {*to=*from;} *to='\0';

对使用字符指针变量和字符数组的讨论 char *cp; 与 char str[20]; 的区别 str由若干元素组成,每个元素放一个字符;而cp中存放字符串首地址 赋值方式: 字符数组只能对元素赋值。 char str[20]; str=“I love China!”; () 字符指针变量可以用: char *cp; cp=“I love China!”; () 赋初值:char *cp="China!"; 等价 char *cp; cp=“China!”; char str[14]={"China"};不等价char str[14]; str[ ]="China" ()

用指针变量指向的格式字符串代替printf中的格式字符串(可变格式输出函数) char *format; format="a=%d,b=%f\n"; printf(format,a,b); 相对于: printf("a=%d,b=%f\n"a,b); 可以用字符数组实现: char format[ ]="a=%d,b=%f\n";

判断和修正: char str[]={“Hello!”}; () char str[]=“Hello!”; () char str[]={‘H’,‘e’,‘l’,‘l’,‘o’,‘!’}; () char *cp=“Hello”; () int a[]={1,2,3,4,5}; () int *p={1,2,3,4,5}; () int *p=&a; char str[10],*cp; int a[10],*p; str=“Hello”; () cp=“Hello!”; () a={1,2,3,4,5}; () p={1,2,3,4,5}; () str[10]=“Hello”; a[10]={1,2,3,4,5}; p=&a;

8.5 指向函数的指针 用函数指针变量调用函数。 函数指针:函数在编译时被分配的入口地址,用函数名表示。函数指针指向的是程序代码存储区。 8.5 指向函数的指针 用函数指针变量调用函数。 函数指针:函数在编译时被分配的入口地址,用函数名表示。函数指针指向的是程序代码存储区。 函数指针变量定义形式: 数据类型 (*指针变量名)( ); 如 int (*p)(); max …... 指令1 指令2 函数指针变量赋值:如 p=max; ( )不能省 int (*p)() 与 int *p()不同 专门存放函数入口地址 可指向返回值类型相同的不同函数 函数返回值的数据类型 函数调用形式: c=max(a,b);  c=(*p)(a,b); 对函数指针变量pn, p++, p--无意义 函数指针变量指向的函数必须有函数说明

例8.22 求a和b中的大者 ⑴一般方法: ⑵通过指针变量访问函数 #include <stdio.h> void main() { int max(int , int); int (*p)(int , int); int a,b,c; p=max; scanf("%d,%d",&a,&b); c=(*p)(a,b); printf("a=%d,b=%d,max=%d\n",a,b,c); } int max(int x,int y) { int z; if(x>y) z=x; else z=y; return(z);} ⑴一般方法: #include <stdio.h> void main() { int max(int ,int); int a,b,c; scanf("%d,%d",&a,&b); c=max(a,b); printf("a=%d,b=%d,max=%d\n",a,b,c); } int max(int x,int y) { int z; if(x>y) z=x; else z=y; return(z);}

接受search函数返回的指向某学生0门课程地址的指针变量 #include <stdio.h> void main() { float score[ ][4]={{60,70,80,90},{56,89,67,88},{34,78,90,66}}; float *search(float (*pointer)[4],int n); float *p; int i,m; printf("Enter the number of student:"); scanf("%d",&m); printf("The scores of No.%d are:\n",m); p=search(score,m); for(i=0;i<4;i++) printf("%5.2f\t",*(p+i)); printf("\n");} float *search(float (*pointer)[4], int n) { float *pt; pt=*(pointer+n-1); return(pt);} 8.6 返回指针值的函数 函数定义形式: 类型标识符 *函数名(参数表); 例 int *f(int x, int y) 接受search函数返回的指向某学生0门课程地址的指针变量 例8.25:有若干学生成绩,要求输入学生序号后,能输出 该学生全部成绩。用指针函数实现。 p p p p pointer pointer+1 34 78 90 66 56 89 67 88 60 70 80 score数组 指向实型变量的指针变量 形参指向一维数组的指针变量

< > 例8.26 找出例8.25中有不及格课程的学生及其学号 #include <stdio.h> 例8.26 找出例8.25中有不及格课程的学生及其学号 #include <stdio.h> void main() { float score[ ][4]={{60,70,80,90},{56,89,67,88},{34,78,90,66}}; float *search(float (*pointer)[4]); float *p; int i,j; for(i=0;i<3;i++) { p=search(score+i); if (p==*(score+i)) { printf("No. %d scores: ",i); for(j=0;j<4;j++) printf("%5.2f\t",*(p+j));} } } float *search(float (*pointer)[4]) { int i; float *pt; pt=NULL; for(i=0;i<4;i++) if(*(*pointer+i)<60) {pt=*pointer;break;} return(pt); } *pointer pt (当有不及格时) NULL pt (当无不及格时) pointer score+1 34 78 90 66 56 89 67 88 60 70 80 score数组 < >

例 int *p[4]; 8.7 指针数组和指向指针的指针 指针数组的概念 用于处理二维数组或多个字符串 定义:数组中的元素均为指针变量 8.7 指针数组和指向指针的指针 用于处理二维数组或多个字符串 指针数组的概念 定义:数组中的元素均为指针变量 定义形式:[存储类型] 类型名 *数组名[数组长度]; 例 int *p[4]; 指针所指向变量的数据类型 区分int *p[4]与int (*p)[4]

指针数组赋值与初始化 初始化: main() { int b[2][3],*pb[ ]={b[0],b[1]}; …….. } 赋值: int *pb[2] pb[0] pb[1] int b[2][3] 1 2 3 4 6 赋值: main() { int b[2][3],*pb[2]; pb[0]=b[0]; pb[1]=b[1]; ┊ }

p[0]=a; p[1]=b; p[2]=c; p[3]=NULL; …….. } 或: { char *p[4]; 指针数组赋值与初始化 L i s p \0 F o r t r a n \0 B a s i c \0 p[0] p[1] p[2] p[3] 赋值: main() { char a[]="Fortran"; char b[]="Lisp"; char c[]="Basic"; char *p[4]; p[0]=a; p[1]=b; p[2]=c; p[3]=NULL; …….. } 或: { char *p[4]; p[0]= "Fortran"; p[1]= "Lisp"; p[2]= "Basic"; p[3]=NULL; 初始化: main() { char *p[]={"Fortran", "Lisp", "Basic",NULL}; …….. } L i s p \0 F o r t r a n \0 B a s i c \0 p[0] p[1] p[2] p[3]

char name[5][9]={“gain”,“much”,“stronger”, “point”,“bye”}; 二维数组与指针数组区别: char name[5][9]={“gain”,“much”,“stronger”, “point”,“bye”}; g a i n \0 s t r o n g e r \0 p o i n t \0 m u c h \0 name[0] name[1] name[2] name[3] name[4] b y e \0 g a i n \0 s t r o n g e r \0 p o i n t \0 m u c h \0 b y e \0 char *name[5]={“gain”,“much”,“stronger”, “point”,“bye”}; 指针数组元素的作用相当于二维数组的行名 但指针数组中元素是指针变量 二维数组的行名是地址常量 二维数组存储空间固定 字符指针数组相当于可变列长的二维数组

for(j=0;j<3;j++,pb[i]++) printf("b[%d][%d]:%2d\n",i,j,*pb[i]); } 例 用指针数组处理二维数组 main() { int b[2][3],*pb[2]; int i,j; for(i=0;i<2;i++) for(j=0;j<3;j++) b[i][j]=(i+1)*(j+1); pb[0]=b[0]; pb[1]=b[1]; for(j=0;j<3;j++,pb[i]++) printf("b[%d][%d]:%2d\n",i,j,*pb[i]); } int *pb[2] pb[0] pb[1] int b[2][3] b[0][0] *pb[0] b[0][1] *(pb[0]+1) b[0][2] *(pb[0]+2) b[1][0] *pb[1] b[1][1] *(pb[1]+1) b[1][2] *(pb[1]+2) 1 2 3 4 6

k k j j j j i=0 例8.26 对字符串排序(简单选择排序) name Follow me name[0] name[1] 例8.26 对字符串排序(简单选择排序) name[0] name[1] name[2] name[3] name[4] name Great Wall FORTRAN Computer Follow me BASIC k k j j j j i=0

例8.26 对字符串排序(简单选择排序) #include <stdio.h> #include <string.h> void main() { void sort(char *name[ ],int n); void print (char *name[ ],int n); char *name[]={"Follow me","BASIC", "Great Wall","FORTRAN","Computer design"}; int n=5; sort(name,n); print(name,n); } void sort(char *name[ ],int n) { char *temp; int i,j,k; for(i=0;i<n-1;i++) { k=i; for(j=i+1;j<n;j++) if(strcmp(name[k],name[j])>0) k=j; if(k!=i) { temp=name[i]; name[i]=name[k]; name[k]=temp;} } } void print(char *name[ ], int n) { int i ; for(i=0; i<n; i++) printf("%s\n",name[ i ]; } name name[0] Follow me name[1] BASIC name[2] Great Wall name[3] FORTRAN name[4] Computer

指向指针的指针—多级指针(了解) 一级指针:指针变量中存放目标变量的地址 例 int *p; int i=3; p=&i; *p=5; 单级间接寻址 二级指针:指针变量中存放一级指针变量的地址 例 int **p1; int *p2; int i=3; p2=&i; p1=&p2; **p1=5; p1 &p2 &i 3 P2(指针变量) i(整型变量) 二级指针 一级指针 目标变量 二级间接寻址

定义形式:[存储类型] 数据类型 **指针名; 如:char **p 定义形式:[存储类型] 数据类型 **指针名; 如:char **p 如果:char *name[ ]={"Follow me"……}; char **p; p=name+2; 则:printf("%s\n",*p); 输出:Great Wall 指针本身的存储类型 最终目标变量的数据类型 name name[0] name[1] name[2] name[3] name[4] name Great Wall FORTRAN Computer Follow me BASIC p

二级指针与指针数组的关系 int **p 与 int *q[10] 指针数组名是二级指针常量 p=q; p+i 是q[i]的地址 指针数组作形参,int *q[ ]与int **q完全等价;但作为变量定义两者不同 系统只给p分配能保存一个指针值的内存区;而给q分配10块内存区,每块可保存一个指针值

指针数组作main函数的形参(掌握) main函数的一般调用形式: main( ) main函数的有参数调用形式 : main( int argc , char *argv[ ] ) 其中( int argc , char *argv[ ] 是形参,可以多个: int argc; 命令名和所有参数个数之和 char *argv[ ]; 各元素是指针,分别指向各参数字符串 在实际运行程序时,实参和命令名(C程序编译和连接后得到的可执行文件名)以命令行形式给出: 命令名 参数1 参数2 …… 参数n [回车]

main(int argc, char *argv[]) { while(argc>1) { ++argv; 例 用命令行参数方式运行程序 /*test.c*/ main(int argc, char *argv[]) { while(argc>1) { ++argv; printf("%s\n",*argv); --argc; } argv[0] argv[1] argv[2] char *argv[] world test hello argv argc=3 1. 编译、链接test.c,生成可执行文件test.exe 2. 在DOS状态下运行(test.exe所在路径下) 例如: C:\TC> test[.exe] hello world! 运行结果:hello world!

main(int argc, char *argv[]) { while(argc-->0) printf("%s\n",*argv++); } argv[0] argv[1] argv[2] char *argv[] world test hello argv argc=3 例如: C:\TC> test[.exe] hello world! 运行结果:test hello world!

malloc(100) calloc(3, 50) free(p) realloc(p,50) 8.8 动态内存分配与指向它的指针变量 8.8 动态内存分配与指向它的指针变量 1、内存动态分配相关函数(头文件:stdlib.h) 示例 作用 malloc(100) 申请一个100个字节大小的连续空间 calloc(3, 50) 申请3个50个字节大小的连续空间 free(p) 释放指针变量所指向的动态空间 realloc(p,50) 将p所指向的动态空间大小改变为50个字节

2、void指针类型 定义时不指定指向哪一类数据 用动态存储分配函数时返回void指针 它的值赋给另一指针变量时,要强制类型转换 例:char *p1; void *p2; ┊ p1=(char *)p2; 或p2=(void *)p1; void *fun(char ch1,char ch2) 返回“空类型”地址 P1=(char *)fun(ch1,ch2); 引用时要类型转换

8.9 有关指针的数据类型和指针运算的小结 有关指针的数据类型的小结 定 义 含 义 int i; 定义整型变量i int *p ; 8.9 有关指针的数据类型和指针运算的小结 有关指针的数据类型的小结 定 义 含 义 int i; 定义整型变量i int *p ; p为指向整型数据的指针变量 int a[n] ; 定义有n个元素的整型数组a int *p[n] ; 定义由n个指向整型数据的指针元素组成的指针数组p int (*p)[n] ; p为指向含n个元素的一维数组的指针变量 int *p( ) ; p为返回一个指针的函数,该指针指向整型数据 int (*p)( ) ; p为指向函数的指针,该函数返回一个整型值 int **p ; p为一个指针变量,它指向一个指向整型数据的指针变量 int f( ) ; f为可返回整型函数值的函数

指针运算小结 ⑴ 指针变量加(减)一个整数 如:p++;p--;p+i;p-i;p+=i;p-=i等,加减的值与类型有关。 ⑵ 指针变量赋值 p=&a (将变量a的地址赋给p) p=array;(将数组array首地址赋给p) p=&array[i];(将数组array第i个元素的地址赋给p) p=max;(max为已定义的函数,将max函数的入口地址赋给p) p1=p2;(p1和p2都是指针变量,将p2的值赋给p1) (3) 指针变量不指向任何变量,即取空值。表示为:p=NULL; (4) 两个指针变量可以相减 如果两个指针变量指向同一个数组为元素,则两个指针变量值之差是 两个指针之间的元素个数。但p1+p2并无实际意义。 (5) 两个指针变量比较 如果两个指针变量指向同一个数组为元素,则可以进行地址比较。

例 下列定义的含义 ⑴ int *p[3]; ⑵ int (*p)[3]; ⑶ int *p(int); ⑷ int (*p)(int); ⑸ int *(*p)(int); ⑹ int (*p[3])(int); ⑺ int *(*p[3])(int); 指针数组 指向一维数组的指针 返回指针的函数 指向函数的指针,函数返回int型变量 函数指针数组,函数返回int型变量 函数指针数组,函数返回int型指针

本章小结 指针C语言的一个重要概念,也是C语言的一个重要特色。正确灵活地运用指针可以有效地表达复杂的数据结构,动态地分配内存以及方便地处理字符串,有效而方便地使用数组,可以直接处理内存等。