1.内存分区使用及注意情况
//按照地址 低->高 分别划分为5个内存区:1.栈区 2.堆区 3.静态区 4.常量区 5.代码区
//1.栈区:局部变量(无static修饰符)存储在栈区;例如:int a = 3, char str = “Hello”等;
//特点:1.系统自动创建并回收开辟的空间;由高到低存储,由低到高访问
// 2.先分配的内存放在栈底(高地址)后分配的空间放在栈顶(地地址)
// 3.函数调用入栈操作,函数释放出栈操作
//2.堆区:使用堆内存分配函数分配的空间malloc(),cmalloc(),free()
//特点:由开发者手动分配并释放内存空间,对内存空间地址和数据的访问更加灵活
//3.静态区:存储在静态区的变量分为两种,分别是:全局变量和用static关键字修饰的静态变量
//特点:1.静态变量若不赋初值则自动赋为0
// 2.只堆静态变量进行一次初始化
// 3.静态变量不会被回收,在整个内存中都存在, 程序执行结束时回收空间
//4.常量区:存储常量的内存空间:1.整型常量 2.字符型常量 3.浮点型常量 4.字符串常量
//特点:常量区内容是只读(readonly),不能被改变
//5.代码区:自定义函数存储在代码区
//注意:洗碗操作
2.堆区分配空间函数
//堆区开辟空间的函数:malloc(), calloc(), realloc(), free()
//注意:只使用于对堆区开辟空间,释放空间
//1.malloc:void *malloc(unsigned int size);
//将分配好size个字节的内存空间的首地址返回
//返回void * 类型的指针,是一个泛型指针,可以由不同的数据类型的指针进行接收
//2.calloc:void *calloc(unsigned int n, unsigned int size);
//分配n个size字节大小的空间,更方便为字符型和数组开辟内存空间
//对开辟的空间进行初始化清0操作,但是效率低于malloc()
//3.realloc:void *realloc(void *p, size_t newSize);
//情况1:如果当前空间后的连续空间大小满足将要扩展空间大小的需求,则在当前空间后开辟空间(返回的地址是原分配空间p的首地址)
//情况2:如果当前空间后的连续空间大小不能满足将要扩展空间大小的需求时,则在内存中另外开辟一块满足需求的空间,并把原先空间内的内容拷贝到新空间中(原空间首地址p被改变)
//注意:新开辟空间后系统自动free原空间,无需手动再次释放
//4.free:将指定地址所对应的空间还给系统(释放内存)
3.栈区空间问题
//1.内存泄露:开辟的内存没有释放,并继续占用内存,导致内存泄露
//2.过度释放:对一块空间重复释放,程序立即crash
//3.野指针:指向空间地址的指针使用完毕后,没有指向NULL,访问没有访问权限的空间
4.内存操作函数
//1.memset() 2.memcpy() 3.memcpy()
//使用范围:即可以对堆区内存操作,又可以操作栈区内存
//1.内存赋值操作:void *memset(void *s, int c, size_t size);从给定的地址s开始将size个字节大小的空间内容赋值为c
//注意:以字节为单位进行赋值
//2.内存拷贝函数:void *memcpy(void *dest, void *source, size_t);从source指向的地址向的地址单元dest拷贝size个字节(拷贝的是内容)
// char wrongName[] = "FanBingBing";
// char rightName[] = "liuYan";
// memcpy(wrongName + 3, rightName + 3, 3);
// 结果:Yan替换Bin
//3.内存比较函数:int memcmp(const void *p, const void *q, unsigned int count);从给定的两个地址p和q一一进行比较count个字节,并且返回第一个不相等字节空间值的差值,若const个字节全相同,则返回0
练习1
分别在堆区创建int,long,double,char的存储空间,将常量赋值给存储在栈区的变量
//定义变量
int intTest = 10;
long longTest = 20;
double doubleTest = 10.0;
char charTest = 'a';
//开辟堆区空间
int *_int = malloc(sizeof(int));
long *_long = malloc(sizeof(long));
double *_double = malloc(sizeof(double));
char *_char = malloc(sizeof(char));
//将栈区变量中存储在常量区内容赋给堆区变量
*_int = intTest;
*_long = longTest;
*_double = doubleTest;
*_char = charTest;
//输出
printf("%d\n", *_int);
printf("%ld\n", *_long);
printf("%.2lf\n", *_double);
printf("%c\n", *_char);
练习2
输⼊⼀个数组长度,动态创建数组,所有元素随机生成,输出元素中的最大值提示并接收一个数组长度
main.m
int n = 0;
printf("Please enter a number:");
scanf("%d", &n);
//调用函数,在堆区开辟空间,并初始化n个随机数
int *array = CreatArray(n);
//传入初始化好的数组首地址,并找出最大值
PrintArray(array, n);
//打印
printf("The max = %-5.2d\n", FindMax(array, n));
//释放空间
free(array);
array = NULL;
CreatArray.m
void *CreatArray(int n) {
int *randomArray = calloc(n, sizeof(int));
for (int i = 0; i < n; i++) {
randomArray[i] = arc4random() % 100;
}
return randomArray;
}
FindMax.m
int FindMax(int *array, int n) {
int max = 0;
for (int i = 0; i < n; i++) {
if (max < array[i]) {
max = array[i];
}
}
return max;
}
PrintArray.m
void PrintArray(int *Array, int n) {
for (int i = 0; i < n; i++) {
printf("%-5.2d", Array[i]);
if ((i+1) % 5 == 0) {
printf("\n");
}
}
}
练习3
已知一个数组 20 个元素(随机 1 到 100 之间包含 1 和 100),求大于平均数的元素个数,并动态生成一个新数组保存(提示:malloc 出 20 个元素保存)
main.m
int n = 0;
int count = 0;
printf("Please enter a number:");
scanf("%d", &n);
int *array = CreatArray(n);
PrintArray(array, n);
int *averArray = AverArray(array, n, &count);
printf("---------------------------\n");
PrintArray(averArray, count);
free(array);
free(averArray);
array = NULL;
averArray = NULL;
AverArray.m
void *AverArray(int *array, int n, int *_count) {
int *averArray = calloc(1, sizeof(int));
int sum = 0, aver = 0;
int count = 0;
int *resuleCount = _count;
for (int i = 0; i < n; i++) {
sum+= array[i];
}
aver = sum / n;
for (int i = 0; i < n; i++) {
if (array[i] > aver) {
averArray[count] = array[i];
count++;
(*resuleCount)++;
averArray = realloc(averArray, sizeof(int) * count + 1);
}
}
return averArray;
}