Chap 8 指针 8.1 寻找保险箱密码 8.2 狸猫换太子 8.3 冒泡排序 8.4 加密变换问题 8.5 任意个整数求和问题*

Slides:



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

第七章 指针 计算机公共教学部.
第7章 指针 存储地址的变量的类型就是指针类型 能直接对内存地址操作, 实现动态存储管理 容易产生副作用, 初学者常会出错
电子成绩单项目实现.
C语言程序设计基础 第10章 指针进阶 刘新国.
10.1 二级指针 10.2 指针与二维数组 10.3 指针的动态存储分配 10.4 函数指针 10.5 main函数的参数
第九章 字串 (String).
補充: Input from a text file
第6章 指针 6.1 指针的概念 6.2 变量与指针 6.3 数组与指针 6.4 字符串与指针 6.5 函数与指针 6.6 返回指针值的函数
6.4 字符串与指针 1. 用字符数组存放一个字符串.
8.1 指针的概念 8.2 指针变量 8.3 指针变量的基础类型 8.4 指针的运算 8.5 指针与一维数组 8.6 指针应用实例
第九章 字符串.
第8章 字元與字串處理 8-1 C語言的字元檢查函數 8-2 C語言的字串 8-3 字串的輸入與輸出 8-4 指標與字串
第6章 指针 学习目的与要求: 了解指针的概念和相关术语 熟练掌握指向变量、数组和字符串的指针变量的使用方法 了解指向函数的指针变量
第六章 数 组 主讲教师 贾月乐 联系电话:
指 针 为什么要使用指针 指针变量 指针与数组 返回指针值的函数 动态内存分配 通过指针引用字符串 指向函数的指针 小 结 习 题.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
程序设计II 第三讲 字符串处理.
第八章 指 针 8.1 指针的概念与定义 8.2 指针作函数参数 8.3 指针与数组 8.4 指针与函数 8.5 复杂指针.
第 十 章 指 针.
C语言高级编程(第四部分) 字符串 北京大学 信息科学技术学院.
Chap 2 用C语言编写程序 2.1 在屏幕上显示 Hello World! 2.2 求华氏温度 100°F 对应的摄氏温度
目录 第八章 数组 1 简单学生成绩管理系统的开发 2 一维数组 3 多维数组 4 字符数组 5 数组作函数参数.
STRUCTURE 授課:ANT 日期:2010/5/12.
计算概论 第十八讲 C语言高级编程 结构与习题课 北京大学信息学院.
Introduction to the C Programming Language
Chap 8 指针 8.1 寻找保险箱密码 8.2 角色互换 8.3 冒泡排序 8.4 电码加密 8.5 任意个整数求和*
C语言程序设计 李祥.
二维数组的指针表示 与复杂的指针例子 专题研讨课之三.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
C语言 程序设计基础与试验 刘新国、2012年秋.
C语言程序设计基础 第8章 指针 刘新国.
字符串和字符数组 字符串的输入和输出 字符串的基本操作
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
第八章 使用指针.
第五章 习题课 电子信息与计算机科学系 曾庆尚.
第5讲 结构化程序设计(Part II) 周水庚 2018年10月11日.
第七章 函数及变量存贮类型 7.1 函数基础与C程序结构 7.2 函数的定义和声明 7.3 函数的调用 7.4 函数的嵌套与递归
第4章 顺序程序设计.
数组 梁春燕 华电信息管理教研室.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
C语言概述 第一章.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
C语言复习3----指针.
C语言大学实用教程 第6章 数组 西南财经大学经济信息工程学院 刘家芬
第八章 指標 (Pointer).
C语言的特点 1. C程序由许多函数组成 2. C程序必须有且只有一个主函数main( ) 3. 函数用“{”和“}”表示起点和终点
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
第6讲 指针与引用 6.1 指针 6.2 引用.
C语言程序设计 第一章 数据类型, 运算符与表达式 第二章 顺序程序设计 第三章 选择结构程序设计 第四章 循环控制 第五章 数组.
Chap 5 函数 5.1 计算圆柱体积 5.2 使用函数编写程序 5.3 变量与函数.
C程序设计.
第4章 数 组.
第九章 指针.
第九节 赋值运算符和赋值表达式.
3.16 枚举算法及其程序实现 ——数组的作用.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
C程序设计.
Introduction to the C Programming Language
C/C++基礎程式設計班 字元與字串 講師:林業峻 CSIE, NTU 3/14, 2015.
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
C语言程序设计 第8章 指针.
Chap 7 数 组 7.1 排序问题 7.2 找出矩阵中最大值所在的位置 7.3 进制转换.
基本知识 数据类型、变量、常量、运算符.
Introduction to the C Programming Language
C/C++基礎程式設計班 C語言入門、變數、基本處理與輸入輸出 講師:林業峻 CSIE, NTU 3/7, 2015.
C/C++基礎程式設計班 陣列 講師:林業峻 CSIE, NTU 3/14, 2015.
台大資訊工程學系 資料系統訓練班 第119期 吳晉賢
第7章 地址和指针 7.1 地址和指针的概念 7.2 指针变量的定义和指针变量的基类型 7.3 给指针变量赋值 7.4 对指针变量的操作
C++语言程序设计 C++语言程序设计 第二章 基本数据类型与表达式 第十一组 C++语言程序设计.
Presentation transcript:

