多维数组与指针 用指针变量可以指向一维数组中的元素,也可以指向多维数组中的元素。但在概念上和使用上,多维数组的指针比一维数组的指针要复杂一些。 1. 多维数组元素的地址 先回顾多维数组的性质,可以认为二维数组是“数组的数组”,例 : 定义int a[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}}; 则二维数组a是由3个一维数组所组成的。设二维数组的首行的首地址为2000 ,则
表 示 形 式 含义 地 址 a 二维数组名,指向一维数组a[0],即0行首地址 2000 a[0], *(a+0), *a 0行0列元素地址 a+1,&a[1] 1行首地址 2016 a[1],*(a+1) 1行0列元素a[1][0]的地址 a[1]+2, *(a+1) +2, &a[1][2] 1行2列元素a[1][2] 的地址 2024 *(a[1]+2), *(*(a+1)+2), a[1][2] 1行2列元素a[1][2]的值 元素值为13
输出二维数组有关的值 #include<stdio.h> #define format ″%d,%d\n″ void main() { int a[3][4]={1,3,5,7,9,11,13, 15,17,19,21,23}; printf(format,a,*a); printf(format,a[0] , *(a+0)); printf(format,&a[0],&a[0][0]); printf(format,a[1],a+1); printf(format,&a[1][0],*(a+1)+0); printf(format,a[2],*(a+2)); printf(format,&a[2],a+2); printf(format,a[1][2],*(*(a+1)+2)); }
某一次运行结果如下: 1244900,1244900 (0行首地址和0行0列元素地址) 1244900,1244900 (0行0列元素地址) 1244900,1244900 (0行0首地址和0行0列元素地址) 1244916,1244916 (1行0列元素地址和1行首地址) 1244916,1244916 (1行0列元素地址) 1244932,1244932 (2行0列元素地址) 1244932,1244932 (2行首地址) 13,13 (1行2列元素的值)
上机过程中的问题 养成良好的程序书写风格 变量、函数的命名:体现其意义 if/else、swith/case、for、while等复合语句中 { }的使用 { }内代码的缩进 适当的空行 适当的注释 避免太长的语句、适当的换行
上机过程中的问题 应该: 误解: 程序运行不正确,怎么办? 在VC环境中写完程序后,就拷贝到编程网格上提交 仔细分析问题 考虑各种情况 把自己当作计算机,给定输入,再运行一下程序 误解: 在VC环境中写完程序后,就拷贝到编程网格上提交 在VC环境中编译正确,程序就是正确的 对于给出的样例输入,输出正确,程序就是正确的 程序运行不正确,怎么办?
程序的调试 语法错误:编译(组建)错误 不要惊慌,编译结果输出窗口已经为你指明了程序的出错行及错误原因,可以据此来修改程序错误。 改错时,应从出错信息中的第一条开始,用鼠标双击该条信息,程序源文件窗口就将定位到出错行。 很多时候,程序编译后会出很多错误,但很可能是由第一个错误衍生而来的,改完第一个错误后,再编译时其他错误就不再出现了。所以,应该每修改完一个错误后就编译一次。
二、关于程序的错误修改及调试 这里少了一个“{”。 这里的一堆错误,都是由于上面少了一个“{”引起的! 双击第一行,定位错误及了解错误原因!
程序的调试 运行结果错:程序跟踪调试 由于程序算法及其他原因,执行结果不正确,这时从源程序表面上就很难发现错误。 跟踪调试:可以手动一步一步执行程序语句,在每条语句执行后,可以查看相关变量的值,以判断和预期结果是否相符;也可以了解程序的执行顺序,看它是否和预期的程序流程相符。 断点设定:在跟踪调试前,还需要确定一下程序可能从哪里出错,设置一个断点,让程序在此停止自动运行,由我们手动一步一步发出程序执行命令。如果不能确定程序是从哪里出错,则可以将断点设置在程序的第一条语句处。
设置程序断点
跟踪方式执行程序 查看变量值 当前程序执行停留在此行 手动设置变量,查看变量值 程序手动执行 进入函数 一步一步执行 从函数中执行出来 执行到光标所在行 查看变量值 当前程序执行停留在此行 手动设置变量,查看变量值
问题1: 骑车与走路
n 没有上限了! 骑车: 找到并启动自行车 27秒; 停车锁车 23秒; 速度 3.0米/秒; 走路: 速度 1.2米/秒;
假设 n 的上限是 10
提交到 编程网格。结果是 … … void compute(int distance){ #include <stdio.h> #define N 10 void compute(int distance); int main(){ int n; int distance[N]; int i; scanf("%d", &n); for(i = 0; i < n; i++){ scanf("%d", &(distance[i])); } compute(distance[i]); return 0; void compute(int distance){ int timeBike = 27 + 23 + distance/3; int timeWalk = (int)(distance/1.2); if(timeBike < timeWalk){ printf("Bike\n"); } else if (timeBike > timeWalk){ printf("Walk\n"); } else { printf("All\n"); } 提交到 编程网格。结果是 … …
把 n 的上限修改为 100
提交到 编程网格。结果是 … … void compute(int distance){ #include <stdio.h> #define N 100 void compute(int distance); int main(){ int n; int distance[N]; int i; scanf("%d", &n); for(i = 0; i < n; i++){ scanf("%d", &(distance[i])); } compute(distance[i]); return 0; void compute(int distance){ int timeBike = 27 + 23 + distance/3; int timeWalk = (int)(distance/1.2); if(timeBike < timeWalk){ printf("Bike\n"); } else if (timeBike > timeWalk){ printf("Walk\n"); } else { printf("All\n"); } 提交到 编程网格。结果是 … …
WHY?
编程网格 判断程序是否正确 的机制 对每一个题目, 编程网格 预先设定了 一组测试数据; 只要你的程序在这组测试数据下正确, 编程网格 判断程序是否正确 的机制 对每一个题目, 编程网格 预先设定了 一组测试数据; 只要你的程序在这组测试数据下正确, 编程网格 即认为 你的程序是正确的; 在 骑车与走路 这个题目中, 编程网格使用的测试数据中,所有的n 都小于 100
有没有更稳妥的办法呢?
动 态 数 组
int sz[10]; 静态数组 必须是一个常量 静态数组 的 长度 在 编译时刻 就确定了; 如何能在程序的运行时刻, 动态地确定一个数组的长度呢?
动态数组 动态数组? #include <stdio.h> int main(){ int n; scanf(“%d”, &n); int shzu[n]; return 0; } 在VC下编译失败! error C2133: 'shuzu' : unknown size 怎样才能实现 动态数组?
动态数组 如何实现动态数组? 1、使用指针 2、自己申请内存
动态数组 #include <stdio.h> #include <malloc.h> int main(){ int n; scanf(“%d”, &n); int *shzu = (int *) malloc(sizeof(int) * n); … … free(shuzu); return 0; } #include <stdio.h> int main(){ int n; scanf(“%d”, &n); int shzu[n]; … … return 0; }
动态数组 #include <stdio.h> #include <malloc.h> int main(){ int n; scanf(“%d”, &n); double *shzu = (double *) malloc(sizeof(double) * n); … … free(shuzu); return 0; } #include <stdio.h> int main(){ int n; scanf(“%d”, &n); double shzu[n]; … … return 0; }
关于malloc()/free()的使用 别忘了: #include <malloc.h> malloc函数的参数为所需申请内存的大小:以字节为单位 malloc函数返回一个void*类型的地址,必须通过强制类型转换,才能赋值给特定的指针变量: int * pint = (int *) malloc( ... ); 用malloc函数生成各种类型的动态数组,最好使用“sizeof(类型名) * 动态数组长度”形式确定分配内存的大小: int * pint = (int *) malloc( sizeof(int) * 100 ); 分配的内存不再使用时一定要释放: free(pint);
动态数组 malloc()在内存中分配的一块连续的内存区域,这与静态数组在内存中的布局是一样的。因此,指向这块内存区域的指针变量就可以像数组一样使用了: int *pint; pint = (int *)malloc(sizeo(int)*10); pint[0], pint[1], ……, pint[9] 在使用动态数组时,一定要注意不要越界引用,即不要引用并没有分配给你使用的内存: 当引用pint[10] 时,对于C语言来说,这是合法的,但是它所引用的却是所分配的内存区域之外的其他内存区域,其内的值是未知的;如果对其进行修改的话,还可能影响整个程序的正确性。 pint 5 6 7 8 9 1 2 3 4 10(?) ? pint+10
#include <stdio.h> #define N 10 void compute(int distance); int main(){ int n; int distance[N]; int i; scanf("%d", &n); for(i = 0; i < n; i++){ scanf("%d", &(distance[i])); } compute(distance[i]); return 0; #include <stdio.h> #include <malloc.h> void compute(int distance); int main(){ int n; int i; scanf("%d", &n); int *distance = (int *) malloc(sizeof(int)*n); for(i = 0; i < n; i++){ scanf("%d", &(distance[i])); } compute(distance[i]); free(distance); return 0;
问题2: 跳绳游戏
关键信息: 计算1分钟内跳了多少下绳; 1秒钟跳1次; 跳坏后,3秒钟后才能又开始跳;
输入、输出 示例 = 60 – 0 * 3 = 60 – 3 * 3 = 60 – 1 * 3 = 60 – 4 * 3 = 60 – 4 * 3 = 47
输入:0 输出:60 在y秒时,小朋友停止了跳绳 0秒 60秒 y秒 60下
输入:3 12 23 45 输出:51 y秒 51 = 60 – 3*3 在y秒时,小朋友停止了跳绳 0秒 12秒 15秒 26秒 29秒 51秒 54秒 60秒 12下 23下 23下 45下 45下 12下 51 = 60 – 3*3
输入:1 17 输出:57 在y秒时,小朋友停止了跳绳 0秒 60秒 y秒 17秒 20秒 17下 17下 57 = 60 – 1*3
输入:4 10 20 30 40 输出:48 y秒 48 = 60 – 4*3 在y秒时,小朋友停止了跳绳 0秒 60秒 10秒 13秒 23秒 26秒 36秒 39秒 49秒 52秒 10下 10下 20下 20下 30下 30下 40下 40下 48 = 60 – 4*3
输入:5 10 20 30 40 58 输出:48 60秒 0秒 10秒 13秒 23秒 26秒 36秒 39秒 49秒 52秒 70秒 73秒 10下 10下 20下 20下 30下 30下 40下 40下 58下 58下 48 = 60 – 4*3
输入:6 10 20 30 40 47 60 输出:47 0秒 60秒 10秒 13秒 23秒 26秒 36秒 39秒 49秒 52秒 59秒 62秒 75秒 78秒 10下 10下 20下 20下 30下 30下 40下 40下 47下 47下 60下 60下 47
问题分析 60秒 Case 1 0秒 60秒 Case 2
请同学们课后思考 如何编写这个程序
下课!