邪恶八进制信息安全团队技术讨论组's Archiver

冰血封情 2004-7-7 13:09

[转载]C语言学习简易教程之数组专题

信息来源:邪恶八进制
文章作者:无锋之刃(E.S.T顾问团成员)

越是简单的规律,越是难于发现。比如数组与地址的关系。
  
  举个例子,有如下一个数组:
  int a[10][10];
  如果想得到数组a的首地址,我们可以使用这样的语句:
  printf("a:\t%p\n", a);   // 1
  这样,在显示屏上就可以输出该数组的十六进制首地址了。一般而言,这个首地址是位于栈上的。
  
  事实上,数组名a只是一个别名,它代表了一个地址常量。打印a的值,实际输出的就是它代表的地址值。通常在使用a的时候,我们可以把它当作数组来看待,使用下标运算符[]来寻址其中的元素;也可以把它当作地址来看待,使用取值运算符*来寻址其中的元素。比如:
  a[0][0] 等价于 *(*a)
  
  然而,要得到数组的首地址,方法有很多,并不限于打印数组名对应的地址值。还可以使用如下语句来输出数组首地址:
  printf("&a[0][0]:\t%p\n", &a[0][0]); // 2
  这个办法学过C的人都应该知道,因为数组中第一个元素总是分配在数组的最前头,因为它的首地址也必然与数组的首地址相同。但是,要注意的是,这两个地址只是值相同,而它们的数据类型并不相同!!!!
  让我们换一种输出方式,就可以让它们数据类型的不同显现出来。方法如下:
  printf("a+1:\t%p\n", a+1);   // 3
  printf("&a[0][0]:\t%p\n", &a[0][0]+1); // 4
  通过观察打印值,可以发现a+1的地址值比a的地址值多出了40个字节,而&a[0][0]+1却只比&a[0][0]多了4个字节。也就是说,a+1一下子跳过了10个整型元素(每个元素占4字节),而&a[0][0]+1只跳过了1个整型元素。
  嘿嘿,发现了吗?虽然首地址相同,可是首地址的数据类型,却并不相同。
  
  a的地址的数据类型,是int (*)[10]。它指向拥有10个元素的一维数组,其中每一个元素的数据类型又是拥有10个元素的一维数组。我们知道,a[0]与a[1]的不同,其实就是跳过了一个元素。而a[0]与*a实际是等价的(在实际使用数组时,通常会退化为对其地址--类似一个指针--进行操作),a[1]与*(a+1)也是等价的。因此,对a+1而言,应该跳过一个元素,即实际输出a+1对应的地址值时,应该跳过40个字节(最后一维数组中的元素个数*每个元素大小)。
  而a[0][0]的数据类型是int,对应地,&a[0][0]的数据类型是int *。按上面说过的,&a[0][0]+1实际上就只跳过了一个整型值占用的字节数,即4字节。

  所以咯,下面的东东就不说作很详细的说明了,我只给出它们对应的数据类型,大家不理解的话就多从它们的数据类型下手去思考吧。

#include <iostream>
#include <stdlib.h>

using namespace std;

int main(int argc, char *argv[])
{
  int a[10][10];
  
  printf("a:\t%p\n", a);       // int (*)[10]  或者是 int [][10]
  printf("a+1:\t%p\n", a+1);    // int (*)[10]
  printf("&a:\t%p\n", &a);      // int (*)[10][10] 或者是 int [][10][10]
  printf("&a+1:\t%p\n\n", &a+1);  // int (*)[10][10]

//  printf("&&a:\t%p\n", &&a);  // 不可能
//  printf("&&a+1:\t%p\n\n", &&a+1);  // 不可能

  printf("a[0]:\t%p\n", a[0]);       // int *  或者是 int []
  printf("a[0]+1:\t%p\n", a[0]+1);    // int *
  printf("&a[0]:\t%p\n", &a[0]);      // int (*)[10]  或者是 int [][10]
  printf("&a[0]+1:\t%p\n\n", &a[0]+1);  // int (*)[10]

  printf("&a[0][0]:\t%p\n", &a[0][0]);      // int *  或者是 int []
  printf("&a[0][0]+1:\t%p\n\n", &a[0][0]+1);  // int *
  
  system("PAUSE");     
  return 0;
}

  仔细观察,呵呵,有规律可循的。
  如果还有什么问题,或者是有什么错误,大家都可以提出咯。

页: [1]
© 1999-2008 EvilOctal Security Team