700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > C语言中结构化数据(变量 指针 数组 字符串 结构体和联合)的内存表示

C语言中结构化数据(变量 指针 数组 字符串 结构体和联合)的内存表示

时间:2019-09-29 09:33:47

相关推荐

C语言中结构化数据(变量 指针 数组 字符串 结构体和联合)的内存表示

目录

结构化数据表示一、内存地址:二、全局变量和局部变量的内存布局三、数据在内存中的表示四、数组在内存中的表示五、字符串在内存中的表示六、结构和联合在内存中的表示

结构化数据表示

一、内存地址:

所有数据都存储在内存中

内存是一个有编号的字节序列,以0x开始。那个编号计算内存的地址。

通常来说,经过编译后变量名和变量类型都不见了,取而代之的是内存地址。

二、全局变量和局部变量的内存布局

通过一个例子,观察它们的内存地址

#include<stdio.h>/*全局未初始化变量*/int global_int1;int global_int2;/*全局初始化变量*/int global_int3=1;int global_int4=1;int main(){/*局部未初始化变量*/int local_int1;int local_int2;/*局部初始化变量*/int local_int3=1;int local_int4=1;printf("全局变量的值:%d %d %d %d\n",global_int1,global_int2,global_int3,global_int4);printf("局部变量的值:%d %d %d %d\n",local_int1,local_int2,local_int3,local_int4);printf("初始化的全局变量地址:%#x %#x\n",&global_int3,&global_int4);printf("未初始化的全局变量地址:%#x %#x\n",&global_int1,&global_int2);printf("局部变量地址:%#x %#x %#x %#x\n",&local_int1,&local_int2,&local_int3,&local_int4);}

运行结果

全局变量的值:0 0 1 1局部变量的值:35 8 1 1初始化的全局变量地址:0x402000 0x40未初始化的全局变量地址:0x40506c 0x405068局部变量地址:0x61fefc 0x61fef8 0x61fef4 0x61fef0

观察运行结果中的值,我们发现:

未初始化的全局变量似乎以某种方式初始化为0,但对于局部变量,并没有进行初始化。

接下来我们观察地址的值,发现:

对于局部变量:

所有的局部变量是连续分配的,聚集在一起

变量往低地址方向增长。

对于全局变量:

初始化的那些变量在一个集群中,未初始化的在另外一个集群中。

未初始化的变量往低地址方向增长,初始化的变量往高地址方向增长。

解释:一次增长4,是因为int类型占4个字节大小。

三、数据在内存中的表示

首先我们需要认识到一点,指针是什么?

指针存储的便是内存地址,这也是c语言的灵活之处。关于指针的详细讲解,可以查看C语言之指针

接着我们来思考一个问题,我们可以用一个char类型来读int型数据吗?

答案是可以的,因为它们在硬件中都用原始位表示。

这和数据在内存中的存储有关,我们来看到一个例子:

#include<stdio.h>int main(){int i=0x8041;char *p;p=(char*)&i;printf("%#x\n",*p);}

它的结果会是什么呢?

//运行结果0x41

怎么回事呢?

变量i在内存中如下所示:

而char字符型只占一个字节,所以只读取到了41;

测试一下,如果将值变成0x12345678;

#include<stdio.h>int main(){int i=0x12345678;char *p;p=(char*)&i;printf("%#x\n",*p);}

运行结果为

0x78

编码

它指定了值到位的映射,也就是哪个位序列表示哪个整数,哪个位序列表示哪个字符

它指定了特定类型需要多少位,比如说int整型,4个字节,需要32位

取决于计算机和我们使用的编码

编译器负责完成这项工作,并为我们处理这些细节。

四、数组在内存中的表示

数组定义

统一类型的元素序列

内存分配

在内存中按递增顺序排列数组元素

#include<stdio.h>int main(){int a=0;int intArray[5]={1,2,3,4,5};int b=6;}

内存表示:

指针VS数组

intArray+N=&(intArray[N])

intArray[N]=*(intArray+N)

多字节类型数组

看一个例子:

#include<stdio.h>int main(){int intArray[10]={1,2,3,4,5,6,7,8,9,10};int *p=(int*)((char*)intArray+7);printf("%#x\n",*p);}

运行结果:

0x300

怎么回事呢?

有空再来写二维数组

五、字符串在内存中的表示

在c中,没有字符串类型

字符串是由字符’\0’(也称为空字符)结尾的字符数组

