Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1863872
  • 博文数量: 343
  • 博客积分: 10342
  • 博客等级: 上将
  • 技术积分: 2892
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-15 12:34
个人简介

你必须非常努力,才能看起来毫不费力!

文章存档

2012年(3)

2011年(5)

2010年(2)

2009年(40)

2008年(293)

分类:

2008-10-06 12:36:00

从指针的使用角度看数组与结构体
数组与结构体有什么区别和联系?如果要找到他们的本质联系我们通过什么途径?下面分别通过多维数组和结构体的几个实例来分析两者之间的关系.
(一) 一维数组与结构体
1.       定义一个一维数组:
main()
{
    int IntValue;//暂时存放从数组中取出来的值
       int a[3]={1,2,3};
       int *p;
       p=a;
       IntValue =*(p+2);
}
 
对于数组a,系统在内存中开辟了3*4字节的连续空间来存放.
对于一维数组的访问一般通过下标.
如:a[0]=1;a[2]=3
不过为与后面的结构体建立联系我们通过指针来访问,
我们知道,对于一维数组来说,数组名就是这个数组的首部地址,他指向某种数据类型对应大小的内存块.如:int a[3],则地址a指向一个字节数为4的内存块.显然对其进行单位量移动表示每移动一个单位量代表了移动4字节.用指针访问则:
int *p;
p=a;
则:*p=0(等价于a[0]);*(p+2)=3(等价于a[2]);
内存中结构如下:
├──────┤← p
│       a[0]   │
├─┄┄┄┄─┤← p+1
│       a[1]   │
├─┄┄┄┄─┤← p+2
│a[2]          │
├─┄┄┄┄─┤
反汇编如下:
5:        int IntValue;
6:        int a[3]={1,2,3};
0040E9C8   mov         dword ptr [ebp-10h],1//注【1
0040E9CF   mov         dword ptr [ebp-0Ch],2
0040E9D6   mov         dword ptr [ebp-8],3
7:        int *p;
8:        p=a;
0040E9DD   lea         eax,[ebp-10h]
0040E9E0   mov         dword ptr [ebp-14h],eax
9:        IntValue =*(p+2);
0040E9E3   mov         ecx,dword ptr [ebp-14h] //注【2
0040E9E6   mov         edx,dword ptr [ecx+8]
0040E9E9   mov         dword ptr [ebp-4],edx
 
2.       定义一个结构体
main()
{
    int IntValue;
       struct student
       {
             
              int num;
              char sex;
              int score;
             
             
       };
       struct student jesse={2316124029,'M',98};
 
    struct student *p;
       p=&jesse;
    IntValue=*((int *)p+2);//说明2
}
 
这个结构体定义了3个成员变量,字节数分别为4,1,4,和数组一样,他们在内存中也占据一组连续的存储空间,但是要注意的是这里他们一共占据的空间并不是4+1+4=9,这里涉及到”对齐原则”,编译器为提供内存访问速度,要保证结构地址满足4字节的对齐要求,所以系统用了4个字节来存放char类型,也即浪费了3个字节的空间,因此,这里总共占据空间为12字节.
同样,对结构体的访问一般为:
jesse.num=2316124029或jesse.sex=M.
同样我们也可以定义个指针来对起成员变量进行访问
struct student *p;
p=&jesse;//将结构体的首部地址赋给指针变量p
则: *((int *)p)=2316124029 (等价于jesse.num); *((int *)p+2)=98(等价于jesse.score)
内存中结构如下:
├──────┤← p
│num          │
├─┄┄┄┄─┤← p+1
│sex           │
├─┄┄┄┄─┤← p+2
│score        │
├─┄┄┄┄─┤
反汇编:
 
