内存区域划分
/* 内存区域的划分 四个:常量区,栈区,堆区,静态全局区 五个:常量区,栈区,堆区,静态全局区,代码区 1.代码区:存代码 2.常量区:存常量 3.静态全局区:静态(static)变量,全局变量 4.栈区:普通局部变量 5.堆区:由程序员手动申请,手动释放 */ # include <stdio.h> int a; // 普通“全局”变量(初识值默认为零) // 作用域:当前项目 // 生命周期:程序开始到结束 static int b; // 静态“全局”变量(初识值默认为零) // 作用域:当前文件 // 生命周期:程序开始到结束 int main() { int c; // 普通局部变量(无初始值) // 作用域:当前语块 // 生命周期:当前语块 static int d; // “静态”局部变量(初识值默认为零) // 作用域:当前语块 // 生命周期:程序开始到结束 return 0; }
# include <stdio.h> void func() { static int num; // 只会定义一次 printf("%d \n", num); num++; printf("%d \n", num); } int main() { func(); func(); func(); return 0; } /* 运行结果: 0 1 1 2 2 3 请按任意键继续. . . */
空类型指针
/* void* 指针 1.不能自增自减 2.不能偏移 3.不能读取内容 但是!可以接收任何类型的指针而不需要强转类型 可以利用这个特点,将 void* 指针当作通用的存放地址的“容器” e.g. int a = 6,b = 8.8; int* p1 = &a; double* p2 = &b; void* p0 = NULL; // 当作存放“内存地址”的容器使用 p0 = p1; p0 = p2; ... */ # include <stdio.h> int main() { void* p0 = NULL; return 0; }
/* 简单开辟内存 1.申请 ---有两个函数能够实现申请内存的功能: A. malloc(参数:需要字节的总数); B. calloc(参数:每个需要的字节数,个数); 返回值都是 void* 类型的指针 2.使用 3.释放 free(参数:首地址) 如果不释放的话,会导致“内存泄露” 4.置空 如果不置空的话,会出现“野指针” */ # include <stdio.h> int main() { /* malloc */ double* p = (double*)malloc(sizeof(double)); // 申请一个double类型大小的内存(8字节) *p = 3.14; // 使用 printf("%lf \n", *p); free(p); // 通过 p 里面存储的首地址,找到相对应的内存,从这里开始释放,一直释放到,申请内存的时候,做了标记的地方 p = NULL; // 通过置空,让指针不再指向已经被释放掉的内存 /* calloc */ float* p1 = (float*)calloc(sizeof(float),1); *p1 = 3.14f; printf("%f \n", *p1); free(p1); p1 = NULL; printf("进阶运用 \n"); // 进阶运用 p = (double*)malloc(sizeof(double)*10); // 申请10个 double 类型大小的连续的内存(补充:因为上面将p定为 double* 而且置空过了,所以可再度利用) for (int i = 0; i < 10; i++ ) { *(p + i) = 10 + i; // 给值 printf("%lf \n", *(p + i)); // 展示值 } free(p); p = NULL; /* 对于上面 for 循环部分的补充: p:里面存的是:申请的内存的首地址 在一次申请中,申请的内存是连续的 *(p + i) <===> p[i] // 注意!它不是数组! */ return 0; }
# include <stdio.h> int main() { // 指针布局 int row = 3; int** pp = (int**)calloc(sizeof(int*), row); int len = 4; for (size_t i = 0; i < row; i++) // size_t是什么?点我跳转学习 { pp[i] = (int*)calloc(sizeof(int), len); } // 内容展示 for (size_t i = 0; i < row; i++) { for (size_t j = 0; j < len; j++) { pp[i][j] = i * 10 + j; // 给值 printf("%-5d", pp[i][j]); // 展示值,注意!这里不是二维数组!(看不懂请回顾上页内容) } printf("\n"); } // 释放内存 for (size_t i = 0; i < row; i++) { free(pp[i]); pp[i] = NULL; } free(pp); pp = NULL; return 0; }
自动扩容
# include <stdio.h> int main() { int len = 5; // 默认长度 int* p = (int*)calloc(sizeof(int), len); int num = 1; for (size_t i = 0; num != 0; i++) // 用户不输入0结束,就一直获取数据并复制到开辟的内存中 { scanf("%d", &num); p[i] = num; // 数据复制到开辟的内存中 } for (size_t i = 0; p[i] != 0; i++) { printf("%-5d", p[i]); // 展示数据 } free(p); p = NULL; return 0; }
/* 扩容的本质是: 将小内存中的所有内容拷贝到大内存中,然后,再继续对大内存进行别的操作 */ # include <stdio.h> int main() { // 长度 int len = 5; // 首次申请内存 int* p = (int*)calloc(sizeof(int), len); int* temp = p; // 成为p的分身,以防万一 // 重复输入数据(并复制到内存中) int num = 1; int i = 0; while (scanf("%d", &num), num != 0) { if (i < len) // 没满的情况下 { temp[i++] = num; // 存完一次,记录一下 } else // 满了的情况下 { len += 5; p = (int*)calloc(sizeof(int), len); // 重新申请更大的内存 for (int j = 0; j < i; j++) { p[j] = temp[j]; } free(temp); temp = NULL; temp = p; // 继续成为当前p的分身 temp[i++] = num; } } // 输出数据 printf("--------------------\n"); for (int j = 0; j != i; j++) { printf("%d \n", temp[j]); } free(p); p = NULL; temp = NULL; return 0; }
浙公网安备 33010602011771号