内存区域的划分(地址从高到底)
- 栈区 // 反复的创建销毁
- 堆区
- 静态区(全局区)
- 常量区
- 代码区
1)栈区
* 栈管理数据的方式LIFO(后进先出) FILO(先进后出)
* 局部变量:定义在函数内部的变量就叫做局部变量,局部变量都是存储在栈区。
int a = 10;
int b = 20;
char c = ‘a’; // 其中 a,b,c都是局部变量;
* 内存管理的时候,系统也是遵守内存对齐原则,因为这样可以提高内存的分配效率
* 局部变量存在于栈区,由系统为其分配空间和释放空间,开发人员不需要管理。
* 一个程序在内存中占据了大概7~8M的栈区内存,递归可以很快吃掉内存;
2)常量区:指针指向一个常量
char *str = “iPhone”; // 指针常量
printf(“%s\n”,str);
char string[20] = “iPhone”;
string[0] = ‘a’;
printf(“%s\n”,string); // “aPhone"
常量区的内容只能访问,不能修改,常量区的数据也是由系统分配的,不需要开发人员管理。
3)静态区(全局区)
* 由static 修饰的变量存放在静态区,静态区的变量在整个程序运行过程中只能被初始化一次,如果没有认为初始化,这是系统默认初始化为零。
* 全局变量也是存放在静态区。
static int d;
printf(“%d\n”,d);
printf(“常量区地址:%p\n”,&number);
printf(“%p\n”,&d);
for (int i = 0; i < 5; i++) {
static int count = 0;
printf(“%d\n”,count);
count++;
}
4)代码区:程序中运行的函数或者变量等等语句都会被编译成CPU指令,存放在代码区
系统提供的函数由于使用比较频繁,我们把它们存放到栈区,原因是栈区的内容会被反复的创建销毁,不需要我们去管理内存,还有一点就是因为栈区的内存开辟和释放都是非常迅速。
int arr[5] = {1,2,3,4,5};
int *p1 = arr;
printf(“%p\n%p\n”,p1,arr);
5)堆区:是唯一一块开发者能够控制的内存区域,这块区域的内存我们要手动申请,并且手动释放。
// 如何管理堆区的内存?
// malloc
// void *malloc(size_t);
// void * ,泛类型,void *返回的指针可以赋值给任何类型的指针,int *,float *,char *,short *
// size_t 代表申请多少个字节大小的内存空间
// malloc的作用: 申请size个字节大小的空间,并把申请空的首地址返回;
char *p = malloc(8); // p内存储的是这8个空间的首地址。
strcpy(p, “iPhone”); // 为数组赋值。
printf(“%s\n”,p);
printf(“堆区的地址:%p\n”,p);
p[0] = ‘a’;
printf(“%s\n”,p);
free(p); // 释放掉p指向的堆区空间,只是标记删除,不清空里边的内容。
// free(p); 过度释放,释放多次,会造成crash(崩溃);
// printf(“%p\n”,p);
p = NULL; // 指向无效空间,防止野指针错误 确保安全。
(**)练习6: 有一个已知的字符串,其中包含数字字符,提取其中的数字,存储到堆区,动态开辟内存;
char st[] = "lanou999zhegnzhou110";
int i = 0;
int n = 0;
while (st[i] != '\0') { // 这一个判断函数为了记录这个字符串中数字的数量。
if (st[i] >= '0' && st[i] <= '9') {
n++;
}i++;
}
char *m = malloc(n+1); // +1 的目的是为了给存储\0
int z = 0;
int index = 0; // 记录m指向内存空间每一个字符下标的位置
while (st[z] != '\0') {
if (st[z] >= '0' && st[z] <= '9') {
*(m+index) = st[z];
index++; // 转向下一个元素
}z++;
}
*(m + index) = '\0';
printf("%s\n",m);
free(m);
m = NULL;
其他内存分配函数:
* 1. calloc (n,4) 两个参数的意思:表示申请n个size大小的空间,返回申请空间的首地址,但是他在申请空格的时候会坐一步处理,就是清除每一个字节里的内容,也就是清零操作,正是因为他多了这一步,执行的效率会比malloc低
练习: 为一个5个元素的整形数组分配空间,存储数据,元素的范围是[30 50];
int *p5 = calloc(5, sizeof(int));
for (int i = 0; i<5; i++) {
*(p5+i) = arc4random_uniform(50-30+1)+30;
printf("%d\n",*(p5 + i));
}
free(p5);
p5 = NULL;
* 2. realloc(p,n) 内存重新分配函数,第一个参数是地址(指针),第二个参数是重新分配的内存大小
使用realloc重新分配空间的时候,如果在原有空间的基础上可以连续在增加(n-原来大小)个空间,指针的指向不会改变,如果这时不可以连续增加,则会将之前的空间给释放掉,然后再去其他堆区的其他位置开辟连续n个空间大小的内存,这时指针的指向也改变了
int *p6 = malloc(12);
*p6 = 10;
*(p6+1) = 20;
*(p6+2) = 30;
printf(“之前的地址:%p\n”,p6);
// 重新申请空间的大小
p6 = realloc(p6, 20);
printf(“之后的地址:%p\n”,p6);
*(p6 +3) = 40;
*(p6 +4) = 50;
// 重新分配的空间会把之前空间里的内容给拷贝过来,放在相应的位置。
for (int i = 0; i < 5; i ++) {
printf(“%d “,*(p6 + i));
}
free(p6);
p6 = NULL
内存操作的其他函数
* 3.memset(开始地址,n,size) 给定一个开始地址,将size字节的空间大小内的数据置为n,如果n为零,size为10,就是把10个字节中的数据置为0。
// memcpy(dest, source, n)// 从源指针开始位置,向目的指针拷贝n个字节的数据 // 往dest里拷贝
char str1[] = "ABC";
char str2[] = "123";
memcpy(str1, str2, 2);
printf("%s\n",str1);
// memcmp (p1,p2,n) 比较p1和p2指向内存里的内容是否相同,比较n个字节,返回值是0,相等。不同的时候,返回差值。比较的过程是逐个字节的比较,返回第一对对应字节位置不相同数据的差值(参加 strcmp 的用法)