首页 > 代码库 > 内存分配的四个例子
内存分配的四个例子
内存分配的四个例子
原文在是:有关内存的思考题 在这篇基础上扩展了些知识,以做记录。
第一个例子:
char *GetMemory(char * p) { p = (char *)malloc(100); return p; } void Test(void) { char *str = NULL; GetMemory(str); strcpy(str, "hello world"); printf(str); }请问运行Test函数会有什么样的结果?
答:程序崩溃。
这是函数形参的问题,函数GetMemory的输入参数char * p是一个形式参数。
形式参数在函数定义时并不占用内存中的存储单元;
形式参数在函数调用时被分配内存单元(在栈上),并且其初始值与被赋的实参相同,调用以后形参与实参之间没有任何联系,它们是物理地址不同的两个变量。因此在函数内部对于形参所做的改变,是不能在实参上得到体现的;
形式参数在函数结束时被释放,它的值将被丢弃。
Test函数中的 str一直都是 NULL。strcpy(str, "hello world");将使程序崩溃。
函数改成:
void Test(void) { char *str = NULL; str = GetMemory(str); strcpy(str, "hello world"); printf(str); }就对了,但是malloc的内存没有释放,有内存泄露问题。
第二个例子:
char *GetMemory(void) { char p[] = "hello world"; return p; } void Test(void) { char *str = NULL; str = GetMemory(); printf(str); }请问运行Test函数会有什么样的结果?
答:可能是乱码。
这是个内存分配问题,char p[] = "hello world";这句话可以理解为:a.在栈上分配长度为12的内存,p指向这个内存地址;b.把"hello world"拷贝到p指向的栈内存里面,再加上一个结束字符‘\0‘(这也是为什么11个字符,长度为12的原因)。p和p指向的地址都在栈上面。当函数退出的时候,释放使用的栈空间给其他的函数使用,因此该地址上的值有可能被其他函数重写,这样打印出来的可能是乱码。由于栈释放只是把栈顶指针移位,并没有把释放的数据段初始化,因此释放后的数据还有保留,如果又没有其他函数重写这部分栈空间,那么打印出来的数据也有可能是对的。
函数改为:
char *GetMemory(void) { char *p = "hello world"; return p; }其他不变,这个Test函数运行的结果恒定为"hello world"。
这是因为:char *p = "hello world"; p是在栈上分配的,"hello world"定义在文字常量区。一个栈上的变量p指向文字常量区的一个字符串。函数返回后str指向的也是这个文字常量区,因此打印的结果也是对的,而且文字常量区是由编译器自动创建释放,不存在内存泄露问题。
类似引申一个问题
char *p0 = "hello world"; char p1[] = "hello world"; *p0='W'; // 可以修改,因为p0指向的空间在栈上 *p1='W'; // 系统错误,因为试图修改文字常量区内容。这就是这个问题的本质区别。
第三个例子:
void GetMemory(char **p, int num) { *p = (char *)malloc(num); } void Test(void) { char *str = NULL; GetMemory(&str, 100); strcpy(str, "hello world"); printf(str); }请问运行Test函数会有什么样的结果?
答:
(1)能够输出hello world
(2)存在内存泄漏
GetMemory输入实参是char *str的地址(指针的地址),在函数里面改变了这个地址指向的空间,因此返回后可以带出修改后的数据值。但是str空间没有被释放,所以有内存泄露。如果不是字符串,这个问题似乎更容易理解。
int get_x(int x, int *y) { x++; *y = x+1; return x; } void Test(void) { int x = 100; int y = 200; int z = get_x(x, &y); printf("x=%d y=%d z=%d\n", z, y,z); }输出结果为:x=100 y=102 z=101。
第四个例子:
void Test(void) { char *str = (char *) malloc(100); strcpy(str, “hello”); free(str); if(str != NULL) { strcpy(str, “world”); printf(str); } }请问运行Test函数会有什么样的结果?
答:篡改动态内存区的内容,后果难以预料。
因为调用free(str)之后,str成为悬垂指针,它还指向原来的堆地址空间(因此str!=NULL 返回为1),但是那个空间已经被系统回收,它已经不是一个系统可知长度的独立的被标识为已用的内存空间段。如果这时候还强行向其中写数据,也不一定会出错。因为该地址真实存在,但是这是不安全的,1.可能写到下一个数据空间,写花别人;2.可能系统把包含这个数据段的空间重新分配给其他指针,然后那个指针赋值后,就写花了自己。这两种情况都是不可预知的,因此要尽量避免这种情况出现。避免的方式很简单 free(str); str=NULL;这两句话不要分开。
内存分配的四个例子
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。