c语言的内存管理方式,c语言内存管理

2017-08-23

作用域

一个C语言变量的作用域可以是代码块 作用域,函数作用域或者文件作用域。代码块是{}之间的一段代码。

auto 自动变量

一般情况下代码块内部定义的变量都是自动变量。当然也可以显示的使用auto关键字

register寄存器变量

通常变量在内存当中,如果能把变量放到CPU的寄存器里面,代码执行效率会更高。

代码块作用域的静态变量

静态变量是指内存位置在程序执行期间一直不改变的变量,一个代码块内部的静态变量只能被这个代码块内部访问。

代码块作用域外的静态变量

代码块之外的静态变量在程序执行期间一直存在,但只能被定义这个变量的文件访问。

全局变量

全局变量的存储方式和静态变量相同,但可以被多个文件访问。

内存四区

程序加载到内存之后,在内存中存放的位置根据代码类型而不同。把内存分为四个区域:代码区:代码区的地址可以通过函数指针来访问。程序当中所有可执行代码都放在代码区。代码区不可读写,只可执行。

静态区:存放全局变量和静态变量

栈区:所有自动变量,包括函数的形参都放在栈区

堆区: 堆是个大容器,程序自由的在堆中放任何变量。

代码区

代码区code,程序被操作系统加载到内存的时候,所有的可执行代码都加载到代码区,也叫代码段,这块内存是不可以在运行期间修改的。

栈区

栈stack是一种先进后出的内存结构,所有的自动变量,函数的形参都是由编译器自动放出栈中,当一个自动变量超出其作用域时,自动从栈中弹出。

堆区

堆heap和栈一样,也是一种在程序运行过程中可以随时修改的内存区域,但没有栈那样先进后出的顺序。

堆是一个大容器,它的容量要远远大于栈,但是在C语言中,堆内存空间的申请和释放需要手动通过代码来完成。

示例

示例01

#include

#include

#define MAXSIZE 1024

#pragma warning(disable:4996)

char *test01()

{

char *str[10] = {"hello"}; // str 是在栈中,出作用域之后变量释放

return str;

}

char *test02()

{

return "hello";

}

在主函数中执行上述两个函数。

int main(){

char *p1 = test01();

printf("%sn",p1); // 输出随机值

char *p2 = test02();

printf("%sn",p2); // 正确输出 hello

return 0;

}

示例02

#include

#include

#define MAXSIZE 1024

#pragma warning(disable:4996)

char *test03()

{

char *s = malloc(sizeof(char) * 10);

strcpy(s,"hello");

return s;

}

void test04(char *p)

{

p = malloc(sizeof(char) * 10);

strcpy(p,"hello");

}

void test05(char *p)

{

strcpy(p,"hello");

}

void test06(char **p)

{

*p = malloc(sizeof(char) * 10);

strcpy(*p,"hello");

}

在主函数中执行上述两个函数:

int main(){

char *p3 = test03();

printf("%sn", p3);

free(p3); // 输出 hello

char *s = NULL;

test04(s);

printf("%sn",s); // NULL

char *s2 = malloc(sizeof(char) * 10);

test05(s2);

printf("%sn",s2); // 可以成功

char *s = NULL;

test06(&s);

printf("%sn",s); // 输出hello

return 0;

}

动态内存分配

原理

数组的元素存储于内存中连续的位置上。当一个数组被声明时,它所需要的内存在编译时就被分配。但是,我们可以使用动态内存分配在运行时为它分配内存。

一块内存的生命周期可以分为四个阶段:分配、初始化、使用、释放。

内存的分配一般使用C函数库里的malloc函数(原型:void *malloc(size_t size))。

关于malloc函数应该注意一下几点:malloc的参数就是需要分配的内存的字节数。

malloc所分配的是一块连续的内存。

分配成功,则返回指向分配内存起始地址的指针。分配失败,返回NULL指针。

对每个malloc返回的指针都进行检查,是好的习惯。

内存的初始化一般要在使用之前手动进行,也可以在分配时由calloc函数一同完成:将分配内存初始化为0。使用就是使用分配所返回的指向内存的指针。

释放内存是为了防止内存泄露,一般使用free函数(原型:void free(void *pointer))完成。它的参数必须是先前从malloc、calloc或realloc返回的值。向free传递一个NULL参数不会产生任何效果。向free传递其他参数会出错。

常见的动态内存错误

常见的动态内存错误有以下几种:忘记对NULL指针进行解引用操作,即忘记对分配返回的值做判断。

对分配的内存进行操作时越过边界。

释放并非动态分配的内存,传递给free的必须是一个从malloc、calloc或realloc返回的指针。

试图释放一块动态分配的内存的一部分。

一块动态内存被释放后被继续使用。

总结

使用动态内存的编程总结:动态内存分配有助于消除程序内部存在的限制。

使用sizeof计算数据类型的长度,调高程序的可移植性。

calloc和realloc函数:

void *calloc(size_t nmemb, size_t size);

void *realloc(void *ptr, size_t size);

calloc与malloc的区别:前者返回指向内存的指针之前把它初始化为0.

calloc的参数包括所需元素的数量和每个元素的字节数。根据这些值,能够计算出总共需要分配的内存。

realloc函数用于修改一个原先已经分配的内存卡的大小。使用该函数,可以使一块内存扩大或缩小。如果原先的内存卡无法改变大小,realloc将分配另一块正确大小的内存,并把原先那块内存的内容复制到新的块上。

示例

利用动态内存分配,写一个字符串追加方法。

#include

#include

#include

#include

#pragma warning(disable:4996)

// 字符串追加

char *array = NULL; // 初始长度为10

void init_array(const char* s)

{

if (array)

{

free(array);

}

int s_len = strlen(s);

array = malloc(s_len + 1);

strcpy(array, s);

}

void add_str(const char *s)

{

if (s == NULL)

{

return;

}

int array_len = strlen(array);

int s_len = strlen(s);

// 首先开辟一个新的堆内存空间,内存大小为 array_len + s_len +1

char *temp = malloc(array_len + s_len + 1);

strcpy(temp, array);

strcpy(temp + array_len, s);

*(temp + array_len + s_len) = 0;

free(array);

array = temp;

}

void add_str_new(const char *s)

{

if (s == NULL)

return;

int len_array = strlen(array);

int len_s = strlen(s);

realloc(array, len_array + len_s +1);

memset(array + len_array, 0, len_s + 1);

strcpy(array + len_array, s);

}

void free_array()

{

if (array)

free(array);

array = NULL;

}

int main()

{

init_array("adfsdfddddddd");

//add_str("1234dgdfgdfgdfgdfgdfgdfgdfgdfgdfgdfgdfgdfgdfgdfgdfg");

add_str_new("1234dgdfgdfgdfgdfgdfgdfgdfgdfgdfgdfgdfgdfgdfgdfgdfg");

printf("array:%sn", array);

free_array();

return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值