`

C是怎样使用内存的

阅读更多

1、应用程序面对的地址实际是虚拟地址空间,每一个进程分配了一个独立的虚拟地址。

printf输出地址值输出的并不是真实的物理地址。

#include <stdio.h>

int main()
{
	int		hoge;
	char	buf[256];

	printf("&hoge...%p\n",&hoge);

	printf("input initial value.");
	/*由于scanf连续从流中读入字符(换行也是一个字符),而不是以单位内容进行解释。
	当输入"123\n"时候,scanf读取"123",而后面的getchar读取"\n"
	而fgets和sscanf组合使用可以避免这个问题
	*/
	fgets(buf,sizeof(buf),stdin);
	sscanf(buf,"%d",&hoge);

	for(;;)
	{
		printf("hoge...%d",hoge);
		getchar();  //等待回车
		hoge++;
	}
	return 0;
}

 让程序在两个窗口运行,发现打印的hoge地址相同,但是,他们数据并没有发生任何影响。

 

2、

C语言的变量有区间性的作用域。这种作用域有三种:全局变量(在函数之外声明的变量,在任何地方可见,用extern连接)、文件内部的静态变量(在函数之外声明的static变量,只在本文件中有效)、局部变量(函数内声明的变量)。

C语言的变量还有存储期的差别。静态存储期(全局变量、文件内部的静态变量、局部static变量的寿命从程序开始运行到结束都一直存在)、自动存储期(非static局部变量,用“栈“的机制来实现)。还有动态分配内存malloc,直到free为止。

  

现在输出各类指针的地址:

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

int			global_var;
static int		file_static_var;

void fun1()
{
	int	f1_var;
	static int f1_static_var;
	printf("&f1_var...%p\n",&f1_var);
	printf("&f1_static_var...%p\n",&f1_static_var);
} 

void fun2()
{
	int	f2_var;
	static int f2_static_var;
	printf("&f2_var...%p\n",&f2_var);
	printf("&f2_static_var...%p\n",&f2_static_var);
}

int main()
{
	printf("fun1...%p\n",fun1);  //指向函数的指针
	printf("fun2...%p\n",fun2);
	printf("string...%p\n","abc");  //指向字符串常量的指针
	printf("&global_var...%p\n",&global_var);  //指向字符串常量的指针
	printf("&file_static_var...%p\n",&file_static_var);  //指向字符串常量的指针

	fun1();
	fun2();

	int *p=(int *)malloc(sizeof(int));
	printf("&p...%p\n",p);  //指向字符串常量的指针
	free(p);

	return 0;
}

 测试可以知道:

静态变量(全局变量、文件内static变量、函数内static变量)的地址很近。

函数指针、字符串常量的地址相对较近。

而自动变量f1_var和f2_var的地址一样,且离其他变量很远。

 

函数指针一般用于:1、GUI作为监听时候调用;2、用函数指针数组对行为进行分类处理。

 

函数自身的指针和字符串分配到“只读内存区域”。由于函数本身不可能修改、字符串常量不允许修改,所以它们放在只读内存区域。

 

静态变量从程序启动一直在内存中,也就是它们占有固定的区域。

 

自动变量存储在栈中,一旦函数结束运行,相应的自动变量的内存区域就会释放。

函数调用的过程如下:

  • 1、调用函数时,参数从后往前按顺序压栈。
  • 2、与函数相关的返回信息返回地址压栈。
  • 3、跳到被调用函数的地址。
  • 4、函数的自动变量压栈。
  • 5、计算,可能有时候会有值放到栈中。
  • 6、函数结束后,自动变量内存释放,使用返回信息返回原来的地址。
  • 7、栈中移除调用方的参数。

 malloc分配指定尺寸大小的内存块,返回内存块的首地址,如果分配失败(内存不足),返回NULL。这块内存需要用free来释放。像这种可以用任意顺序来释放的内存区域称为“堆”。

free需要注意的问题:调用free之后是不能引用对应的内存区域;但是,这块区域并不会马上被破坏掉。例如下面中pa释放掉了 ,但是pb还在用他。

int *pa;
pa=(int *)malloc(sizeof(int));
*pa=1234;
int *pb=pa;
free(pa);
pa=NULL;
printf("%d",*pb);

 在大型程序中,可以做一个函数给free披一张皮,并且程序猿只能调用这个函数,在释放区域之前故意将区域破坏(可以胡乱的用一个像0xcc这样的值填充)。

 

3、大小端

小端模式:数据低位位于低字节中,数据高位位于高字节中;数据地址是低字节地址。

 

int a=0x12345678;
unsigned char *pa=(unsigned char *)&a;

printf("%x  %p\n",pa[0],&pa[0]); //16进制整数输出第一个字节的值
printf("%x  %p\n",pa[1],&pa[1]); //16进制整数输出第一个字节的值
printf("%x  %p\n",pa[2],&pa[2]); //16进制整数输出第一个字节的值
printf("%x  %p\n",pa[3],&pa[3]); //16进制整数输出第一个字节的值

 测试结果为:

     78  0012FF60

     56  0012FF61

     34  0012FF62

     12  0012FF63

小端模式的数据存储如下:

                

 

4、字节对齐
 

  • 大小: 6.4 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics