2024-2025-1 20241310 《计算机基础与程序设计》第12周学习总结
作业信息
这个作业属于哪个课程 | [2024-2025-1-计算机基础与程序设计](https://edu.cnblogs.com/campus/besti/2024-2025-1-CFAP) |
---|---|
这个作业要求在哪里 | 2024-2025-1计算机基础与程序设计第一周作业 |
这个作业的目标 | 自学教材《C语言程序设计》第11章并完成云班课测试 |
作业正文 | 本博客链接 |
教材学习内容总结
一、指针和一维数组的关系
(一)数组名作为指针常量
-
本质
- 在C语言中,一维数组名可以看作是一个指针常量,它指向数组的第一个元素。例如,对于数组
int arr[5];
,arr
就相当于&arr[0]
,这个地址是常量,不能被重新赋值。
- 在C语言中,一维数组名可以看作是一个指针常量,它指向数组的第一个元素。例如,对于数组
-
通过指针访问数组元素
- 可以定义一个指针变量指向数组,然后通过指针来访问数组元素。例如:
int arr[5] = {1, 2, 3, 4, 5}; int *p = arr; // 访问数组元素 printf("%d", *p); // 输出arr[0],即1 p++; printf("%d", *p); // 输出arr[1],即2
- 这里
p++
操作会使指针指向下一个数组元素,因为p
是指向int
类型的指针,所以p++
实际上是让p
的地址值增加sizeof(int)
字节。
-
指针算术运算与数组下标等效
- 对于数组
arr
和指针p
(p = arr
),arr[i]
和*(p + i)
是等效的。这是因为数组在内存中是连续存储的,p + i
表示从数组首地址偏移i
个元素的地址,再通过*
解引用就可以得到该地址存储的值,这与通过数组下标访问元素的效果相同。
- 对于数组
(二)函数参数中的数组与指针
- 数组作为函数参数退化为指针
- 当一维数组作为函数参数传递时,数组名会退化为指向数组首元素的指针。例如:
void func(int arr[]) { // 这里的arr实际上是一个指针 } int main() { int arr[5]; func(arr); return 0; }
- 在函数
func
内部,无法通过sizeof
获取数组的实际大小,因为arr
已经是一个指针,sizeof(arr)
得到的是指针的大小(在32位系统中为4字节,64位系统中为8字节),而不是数组的大小。
二、指针和二维数组的关系
(一)二维数组的存储结构
- 按行存储
- 二维数组在内存中是按行存储的,即先存储第一行的所有元素,再存储第二行的元素,以此类推。例如,对于二维数组
int arr[2][3];
,其存储顺序为arr[0][0]
、arr[0][1]
、arr[0][2]
、arr[1][0]
、arr[1][1]
、arr[1][2]
。
- 二维数组在内存中是按行存储的,即先存储第一行的所有元素,再存储第二行的元素,以此类推。例如,对于二维数组
- 数组名的含义
- 二维数组名也是一个指针常量,它指向二维数组的第一个元素,不过这里的第一个元素是一个一维数组。例如,对于
int arr[2][3];
,arr
的类型是int (*)[3]
,它指向一个包含3个int
元素的一维数组。
- 二维数组名也是一个指针常量,它指向二维数组的第一个元素,不过这里的第一个元素是一个一维数组。例如,对于
(二)通过指针访问二维数组
- 使用数组指针
- 可以定义一个数组指针来指向二维数组,例如:
int arr[2][3] = {{1, 2, 3}, {4, 5, 6}}; int (*p)[3] = arr; // 访问元素 printf("%d", (*p)[0]); // 输出arr[0][0],即1 p++; printf("%d", (*p)[0]); // 输出arr[1][0],即4
- 这里
(*p)[i]
的形式用于访问二维数组中的元素,其中p
是指向包含3个int
元素的一维数组的指针,*p
得到这个一维数组,再通过[i]
访问其中的元素。
- 与一维数组指针的关系
- 可以将二维数组看作是由多个一维数组组成的数组。例如,
int arr[2][3]
可以看作是一个包含2个元素的数组,每个元素是一个包含3个int
元素的一维数组。从这个角度理解,二维数组名是指向一维数组的指针,而通过适当的指针运算可以访问到二维数组中的每个元素。
- 可以将二维数组看作是由多个一维数组组成的数组。例如,
三、指针数组及其应用
(一)定义和初始化
- 定义
- 指针数组是一个数组,其元素为指针类型。例如,
int *arr[5];
定义了一个包含5个元素的指针数组,每个元素都是指向int
类型的指针。
- 指针数组是一个数组,其元素为指针类型。例如,
- 初始化
- 可以在定义时初始化指针数组,例如:
int num1 = 1, num2 = 2, num3 = 3; int *arr[3] = {&num1, &num2, &num3};
- 这里
arr[0]
指向num1
,arr[1]
指向num2
,arr[2]
指向num3
。
(二)应用
- 字符串数组
- 指针数组常用于表示字符串数组。例如:
char *strs[] = {"hello", "world", "C language"}; for (int i = 0; i < 3; i++) { printf("%s\n", strs[i]); }
- 这里
strs
是一个指针数组,每个元素指向一个字符串常量。这种方式比使用二维字符数组来存储字符串更加节省内存,因为字符串常量在内存中只存储一份,而指针数组只是存储了这些字符串常量的地址。
- 函数指针数组
- 可以定义函数指针数组,用于根据不同的条件调用不同的函数。例如:
int add(int a, int b) { return a + b; } int sub(int a, int b) { return a - b; } int (*func_arr[])(int, int) = {add, sub}; int result = func_arr; // 调用add函数,result为3
四、C程序的内存映像
(一)内存分区
- 栈区(Stack)
- 由编译器自动分配和释放,用于存储函数的局部变量、函数参数等。例如:
void func() { int num = 10; // num存储在栈区 }
- 栈区的内存分配是从高地址向低地址增长的,函数调用结束时,栈上的局部变量会自动销毁。
- 堆区(Heap)
- 由程序员手动分配和释放(使用
malloc
、calloc
、realloc
等函数分配,使用free
函数释放),用于动态分配内存。例如:
int *p = (int *)malloc(sizeof(int)); // 在堆区分配内存 *p = 10; free(p);
- 堆区的内存分配是从低地址向高地址增长的。
- 由程序员手动分配和释放(使用
- 全局区(静态区,Static)
- 用于存储全局变量和静态变量。全局变量在整个程序的生命周期内都存在,静态变量的生命周期也贯穿整个程序的执行过程。例如:
int global_num = 10; // 全局变量,存储在全局区 void func() { static int static_num = 20; // 静态局部变量,也存储在全局区 }
- 常量区
- 用于存储常量数据,如字符串常量等。例如:
char *str = "hello"; // "hello"存储在常量区,str是指向常量区的指针
- 常量区的数据是只读的,不能被修改。
- 代码区
- 用于存储程序的可执行代码。
(二)内存布局示例
- 简单的C程序内存布局
- 考虑以下程序:
#include <stdio.h> #include <stdlib.h> int global_var = 10; void func() { int local_var = 20; static int static_var = 30; int *heap_var = (int *)malloc(sizeof(int)); *heap_var = 40; printf("global_var: %d\n", global_var);
基于AI的学习
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 50/50 | 2/2 | 4/4 | |
第二周 | 200/200 | 1/3 | 12/12 | |
第三周 | 200/1000 | 1/4 | 10/10 | |
第四周 | 400/400 | 1/5 | 12/12 | |
第五周 | 200/1300 | 1/6 | 10/10 | |
第六周 | 600/1000 | 1/7 | 10/10 | |
第七周 | 400/500 | 1/8 | 9/9 | |
第八周 | 600/600 | 1/9 | 10/10 | |
第九周 | 800/800 | 1/10 | 12/12 | |
第十周 | 800/800 | 1/11 | 10/10 | |
第十一周 | 800/800 | 1/12 | 10/10 | |
第十二周 | 800/800 | 1/13 | 10/10 |
尝试一下记录「计划学习时间」和「实际学习时间」,到期末看看能不能改进自己的计划能力。这个工作学习中很重要,也很有用。
耗时估计的公式
:Y=X+X/N ,Y=X-X/N,训练次数多了,X、Y就接近了。
-
计划学习时间:XX小时
-
实际学习时间:XX小时
-
改进情况:
(有空多看看现代软件工程 课件
软件工程师能力自我评价表)
参考资料
- 《计算机科学概论(第七版)》
- ...