常见的标准的字符串库如char *strcat(char *dest,char *src),函数中传入的是字符串数组首地址,那么为什么不用传入数组长度呢?个人理解,这就是字符串是由字符’\0’(也称为空字符)结尾的原因之一,可以用以遍历。

例子:

#include<stdio.h>int main(){int i;char a[4]="hi?";char b[3]="hi?";//错误写法,很危险for(i=0;i<4;i++){printf("%#x:%c(%d)\n",&a[i],a[i],a[i]);}printf("\n");for(i=0;i<3;i++){printf("%#x:%c\n",&b[i],b[i]);}puts(b);}

运行结果

0x61fef8:h(104)0x61fef9:i(105)0x61fefa:?(63)0x61fefb: (0)0x61fef5:h0x61fef6:i0x61fef7:?hi?hi?

怎么回事呢?

六、结构和联合在内存中的表示

聚合数据类型能够同时存储超过一个的单独数据。C提供了两种类型的聚合数据类型,数组和结构。

数组是相同类型的元素集合,它的每个元素是通过下标引用或指针间接访问来选择的。

结构也是一些值的集合,这些值被称为它的成员,但一个结构的各个成员可能具有不同的类型。

数组元素下标可以通过下标访问是因为数组元素的长度相同。

但是,在结构体中情况并非如此。由于一个结构的成员长度不同,所以不能使用下标来访问它们,相反每个结构成员都有自己的名字,它们是通过名字访问的。

在讨论结构的内存之前,我们先来看到结构的声明:

例子一:这个声明创建了一个名叫x的变量,它包含三个成员:一个整数、一个字符和一个浮点数。

struct{int a;char b;float c;}x;

例子二:这个声明创建了y和z。y是一个数组,它包含了20个结构。z是一个指针,它指向这个类型的结构。

struct{int a;char b;float c;}y[20],*z;

这两个结构的的成员变量一样,它们是同一种类型吗?

答案是否,这两个声明被编译器当作两种截然不同的类型。也就是说z=&x是非法的。

那么问题来了,如果我想在后续继续使用之前声明过的类型,是不是必须在一个单独的声明中创建呢?

答案是否的,可以使用标签。标签允许多个声明使用同一个成员列表。如下所示:

struct SIMPLE{int a;char b;float c;};struct SIMPLE x;struct SIMPLE y[20],*z;z=&x;//这时候是合法的;

不过声明结构的一个更良好的习惯是使用typedef创建一种新类型,如下所示:

typedef struct{int a;char b;float c;}SIMPLE;//此时SIMPLE是个类型名而不是结构标签SIMPLE x;SIMPLE y[20],*z;

进入正题:我们来看看结构体在内存中的实际存储

先来看到一个例子

#include<stdio.h>int main(){typedef struct {char a;char b;int c;double d;}test;test x;printf("%#x\n%#x\n%#x\n%#x\n",&x.a,&x.b,&x.c,&x.d);printf("%d",sizeof(x));}

运行结果:

0x61fef00x61fef10x61fef40x61fef816

为什么会是这样呢?那就需要搞清楚结构中内存存储的对齐规则:

1.编译器按照成员列表的顺序一个接一个地为每个成员分配空间

2.结构体的对齐与其元素的最大对齐相同

3.一个结构体的大小是其对齐方式的倍数

4.K字节大小的数据必须要存储在K的整数倍的地址上

改变一下这个例子:

#include<stdio.h>int main(){typedef struct {char a;char b[4];int c;double d;}test;test x;printf("%#x\n%#x\n%#x\n%#x\n",&x.a,&x.b,&x.c,&x.d);printf("%d",sizeof(x));}

0x62fe000x62fe010x62fe080x62fe1024

那么为什么要这样对齐呢?不会浪费了空间吗?

和CPU处理内存的方式有关,这样可以提高系统的性能,加快访问数据的速度。

那么联合是什么?

和结构体不同,联合中的各个成员共享一块内存,使用时只会选择其中的一个。

结构体的在内存中的存储

所占的空间取决于联合中的最大元素

看一个例子

#include<stdio.h>int main(){typedef union{char a;char b[4];int c;double d;}test;test x;printf("%#x\n%#x\n%#x\n%#x\n",&x.a,&x.b,&x.c,&x.d);printf("%d",sizeof(x));}

运行结构:

0x61fef80x61fef80x61fef80x61fef88

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。