5:        int IntValue;
6:        struct student
7:        {
8:
9:            int num;
10:           char sex;
11:           int score;
12:
13:
14:       };
15:       struct student jesse={2316124029,'M',98};
0040E9C8   mov         dword ptr [ebp-10h],8A0D3F7Dh//注【3
0040E9CF   mov         byte ptr [ebp-0Ch],4Dh
0040E9D3   mov         dword ptr [ebp-8],62h
16:
17:       struct student *p;
18:       p=&jesse;
0040E9DA   lea         eax,[ebp-10h]
0040E9DD   mov         dword ptr [ebp-14h],eax
19:       IntValue=*((int *)p+2);
0040E9E0   mov         ecx,dword ptr [ebp-14h] //注【4
0040E9E3   mov         edx,dword ptr [ecx+8]
0040E9E6   mov         dword ptr [ebp-4],edx
注【1注【3分别对应系统给数组、结构体分配内存的反汇编代码,可见,除了赋给寄存器具体的值不一样外,两中数据类型在内存中的分配结构是一模一样的.再看看注【2注【4他们分别对应的是访问两种数据结构的反汇编代码,令人惊喜的是,他们也是一样的,由此说明,虽然他们是不同的数据类型,但是在内存中结构是没有任何区别的.
说明:1.事例中我们定义的数组和结构体的大小有一定的特殊性,这是为了便于我们理解两这之间的关联,这并不防碍对其他结构的理解.
说明2. IntValue=*((int *)p+2);是将结构体的首部地址强制转换为int类型,这样就能通过对指针的加减对结构体中的成员进行访问了,具体原理请参见我以前写的<学会用指针—指针的强制转化>.
那么对于多维数组和结构体又有什么联系?
(二)多维数组和结构体数组
1.       定义一个多维数组
main()
{
   
    int IntValue_1,IntValue_2;
    int x[4][3]={{1,2,3},{5,6,7},{9,10,11},{13,14,15}};
       int (*p)[3];
       p=x;
       IntValue_1=*((int *)p);
    IntValue_2=*((int *)(p+2)+2);
      
}
 
.我们可以这样来理解多维数组:一个为int x[4]的一维数组每个成员分别又内嵌了3个int类型的子成员.但是与一维数组相比较它在内存中的结构没有什么太大的区别,仍然开辟了12*4字节的连续空间来存放.
对于多维数组的访问一般通过下标.
如:a[0][0]=1;a[2][2]=11
我们还是用指针访问成员:
int (*p)[3]; //表示P是一个指向4个int类型的一维数组,这里的p就是这个一维数组的首部地址,见图中兰色部分.
p=x;
则: *((int *)p)=1(等价于a[0][0]=1); *((int *)(p+2)+2)=11(d等价于a[2][2]=11)
内存结构如下:
├──────┤← p
│a[0][0]      
─┄┄┄┄─
a[0][1]     
─┄┄┄┄─
a[0][2]     
├──────┤← p+1
│a[1][0]      │
├─┄┄┄┄─┤
│a[1][1]      │
├─┄┄┄┄─┤
│a[1][2]      │
├──────┤← p+2
│a[2][0]      │
├─┄┄┄┄─┤
│a[2][1]      │
├─┄┄┄┄─┤
│a[2][2]      │   *((int *)(p+2)+2)
├──────┤← p+3
│a[3][0]      │
├─┄┄┄┄─┤
│a[3][1]      │
├─┄┄┄┄─┤
│a[3][2]      │
├──────┤
 
 
 
 
 
反汇编代码如下:
 
6:        int IntValue_1,IntValue_2;
7:        int x[4][3]={{1,2,3},{5,6,7},{9,10,11},{13,14,15}};
0040E9C8   mov         dword ptr [ebp-38h],1
0040E9CF   mov         dword ptr [ebp-34h],2
0040E9D6   mov         dword ptr [ebp-30h],3
0040E9DD   mov         dword ptr [ebp-2Ch],5
0040E9E4   mov         dword ptr [ebp-28h],6
0040E9EB   mov         dword ptr [ebp-24h],7
0040E9F2   mov         dword ptr [ebp-20h],9
0040E9F9   mov         dword ptr [ebp-1Ch],0Ah
0040EA00   mov         dword ptr [ebp-18h],0Bh
0040EA07   mov         dword ptr [ebp-14h],0Dh
0040EA0E   mov         dword ptr [ebp-10h],0Eh
0040EA15   mov         dword ptr [ebp-0Ch],0Fh
8:        int (*p)[3];
9:        p=x;
10:       IntValue_1=*((int *)p);
0040EA1C   lea         eax,[ebp-38h]
0040EA1F   mov         dword ptr [ebp-3Ch],eax
11:       IntValue_2=*((int *)(p+2)+2);
0040EA22   mov         ecx,dword ptr [ebp-3Ch]
0040EA25   mov         edx,dword ptr [ecx]
0040EA27   mov         dword ptr [ebp-4],edx
12:
0040EA2A   mov         eax,dword ptr [ebp-3Ch]
0040EA2D   mov         ecx,dword ptr [eax+20h]
0040EA30   mov         dword ptr [ebp-8],ecx
 