Chap 8 指针 8.1 寻找保险箱密码 8.2 狸猫换太子 8.3 冒泡排序 8.4 加密变换问题 8.5 任意个整数求和问题*

例8-1 利用指针模拟寻找保险箱密码的过程 获取密码的两种方法 int main(void) 例8-1 利用指针模拟寻找保险箱密码的过程 The key is: 911 If I know the address of the key, I also can get it: 911 获取密码的两种方法 int main(void) { int key = 911; /* 变量key存放密码 */ int *addr = NULL; /* 变量addr存放地址 */   addr = &key; /* 将key的地址赋给addr */ /* 通过变量key输出密码值*/ printf("The key is: %d\n", key); /* 通过变量key的地址来输出密码值 */ printf("If I know the address of the key, I also can get it: %d\n", *addr);   return 0; }

8.1.2 地址和指针-指针的概念 内存单元 地址 内容 变量 直接访问:通过变量名访问 8.1.2 地址和指针-指针的概念 内存单元 地址 内容 变量 直接访问:通过变量名访问 1000 20 x 1002 1 y 1004 155 z int x = 20, y = 1, z = 155; printf("%d", x;) 间接访问:通过另一个变量访问 把变量的地址放到另一变量中 使用时先找到后者 再从中取出前者的地址 2000 1000 p 2002 地址 指针变量

8.1.3 指针变量的定义 类型名 * 指针变量名 int *p; float *fp; char *cp; 8.1.3 指针变量的定义 类型名 * 指针变量名 指针声明符 指针变量所指向的变量的类型 int *p; p 是整型指针,指向整型变量 float *fp; fp 是浮点型指针,指向浮点型变量 char *cp; cp 是字符型指针,指向字符型变量

指针变量的定义 类型名 * 指针变量名 int * p; 指针变量名是 p,不是*p * 是指针声明符 int k, *p1, *p2; 类型名 * 指针变量名 int * p; 指针变量名是 p,不是*p * 是指针声明符 int k, *p1, *p2; 等价于: int k; int *p1; int *p2;

8.1.4 指针的基本运算 如果指针的值是某个变量的地址,通过指针就能间接访问那个变量。 1、取地址运算和间接访问运算 & 取地址运算符,给出变量的地址 int *p, a = 3; p = &a; 把 a 的地址赋给 p,即 p 指向 a a 3 &a p *p * 间接访问运算符,访问指针所指向的变量 *p:指针变量 p 所指向的变量

例8-2指针取地址运算和间接访问运算 a 3 &a p *p # include <stdio.h> int main (void) { int a = 3, *p; p = &a; printf (“a=%d, *p=%d\n”, a, *p); *p = 10; printf("a=%d, *p=%d\n", a, *p); printf("Enter a: "); scanf("%d", &a); (*p)++;   return 0; } a 3 &a p *p a = 3, *p = 3 a = 10, *p = 10 Enter a: 5 a = 5, *p = 5 a = 6, *p = 6

说明 (1) int *p; 定义指针变量 p (2) 当 p = &a 后,*p 与 a 相同 *p =10; 指针p所指向的变量,即a *&a 与 a 相同,是变量 (4) (*p)++ 等价于 a++ 将 p 所指向的变量值加1 *p++ 等价于 *(p++) (教材107页, 左右) 此时p不再指向a int a = 1, x, *p; p = &a; x = *p++; a 3 &a p *p

例8-3 通过指针改变变量的值 2 b &b p2 *p2 a 1 &a p1 *p1 2 1 例8-3 通过指针改变变量的值 b 2 &b p2 *p2 a 1 &a p1 *p1 # include <stdio.h> int main (void) { int a = 1, b = 2, t; int *p1, *p2; p1 = &a; p2 = &b; printf ("a=%d, b=%d, *p1=%d, *p2=%d\n", a, b, *p1, *p2); t = *p1; *p1 = *p2; * p2 = t;   return 0; } 2 1 a = 1, b = 2, *p1 = 1, *p2 = 2 a = 2, b = 1, *p1 = 2, *p2 = 1

2、赋值运算 int a = 3, *p1, *p2; p1 = &a; p2 = p1; 把 a 的地址赋给 p1,即 p1 指向 a 相同类型的指针才能相互赋值 a 3 &a p1 *p1 *p2 &a p2

例8-4 指针赋值 b 4 &b p2 *p2 a 2 &a p1 *p1 6 c &a &c *p2 *p1 例8-4 指针赋值 b 4 &b p2 *p2 a 2 &a p1 *p1 6 c &a &c *p2 *p1 int main (void) { int a, b, c, *p1, *p2; a = 2; b = 4; c = 6; p1 = &a; p2 = &b; printf ("a=%d, b=%d, c=%d, *p1=%d, *p2=%d\n", a, b, c, *p1, *p2); p2 = p1; p1 = &c; printf ("a=%d, b=%d, c=%d, *p1=%d, *p2=%d\n", a, b, c, *p1, *p2);  return 0; } a = 2; b = 4; c = 6; *p1 = 2, *p2 = 4 a = 2; b = 4; c = 6; *p1 = 6, *p2 = 2

8.1.5 指针变量的初始化 例8-5 int main (void ) { int a=1, b=2; int *p1 = &a, *p2 = &b, *pt;   printf ("a=%d, b=%d, *p1=%d, *p2=%d\n", a, b, *p1, *p2); pt = p1; p1 = p2; p2 = pt; printf (“a=%d, b=%d, *p1=%d, *p2=%d\n”, a, b, *p1, *p2); return 0; } a = 1; b = 2; *p1 = 1, *p2 = 2 a = 1; b = 2; *p1 = 2, *p2 = 1 b 2 &a p2 *p1 a 1 &b p1 *p2 pt p1 b 2 &b p2 *p2 a 1 &a *p1 pt

对指针的操作 / 对指针所指向变量的操作 *p1 和 *p2 的值都由 1 和 2 变成了 2 和 1 (1) 直接改变指针的值 (2) 改变指针所指变量的值 p1 b 2 &b p2 *p2 a 1 &a *p1 a p1 b 2 &a p2 *p1 1 &b *p2 p1 b 1 &b p2 *p2 a 2 &a *p1

8.2 狸猫换太子 一个关于发生在北宋年间变量替换的故事… 关键点分析 真宗和李玉未出生的孩子:小王子 刘娥的阴谋:用狸猫替换掉孩子 筹备工作:设计两套替换行动方案 实施结果:行动一失败,行动二成功

例8-6 指针作为函数参数模拟狸猫换太子 before change, baby is 王子 after first action, baby is王子 after second action, baby is狸猫 int main(void) { int baby = PRINCE; /* baby代表孩子, 刚出生时是王子 */   printf("before change, baby is "); display(baby); replace1(baby); /* 实施狸猫换太子第一次行动*/ printf("\n"); printf("after first action, baby is "); display(baby);   replace2(&baby); /* 实施狸猫换太子第二次行动*/  printf("\n"); printf("after second action, baby is "); display(baby); return 0; } void display(int who) { if (who == CIVET) printf("狸猫"); else if (who == PRINCE) printf("王子"); } void replace1(int baby) { baby = CIVET; } #define CIVET 0 定义狸猫值为0 #define PRINCE 1 定义王子值为1 void replace2(int *baby) { *baby = CIVET; }

8.2.2 指针作为函数的参数 函数参数包括实参和形参,两者的类型要一致,可以是指针类型。 如果实参是某个变量的地址,相应的形参就是指针。 int main (void) { int a = 1, b = 2; int *pa = &a, *pb = &b; void swap1(int x, int y), swap2( int *px, int *py ), swap3 (int *px, int *py); swap1 (a, b); printf (“After calling swap1: a=%d b=%d\n”, a, b);   a = 1; b = 2; swap2(pa, pb); printf (“After calling swap2: a=%d b=%d\n”, a, b); a = 1; b = 2; swap3(pa, pb); printf (“After calling swap3: a=%d b=%d\n”, a, b); return 0; } 调用哪个函数,可以交换main ()中变量a和b的值?

例8-7 swap1() a 1 2 b swap1 (a, b); void swap1 (int x, int y) { int t; x = y; y = t; } x 1 2 y 2 1

