P 120 数组应用案例 2023/1/29
一、应用案例
案例一:创建一个char类型的26个元素的数组,分别 放置’A’-'Z‘。使用for循环访问所有元素并打印出来。提示:字符数据运算 ‘A’+1 -> ‘B’
#include<stdio.h>
void main(){
/*
创建一个char类型的26个元素的数组,分别 放置'A'-'Z‘。使用for循环访问所有元素
并打印出来。提示:字符数据运算 'A'+1 -> 'B
*/
char arr[26];
int i;
for(i = 0; i < 26 ; i++){
arr[i] = 'A' + i; // 第一个是0,A+0依然是0
}
for(i = 0; i < 26; i++){
printf("arr[%d]=%c\n",arr,arr[i]);
}
getchar();
}
案例二:请求出一个数组的最大值,并得到对应的下标。
#include<stdio.h>
void main(){
/*
请求出一个数组的最大值,并得到对应的下标。
分析:
1.自定义数组大小5
2.假定第一个元素max= arr[0]就是最大值,然后我们依次和数组后面的数进行比较,
如果发现有比max更大的数,就相应的变化,遍历完整个数组,max就是最大数。
*/
int arr[] = {0,-1,89,99,4};
int arrLen = sizeof(arr) / sizeof(int);
int max = arr[0];
int maxIndex = 0;
int i;
for(i = 1; i < arrLen; i++){ // 这里 i 的初始值为1;因为为0则是和自己比较没有意义
// 发现有比max更大的数,就相应的变化
if(arr[i] > max){
max = arr[i];
maxIndex = i; // 对应下标就是i,所以把i 赋值即可
}
}
printf("max = %d maxIndex = %d",max,maxIndex); // 99,3
getchar();
}
P 121 字符串介绍和内存布局 2023/1/29
一、字符数组的介绍
基本介绍:用来存放字符的数组称为字符数组, 看几个案例。
char a[10]; //一维字符数组, 长度为10
char b[5][10]; //二维字符数组, 后面我们详细介绍二维数组
char c[20]={'c', ' ', 'p', 'r', 'o', 'g', 'r', 'a','m'}; // 给部分数组元素赋值
总结:字符数组实际上是一系列字符的集合,也就是字符串(String)。在C语言中,没有专门的字符串变量,没有string类型,通常就用一个字符数组来存放一个字符串。
#include<stdio.h>
void main(){
// c是一个一维字符数组,给部分元素赋值
char c[20]={'t','o','m'};
// 输出
printf("%s",c); // 输出tom
getchar();
}
二、字符串注意事项
- 在 C 语言中,字符串实际上是使用 null 字符 (‘\0’) [null字符就是\0,因为ASCII 0 表示空],终止的一维字符数组。因此,一个以 null 结尾的字符串,包含了组成字符串的字符。【以下为内存布局图】
- '\0’是ASCII码表中的第0个字符,用NUL表示,称为空字符。该字符既不能显示,也不是控制字符,输出该字符不会有任何效果,它在C语言中仅作为字符串的结束标志。
- 字符数组(字符串)在内存中的布局分析 [案例]。
- 思考 char str[3] = {‘a’,‘b’,‘c’} 输出什么? 为什么?
char c[7]={'t','o','m'};
// 正常输出tom
char str[3] = {'a','b','c'};
// 输出a,b,c后,后面可能会出现乱码,一些垃圾值
char str[] = {'a','b','c'};
// 不指定长度,输出结果可能同样会出现乱码
分析示意图:
结论:如果在给某个字符数组赋值时,(1)赋给的元素的个数小于该数组的长度,则会自动在后面加 ‘\0’, 表示字符串结束,(2)赋给的元素的个数等于该数组的长度,则不会自动添加 ‘\0’。
P 122 字符指针和内存布局 2023/1/30
一、字符串的访问和遍历
小结:因为字符串的本质就是字符数组,因此可以按照数组的方式遍历和访问某个元素即可, 案例如下:
#include<stdio.h>
#include<string.h>
void main(){
// 这种方式定义字符数组不会出现任何的乱码,会自动添加一个\0
char greeting[] = "Hello";
int i;
int len = strlen(greeting); // len = 5
printf("\n greeting = %s",greeting);
printf("\nlen=%d", len);
printf("\n字符串第3个字符是=%c", greeting[2]); // 下标是从0开始的,第三个字符
for(i = 0; i < len; i++) {
printf("\n%c", greeting[i]);
}
getchar();
}
- 内存布局
二、字符串的表示形式
- 用字符数组存放一个字符串
1 . char str[]=“hello tom”;
2 . char str2[] = {‘h’, ‘e’};
- 用字符指针指向一个字符串
1 . 比如: char pStr=" hello";*
#include<stdio.h>
void main(){
// 使用一个指针pStr,指向一个字符数组
char* pStr = "Hello";
printf("\n pStr指向的字符串= %s",pStr); // 输出Hello
getchar();
}
2 . 总结:
- C语言对字符串常量" hello"是按字符数组处理的,在内存中开辟了一个字符数组用来存放字符串常量,程序在定义字符串指针变量str时只是把字符串首地址(即存放字符串的字符数组的首地址)赋给pStr。
- 内存布局图
- printf(“%s\n”,str); 可以输出 str 指向的字符串。
三、两种方法表示字符串的讨论
-
字符数组由若干个元素组成,每个元素放一个字符;而字符指针变量中存放的是地址(字符串/字符数组的首地址),绝不是将字符串放到字符指针变量中(是字符串首地址)。
-
对字符数组只能对各个元素赋值,不能用以下方法对字符数组赋值:
char str[14]; // str 实际是一个常量
str=" hello tom"; //错误
str[0] = 'i'; //ok ,因为只是找到第一个元素在那里填了一个i而已
内存布局图:
- 对字符指针变量,采用下面方法赋值, 是可以的:
#include<stdio.h>
void main(){
char* a="yes";
// 赋值前的地址:
printf("\na本身的地址是%p,指向的地址是%p",&a,a);
a=" hello tom"; // 定义一个字符指针变量时,可以多次赋值
// 赋值后的地址:
printf("\na本身的地址是%p,指向的地址是%p",&a,a);
printf("\n%s",a);
getchar();
}
内存布局图:
- 如果定义了一个字符数组,那么它有确定的内存地址(即字符数组名是一个常量);而定义一个字符指针变量时,它并未指向某个确定的字符数据,并且可以多次赋值 [代码+图解]。
P 123 字符数组注意事项和细节 2023/1/31
一、字符串相关函数回顾
- 常用字符串函数一览
序号 | 函数 | 目的 |
---|---|---|
1 | strcpy(s1, s2); | 复制字符串 s2 到字符串 s1。 |
2 | strcat(s1, s2); | 连接字符串 s2 到字符串 s1 的末尾。 |
3 | strlen(s1); | 返回字符串 s1 的长度。 |
4 | strcmp(s1, s2); | 如果 s1 和 s2 是相同的,则返回 0;如果 s1<s2 则返回小于 0;如果 s1>s2 则返回大于 0。 |
5 | strchr(s1, ch); | 返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置。 |
6 | strstr(s1, s2); | 返回一个指针,指向字符串 s1 中字符串 s2 的第一次出现的位置。 |
#include<stdio.h>
#include<string.h>
void main(){
char str1[12] = "Hello";
char str2[12] = "World";
char str3[12];
int len ;
/* 复制 str1 到 str3 */
strcpy(str3, str1); // str3内容 "Hello"
printf("strcpy( str3, str1) : %s\n", str3 );
/* 连接 str1 和 str2 */
strcat( str1, str2);
printf("strcat( str1, str2): %s\n", str1 ); // "Hello world"
/* 连接后,str1 的总长度 */
len = strlen(str1); // 因为进行了连接,所以总长度应该是10,10个字符
printf("strlen(str1) : %d\n", len );
if(strcmp(str1, str2)<0){
printf("小于0");
}else{
printf("大于0");
}
getchar();
}
二、字符数组使用注意事项和细节
-
程序中往往依靠检测 ‘\0’ 的位置来判定字符串是否结束,而不是根据数组的长度来决定字符串长度。因此,字符串长度不会统计 ‘\0’, 字符数组长度会统计 [案例]。
-
在定义字符数组时应估计实际字符串长度,保证数组长度始终大于字符串实际长度,否则,在输出字符数组时可能出现未知字符。
-
系统对字符串常量也自动加一个’\0’作为结束符。例如"C Program”共有9个字符,但在内存中占10个字节,最后一个字节’\0’是系统自动加上的。(通过sizeof()函数可验证)。
-
定义字符数组时,如果 给的字符个数 比 数组的长度小,则系统会默认将剩余的元素空间,全部设置为 ‘\0’, 比如 char str[6] = “ab” , str内存布局就是[a] [b] [ \0 ] [\0] [\0] [\0]。
-
字符数组定义和初始化的方式比较多,比如:
#include<stdio.h>
void main(){
char str1[ ]={"I am happy"}; // 默认后面加 '\0'
char str2[ ]="I am happy"; // 省略{}号 ,默认后面加 '\0'
char str3[ ]={'I',' ','a','m',' ','h','a','p','p','y'}; // 字符数组后面不会加 '\0', 可能有乱码
char str4[5]={'C','h','i','n','a'}; //字符数组后面不会加 '\0', 可能有乱码
char * pStr = "hello"; // OK, 使用一个指针pStr,指向一个字符数组
printf("\n str1 = %s",str1);
printf("\n str1 = %s",str2);
printf("\n str1 = %s",str3);
printf("\n str1 = %s",str4);
getchar();
}
P 124 冒泡排序分析和实现 2023/1/31
一、排序算法
介绍:排序也称排序算法(Sort Algorithm),排序是将一组数据,依指定的顺序进行排列的过程。
排序的分类:
-
内部排序:指将需要处理的所有数据都加载到**内部存储器(内存)**中进行排序。
-
外部排序法:数据量过大,无法全部加载到内存中,需要借助外部存储进行排序。
二、冒泡排序
基本介绍:冒泡排序(Bubble Sorting)的基本思想是:通过对待排序序列从前向后(从下标较小的元素开始),依次比较相邻元素的值,若发现逆序则交换,使值较大的元素逐渐从前移向后部,就象水底下的气泡一样逐渐向上冒。
结论:因为排序的过程中,各元素不断接近自己的位置,如果一趟比较下来没有进行过交换,就说明序列有序,因此要在排序过程中设置一个标志flag判断元素是否进行过交换。从而减少不必要的比较。
- 冒泡排序应用实例
案例:我们举一个具体的案例来说明冒泡法。我们将五个无序的数:{3, 9, -1, 10, -2}使用冒泡排序法将其排成一个从小到大的有序数列。
分析过程:
// 冒泡排序的过程(从小到大) ===> 分析过程(思路) ===》 代码
原始数组{3, 9, -1, 10, -2}
第1轮排序:
(1) 3,9,-1,10,-2
(2) 3,-1,9,10,-2
(3) 3,-1,9,10,-2
(4)3,-1,9,-2,10 // 第1大的数就移动到最后
第2轮排序:
(1) -1,3,9,-2,10
(2)-1,3,9,-2,10
(3)-1,3,-2,9,10 //第2大的数就移动适当位置
第3轮排序:
(1)-1,3,-2,9,10
(2)-1,-2,3,9,10 第3大的数就移动适当位置
第4轮排序:
(1) -2,-1,3,9,10//第4大的数就移动适当位置
排序结束
// 是不需要进行第五轮的比较,因为四个数都已经找到合适的位置了
将上述的分析过程然后写成代码:
#include<stdio.h>
void main(){
int arr[] = {3,9,-1,10,-2};
// 因为每次排序几乎一样,因此,我们可以使用for循环处理
int j;
int t; // 临时变量
// 第一轮排序:
for(j = 0; j < 4; j++){
// 如果前面的数大于后面的数就,交换
if(arr[j] > arr[j+1]){
t = arr[j];
arr[j] = arr[j+1];
arr[j+1] = t;
}
}
// 输出看看第一轮排序的的情况
for(j = 0 ; j < 5 ; j++){
printf("%d ",arr[j]);
}
printf("\n");
// 第二轮排序:
for(j = 0; j < 3; j++){ // 第二轮比较3次就可以了,因为前一轮最大数已经固定了
// 如果前面的数大于后面的数就,交换
if(arr[j] > arr[j+1]){
t = arr[j];
arr[j] = arr[j+1];
arr[j+1] = t;
}
}
for(j = 0 ; j < 5 ; j++){
printf("%d ",arr[j]);
}
printf("\n");
// 第三轮排序:
for(j = 0; j < 2; j++){ // 第二轮比较2次就可以了,因为前两轮已经固定两个数
// 如果前面的数大于后面的数就,交换
if(arr[j] > arr[j+1]){
t = arr[j];
arr[j] = arr[j+1];
arr[j+1] = t;
}
}
for(j = 0 ; j < 5 ; j++){
printf("%d ",arr[j]);
}
printf("\n");
// 第四轮排序:
for(j = 0; j < 1; j++){ // 第二轮比较2次就可以了
// 如果前面的数大于后面的数就,交换
if(arr[j] > arr[j+1]){
t = arr[j];
arr[j] = arr[j+1];
arr[j+1] = t;
}
}
for(j = 0 ; j < 5 ; j++){
printf("%d ",arr[j]);
}
printf("\n");
getchar();
}
代码优化:
// 因为每次排序几乎一样,因此,我们可以使用for循环处理
#include<stdio.h>
void main(){
int arr[] = {3,9,-1,10,-2,-11,989};
// 因为每次排序几乎一样,因此,我们可以使用for循环处理
int j;
int i;
int t; // 临时变量
int arrLen = sizeof(arr) / sizeof(int); // 数组的大小,通过计算得到,这样就很方便,可以随意改变数组大小
for(i = 0 ; i < arrLen-1 ; i++){ // 这里可以写活,刚好等于数组的大小减1
// 第一层循环就是总的轮数
for(j = 0; j < arrLen-1-i; j++){
// 第二层循环就是执行交换,进行轮中的排序
// 如果前面的数大于后面的数就,交换
if(arr[j] > arr[j+1]){ // 从大到小,把大于改成小于就可以了
t = arr[j];
arr[j] = arr[j+1];
arr[j+1] = t;
}
}
// 获取每一轮循环后的结果
for(j = 0 ; j < arrLen ; j++){
printf("%d ",arr[j]);
}
printf("\n"); // 每一轮循环输出结果后换行
}
getchar();
}
函数优化处理:
#include<stdio.h>
// 冒泡排序的函数:
void bubbleSort(int arr[],int arrLen){
// 因为每次排序几乎一样,因此,我们可以使用for循环处理
int j;
int i;
int t; // 临时变量
for(i = 0 ; i < arrLen-1 ; i++){ // 这里可以写活,刚好等于数组的大小减1
// 第一层循环就是总的轮数
for(j = 0; j < arrLen-1-i; j++){
// 第二层循环就是执行交换,进行轮中的排序
// 如果前面的数大于后面的数就,交换
if(arr[j] > arr[j+1]){ // 从大到小,把大于改成小于就可以了
t = arr[j];
arr[j] = arr[j+1];
arr[j+1] = t;
}
}
// 获取每一轮循环后的结果
for(j = 0 ; j < arrLen ; j++){
printf("%d ",arr[j]);
}
printf("\n"); // 每一轮循环输出结果后换行
}
}
void main(){
int j;
int arr[] = {3,9,-1,10,-2,-11,};
int arrLen = sizeof(arr) / sizeof(int); // 数组的大小,通过计算得到,这样就很方便,可以随意改变数组大小
bubbleSort(arr,arrLen); // 数组默认是地址传递(指针)
getchar();
}
总结: 以上案例的优化过程总结了前面所学,进行了一个综合。
P 125 顺序查找和二分查找 2023/2/1
一、基本介绍
在C中,我们常用的查找有两种
1) 顺序查找
2) 二分查找(默写)【比较重要】
- 案例演示:
二、顺序查找
案例一:有一个数列:{23, 1, 34,89, 101},猜数游戏:从键盘中任意输入一个数,判断数列中是否包含该数,
【顺序查找】要求: 如果找到了,就提示找到,并给出下标值, 找不到提示 没有。
#include<stdio.h>
int seqSearch(int arr[], int arrLen, int val){
int i;
for(i = 0; i < arrLen ; i++){
if(val == arr[i]){
return i;
}
}
// 如果在for循环中,没有执行到return,说明没有找到
return -1; // 可以返回一个-1,因为下标是没有-1的
}
void main(){
/*
有一个数列:{23, 1, 34,89, 101},
猜数游戏:从键盘中任意输入一个数,判断数列中是否包含该数,
【顺序查找】要求: 如果找到了,就提示找到,并给出下标值, 找不到提示 没有。
*/
// 分析思路:
//1. 按照数组进行数组进行遍历,如果相等则找到。
int arr[] = {23,1,34,89,101};
int arrLen = sizeof(arr) / sizeof(int);
int index = seqSearch(arr,arrLen,-101); // 将形参传入进去,返回值用index进行接收
if(index != -1){
printf("找到了下标为%d",index);
}else{
printf("没有找到");
}
getchar();
}
三、二分查找
案例二:请对一个有序数组进行【二分查找】 {1,8, 10, 89, 1000, 1234} ,输入一个数看看该数组是否存在此数,并且求出下标,如果没有就提示"没有这个数"
。二分查找的前提是,该数组是一个有序数组。
#include<stdio.h>
// 二分查找:
int binarySearch(int arr[], int leftIndex, int rightIndex, int findVal){
// 先找到中间这个数midVal
int midIndex = (leftIndex + rightIndex) / 2; // 比如数组大小为5,左下标(0+5)/2=2.5取整为2
int midVal = arr[midIndex]; // 中间值
//如果leftIndexf > rightIndex ,说明这个数组都比较过,但是没有找到。
// 因为:leftIndex是在逐渐向右边移动,rightIndex是逐渐向左边移动,所以如果左边大于右边,
// 就说明已经将整个数组范围全部查找完但是没有找到。
if(leftIndex > rightIndex){
return -1; // !!!
}
// 如果midVal > finVal说明 应该在midVal的左边去查找
if(midVal > findVal){
binarySearch(arr,leftIndex,midIndex-1,findVal); // !!! 函数递归,递归相当于缩小范围进行查找
// 如果midVal < finaVal说明 应该在midVal的右边去查找
}else if(midVal < findVal){
binarySearch(arr,midIndex+1,rightIndex,findVal); // 在右边查找,右边索引不变,左边索引加一
}else{
return midIndex; // 返回该数的下标
}
}
void main(){
/*
请对一个有序数组进行二分查找 {1,8, 10, 89, 1000, 1234} ,输入一个数
看看该数组是否存在此数,并且求出下标,如果没有就提示"没有这个数"
。二分查找的前提是,该数组是一个有序数组
*/
int arr[]= {1,8, 10, 89, 1000, 1234};
int arrLen = sizeof(arr) / sizeof(int);
int index = binarySearch(arr, 0 ,arrLen-1,-1234); // 这里长度-1,因为下标从0开始,得到长度是6,但第六个下标为5
if(index != -1){
printf("index = %d",index);
}else{
printf("没有找到");
}
getchar();
// 思路分析:
// 比如我们要查找的数是findVal
// 1.先找到 数组中间这个数midVal,和finVal比较
// 2.如果midVal > finVal说明 应该在midVal的左边去查找
// 3.如果midVal < finVal说明 应该在midVal的右边去查找
// 4. 如果midVal == findVal ,说明找到
// 5. 如果leftIndexf > rightIndex ,说明这个数组都比较过,但是没有找到
}
P 126 二维数组的基本使用 2023/2/1
一、基本介绍
多维数组我们介绍二维数组。
- 应用场景
比如我们开发一个五子棋游戏,棋盘就是需要二维数组来表示。如图:
二、入门案例
**案例一:**请用二维数组输出如下图形。
#include<stdio.h>
void main () {
// a[4][6] :表示的是一个4行6列的二维数组
// (1)先定义在初始化:
int a[4][6]; // 没有初始化,则是分配的内存垃圾值(不确定的值)
int i, j;
//全部初始化 0
for(i = 0; i < 4; i++) { // 先遍历行
for(j = 0; j < 6; j++) { // 在遍历列
a[i][j] = 0;
}
}
a[1][2] = 1;
a[2][1] = 2;
a[2][3] = 3;
// 输出二维数组
for(i = 0; i < 4; i++) {
for(j = 0; j < 6; j++) {
//printf("a[%d][%d]=%d ", i, j, a[i][j]);
printf("%d ", a[i][j]);
}
printf("\n");
}
相关地址输出:
//看看二维数组的内存布局
printf("\n二维数组a的首地址=%p", a);
printf("\n二维数组a[0]的地址=%p", a[0]);
printf("\n二维数组a[0][0]的地址=%p", &a[0][0]);
printf("\n二维数组a[0][1]的地址=%p", &a[0][1]);
//将二维数组的各个元素得地址输出
printf("\n");
for(i = 0; i < 4; i++) {
printf("a[%d]的地址=%p ", i, a[i]); // 输出a[0-4]的地址
for(j=0; j < 6; j++) {
printf("a[%d][%d]的地址=%p ", i, j , &a[i][j]); // 输出全部地址
}
// 地址是连续分部的,虽然看着换行了,第二行的第一个元素地址是上一行最后加4
printf("\n");
}
getchar();
}
内存分析图:
总结:
- 语法: 类型 数组名[大小] [大小],比如: int a [2] [3];
- 二维数组在内存的存在形式,各个元素的地址是连续分布的,即在前一个元素基础上+4(int类型)。
三、直接初始化
- 定义 类型 数组名[大小] [大小] = {{值1,值2…},{值1,值2…},{值1,值2…}};
或者 类型 数组名[大小] [大小] = { 值1,值2,值3,值4,值5,值6 …};
P 127 二维数组的应用案例 2023/2/2
一、应用案例
案例一:请使用灵活的方式遍历如下数组 :
int map[3][3] = {{0,0,1},{1,1,1},{1,1,3}};
#include<stdio.h>
void main(){
int map[3][3] = {{0,0,1},{1,1,1},{1,1,3}};
// 遍历
// 先得到行
// 1. sizeof(map) 得到这个map数组的大小 9 * 4 = 36
// 2. sizeof(map[0]) 得到map中,第一行有多大 3 * 4 = 12
int rows = sizeof(map) / sizeof(map[0]); // 3个元素
//printf("rows = %d",rows);
// 得到列
int cols = sizeof(map[0]) / sizeof(int); // 一行的大小是12,int占4字节,除以4可以得到列。 sizeof([0][0])
int i;
int j;
for(i = 0; i < rows; i++){
for(j = 0; j < cols; j++){
printf("%d ",map[i][j]);
}
printf("\n");
}
getchar();
}
案例二:int arr[3][2]={{4,6},{1,4},{-2,8}};
遍历该二维数组,并得到和?
#include<stdio.h>
void main(){
int arr[3][2]={{4,6},{1,4},{-2,8}};
int i,j;
int sum = 0;
int rows = sizeof(arr) / sizeof(arr[0]);
int column = sizeof(arr[0]) / sizeof(int);
for(i = 0; i < rows ; i++){
for(j = 0; j < column ; j++){
printf("%d ",arr[i][j]);
sum += arr[i][j]; // 定义一个sum,每次累加
}
printf("\n");
}
printf("sum=%d",sum); // 21
getchar();
}
案例三:定义二维数组,用于保存三个班,每个班五名同学成绩,并求出每个班级平均分、以及所有班级平均分【 数据要求从控制台输入 】。
#include<stdio.h>
void main(){
/*
定义二维数组,用于保存三个班,每个班五名同学成绩,并求出每个班级平均分、
以及所有班级平均分【 数据要求从控制台输入 】
*/
// 分析:
// 1 .创建一个scores[3][5]
// 2. 遍历,给赋值
// 3. 再次遍历统计总分和平均分
// 4. 最后输出
double score[3][5]; //
int rows = sizeof(score) / sizeof(score[0]),cols = sizeof(score[0]) / sizeof(double), i, j; //
//classTotalScore 各个班级总成绩, totalScore 所有学生成绩
double totalScore = 0.0, classTotalScore = 0.0; // 定义所有班级总成绩、个各班的成绩
for (i = 0; i < rows; i++ ) {
for (j = 0; j < cols ; j++ ) {
score[i][j] = 0.0; // 初始化
}
}
//遍历给每个学生输入成绩
for (i = 0; i < rows; i++ ) {
for (j = 0; j < cols ; j++ ) {
printf("请输入第 %d 个班的 第 %d 个 学生的成绩", i + 1, j + 1); // 下标从0开始,但是没有第0个班,所以+1
scanf("%lf", &score[i][j]);
}
}
// 显示成绩情况
for(i = 0; i < rows ; i++){
for(j = 0 ; j < cols; j++){
printf("%.2f ",score[i][j]);
}
printf("\n");
}
// 统计各个班的总成绩,和所有学生的总成绩
for(i = 0; i < rows; i++){
classTotalScore = 0.0; // 每次清0,这样才能统计每个班的总分
for(j = 0; j < cols; j++){
classTotalScore += score[i][j];
}
printf("\n 第%d个班的平均成绩时%.2f",i+1,classTotalScore/cols);
totalScore += classTotalScore; // 将该班级的总分,累积到totalScore
}
printf("\n 所有学生的总成绩是 %.2f ,平均成绩%.2f",totalScore,totalScore/(rows * cols));
// 平均成绩=总成绩/人数(rows * cols)
getchar();
getchar();
}
P 128 二维数组的注意事项和细节 2023/2/2
一、注意事项
- 可以只对部分元素赋值,未赋值的元素自动取“零”值【案例】。
#include<stdio.h>
int main(){
int a[4][5] = {{1},{2},{3},{1}}; // 每行后面是没有赋值的
//{1}等价于 {1,0,0,0,0}
int i,j;
for(i = 0; i < 4; i++){
for(j = 0; j < 5; j++){
printf("%d ",a[i][j]);
}
printf("\n");
}
getchar();
}
- 如果对全部元素赋值,那么第一维的长度可以不给出(二维数组可以省略行)。比如:
int a[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
可以写为:
int a[][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // 是等价于前面的写法
- 二维数组可以看作是由一维数组嵌套而成的;如果一个数组的每个元素又是一个数组,那么它就是二维数组。
// 二维数组a[3][4]可看成三个一维数组,它们的数组名分别为 a[0]、a[1]、a[2]。
// 这三个一维数组都有 4 个元素,如,一维数组 a[0] 的元素为 a[0][0]、a[0][1]、a[0][2]、a[0][3]
P 129 断点调试介绍和快捷键 2023/2/3
一、需求引入
引入:在开发中,程序员发现一个非常诡异的错误,怎么看源代码都发现不了这个错误,这时老程序员就会温馨提示,可以使用断点调试,一步一步的看源码执行的过程,从而发现错误所在。
基本介绍:断点调试是指自己在程序的某一行设置一个断点,调试时,程序运行到这一行就会停住,然后你可以一步一步往下调试,调试过程中可以看各个变量当前的值,出错的话,调试到出错的代码行即显示错误,停下。然后程序可以进行分析从而找到这个Bug。
二、断点调试的快捷键
F5 | 开始调试、执行到下一个断点 |
---|---|
F11 | 逐句执行代码,会进入到函数体 |
F10 | 逐过程执行(遇到函数,不会进入到函数体) |
Shift+F11 | 跳出(跳出某个函数,跳出前会将该函数执行完) |
Shiit+F5 | 终止调试 |
P 130 断点调试应用案例(1)2023/2/3
一、应用案例
案例一:看一下变量的变化情况等:(逐过程执行代码……)
#include<stdio.h>
void main() {
int sum = 0;
int i = 0;
for(i = 0; i < 10; i++) {
sum += i;
printf("\n i=%d", i);
printf("\n sum=%d", sum);
}
printf("退出for循环了~~");
}