深入理解C语言变量和内存

相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

深入理解C语言变量和内存

1、基本数据类型变量名和内存的关系:

int i;

scanf_s("%d", &i);

int i;,在这一句就为i分配了内存(但尚未对这块内存进行初始化),所以可以通过&i直接使用这块内存。赋值就更不用说啦,i = 3;。

变量名i,是为方便编程人员使用,是这块内存的别名,指代到块内存,对编程人员i代表这块内存中存储的值(实际上是i指到这个内存,然后取值)。通常我们都是通过变量名来使用已知的内存的。

i代表取(这块内存中存储的)值,而&i代表取(这块内存的)址。程序本身是不为i这个变量名分配空间的。在最终的机器代码中,是不会出现变量名的,这一点在分析反汇编语言时可以看出(命令:dumpbin /disasm xx.obj >xx_disasm.asm 可以查看反汇编语言)。那么编译器是如何处理变量名的呢,变量名会存储在符号表中,并将符号表中的索引对应到实际物理空间(地址)上去,当调用这个变量时,查找符号表就可以找到对应的地址并取值了。

2、不同类型变量的变量名和内存间的关系:

上面分析的是基本数据类型(如int、char等)的变量名。C中除了变量名之外,还有函数名、常量名、指针名、数组名、结构名等。和变量名不同,这些标识符都是直接对应着地址的。基本数据类型的变量,和地址的对应关系需要取址符&才能得到地址,而其余的这些,名字本身就对应着地址。

例如char *pc = “se”;,就是将字符串常量”se”的首地址(位于常量存储区)赋值给了字符指针pc。这也就解释了为什么不需要为pc分配地址就可以为其赋值,而不会遇到类似下面代码所带来的野指针问题:

int *pi;

*pi = 1;

int *pi句,是为pi分配空间,而不是开辟pi所指向的空间。

2.1 C语言中的常量:

C对常量是怎么处理的呢?比如上面的i = 3;中的常量3,存储常量3的地址并不是随机分配的,是在程序中的数据段中(.data?这个我也还不是很确定,希望知道的前辈们给个指导),也就是程序本身并不为3分配内存,而是直接写入指令。3是数字常量,对于字符常量和字符串常量,又分别是怎么处理的呢?

字符常量和数字常量是一样的处理方式,都是类似汇编中的立即数,直接写入指令;

而字符串常量,则是存储在常量存储区,可以使用&(“string”)取得具体地址。也就是字符串常量名字本身指代着地址,只是不能直接操作(和int i中的i相同)。

2.2 C语言的变量名

c中的数据类型除常量之外大致有5种:

基本数据类型:short、int、float、double、char:

对各基本数据类型的变量名及其声明时的处理方式都是一样的,声明时即分配内存,并使用变量名直接操作这段内存;使用取地址符号&取得地址的数字表示,至于声明时要不要做初始化,要看是不是全局变量或者 static变量了。

这类变量名指向一个地址空间,但不能直接当做地址使用,而是通过取址符&操作其地址。

2.3 构造数据类型:数组、结构、联合:

1) 数组

数组在声明时,即分配了空间:

int a[5];

一旦声明a[5],相当于有a、a[0]、a[1]、a[2]、a[3]、a[4]这6个变量名。a[i]的指代方式和普通的变量名int i相同,指到一个对应的内存空间;关键是变量名a,本身就可以做地址用。我们知道a是数组名,但a并不代表整个数组的地址,而是指向数组首元素的地址(虽然在数值上是相同的,下面会有详细解释),所以可以有 int *p = a;。那么&a又怎么解释呢?对于int i而言,i代表一个空间,&i表示i所代表的空间地址;那么&a应该也是表示a所代表的地址了,也就是整个数组的地址。

a、&a和&a[0]同代表地址,且由于数组是顺序存储,所以a、&a和&a[0]所表示的地址在数据上是相同的,但是实际的指代意义却是不同的:

a是个int*类型的数据,相当于&(*a),是指向数组首元素的地址;

&a指代整个数组,是个int(*)[]类型的数据,是指针数组的地址;

&a[0]则是仅指代一个存储int的空间,是int*类型的数据。

也就是数组名,本身可以作为地址使用,指代该结构的首元素的地址。

2) 结构

结构在声明的时候,就分配了空间。结构体和数组不同,结构体类型的变量名并不能直接当作地址使用,这一点和基本数据类型相同。需要对结构体名使用取址符&才能进行地址操作,并且取址所得到地址代表的是指向结构体的指针,只是

在数据上和结构体中的首元素地址相同。

对于结构体中的各个元素,其名称的指代关系和其数据类型相同,并不因为是结构体的元素而受到影响。具体见下面代码:

struct stu{

int age;

char sex;

char* name;

int score[5];

};

int main()

{

int i;

struct stu st1; //st1是结构体stu类型

printf("%d\n", &st1); //&st1是 stu*类型

printf("%d\n", &st1.age); //&st1.age是 int*类型,st1.age 就是个int型,名字指向地址,但不能直接作地址

printf("%d\n", &st1.sex); //&st1.sex是 char*类型,名字解析同上

printf("%d\n", &); //&是char**类型,是char*类型

printf("%d\n", st1.score); // st1.score是个数组类型,名字代表数组中首元素的地址

return 0;

}

3) 联合

联合是特殊的结构体,为节省空间,在其各元素依次存储,各元素的首地址均相对变量的基地址偏移为0,具体各变量名的分析和结构体同。

2.4 指针类型

声明一个指针类型 int *p;,则是为存储指针p分配空间,而并不会为p所指向的内存做任何动作,这就是野指针的原因。如下代码,p就是一个未指向任何已知内存的指针,为*p赋值,自然会出现错误:

int *p;

*p = 1;

相关文档
最新文档