2.定义一个结构体数组
main()
{
    int IntValue_1,IntValue_2;
       struct student
       {
             
              int num;
              char sex;
              int score;
       };
    struct student stu_1[4]={{00001,'m',506},{00002,'M',125},{00003,'F',405},{00004,'D',758}};
       struct student *p;
       p=stu_1;
    IntValue_1=*((int *)p);
       IntValue_2=*((int *)(p+2)+2);
 
}
内存结构如下:
├──────┤← p
│00001      
─┄┄┄┄─
 m           
─┄┄┄┄─
 506         
├──────┤← p+1
│ 00002      │
├─┄┄┄┄─┤
│ M             │
├─┄┄┄┄─┤
│ 125          │
├──────┤← p+2
│00003       │
├─┄┄┄┄─┤
│ F             │
├─┄┄┄┄─┤
│ 405          │   *((int *)(p+2)+2)
├──────┤← p+3
│00004        │
├─┄┄┄┄─┤
│ D            │
├─┄┄┄┄─┤
│ 758         │
├──────┤
反汇编
5:        int IntValue_1,IntValue_2;
6:        struct student
7:        {
8:
9:            int num;
10:           char sex;
11:           int score;
12:       };
13:       struct student stu_1[4]={{12345,'m',506},{22222,'M',125},{333333,'F',5063333},{44444,'D',5064444}};
0040E9C8   mov         dword ptr [ebp-38h],3039h
0040E9CF   mov         byte ptr [ebp-34h],6Dh
0040E9D3   mov         dword ptr [ebp-30h],1FAh
0040E9DA   mov         dword ptr [ebp-2Ch],56CEh
0040E9E1   mov         byte ptr [ebp-28h],4Dh
0040E9E5   mov         dword ptr [ebp-24h],7Dh
0040E9EC   mov         dword ptr [ebp-20h],51615h
0040E9F3   mov         byte ptr [ebp-1Ch],46h
0040E9F7   mov         dword ptr [ebp-18h],4D42A5h
0040E9FE   mov         dword ptr [ebp-14h],0AD9Ch
0040EA05   mov         byte ptr [ebp-10h],44h
0040EA09   mov         dword ptr [ebp-0Ch],4D46FCh
14:       struct student *p;
15:       p=stu_1;
0040EA10   lea         eax,[ebp-38h]
0040EA13   mov         dword ptr [ebp-3Ch],eax
16:       IntValue_1=*((int *)p);
0040EA16   mov         ecx,dword ptr [ebp-3Ch]
0040EA19   mov         edx,dword ptr [ecx]
0040EA1B   mov         dword ptr [ebp-4],edx
17:       IntValue_2=*((int *)(p+2)+2);
0040EA1E   mov         eax,dword ptr [ebp-3Ch]
0040EA21   mov         ecx,dword ptr [eax+20h]
0040EA24   mov         dword ptr [ebp-8],ecx
 
我们可以看到,多维数组与结构体数组在内存中分配结构还是一样的.
 
结语
首先,通过上面的事例看出数组和结构体其实在内存级根本就没有什么本质的区别,而且访问也可以归结为同一种方式----指针.我想同一种语言给我们提供了不同的数据类型以及一些规则来使用,就象你可以方便的使用数组来对同一中数据结构进行操作,而结构体又满足了你对不同数据操作的要求,但是归根到底,在计算机底层他们的操作方式都是一样,计算机本身只是给我们提供了硬件平台,如内存,至于怎么使用,你要用怎样的规则来使用这就要看高级语言给你提供了怎样的机制了.在这里我们可以大胆设想结构体和类又会是怎样的联系呢?
谈到这我想起了在学校大家最爱谈论的事----“某某语言现在很热,快去学了说这话的时候,C语言都还没弄清醒,结果大学4年就这样奔命式的度过了.准确的说是我们在语言规则上兜了一个不大不小的圈子.
 
阅读(1845) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~