420 likes | 574 Views
数据结构 DATA STRUCTURE. —— C 语言描述. 胡 海 EMail : hh_whu@yahoo.cn. 引 数据结构讨论的范畴 —— 数据抽象. 实体 信息 数据. 引 数据结构讨论的范畴 —— 程序设计. Niklaus Wirth Algorithm + Data Structures = Programs. 程序设计: 为计算机处理问题编制 一组指令集 算法: 怎样处理? —— 处理问题的策略 数据结构: 信息怎样表示? —— 数学模型.
E N D
数据结构DATA STRUCTURE ——C语言描述 胡 海 EMail:hh_whu@yahoo.cn
引 数据结构讨论的范畴——数据抽象 实体 信息 数据
引 数据结构讨论的范畴——程序设计 Niklaus Wirth Algorithm + Data Structures = Programs 程序设计:为计算机处理问题编制 一组指令集 算法: 怎样处理?——处理问题的策略 数据结构:信息怎样表示?——数学模型
引 数据结构讨论的范畴——数据结构 1 数值计算问题: 线性代数方程、常微分方程 2 非数值计算问题: 数据结构描述现实世界实体的数学模型及其上的操作在计算机中的表示和实现
数据结构的重要性 • 现实世界 计算机世界的桥梁 • 程序设计的根本所在 • 信息科学的基础 • GIS学科研究的核心内容之一 • IT企业考察技术能力的关键
注意事项 • 最终成绩:作业+上机实习报告+考勤+考试 • 按时按量完成作业,不要抄袭,就算抄也要动着脑筋抄 • 学过的内容有条件的话尽量编程实现 • 作业用本子不要纸方便留作资料;随身携带,会有随堂作业
课内参考书目 1.数据结构(C语言版),严蔚敏 吴伟民,清华大学出版社,1997年4月第一版 2.数据结构题集(C语言版),严蔚敏 吴伟民,清华大学出版社,1999年2月第一版 3.数据结构 ——使用c语言,朱站立,西安交大出版社
第0章 结构化程序设计、c语言重点回顾 计算机、程序设计的本质 内存地址、指针 主要知识点 函数及其运行机制,头文件 结构体 typedef 类型定义 动态内存分配 程序调试
什么是“计算机”? • 图灵机1937(计算机理论之父) 是么是 “算法” ? 问题的可计算性 人工智能的界限 • 冯 ·诺依曼思想 1946(现代计算机之父) 1.用二进制代码表示程序和数据; 2.计算机采用存储程序的工作方式; 3.计算机硬件由存储器、运算器、控制 器、输入设备和输出设备组成。
结构化程序设计 • 使用顺序结构、选择结构、循环结构以及它们的组合来组织一个程序。 • 采用自顶向下逐步求精的方法编写程序。 求两整数的最大公约数和最小公倍数
计算机、程序设计的本质 内存地址、指针 主要知识点 函数及其运行机制 结构体 typedef 类型定义 动态内存分配 程序调试
0000002 65 a 0 0000003 0 0000004 b 0 0000005 1 0000006 0 0000007 0 0000008 c 0 0000009 2 0000010 内存地址 int main(){ char a = ‘A’; int b = 1; float c = 2; double d = 3; return 0; } 值:内存单元中存放的数据 地址:系统分配给变量的内存单元的起始地址
0000002 0 0000004 65 000000E 0000002 指针变量 存放地址的变量称为指针变量,它用来指向另一个变量,通常用*表示。 int main() { int i=65; int*i_pointer; i_pointer = &i; return 0; }
定义后 p=&i *p=3 j=*p+2 i 1000 i 1000 3 i 1000 3 i j j j 5 j 1004 1004 1004 p 1000 p 1000 p 1000 p 1008 1008 1008 指针操作 int i, j, *p; p=&i; *p=3; j=*p+2; &:取变量的首地址,即指针; *:取指针所指向的地址中的值; 1000 1004 1008
计算机、程序设计的本质 内存地址、指针 主要知识点 函数及其运行机制,头文件 结构体 typedef 类型定义 动态内存分配 程序调试
内存管理和函数调用 • 计算机采用存储程序的工作方式 • 程序内各成分在计算机中的存储: 代码段(程序) 数据段(全局、静态) 系统栈(局部、形参) 堆 (动态)
main函数 a函数 b函数 ② ③ ④ ① 调用b函数 ⑤ 调用a函数 ⑨ ⑦ ⑥ ⑧ 结束 函数调用中究竟发生了什么? (1)为所有的形参分配内存,计算各个实际参数表达式的值,依次赋予对应的形式参数。(若是“无参函数”,上述工作不执行) (2)进入函数体,执行函数中的语句,实现函数的功能,当执行到“返回语句”时,计算返回值,释放本函数体中的变量等(静态型变量不释放),收回分配给形参的内存,返回主调函数。 (3)继续执行主调函数中的后继语句。
参数传递 函数间传递数据有四种方式:值传递方式;地址传递方式;返回值传递方式;全局变量传递。 例设计一个数据交换函数swap( ),实现两个数的交换 int main(){ int m, n; scanf(“%d %d”, &m, &n); swap(m, n); printf(“%d %d”, m, n); return 0; } void swap(int a, int b){ int temp; temp = a; a = b; b = temp; }
void swap(int *a, int *b){ int temp; temp = *a; *a = *b; *b = temp; } int main(){ int m, n; scanf(“%d %d”, &m, &n); swap(&m, &n); printf(“%d %d”, m, n); return 0; }
void swap(int *a, int *b){ int temp; temp = *a; *a = *b; *b = temp; } m 0000002 1 2 n 0000006 temp 0000012 00000002 0000016 a 00000006 000001A b
计算机、程序设计的本质 内存地址、指针 主要知识点 函数及其运行机制,头文件 结构体 typedef 类型定义 动态内存分配 程序调试
结构体 结构体类型的说明 一个结构体类型由若干个称为成员的成分组成,其类型说明的一般形式为: struct 结构体标识名 {类型名1 结构体成员名1; 类型名2 结构体成员名2; …… 类型名n 结构体成员名n; }; 其中,struct是关键字,结构体名和结构成员名是用户定义的标识符。注意必须在结尾加分号,因为结构体类型声明本身为一条语句。 依此格式,可以说明如下结构体类型来描述上述学生档案信息: struct student { char name[20]; int code; char sex; int age; char address[40]; };
结构体变量成员的引用 若已定义了结构体变量,使用成员运算符“.”来访问结构体成员,形式如下: 结构体变量名. 成员名 假设有如下定义: struct person { char name[20]; long int code; char sex; struct {int day,month,year;}birthday; char address[40]; } std1,std[3]; 则:std1.code 引用结构体变量std1中的成员code, std[1].code 引用结构体数组std中第二个元素std[1]的成员code。 若定义了基类型为结构体类型的指针变量,可以用成员运算符“.”和结构指向运算符“->”两种方式引用,形式如下: 指针变量名->成员名 (*指针变量名).成员名 假设有如下语句: struct person std1,*pstd; pstd=&std1; 则引用结构体变量std1的成员code,可写成: pstd->code (*pstd).num
a0 … a1 ^ an head data next 数据域 指针域 或 用 结构体+指针 实现的链式单元 结点结构如图示: typedef struct Node { DataType data; struct Node *next; }SLNode; 数据域:存储元素数值数据 指针域:存储直接后继的存储位置
计算机、程序设计的本质 内存地址、指针 主要知识点 函数及其运行机制,头文件 结构体 typedef 类型定义 动态内存分配 程序调试
Typedef 的用途 • 代码简化 (别名) structtagPOINT1 { intx; inty; }; structtagPOINT1p1; typedefstructtagPOINT { intx; inty; }POINT; POINTp1;//这样就比原来的方式少写了一个struct,比较省事,尤其在大量使用的时候 • 跨平台开发
计算机、程序设计的本质 内存地址、指针 主要知识点 函数及其运行机制 结构体 typedef 类型定义 动态内存分配 程序调试
动态内存分配函数简介 动态内存分配 在前面的程序设计中,存在一个问题,就是在编写程序时,因为无法确定要处理数据的规模,在定义变量时就为它说明一个特别大的空间,这对内存资源利用和程序设计都是不利的。我们希望,计算机能按需分配内存,在运行时需要多大的空间就分配多大的空间。 上面提出的问题,实际上是计算机内存的动态管理问题。
动态内存分配函数 malloc()函数 其函数原型为: void *malloc(unsigned int size); 其功能是:分配一块长度为size字节的连续空间,并将该空间的首地址作为函数的返回值。如果函数没有成功执行,返回值为空指针(NULL或0)。由于返回的指针的基类型为void,应该通过显式类型转换后才能存入其他基类型的指针变量中,否则会有警告提示。 例如: int *p; p=(int *)malloc(sizeof(int));
动态内存分配函数 free()函数 其函数原型为: void free(void *block); 其功能是:释放以前分配给指针变量block的动态空间,但指针变量block不会自动变成空指针。
数组(静态、动态)和指针 • 静态 : int x; int A[10]; int y; • 动态 : int x; int *pA; int y;
动态数组定义和使用流程 • 定义指针(数组名) Datatype *pA; • 分配内存空间 pA=(Datatype *)malloc(sizeof(Datatype)*数组大小)); • 初始化 for (;;) pA[i] = … • 使用 • 结束前释放空间 free(pA); pA=NULL;
动态分配常犯的错误 1)内存分配未成功,却使用了它。 2)内存分配虽然成功,但是尚未初始化就引用它。 3)内存分配成功并且已经初始化,但操作越过了内存的边界。 4)忘记了释放内存,造成内存泄露。 5)释放了内存却继续使用它。 • 有三种情况: • A 程序中的对象调用关系过于复杂,实在难以搞清楚某个对象究竟是否已经释放了内存,此时应该重新设计数据结构,从根本上解决对象管理的混乱局面。 • B 函数的return语句写错了,注意不要返回指向“栈内存”的“指针”或者“引用”,因为该内存在函数体结束时被自动销毁。 • C 使用free或delete释放了内存后,没有将指针设置为NULL。导致产生“野指针”。
计算机、程序设计的本质 内存地址、指针 主要知识点 函数及其运行机制 结构体 typedef 类型定义 动态内存分配 程序调试
文件输入输出 • fopen • fprintf • fscanf • fclose • fwrite • fread
程序调试 • 程序执行期行进控制 1)单步行进(跳过函数 step over) 2)进入函数 (Step into) 3)运行到光标 • 参数监控
作 业 P13 0-5, 补1:有: int x=1,y=2; 编制函数交换两者的值。 补2:有:struct student{ long Number;…..} 1)写出动态分配100个student空间的语句 2)绘制动态分配5*4二维int数组的内存空间示意图,并写出对应语句
上机实习 学生信息管理: 从文件读写本班同学信息记录。从“GIS3.txt”,读出数据,写入到“newGIS3.txt” 要求: 1)学生记录:学号,姓名,年龄,身高; 2)工程由3个文件组成:main.c; Stu.h; Stu.c 3)学生记录使用动态数组管理 4)交换第一位与最后一位同学的全部信息并输出到(swapGIS3.txt) 上机前本班学习委员 按照学号次序组织本班 XXX.txt文件 时间地点:第二周 周5(9月18日) 1~2节 资环院4楼机房
补充思考题: • 1.int,int*; char,char*; double,double*; student(自定义),student*….,这些数据类型各占用多少内存,编程验证之。 • 2.为什么c语言中定义数组如:double a[NUM]; 时,NUM必须为常数?试从内存分配的角度讨论一下。 • 3.下面的程序: Test函数的语句GetMemory(str, 200)并没有使str获得期望的内存,str依旧是NULL,为什么?如何修改? void GetMemory(char *p, int num) { p = (char *)malloc(sizeof(char) * num); } void Test(void) { char *str = NULL; GetMemory(str, 100); // str 仍然为 NULL strcpy(str, “hello”); // 运行错误 }