您的位置:首页 > 编程语言

C专家编程——第四章:数组与指针并不相同

2010-03-23 13:25 253 查看
1. 数组并非指针
       注意以下声明的区别:
      extern int *x;          //声明 x 是个int型的指针;
       extern int y[];         //声明 y 是个int型数组,长度尚未确定,其存储在别处定义。
错误示例:
       文件1:
       int mango[100];
       文件2:
       extern int *mango;                           //正确形式: extern int mango[];
        …………
       /*一些引用mango[ i ]的代码*/
补充:
      C语言中的对象必须有且只有一个定义,但它可以有多个extern声明。
      定义:只能出现在一个地方; 确定对象的类型并分配内存,用于创建新的对象。如:int my_array[100];
      声明:可以多次出现; 描述对象的类型,用于指代其他地方定义的对象。如:extern int my_array[];
      由于extern对象声明告诉编译器对象的类型和名字,对象的内存分配则在别处进行。由于并未在声明中位数组分配内存,所以并不需要提供关于数组长度的信息。对于多维数组,需要提供最左边一维最外的其他维德长度。所以,extern int my_array[] 与 extern int my_array[100]等价。
2. 指针和数组是如何访问的
       首先要区分“地址y” 和“地址y的内容”之间的区别,如 x = y;
       在这个上下文环境里,符号 x 的含义是 x 所代表的地址。被称为左值。左值在编译时可知,左值表示存储结果的地方。
       符号 y 的含义是 y 所代表的地址的内容。这被称为右值。右值直到运行时才知。如无特别说明,右值表示“y的内容”。
  :C语言引入了“可修改的左值”这个术语。它表示左值允许出现这赋值语句的左边。这个奇怪的术语是为了和数组名区分,驻足名也用于确定对象在内存中的位置,也是左值,但它不能作为赋值的对象。因此,数组名是个左值但不是可修改的左值。 标准规定赋值符必须用可修改的左值作为它左边一侧的操作数。用通俗的话讲:只能给可以修改的东西赋值。
       编译器为每个变量分配一个地址(左值),这个地址在编译时可知,而且该变量在运行时一直保存于这个地址。相反,存储于变量中的值(它的右值)只有在运行时才可知。如果需要用到变量中存储的值,编译器就发出指令从指定地址读入变量值并将它存于寄存器中。
       这里的关键之处在于:每个符号的地址在编译时可知。所以,如果编译器需要一个地址(可能还需要加上偏移量)来执行某种操作,它就可以直接进行操作,并不需要增加指令首先取得具体的地址。相反,对于指针,必须首先在运行时取得它的当前值,然后才能对它进行解除引用操作(作为以后进行查找的步骤之一)。下图展示了对数组下标的引用。



      上图同时也说明为什么extern  char  a[]与extern  char  a[100]等价。这两个声明都指明 a 是一个数组,也就是一个内存地址。编译器并不知道数组有多长,因为它只产生偏离其实地址的偏移地址。从数组提取一个字符,只要简单地从符号表显示的 a 的地址加上下标,需要的字符就位于这个地址中。
      相反,如果声明 extern char *p,它告诉编译器 p 是一个指针(在许多现代的机器里它是四字节的对象),它指向的对象是一个字符。为了取得这个字符,必须得到地址 p 的内容,把它作为字符的地址并从这个地址中取得这个字符。指针的访问要灵活的多,但需要增加一次额外的提取,如下图所示。



 
3. 当你“定义为指针,但以数组方式引用”时会发生什么
       当一个外部数组的实际定义是一个指针,但却以数组方式引用时,会引起什么问题。(本来针对数组)需要对内存进行直接的引用(如第一个图所示),但是这时编译器所执行的确是对内存进行间接引用(如上图)。之所以会这样,是因为我们告诉编译器我们拥有的是一个指针,如下图所示。



4. 数组和指针的其他区别
       数组和指针都可以在他们的定义中用字符串常量进行初始化。尽管看上去一样,底层的机制却不相同。
       定义指针时,编译器并不为指针所指向的对象分配空间,它只是分配指针本身的空间,除非在定义时同时赋给指针一个字符串常量进行初始化。例如,下面的定义创建了一个字符串常量(为其分配了内存):
      char  *p = “breadfruit”;
       注意:只有对字符串常量才是如此。不能指望为浮点数之类的常量分配空间,如:
       float *pip = 3.14;            //错误!无法通过编译
       注:在ANSI C中,初始化指针所创建的字符串常量被定义为只读。如果试图通过指针修改这个字符串常量,程序会出现未定义的行为。
      与指针相反,由字符串常量初始化的数组是可以修改的。其中的单个字符在以后可以改变,比如下面语句:
      strncpy( a, “black”, 5 );
      就将数组的值修改为 “blackberry”。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: