C语言内存分配及函数返回值的解析。

C语言的内存分配主要如下:

(1)栈区:在执行函数时,函数内局部变量(不包含static变量)、函数返回值的存储单元在栈区上创建,

函数执行结束时这些存储单元自动被释放。栈区内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

(2)堆区:即动态分配内存分配,程序在运行时用malloc(calloc,realloc等)申请的内存,程序员自己负责用free释放内存。

(3)静态存储区:该内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。此处存放全局变量、static变量。

(4)常量区:整型常量、浮点型常量、字符型常量及字符串常量都分配在文字常量区,程序结束后由系统释放。

(5)代码区:存放整个程序的代码。数据和代码是分开存储的。


如下有几种容易出错的情况:

#include <stdlib.h>
#include <stdio.h>
char* function();

main()
{

	char *b;

	char *  golble_b;
	
	char a=(char)(100);
	b=&a;

	golble_b=&a;

	printf("the int value of a:%d,%c\n",a,a);
	printf("before functin:%c,g_b:%c\n",*b,*golble_b);
golble_b=function();
	printf("after functin:%c,g_b:%d\n",*b,*golble_b);
getchar();




}
char* function()
{

char a[2];
char *b;
b=&a;
printf("please input a char:");
scanf("%s",b);
printf("inner of function %c\n",*b);

	return b;

	
}

运行结果:

下面简单分析一下。

对于子函数char* function()。

内部分配了

char a[2];
char *b;
很明显a[2]用来存储一个字符串。

而b执行一个字符。如下图。a[1]存储的是字符串结束符。



返回的是b。是一个指向指向字符的指针。

修改一下function()

char* function()
{

char a[2];
char *b;
b=&a;
printf("please input a char:");
scanf("%s",b);
printf("inner of function %c\n",*b);

	return a;

	
}

存在一个warning

这个很好解释。a是数组名,就是一个指针,是一个执行含有两个char元素的数组的指针。

但是传过去的还是一个字符。

再改一下:


#include <stdlib.h>
#include <stdio.h>
char(*function())[2];

main()
{

	char *b;

	char *  golble_b;
	
	char(*array_b)[2];
	char a=(char)(100);
	b=&a;

	golble_b=&a;

	printf("the int value of a:%d,%c\n",a,a);
	printf("before functin:%c,g_b:%c\n",*b,*golble_b);
//golble_b=function();

array_b=function();
	printf("after functin:%c,g_b:%d\n",*b,*golble_b);
	printf("after functin:%c,array_b:%c\n",*b,*array_b);
getchar();




}
char(*function())[2] 
{

char a[2];
char *b;
b=&a;
printf("please input a char:");
scanf("%s",b);
printf("inner of function %c\n",*b);

	return a;

	
}
注意

char(*function())[2];

	char(*array_b)[2];
前者为声明了一个返回指向存储2个char元素数组的指针的函数。声明了一个函数,函数无形参,返回值为返回一个指针,一个指向数组的指针,一个指向存储了两个char元素数组的指针。

后者为声明了一个指针,一个指向存储了两个char元素的数组的指针。

看结果:

看,并没有传过来,是因为return a 中的a是局部数组的首地址,它是栈区地址。funciton函数执行结束时组数a存储单元自动释放。所以不应该返回过去。如果想要正确返回组数a的地址,可以再定义数组时加static修饰或定义为全局变量。

看结果:

至今为止没有使用malloc。其实这个也可以达到这个结果。但是不能忘记free。

看如下程序:

#include <stdlib.h>
#include <stdio.h>
int* function();

main()
{

	int *c,d;
	d=888;
	c=&d;


printf("after function,b:%d\n",*c);
c=function();
printf("after function,b:%d\n",*c);

getchar();




}
int* function()
{
int a,*b;
a=1314521;
b=&a;
(*b)++;
printf("inner of function %d\n",a);

	return b;

	
}

看结果:

不是说“函数执行结束时这些存储单元自动被释放。”么?

没关系我们再修改一下:

#include <stdlib.h>
#include <stdio.h>
int* function();
int* function2();

main()
{

	int *c,d;
	d=888;
	c=&d;


	printf("before function,c:%d\n",*c);
    c=function();
    printf("after function,c:%d,address=%p\n",*c,c);
    c=function2();
    printf("after function2,c:%d,address=%p\n",*c,c);

    getchar();






}
int* function()
{
	int a,*b;
	a=1314521;
	b=&a;
	(*b)++;
	printf("inner of function %d\n",a);

	return b;


}

int* function2()
{
	int a,*b;
	a=12580;
	b=&a;
	(*b)++;
	printf("inner of function %d\n",a);

	return b;


}

看结果:




两个子函数,形参、返回值、函数体出了存储在静态区的常量不同其他都一样。

所以进入子函数时,系统为之分配的栈空间一样,再因为操作系统和编译器都一样。外部环境很相似。所以栈的地址区域和所有变量的分配地址都一样。

我们这里再说明一下:

(1)我们是在xp操作系统上运行的。是有MMU的。是有内存映射的。所以我们的地址这时都是虚拟地址,是操作系统为每一个

进程分配的4G的虚拟地址,通过内存映射这些地址会被映射到物理地址上。

(2)当第一个自函数退出时,为之分配的栈空间就会被释放。但并不是清零的操作,而是这块内存标明可以被使用,

在学习操作系统的过程中,还记得内存分配的。是沿着那个链表式的东西在找一块儿合适的内存空间。

被释放只是说明这块儿内存可以被重新分配。没有清空的操作,这个对比试验可以得出这个结果。

看程序:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int address_array;
int address_pointer;
int address_pointer_char;
int function();
int main()
{
	char *p,*q;
	function();

	printf("address_array=%d,address_pointer=%d,address_pointer_char=%d\n",address_array,address_pointer,address_pointer_char);

	p=(char *)address_pointer;

	q=(char *)address_pointer_char;

	printf("p=%p\n",p);
		printf("q=%p,%c\n",q,*q);

}


int function()
{

	char *c,d;
	char a[50]="Hello word!!";

	char *b;

	

	b=a;

	d='a';

	c=&d;
	

	printf("a[]=%s,*b=%s",a,b);

	address_array=a;

	address_pointer=b;

	address_pointer_char=e;



}

看结果:

子函数中初始化了一个字符数组,一个char指针,一个指向字符的char指针。结束前把这些局部变量的地址都传给了全局变量。

在主函数中,访问这些地址,都未成功。这是因为在函数结束后和打印变量之间还有其他函数的调用。所以,那块栈空间又被改写了。

注意,为了安全,在子函数中千万不要return 指针类型的局部变量值。栈内地址不能安全的传递到函数外。可以传,但是不安全,因为很肯能会改变。

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值