# 2024-2025-1 20241310 《计算机基础与程序设计》第12周学习总结

2024-2025-1 20241310 《计算机基础与程序设计》第12周学习总结

作业信息

这个作业属于哪个课程 [2024-2025-1-计算机基础与程序设计](https://edu.cnblogs.com/campus/besti/2024-2025-1-CFAP)
这个作业要求在哪里 2024-2025-1计算机基础与程序设计第一周作业
这个作业的目标 自学教材《C语言程序设计》第11章并完成云班课测试
作业正文 本博客链接

教材学习内容总结

一、指针和一维数组的关系

(一)数组名作为指针常量

  1. 本质

    • 在C语言中,一维数组名可以看作是一个指针常量,它指向数组的第一个元素。例如,对于数组int arr[5];arr就相当于&arr[0],这个地址是常量,不能被重新赋值。
  2. 通过指针访问数组元素

    • 可以定义一个指针变量指向数组,然后通过指针来访问数组元素。例如:
    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)字节。
  3. 指针算术运算与数组下标等效

    • 对于数组arr和指针pp = arr),arr[i]*(p + i)是等效的。这是因为数组在内存中是连续存储的,p + i表示从数组首地址偏移i个元素的地址,再通过*解引用就可以得到该地址存储的值,这与通过数组下标访问元素的效果相同。

(二)函数参数中的数组与指针

  1. 数组作为函数参数退化为指针
    • 当一维数组作为函数参数传递时,数组名会退化为指向数组首元素的指针。例如:
    void func(int arr[]) { 
        // 这里的arr实际上是一个指针 
    } 
    int main() { 
        int arr[5]; 
        func(arr); 
        return 0; 
    } 
    
    • 在函数func内部,无法通过sizeof获取数组的实际大小,因为arr已经是一个指针,sizeof(arr)得到的是指针的大小(在32位系统中为4字节,64位系统中为8字节),而不是数组的大小。

二、指针和二维数组的关系

(一)二维数组的存储结构

  1. 按行存储
    • 二维数组在内存中是按行存储的,即先存储第一行的所有元素,再存储第二行的元素,以此类推。例如,对于二维数组int arr[2][3];,其存储顺序为arr[0][0]arr[0][1]arr[0][2]arr[1][0]arr[1][1]arr[1][2]
  2. 数组名的含义
    • 二维数组名也是一个指针常量,它指向二维数组的第一个元素,不过这里的第一个元素是一个一维数组。例如,对于int arr[2][3];arr的类型是int (*)[3],它指向一个包含3个int元素的一维数组。

(二)通过指针访问二维数组

  1. 使用数组指针
    • 可以定义一个数组指针来指向二维数组,例如:
    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]访问其中的元素。
  2. 与一维数组指针的关系
    • 可以将二维数组看作是由多个一维数组组成的数组。例如,int arr[2][3]可以看作是一个包含2个元素的数组,每个元素是一个包含3个int元素的一维数组。从这个角度理解,二维数组名是指向一维数组的指针,而通过适当的指针运算可以访问到二维数组中的每个元素。

三、指针数组及其应用

(一)定义和初始化

  1. 定义
    • 指针数组是一个数组,其元素为指针类型。例如,int *arr[5];定义了一个包含5个元素的指针数组,每个元素都是指向int类型的指针。
  2. 初始化
    • 可以在定义时初始化指针数组,例如:
    int num1 = 1, num2 = 2, num3 = 3; 
    int *arr[3] = {&num1, &num2, &num3}; 
    
    • 这里arr[0]指向num1arr[1]指向num2arr[2]指向num3

(二)应用

  1. 字符串数组
    • 指针数组常用于表示字符串数组。例如:
    char *strs[] = {"hello", "world", "C language"}; 
    for (int i = 0; i < 3; i++) { 
        printf("%s\n", strs[i]); 
    } 
    
    • 这里strs是一个指针数组,每个元素指向一个字符串常量。这种方式比使用二维字符数组来存储字符串更加节省内存,因为字符串常量在内存中只存储一份,而指针数组只是存储了这些字符串常量的地址。
  2. 函数指针数组
    • 可以定义函数指针数组,用于根据不同的条件调用不同的函数。例如:
    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程序的内存映像

(一)内存分区

  1. 栈区(Stack)
    • 由编译器自动分配和释放,用于存储函数的局部变量、函数参数等。例如:
    void func() { 
        int num = 10; // num存储在栈区 
    } 
    
    • 栈区的内存分配是从高地址向低地址增长的,函数调用结束时,栈上的局部变量会自动销毁。
  2. 堆区(Heap)
    • 由程序员手动分配和释放(使用malloccallocrealloc等函数分配,使用free函数释放),用于动态分配内存。例如:
    int *p = (int *)malloc(sizeof(int)); // 在堆区分配内存 
    *p = 10; 
    free(p); 
    
    • 堆区的内存分配是从低地址向高地址增长的。
  3. 全局区(静态区,Static)
    • 用于存储全局变量和静态变量。全局变量在整个程序的生命周期内都存在,静态变量的生命周期也贯穿整个程序的执行过程。例如:
    int global_num = 10; // 全局变量,存储在全局区 
    void func() { 
        static int static_num = 20; // 静态局部变量,也存储在全局区 
    } 
    
  4. 常量区
    • 用于存储常量数据,如字符串常量等。例如:
    char *str = "hello"; // "hello"存储在常量区,str是指向常量区的指针 
    
    • 常量区的数据是只读的,不能被修改。
  5. 代码区
    • 用于存储程序的可执行代码。

(二)内存布局示例

  1. 简单的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小时

  • 改进情况:

(有空多看看现代软件工程 课件
软件工程师能力自我评价表
)

参考资料

posted @ 2024-12-11 19:51  诺奇布卡  阅读(32)  评论(0)    收藏  举报