例8-7 swap2() 值传递,地址未变, 但存放的变量的值改变了 swap2 (&a, &b); void swap2 (int *px, int *py) { int t; t = *px; *px = *py; *py = t; } a b px py 1 2 2 1 值传递,地址未变, 但存放的变量的值改变了

例8-7 swap3() 值传递,形参指针的改变不会影响实参 swap3 (&a, &b); void swap3 (int *px, int *py) { int *pt; pt = px; px = py; py = pt; } a b px py 1 2 值传递,形参指针的改变不会影响实参

指针作为函数参数的应用 swap2 (&a, &b); void swap2 (int *px, int *py) { int t; *px = *py; *py = t; } a b px py 1 2 2 1 After calling swap1: a=1, b=2 After calling swap2: a=2, b=1 After calling swap3: a=1, b=2 要通过函数调用来改变主调函数中某个变量的值: (1) 在主调函数中,将该变量的地址或者指向该变量的指针作为实参 (2) 在被调函数中,用指针类型形参接受该变量的地址 (3) 在被调函数中,改变形参所指向变量的值

通过指针实现函数调用返回多个值 例8-8 输入年和天数,输出对应的年、月、日。 例8-8 输入年和天数,输出对应的年、月、日。 例如:输入2000和61,输出2000-3-1。 定义函数month_day(year, yearday, *pmonth, *pday) 用2个指针作为函数的参数,带回2个结果 int main (void) { int day, month, year, yearday; void month_day(int year,int yearday, int *pmonth,int *pday); printf(“input year and yearday: ”); scanf ("%d%d", &year, &yearday ); month_day (year, yearday, &month, &day ); printf ("%d-%d-%d \n", year, month, day ); return 0; }

例8-8 3 1 day month pmonth pday void month_day ( int year, int yearday, int * pmonth, int * pday) { int k, leap; int tab [2][13] = { {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, };   /* 建立闰年判别条件leap */ leap = (year%4 == 0 && year%100 != 0) || year%400 == 0; for ( k = 1; yearday > tab[leap][k]; k++) yearday -= tab [leap][k]; *pmonth = k; *pday = yearday; } month day pmonth pday 3 1 input year and yearday: 2000 61 2000-3-1

8.3 冒泡排序-程序解析 void bubble (int a[ ], int n) { int i, j; for( i = 1; i < n; i++ ) for (j = 0; j < n-i; j++ ) if (a[j] > a[j+1]) swap2 (&a[j], &a[j+1]); } void swap2 (int *, int *); void bubble (int a[ ], int n); int main(void) { int n, a[8]; int i; printf("Enter n (n<=8): "); scanf("%d", &n); printf("Enter a[%d] : ",n); for (i=0; i<n;i++) scanf("%d",&a[i]); bubble(a, n);   printf("After sorted, a[%d] = ", n); for (i=0; i<n; i++) printf("%3d",a[i]);  return 0; } void swap2 (int *px, int *py) { int t; t = *px; *px = *py; *py = t; } Enter n (n<=8): 8 Enter a[8] : 7 3 66 3 -5 22 -77 2 After sorted, a[8] = -77 -5 2 3 3 7 22 66

8.3.2 数组和地址间的关系 int a[100], *p; 数组名代表一个地址,它的值是数组首元素的地址(基地址) a+i 是距数组a的基地址的第i个偏移 3000 a[0] 地址 内容 数组元素 3002 a[1] 3198 a[99] a[i] a a+1 a+99 a+i &a[i] *(a+i) sum = 0; for(i = 0; i < 100; i++) sum = sum + a[i] ; 下标运算符[ ]的含义 *(a+i)

指针和数组的关系 任何由数组下标来实现的操作都能用指针来完成 int a[100], *p; p = a; 或 p = &a[0]; 地址 内容 数组元素 3002 a[1] 3198 a[99] a[i] p p+1 p+99 p+i a a+1 a+99 a+i &a[i] a[i] a+i *(a+i) p = a; sum = 0; for(i = 0; i < 100; i++) sum = sum + p[i]; 等价 p+i *(p+i) &p[i] p[i] 等价

用指针完成对数组的操作 int a[100], *p; 移动指针 sum = 0; 地址 内容 数组元素 3002 a[1] 3198 a[99] a[i] p a a+1 a+99 a+i p p p sum = 0; for(p = a; p <= &a[99]; p++) sum = sum + *p;

例8-10 使用指针计算数组元素个数和数组元素的存储单元数 p q 3000 a[0] 地址 内容 数组元素 3008 a[1] a a+1 # include <stdio.h> int main (void) { double a[2], *p, *q; p = &a[0]; q = p + 1; printf ("%d\n", q - p); printf ("%d\n", (int) q - (int) p); return 0; } 1 8 指针p和q之间元素的个数 指针p和q之间的字节数 地址值

指针的算术运算和比较运算 double *p, *q; q - p p + 1 和 p-1 其他操作都是非法的 p < q p q 3000 a[0] 地址 内容 数组元素 3008 a[1] a a+1 double *p, *q; q - p 两个相同类型的指针相减,表示它们之间相隔的存储单元的数目 p + 1 和 p-1 指向下一个存储单元 和 上一个存储单元 其他操作都是非法的 指针相加、相乘和相除,或指针加上和减去一个浮点数 p < q 两个相同类型指针可以用关系运算符比较大小

例8-11 使用指针计算数组元素之和 3000 a[0] 地址 内容 数组元素 3002 a[1] 3018 a[9] a[i] a a+1 地址 内容 数组元素 3002 a[1] 3018 a[9] a[i] a a+1 a+9 a+i # include <stdio.h> int main(void) { int i, a[10], *p; long sum = 0; printf("Enter 10 integers: ");   for(i = 0; i < 10; i++) scanf("%d", &a[i]); for(p = a; p <= a+9; p++) sum = sum + *p; printf("sum=%ld \n", sum); return 0; } p p p p Enter 10 integers: 10 9 8 7 6 5 4 3 2 1 sum=55

8.3.3 数组名作为函数的参数 数组元素作为函数实参时,函数形参为变量 与变量作为函数实参相同,值传递 double fact (int n); int main(void ) { int i, n = 5; double sum; sum = 0; for(i = 1; i <= n; i++ ) sum = sum + fact (i); printf("sum = %e\n", sum); return 0; } double fact (int n) { int i; double result = 1; for (i = 1; i <= n; i++) result = result * i ; return result ; } int a[5]={1, 4, 5, 7, 9}; fact(a[i-1]); 1!+4!+5!+7!+9!

数组名作为函数的参数 数组名是指针常量,相当于指针作为函数的参数 数组名做为实参,形参是指针变量(数组) (1) 实参是数组名 (2) 形参是指针变量 可以写成数组形式 或者用 array[] int sum (int array[], int n) int sum (int *array, int n) { int i, s = 0; for(i=0; i<n; i++) s += array[i]; return(s); } 例8-12 int main(void ) { int i; int b[5] = {1, 4, 5, 7, 9}; printf("%d\n", sum(b, 5)); return 0; } 或者 s += *(array+i)

b int sum (int *array, int n) { int i, s = 0; for(i=0; i<n; i++) s += array[i]; return(s); } int main(void ) { int i; int b[5] = {1, 4, 5, 7, 9}; printf("%d\n", sum(b, 5)); return 0; } b b[0] b[5] sum(b, 5) b[0]+b[1]+...+b[4] array sum(b, 3) b[0]+b[1]+b[2] sum(b+1, 3) b[1]+b[2]+b[3] sum(&b[2], 3) b[2]+b[3]+b[4]

例8-13 将数组元素逆序存放 #include <stdio.h> int main(void) { int i, a[10],n; void reverse(int p[ ], int n); printf("Enter n: "); scanf("%d", &n); printf("Enter %d integers: ", n); for(i = 0; i < n; i++) scanf("%d", &a[i]); reverse(a, n); printf("%d\t", a[i]); return 0; } Enter n:10 Enter 10 integers: 10 9 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7 8 9 10 void reverse(int p[ ], int n) { int i, j, t; for(i=0, j=n-1; i<j; i++, j--){ t = p[i]; p[i] = p[j]; p[j] = t; }

数组名做为函数的参数,在函数调用时,将实参数组首元素的地址传给形参(指针变量),因此,形参也指向实参数组的首元素。如果改变形参所指向单元的值,就是改变实参数组首元素的值。 或:形参数组和实参数组共用同一段存贮空间,如果形参数组中元素的值发生变化,实参数组中元素的值也同时发生变化。 a a[0] a[5] p

指针实现 数组元素 内容 指针 a[0] p #include <stdio.h> int main(void) 数组元素 内容 指针 a[1] a[9] pj #include <stdio.h> int main(void) { int i, a[10],n; void reverse(int p[ ], int n); printf("Enter n: "); scanf("%d", &n); printf("Enter %d integers: ", n); for(i = 0; i < n; i++) scanf("%d", &a[i]); reverse(a, n); printf("%d\t", a[i]); return 0; } void reverse(int *p, int n) { int *pj, t; for(pj=p+n-1; p<pj; p++, pj--){ t=*p; *p=*pj; *pj=t; } p,pj 作为游走的指针 }

8.3.4 冒泡排序算法分析 相邻两个数比较,小的调到前面,大的调到后面 9 8 8 8 8 8 5 4 4 0 8 9 5 5 5 5 4 5 0 4 5 5 9 4 4 4 6 0 5 4 4 4 9 6 6 0 6 6 6 6 6 9 0 8 0 0 0 0 0 9

9 8 8 8 8 8 5 4 4 0 8 9 5 5 5 5 4 5 0 4 5 5 9 4 4 4 6 0 5 4 4 4 9 6 6 0 6 6 6 6 6 9 0 8 0 0 0 0 0 9 i=1 i=2 i=3 i=4 i=5 j=0 to 2 j=0 to 3 j=0 to 4 j=0 to 6-1-i a[j]>a[j+1]

int main(void ) { int i, j, n, t, a[10]; n = 6; for(i = 0; i < n; i++) scanf("%d", &a[i]); for(i = 1; i < n; i++) for(j = 0; j < n-i; j++) if(a[j] > a[j+1]) { t = a[j]; a[j] = a[j+1]; a[j+1] = t; } return 0; 9 8 5 4 6 0 i=1 j=0: 8 9 5 4 6 0 j=1: 8 5 9 4 6 0 j=2: 8 5 4 9 6 0 j=3: 8 5 4 6 9 0 j=4: 8 5 4 6 0 9

void sort(int *array, int n) { int i, j, t; for(i=1; i<n; i++) for(j=0; j<n-i; j++) if(array[j]>array[j+1]){ t = array[j]; array[j] = array[j+1]; array[j+1] = t; } int main(void ) { int i, a[10]; for(i=0; i<10; i++) scanf("%d", &a[i]); sort(a, 10); printf("%d ", a[i]); printf("\n"); return 0; }

8.4 加密问题 字符串:字符数组 字符指针 8.4.1 程序解析 8.4.2 字符数组和字符指针 8.4.3 常用的字符串处理函数

8.4.1 程序解析-加密 void encrypt ( char *s) { for ( ; *s != '\0'; s++) if (*s == 'z') *s = 'a'; else *s = *s+1; } # define MAXLINE 100 void encrypt(char *s); int main (void) { char line [MAXLINE]; printf ("Input the string: "); gets(line); encrypt (line); printf (“After being encrypted: %s\n", line); return 0; } Input the string:hello hangzhou After being encrypted: ifmmp!ibohaipv

8.4.2 字符串和字符指针 字符串常量 "array" "point" 用一对双引号括起来的字符序列 被看做一个特殊的一维字符数组,在内存中连续存放 实质上是一个指向该字符串首字符的指针常量 char sa[ ] = "array"; char *sp = "point";

数组名sa、指针sp和字符串 "string" 的值都是地址 char sa[ ] = "array"; char *sp = "point"; printf("%s ", sa); printf("%s ", sp); printf("%s\n", "string"); printf("%s ", sa+2); printf("%s ", sp+3); printf("%s\n", string"+1); ray nt tring array point string 数组名sa、指针sp和字符串 "string" 的值都是地址

字符数组与字符指针的重要区别 char sa[ ] = "This is a string"; char *sp = "This is a string"; sa T h i s a t r n g \0 sp T h i s a t r n g \0 如果要改变数组sa所代表的字符串,只能改变数组元素的内容 如果要改变指针sp所代表的字符串,通常直接改变指针的值,让它指向新的字符串

示例 char sa[ ] = "This is a string"; char *sp = "This is a string"; strcpy (sa, "Hello"); sp = "Hello"; sa = “Hello”; 非法 数组名是常量,不能对它赋值

字符指针-先赋值,后引用 定义字符指针后,如果没有对它赋值,指针的值不确定。 char *s ; scanf(“%s”, s); char *s, str[20]; s = str; 定义指针时,先将它的初值置为空 char *s = NULL 不要引用未赋值的指针

加密函数的两种实现 void encrypt (char s[ ]) void encrypt ( char *s) { { int i; for(i = 0; s[i] != '\0'; i++) if (s[i] == 'z') s[i] = 'a'; else s[i] = s[i]+1; } void encrypt ( char *s) { for ( ; *s != '\0'; s++) if (*s == 'z') *s = 'a'; else *s = *s+1; }

8.4.3 常用的字符串处理函数 函数原型在 stdio.h 或 string.h 中给出 1、字符串的输入和输出 输入字符串:scanf( )或gets( ) 输出字符串:printf( )或puts( ) stdio.h

字符串的输入 '\n' ' ' '\t' char str[80]; i = 0; while((str[i] = getchar( )) != '\n') i++; str[i] = '\0'; (1) scanf("%s", str) 输入参数:字符数组名,不加地址符 遇回车或空格输入结束,并自动将输入的一串字符和 ‘\0’ 送入数组中 (2) gets(str) 遇回车输入结束,自动将输入的一串字符和 ‘\0’ 送入数组中 '\n' ' ' '\t'

字符串的输出 char str[80]; for(i = 0; str[i] != ‘\0 ’; i++) putchar(str[i]); (3) printf("%s", str) printf("%s", "hello"); (4) puts(str) puts("hello"); 输出字符串后自动换行 输出参数可以是字符数组名或字符串常量,输出遇 '\0' 结束

例8-15 字符串输入输出函数示例 #include <stdio.h> #include <stdio.h> int main( ) { char str[80]; gets(str); puts(str); puts("Hello"); return 0; } #include <stdio.h> int main( ) { char str[80]; scanf("%s", str); printf("%s", str); printf("%s", "Hello"); return 0; } Programming ProgrammingHello Programming Hello Programming is fun! Hello Programming is fun! ProgrammingHello

2、字符串的复制、连接、比较、 求字符串长度 字符串复制:strcpy(str1, str2) 字符串连接:strcat(str1, str2) 字符串比较:strcmp(str1, str2) 求字符串长度:strlen(str) string.h

字符串复制函数strcpy() \0 h a p p y \0 h a p p y \0 w o r l d \0 strcpy(str1, str2); 将字符串 str2 复制到 str1 中 static char str1[20]; static char str2[20] = “happy”; \0 h a p p y \0 strcpy(str1, str2); str1中 h a p p y \0 strcpy(str1, “world”); str1中: w o r l d \0

strcpy() 示例 # include “stdio.h” # include “string.h” int main(void ) { char str1[20], str2[20]; gets(str2); strcpy(str1,str2); puts(str1); return 0; } 1234

字符串连接函数strcat strcat(str1, str2); 连接两个字符串str1和str2, 并将结果放入str1中 # include "stdio.h" # include "string.h" int main(void) { char str1[80], str2[20]; gets(str1); gets(str2); strcat(str1, str2); puts(str1); return 0; } str1中: Let us \0 str2中:go.\0 str1中: Let us go.\0 str2中:go.\0 Let us go. Let us go.

字符串比较函数strcmp strcmp(str1, str2) 比较 两个字符串str1和str2的大小。 规则:按字典序(ASCII码序) 如果 str1 和 str2 相等,返回 0; 如果 str1 大于 str2 ,返回一个正整数; 如果 str1 小于 str2 ,返回一个负整数; static char s1[20] = "sea"; strcmp(s1, "Sea"); strcmp("Sea", "Sea "); strcmp("Sea", "Sea"); 正整数 负整数

strcmp() 示例 # include “stdio.h” # include “string.h” int main(void ) { int res; char s1[20], s2[20]; gets(s1); gets(s2); res = strcmp(s1, s2); printf(“%d”, res); return 0; } 1234 5 -4

用strcmp()比较字符串 利用字符串比较函数比较字符串的大小 strcmp(str1, str2); 为什么定义这样的函数? strcmp(str1, “hello”) < 0 strcmp(str1, str2) == 0 str1 > str2 str1 < “hello” str1 == str2 比较字符串首元素的地址 比较字符串的内容

字符串长度函数strlen strlen(str) 计算字符串的有效长度,不包括 ‘\0’。 static char str[20]=“How are you?” strlen(“hello”) 的值是: strlen(str) 的值是: 5 12

字符串处理函数小结 函数 功能 头文件 puts(str) 输出字符串 stdio.h gets(str) 输入字符串(回车间隔) 函数 功能 头文件 puts(str) 输出字符串 stdio.h gets(str) 输入字符串(回车间隔) strcpy(s1,s2) s2 ==> s1 strcat(s1,s2) s1 “+” s2 ==> s1 若 s1“==”s2, 函数值为0 strcmp(s1,s2) 若 s1 “>” s2, 函数值 >0 string.h 若 s1 “<” s2, 函数值<0 计算字符串的有效长度, strlen(str) 不包括 ‘\0’

例8-16 求最小字符串 #include <string.h> int main( ) { int i; char sx[80], smin[80]; scanf("%s", sx); strcpy(smin,sx); for(i = 1; i < 5; i++){ if(strcmp(sx, smin)<0) } printf("min is %s\n", smin); return 0; int main( ) { int i; int x, min; scanf("%d", &x); min = x; for(i = 1; i < 5; i++){ if(x < min) } printf("min is %d\n", min); return 0; 2 8 -1 99 0 min is –1 tool key about zoo sea min is about

8.5 任意个整数求和问题 * 例8-17 先输入一个正整数n,再输入任意n个整数,计算并输出这n个整数的和。 8.5 任意个整数求和问题 * 例8-17 先输入一个正整数n,再输入任意n个整数,计算并输出这n个整数的和。 要求使用动态内存分配方法为这n个整数分配空间。

8.5.1 程序解析 int main ( ) { int n, sum, i, *p; printf("Enter n: "); scanf("%d", &n); if ((p = (int *) calloc (n, sizeof(int))) == NULL) { printf("Not able to allocate memory. \n"); exit(1); } printf("Enter %d integers: ", n); for (i = 0; i < n; i++) scanf("%d", p+i); sum = 0; sum = sum + *(p+i); printf("The sum is %d \n",sum); free(p);   return 0; Enter n: 10 Enter 10 integers: 3 7 12 54 2 –19 8 –1 0 15 The sum is 81

8.5.2 用指针实现内存动态分配 变量在使用前必须被定义且安排好存储空间 8.5.2 用指针实现内存动态分配 变量在使用前必须被定义且安排好存储空间 全局变量、静态局部变量的存储是在编译时确定,在程序开始执行前完成。 自动变量,在执行进入变量定义所在的复合语句时为它们分配存储,变量的大小也是静态确定的。 一般情况下,运行中的很多存储要求在写程序时无法确定。

动态存储管理 不是由编译系统分配的,而是由用户在程序中通过动态分配获取。 使用动态内存分配能有效地使用内存 同一段内存可以有不同的用途 使用时申请 用完就释放 同一段内存可以有不同的用途

动态内存分配的步骤 (1)了解需要多少内存空间 (2)利用C语言提供的动态分配函数来分配所需要的存储空间。 (3)使指针指向获得的内存空间,以便用指针在该空间内实施运算或操作。 (4)当使用完毕内存后,释放这一空间。

动态存储分配函数malloc() void *malloc(unsigned size) 若申请成功,则返回一个指向所分配内存空间的起始地址的指针 若申请内存空间不成功,则返回NULL(值为0) 返回值类型:(void *) 通用指针的一个重要用途 将malloc的返回值转换到特定指针类型,赋给一个指针

malloc()示例 /* 动态分配n个整数类型大小的空间 */ if ((p = (int *)malloc(n*sizeof(int))) == NULL) { printf(“Not able to allocate memory. \n”); exit(1); } 调用malloc时,用 sizeof 计算存储块大小 每次动态分配都要检查是否成功,考虑例外情况处理 虽然存储块是动态分配的,但它的大小在分配后也是确定的,不要越界使用。

计数动态存储分配函数calloc () void *calloc( unsigned n, unsigned size) 在内存的动态存储区中分配n个连续空间,每一存储空间的长度为size,并且分配后还把存储块里全部初始化为0 若申请成功,则返回一个指向被分配内存空间的起始地址的指针 若申请内存空间不成功,则返回NULL malloc对所分配的存储块不做任何事情 calloc对整个区域进行初始化

动态存储释放函数free void free(void *ptr) 当某个动态分配的存储块不再用时,要及时将它释放

分配调整函数realloc void *realloc(void *ptr, unsigned size) 更改以前的存储分配 如果调整失败,返回NULL,同时原来ptr指向存储块的内容不变。 如果调整成功,返回一片能存放大小为size的区块,并保证该块的内容与原块的一致。如果size小于原块的大小,则内容为原块前size范围内的数据;如果新块更大,则原有数据存在新块的前一部分。 如果分配成功,原存储块的内容就可能改变了,因此不允许再通过ptr去使用它。

本章要点 变量、内存单元和地址之间是什么关系? 如何定义指针变量,怎样才能使用指针变量? 什么是指针变量的初始化? 指针变量的基本运算有哪些?如何使用指针操作所指向的变量? 指针作为函数参数的作用是什么? 如何使用指针实现函数调用返回多个值? 如何利用指针实现内存的动态分配?