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、字节对齐