C语言程序设计 北京工业大学计算机学院 软件学科部 宋凯 学时40:课堂24+上机16

Slides:



Advertisements
Similar presentations
数据结构的引入. 通讯录管理 社团机构管理 校园导航管理 通讯录管理 社团机构管理 校园导航管理.
Advertisements

第九章 指针 西安工程大学.
第七章 指针 计算机公共教学部.
电子成绩单项目实现.
二级指针与二维数组.
C语言程序设计基础 第10章 指针进阶 刘新国.
第6章 指针 6.1 指针的概念 6.2 变量与指针 6.3 数组与指针 6.4 字符串与指针 6.5 函数与指针 6.6 返回指针值的函数
6.4 字符串与指针 1. 用字符数组存放一个字符串.
C语言实验 第一课 标题:学号+姓名.
8.1 指针的概念 8.2 指针变量 8.3 指针变量的基础类型 8.4 指针的运算 8.5 指针与一维数组 8.6 指针应用实例
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
第九章 字符串.
Using C++ The Weird Way Something about c++11 & OOP tricks
指 针 为什么要使用指针 指针变量 指针与数组 返回指针值的函数 动态内存分配 通过指针引用字符串 指向函数的指针 小 结 习 题.
第 十 章 指 针.
C语言高级编程(第四部分) 字符串 北京大学 信息科学技术学院.
Chap 8 指针 8.1 寻找保险箱密码 8.2 角色互换 8.3 冒泡排序 8.4 电码加密 8.5 任意个整数求和*
Chap 8 指针 8.1 寻找保险箱密码 8.2 狸猫换太子 8.3 冒泡排序 8.4 加密变换问题 8.5 任意个整数求和问题*
走进编程 程序的顺序结构(二).
辅导课程六.
二维数组的指针表示 与复杂的指针例子 专题研讨课之三.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
C语言程序设计基础 第8章 指针 刘新国.
字符串和字符数组 字符串的输入和输出 字符串的基本操作
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
第二章 Java语言基础.
第五章 习题课 电子信息与计算机科学系 曾庆尚.
第七章 操作符重载 胡昊 南京大学计算机系软件所.
第五章 指针 5.1 指针的概念 5.2 指针与数组 5.3 字符串指针.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
C语言程序设计 主讲教师:陆幼利.
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
本节内容 随机读取 视频提供:昆山爱达人信息技术有限公司.
C语言大学实用教程 第7章 指针 西南财经大学经济信息工程学院 刘家芬
第二章 Java基本语法 讲师:复凡.
微机原理与接口技术 微机原理与接口技术 朱华贵 2015年11月13日.
函式庫補充資料.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
第6讲 指针与引用 6.1 指针 6.2 引用.
<编程达人入门课程> 本节内容 内存的使用 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群: ,
C语言程序设计 第一章 数据类型, 运算符与表达式 第二章 顺序程序设计 第三章 选择结构程序设计 第四章 循环控制 第五章 数组.
成绩是怎么算出来的? 16级第一学期半期考试成绩 班级 姓名 语文 数学 英语 政治 历史 地理 物理 化学 生物 总分 1 张三1 115
第4章 Excel电子表格制作软件 4.4 函数(一).
C qsort.
本节内容 内存复制指令 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第九节 赋值运算符和赋值表达式.
3.16 枚举算法及其程序实现 ——数组的作用.
第二章 类型、对象、运算符和表达式.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
本节内容 C语言的汇编表示 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
_03宽字符与Unicode编程 本节课讲师——void* 视频提供:昆山爱达人信息技术有限公司 官网地址:
程序设计基础A(C语言) 第一章 C语言概述 主讲教师: 许 康
实验目的:掌握数据的顺序存储结构及它们在计算机中的操作。 实验内容:
C/C++基礎程式設計班 字元與字串 講師:林業峻 CSIE, NTU 3/14, 2015.
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
本节内容 动态链接库 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C语言程序设计 第8章 指针.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
基本知识 数据类型、变量、常量、运算符.
C/C++基礎程式設計班 C語言入門、變數、基本處理與輸入輸出 講師:林業峻 CSIE, NTU 3/7, 2015.
第八章 指 针 北京邮电大学出版社.
本节内容 进程 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C 程式設計— 字元與字串 台大資訊工程學系 資訊系統訓練班.
第9章 C++程序设计初步 9.1 C++的特点 9.2 最简单的C++程序 9.3 C++的输入输出 9.4 函数的重载
顺序结构程序设计 ——关于“字符串”和数值.
台大資訊工程學系 資料系統訓練班 第119期 吳晉賢
第7章 地址和指针 7.1 地址和指针的概念 7.2 指针变量的定义和指针变量的基类型 7.3 给指针变量赋值 7.4 对指针变量的操作
C++语言程序设计 C++语言程序设计 第二章 基本数据类型与表达式 第十一组 C++语言程序设计.
Presentation transcript:

C语言程序设计 北京工业大学计算机学院 软件学科部 宋凯 学时40:课堂24+上机16 软件学科部 宋凯 学时40:课堂24+上机16 教案下载:http://172.21.14.209/网上教学/ E-mail:songkai@bjut.edu.cn

教学安排 总学时: 40 上课:24学时 星期二 7-8节(1,10周) 1-316 星期四 5-6节(1-10周) 1-316 星期二 7-8节(1,10周) 1-316 星期四 5-6节(1-10周) 1-316 上机:16学时 星期二 7-8节(2-9周) 信南206 (微机1室)

计算机与算法初步总结 教学效果 存在问题 初步的程序设计基础知识 初步的程序编程和调试能力 工程能力:设计规范、算法描述等 分析问题能力 动手能力 考试要求低,不反映实际水平

本学期的教学内容调整 教学内容 作业要求 增加软件工程初步、程序文档编制 编程体要求提供数据说明和程序流程图 上机题 预先完成算法设计(数据说明和程序流程图) 上交实验报告(功能简介、数据说明和流程图)

一、什么是地址? 计算机内存是以字节为单位的一片连续的存储空间,每个字节都有一个编号,这个编号就称为内存地址。 内存地址的特点: 地址是连续的; 通常用二进制表示。为直观起见,在高级语言中,可以用十进制表示。

二、变量与地址的关系 每个变量在内存中都占有一定字节数的存储单元。 int a, b; float x; 1012 1013 1015 1016 1201 1202 1203 1204 ... a b x 变量的地址是指该变量所占存储单元的首字节地址。 可以使用运算符&获取变量的地址: &a、 &b、&x。 变量的内容是指在内存的存储单元中存放的数据。

第六章 指针 6.1 指针的概念 什么是指针 指针变量的声明 保存内存单元地址的变量 为内存中的数据提供了直接访问手段 第六章 指针 6.1 指针的概念 什么是指针 保存内存单元地址的变量 为内存中的数据提供了直接访问手段 指针变量的声明 int *p; 声明p 用于保存整型数据的地址 double *q; 声明q 用于保存双精度数据的地址 变量p, q本身各占用4个字节(地址需用的空间) 指针变量本身的数据长度是由系统决定的。

指针变量示意图 1012 1012 1013 a ptr 2002 1012 1013 a ptr 2002 a ptr

操作方式 a a=123 123 直接操作 ptr *ptr=123 间接操作 ptr = &a 间接访问提供了另一种访问内存数据的手段

指针变量的特性有2点: (1)变量的值为地址值; (2)变量的类型为该指针所指向的实体的类型。 指针的名字与一般变量名相同。

通过指针的引用与赋值 注意: 定义后的指针在没有赋初值或赋值之前是不能使用的. x 3.02 double x, y; double *q; q = &x; /* 取 x 的地址 */ *q = 3.02 /* 等效于 x = 3.02 */ y = *q; /* 等效于 y = x */ 变量的地址 = 所占用单元的首地址 3.02 注意: 定义后的指针在没有赋初值或赋值之前是不能使用的.

&和*是 指针操作中两个特殊的单目运算符。 指针相关运算符 &和*是 指针操作中两个特殊的单目运算符。 取地址运算符: & 指针运算符(间接访问运算符): * (简称:取内容) 它们优先级与结合方式同其他单目运算符。

不同指针类型操作示意图: int data1 = 12 , *ptr1; float data2 = 56.8, *ptr2; data1 1000 1002 2001 2003 1000 • 1002 • ptr1 ptr2 ptr1=&data1 ptr2=&data2 data1 data2

数组与指针运算 数组名 = 数组占用的内存单元的首地址 int arr[ 32 ], x; int *p = arr; /* 将数组首地址保存在 p */ x = *(p + 2); /* 取数组中的第 3 个元素 */ p++; /* 使指针指向第 2 个元素 */ p = p + 5; /* 使指针指向第 7 个元素 */ *p = 308; /* 改变第 7 个元素 */ x = p – arr; /* 得到 6 */ /* 计算两个地址之间有几个整数的空间 */

注意: 在指针加、减运算中,数字“1”不是指一个字节,而是以一个数据(基类型)为基本单位。 地址计算与地址中存放的数据长度有关。

对于不同的数据类型的指针p,p  n表示的实际位置的地址是: (p)  n * 数据长度(含几个字节) 计算后的指针地址值的变化取决于它指向的数据类型。 见例pointsz2.c pointsz3.c

例6-1: 设计一个函数,用于交换两个变量中的整数 #include <stdio.h> void swap(int *p, int *q) { int t; t = *p; *p = *q; *q = t; } main( ) { int x, y; scanf( “%d%d”, &x, &y ); swap( &x, &y ); printf( “%d %d\n”, x, y );

下面的函数能否实现两个变量中的整数交换吗? #include <stdio.h> void swap(int x, int y) { int t; t = x; y = x; y = x; } main( ) { int x, y; scanf( “%d%d”, &x, &y ); swap( x, y ); printf( “%d %d\n”, x, y );

程序分析 作为参数的是指针类型变量 参数传递(按单向值调用) 函数体内 分析方法的特点 参数变量有自己的内存单元(存地址) 将变量 x 的地址值传到参数 p 中 用 *p 访问 x 函数体内 以间接访问方式操作 分析方法的特点 利用内存单元的图示 表示所有变量的变化(包括指针)

例6-2:设计一个函数,用于将字符串中的小写字母改为大写字母 #include <stdio.h> void toUpper( char p[ ] ) { for( ; *p != ‘\0’; p++ ) if( ‘a’ <= *p && *p <= ‘z’ ) *p = *p – ‘a’ + ‘A’; } main( ) { char *buf = “characters.”; toUpper( buf ); printf( “%s\n”, buf );

程序分析 数组与指针 空间分配 字符串 char p[ ] 等价于 char *p p[ i ] 等价于 *( p + i ) 指针代替了下标变量 空间分配 数组:数组大小 * 元素占用空间 数组名 = 首元素地址 (本身无空间) 指针:4个字节保存地址 字符串 以‘\0’结束的字符数组 用首字符地址参加运算

例 6.3 求两个向量之和的函数 double *addVector( double a[ ], double b[ ], int n ) 例 6.3 求两个向量之和的函数 double *addVector( double a[ ], double b[ ], int n ) { int i; double *p; p = (double *)malloc( n * sizeof(double) ); for( i=0; p != NULL && i<n; i++ ) p[ i ] = *a++ + *b++; return p; } /* 用指针代替下标变量 */

主函数 free(p); main() { double x[3], y[3]; double *p; x[0] = x[1] = x[2] = 4; y[0] = y[1] = y[2] = 5; p = addVector( x, y, 3 ); printf(“%lf”, *p); printf(“%lf”, *(p+1); printf(“%lf”, p[2]); } free(p);

动态空间分配 申请存储单元的函数 释放该空间 存储单元大小的计算 void *malloc( long size ); 给定所需字节数,取得系统分配的存储单元,返回首地址 如果分配失败,返回空指针 NULL 释放该空间 void free( void *p ); 给定malloc获得的存储单元首地址 存储单元大小的计算 sizeof( 类型 ) sizeof( 变量 )

6.2 字符串处理 常用字符串处理函数 int strlen( char *s ); 求字符串中字符个数 6.2 字符串处理 常用字符串处理函数 int strlen( char *s ); 求字符串中字符个数 int strcmp( char *s1, char *s2 ); 按照字母顺序比较, 0 表示相等 char *strcpy( char *dec, char *src ) 字符串从 src 复制到 dec,返回 dec char *strcat( char *dec, char *src ) 将字符串 src 连接到 dec 后面,返回 dec

例6-4:字符串连接 使用前提:dec字符数组中必须有足够的空间 char *strcat( char *dec, char *src ) { char *p ; p = dec; while( *p != ‘\0’ ) p++; while( *src != ‘\0’ ) *p++ = *src++; *p = ‘\0’; return dec; } 使用前提:dec字符数组中必须有足够的空间

使用合法的内存单元 main( ) { int n; char *p = “abc”, *q = “xyz”, *s; strcat( p, q ); /* 非法 */ n = strlen(p) + strlen(q); s = (char *)malloc( n+1 ); /* 分配空间 */ strcpy( s, p ); strcat( s, q ); printf( “%s\n”, s ); free( s ); /* 释放空间 */ }

例6-5:子字符串的查找 要求:实现函数 char *strstr( char *s1, char *s2 ) 用于在 s1 中找出子串 s2,返回首元素地址;若 s2 不存在,则返回 NULL s1比s2短 返回NULL s2是s1的 前缀 返回 s1 在s1首字符之 后的字符串中 查找,返回 结果 Y N

函数实现(递归法) char *strstr( char *s1, char *s2 ) { if( strlen(s1) < strlen(s2 ) return NULL; if( 0 == strncmp( s1, s2, strlen(s2) ) ) return s1; /* 前n个字符相等 */ return strstr( s1+1, s2 ); /* 递归查找 */ }

strncmp 的设计 int strncmp( char *s1, char *s2, int n ) 比较2个字符串,返回字符的差 返回 0 n=0? 首字符相等? 首字符=\0? 返回首字 符之差 比较其余字符 返回比较结果 Y N strncmp 的设计 int strncmp( char *s1, char *s2, int n ) 比较2个字符串,返回字符的差 非结构化 控制流图

strncpy 的实现(递归法) int strncmp( char *s1, char *s2, int n ) { if( 0 == n ) return 0; /* 前 n 个相同 */ if( *s1 != *s2 ) return *s1 - *s2; /* 首元素之差 */ if( *s1 == ‘\0’ ) /* 2个字符串都结束 */ return 0; return strncmp( s1+1, s2+1, n-1 ); } /* 比较其余字符 */

6.3 指针应用 例6-6:排序函数(按照字符顺序) 要求:对n个字符串进行排序 基本算法:(冒泡排序) 6.3 指针应用 例6-6:排序函数(按照字符顺序) 要求:对n个字符串进行排序 基本算法:(冒泡排序) 逐个比较相邻元素,交换前大后小的元素 重复以上处理(n-1次) void bSort( int n, char *a[ ] ); 采用指针数组指示 n 个字符串

程序实现 void bSort( int n, char *a[ ] ) { char **p, *tmp; int i; for( i=0; i<n-1; i++ ) /* 重复n-1次 */ for( p=a; p<a+n-1; p++ ) /* 逐个检查 */ if( strcmp(*p, *(p+1)) > 0 ) { /* 比较相邻元素 */ tmp = *p; /* 交换 */ *p = *(p+1); *( p+1 ) = tmp; }

程序分析 char **p = a; a 是数组名(首元素地址),数组元素是字符指针 因此 a 是保存字符地址的内存单元的地址, tmp = *p; 将变量 p 中保存的字符指针地址赋给 tmp

例6-7:将命令行参数排序后输出 程序处理过程的回顾 myProc.c  myProc.obj  myProc.exe 编译 连接 编译 连接 myProc.exe 可执行文件 鼠标双击 (如:TC.exe) 在DOS环境:myProc 回车 命令行(命令 + 若干个参数) C:\ myProc arg1 arg2 程序启动时指定;而不是运行中输入 也可以在资源管理器中文件属性中指定 或 TC 菜单Option/arguments中指定(调试中用)

命令行参数的组织 例:myProc arg1 arg2 空间已分配 m y P r o c ‘\0’ a r g 1 ‘\0’ void main( int ac, char *av[ ] ) m y P r o c ‘\0’ a r g 1 ‘\0’ a r g 2 ‘\0’ 3

程序实现 void main(int ac, char *av[ ]) { /* 给定命令行参数个数 ac */ bSort( ac-1, av+1 ); while( --ac ) /* 循环ac-1次 */ printf( “%s\n”, *(++av) ); } /* 指针位移后,取元素 */ av 是变量,保存字符指针的指针 系统负责统计命令行参数个数传递给 ac 同时构造命令行参数的指针数组,传递给 av

例6-8:单词统计 要求 数据对象 从键盘输入一篇英文文章,统计各单词的出现次数,以<单词:出现次数>的格式列表输出 单词表:字符串数组 wdTab 出现次数表:整数表 nmTab 用下标联系单词及其出现次数

读入一单词 读成功? 在wdTab中 查找该单词 找到? 添加到 wdTab 出现次数 加一 输出wdTab 和nmTab N Y 算法描述

模块设计(函数抽象) int wdRead( char buf[ ] ) 从键盘读入一单词(字母和数字组成), 读入失败时,返回0。 int wdLook( char buf[ ], char *tab[ ], int n ) 在单词表 tab 中查找单词 buf, (n 是 tab 中的单词个数) 如果找到,返回下标;未找到返回 –1。 void wdPrint( int n, char *wtab[ ], int ntab[ ] ) 输出单词表 wtab 和出现次数表 ntab 中的 n 个单词及其出现次数

主程序的实现 #include <stdio.h> #include <string.h> main( ) { char *wdTab[ 1024 ], p; /* 最多1024个 */ int nmTab[ 1024 ], num = 0, idx, n; char buf[ 256 ]; /* 当前单词 */ while( 0 != (n = wdRead( buf )) ) { idx = wdLook( buf, wdTab, num ); if( idx >= 0 ) nmTab[ idx ] += 1; /* 出现次数加一 */ else { p = (char *)malloc( n+1 ); /* 分配空间 */ wdTab[ num ] = strcpy( p, buf ); nmTab[ num++ ] = 1; } } /* 保存复制后的单词 */ wdPrint( num, wdTab, nmTab ); } 主程序的实现

单词的读入 int wdRead( char buf[ ] ) { int ch, i=0; do ch = getchar( ); /* 跳过其他字符 */ while( !isalnum(ch) && ch != EOF ); while( ch != EOF && isalnum(ch) ) { buf[ i++ ] = ch; /* 保存字符 */ ch = getchar( ); } buf[ i ] = ‘\0’; /* 字符串结尾 */ return i;

单词查找和输出 int wdLook( char buf[ ], char *tab[ ], int n ) { char **p; for( p=tab; p<tab+n; p++ ) if( strcmp( *p, buf ) == 0 ) return p-tab; return -1; } void wdPrint( int n, char *ws[ ], int ns[ ] ) { int i; for( i=0; i<n; i++ ) printf( “<%s:%d>\n”, ws[ i ], ns[ i ] );

程序分析 结构化设计 实现技术 存在问题 功能分解、逐步求精 模块化函数抽象 数据处理局部化 指针数组、字符输入输出、指针索引 数组大小(1024)的限制 数组下标的关联作用(有限)

指针小结 指针: 指针运算: 用途: 安全性 保存地址,提供高效访问手段 以基类型数据单元为单位,不等于地址运算 函数参数、数组元素遍历、字符串处理 指针数组(含字符串数组)、命令行 安全性 可访问外部函数申请的内存单元 始终指向申请到的内存单元

本章作业 阅读教科书第七章和第八章 程序设计练习 上机题 完成自我测验练习 7.3 7.4 7.6 完成自我测验练习 8.3 8.4 完成自我测验练习 7.3 7.4 7.6 完成自我测验练习 8.3 8.4 程序设计练习 7.21 7.22 7.30 8.8 8.14 8.16 8.36 8.37 上机题 8.16 8.37