C语言要点—— 动态内存

*malloc和free

1、malloc所分配的是一块连续的内存,以字节为单位,并不带任何的类型信息。
2、free用于将动态内存归还系统。
void* malloc(size_t size);
void free(void* pointer);
3、malloc实际分配的内存可能会比请求的稍微多一点,但是不能依赖于编译器的这个行为。
4、当请求的动态内存无法满足时,malloc返回NULL。
5、当free的参数为NULL,函数直接返回。

*calloc和realloc

void* calloc(size_t num, size_t size);
void* realloc(void* pointer, size_t new_size);
1、calloc的参数代表所返回的内存的类型信息,calloc会将返回的内存初始化为0。
2、realloc用于重置一个已分配的内存块的大小。
3、malloc单纯地从系统中申请固定字节大小的内存,calloc能以类型大小为单位申请内存并初始化为0。

*栈

栈保持了一个函数调用所需的维护信息:
1、函数参数,函数返回地址。
2、局部变量。
3、函数调用上下文。

*堆

1、堆是程序中一块巨大的内存空间,可由程序自由使用。
2、堆中被程序申请使用的内存在程序主动释放前将一直有效。
3、系统对堆空间的管理方式:空闲链表法,位图法,对象池法等等。
eg:空闲链表法


*静态存储区

1、静态存储区主要用于保存程序中的全局变量和静态变量。
2、静态存储区随着程序的运行而分配空间,直到程序运行结束。
3、在程序的编译期静态存储区的大小就已经确定。
4、与栈和堆不同,静态存储区的信息最终会保存到可执行程序中。

*堆、栈和静态存储区的对比

1、栈区主要用于函数调用的使用。
2、堆区主要是用于内存的动态申请和归还。
3、静态存储区用于保存全局变量和静态变量。

*程序的内存布局

1、堆、栈段在程序运行后才正式存在,是程序运行的基础。
2、.bss段存放的是未初始化的全局变量和静态变量。
3、.text段存放的是程序中的可执行代码。
4、.data段存放的是那些已经初始化了的全局变量和静态变量。
5、.rodata段存放的是程序中的常量值,如字符串常量。

*野指针

1、野指针通常是因为指针变量中保存的值不是一个合法的内存地址而造成的。
2、野指针不是NULL指针,是指向不可用的内存的指针。
3、NULL指针不容易用错,因为if语句可以判断一个指针是不是NULL。
4、C语言中没有任何手段可以判断一个指针是否为野指针。

*野指针的由来

1、局部指针变量没有被初始化。
2、使用已经释放过后的指针。
3、指针所指向的变量在指针之前被销毁。

*非法内存操作分析

1、结构体成员指针未初始化。
没有为结构体指针分配足够的内存。
eg:
以下例子中d1.p、d2.p未初始化。
struct Demo
{
int* p;
};
int main(void)
{
struct Demo d1;
struct Demo d2;
int i = 0;
for(i=0; i<10; i++)
{
d1.p[i] = 0;
}
d2.p = (int*) calloc(5, sizeof(int));
for(i=0; i<10; i++)
{
d2.p[i] = i;
}
free(d2.p);
return 0;
}

2、数组越界(内存越界)。
eg:
以下例子中实参数组只有5个元素,形参数组中却分配了10个元素的空间。
void f(int a[10])
{
int i = 0;
for(i=0; i<10; i++)
{
a[i] = 0;
printf("%d\n", a[i]);
}
}
int main()
{
int a[5];
f(a);
return 0;
}

3、内存分配成功,但未初始化。
eg:
int main()
{
char* s = (char*)malloc(10);
printf(s);
free(s);
return 0;
}

4、内存泄露。

5、多次释放指针。
eg:
以下例子指针p在main和f中分别释放过。重复释放。
void f(int* p, int size)
{
int i = 0;
for(i=0; i<size; i++)
{
p[i] = 0;
printf("%d\n", p[i]);
}
free(p);
}
int main()
{
int* p = (int*)malloc(5*sizeof(int));
f(p, 5);
free(p);
return 0;
}

6、使用已释放的指针
eg:
以下例子中main函数中的p指针在函数f中已经释放过,不能再次使用。
void f(int*p, int size)
{
int i = 0;
for(i=0; i<size; i++)
{
printf("%d\n", p[i]);
}
free(p);
}
int main()
{
int* p = (int*)malloc(5*sizeof(int));
int i = 0;
f(p, 5);
for(i=0; i<5; i++)
{
p[i] = i;
}
return 0;
}

*C语言中内存操作规则

1、用malloc申请了内存之后,应该立即检查指针值是否为NULL,防止使用值为NULL的指针。
eg:
int* p = (int*)malloc(5*sizeof(int));
if(p != NULL)
{
//do something
}
free(p);
2、牢记数组的长度,防止数组越界操作,考虑使用柔性数组。
3、动态申请操作必须和释放操作匹配,防止内存泄露和多次释放。
4、free指针之后必须立即赋值为NULL。
eg:
int* p = (int*)malloc(10);
free(p);
p = NULL;
//....
//....
//....
if(p != NULL)
{
int i = 0;
for(i=0; i<5; i++)
{
p[i] = i;
}
}

附:本文对应文档:

https://download.csdn.net/download/bulebin/10293658























猜你喜欢

转载自blog.csdn.net/bulebin/article/details/79600985