目录
一,动态内存函数
malloc
free
calloc
realloc
二,常见的动态内存错误
经典试题
三,C/C++程序的内存开辟
栈区stack
堆区heap
数据段(静态区)static
代码段
四,柔性数组 — flexible array
案例
- 通常开辟的内存是固定的(数组的内存是编译时分配的,但申明时需指定长度);
- 针对已事先指定内存大小比较合适,对事先不确定的内存大小可使用动态内存函数;
一,动态内存函数
void* malloc( size_t size )
//在堆区,开辟4个整型16个字节的空间
int* p = (int*)malloc(4 * sizeof(int));
void free( void *memblock )
注:动态内存释放有两种方式
int main()
{
//在堆区,开辟4个整型16个字节的空间
int* p = (int*)malloc(4 * sizeof(int));
//检查p是否为空指针
if (p == NULL)
{
perror("main"); //p为空指针返回错误信息
return 0;
}
//释放动态内存空间
free(p);
p = NULL; //避免错误使用
return 1;
}
void *calloc( size_t num, size_t size )
int main()
{
//在堆区,开辟4个整型16个字节的空间
int* p = (int*)calloc(4, sizeof(int));
if (p == NULL)
{
perror("main");
return 0;
}
printf("%d", *p); //0
free(p);
p = NULL;
return 1;
}
void *realloc( void *memblock, size_t size )
int main()
{
//在堆区,开辟4个整型16个字节的空间
int* p = (int*)malloc(4 * sizeof(int));
if (p == NULL)
{
perror("main");
return 0;
}
//将p的空间拓展为10整型40个字节的空间
int* ptr = realloc(p, 10 * sizeof(int));
if (ptr != NULL)
{
p = ptr;
}
free(p);
p = NULL;
return 1;
}
//二者等同
int* p = (int*)malloc(4 * sizeof(int));
int* p = (int*)realloc(NULL, 4 * sizeof(int));
二,常见的动态内存错误
//动态内存的指针可能为NULL,在进行解引用操作前,需进行判断;
int main()
{
int* p = (int*)malloc(4 * sizeof(int));
//使用前,需判断p是否为空
*p = 10;
return 0;
}
//对动态开辟空间的越界访问;
int main()
{
int* p = (int*)calloc(4, sizeof(int));
if (p == NULL)
{
perror("main");
return 0;
}
*(p+4) = 10;
free(p);
p = NULL;
return 1;
}
//对非动态开辟的内存使用free释放;
int main()
{
int i = 10;
int* p = &i;
free(p);
p = NULL;
return 1;
}
//使用free释放一块动态开辟内存的一部分;
int main()
{
int* p = (int*)calloc(4, sizeof(int));
if (p == NULL)
{
perror("main");
return 0;
}
free(p + 2);
p = NULL;
return 1;
}
//对同一块动态内存多次释放;
int main()
{
int* p = (int*)calloc(4, sizeof(int));
if (p == NULL)
{
perror("main");
return 0;
}
free(p);
free(p);
p = NULL;
return 1;
}
//忘记释放动态开辟内存(内存泄漏)
int main()
{
int* p = (int*)calloc(4, sizeof(int));
if (p == NULL)
{
perror("main");
return 0;
}
return 1;
}
注:栈区、堆区、静态区;
//试题一
void GetMemory(char* p)
{
//在堆区开辟内存
//忘记释放,内存泄露
p = (char*)malloc(100);
}
int main()
{
char* str = NULL;
GetMemory(str); //函数调用结束p已销毁,并未更改str
strcpy(str, "hello world");
printf(str);
return 0;
}
//结果:异常访问冲突
//修改1
char* GetMemory(char* p)
{
p = (char*)malloc(100);
return p;
}
int main( )
{
char* str = NULL;
str = GetMemory(str);
strcpy(str, "hello world");
printf(str);
free(str);
str = NULL;
return 0;
}
//结果:hello world
//修改2
void GetMemory(char** p)
{
*p = (char*)malloc(100);
}
int main()
{
char* str = NULL;
GetMemory(&str);
strcpy(str, "hello world");
printf(str);
free(str);
str = NULL;
return 0;
}
//结果:hello world
//试题二
char* GetMemory(void)
{
char p[] = "hello world";
return p;
}
int main()
{
//函数调用结束p已销毁,开辟的内存也还回系统
char* str = NULL;
str = GetMemory();
printf(str);
return 0;
}
//结果:烫烫烫烫烫烫烫烫
//修改
char* GetMemory(void)
{
//static关键字避免销毁(栈区变为静态区)
static char p[] = "hello world";
return p;
}
int main()
{
char* str = NULL;
str = GetMemory();
printf(str);
return 0;
}
三,C/C++程序的内存开辟
四,柔性数组 — flexible array
struct S
{
char c;
int arr[]; //或arr[0],此数组即为柔性数组成员
};
特点:
struct S
{
char c;
int arr[];
};
int main()
{
printf("%d", sizeof(struct S)); //4
}
//会考虑对齐数
//柔性数组形式
struct S
{
int n;
int arr[];
};
int main()
{
//sizeof(struct S)是分配给n的
//10 * sizeof(int)是分配给arr的
struct S* p = (struct S*)malloc(sizeof(struct S) + 10 * sizeof(int));
if (p == NULL)
{
perror("main");
return 0;
}
free(p);
p = NULL;
return 1;
}
//指针形式
struct S
{
int n;
int* arr;
};
int main()
{
struct S* p = (struct S*)malloc(sizeof(struct S));
if (p == NULL)
{
perror("p");
return 0;
}
p->arr = (int*)malloc(10 * sizeof(int));
if (p->arr == NULL)
{
perror("p->arr");
return 0;
}
free(p->arr); //需先释放
p->arr = NULL;
free(p);
p = NULL;
return 1;
}
优势:
注:局部性原理
C语言结构体里的成员数组和指针
案例