`
yuyeyi
  • 浏览: 36543 次
  • 性别: Icon_minigender_1
  • 来自: 湖南
社区版块
存档分类
最新评论

理解指针

阅读更多
原文
http://blog.csdn.net/sdspp/archive/2006/02/27/611611.aspx
指针是c语言的精髓,理解它对于学习c语言至关重要。
1.指针和地址
    指针是能够存放一个地址的一组存储单元。是一种保存变量地址的变量。
   
如    int x=1,y=2,z[10];
       int *ip;                /* ip是指向int类型的指针 */

       ip = &x;              /* ip 指向 x */
       y = *ip;               /* y 的值现在是1 */
       *ip = 0;             /* x的值现在是0*/
       ip = &z[0];          /* ip指向z[0] */  

  其中一元运算符&可用于取一个对象的地址。地质运算符&只能应用于内存中的对象,即变量和数组元素。他不能作用于表达式,常量或register类型的变量。
  一元运算符* 是间接寻址或间接引用运算符。当他作用于指针时,将访问指针所指向的对象。      

   y = *ip + 1;
   *ip += 1;
   ++*ip;
   (*ip)++;
这几条语句是等价的。其中(*ip)++中的括号是必需的。如果是*ip++,该表达式将是对ip进行加一运算,而不是对ip指向的对象进行加一运算。这是因为,类似于*和++这样的一元运算符遵循从右制左的结合顺序。
   理解这点非常重要,它可以帮我们写出很简洁的程序。
void strcpy(char *s, char *t)
{
    while(*s++ = *t++)
         ;
}
再如:
int strcmp(char *s, char *t)
{
    while(*s++ == *t++)
        if(*s =='\0')
            return 0;
    return *s-*t;
}

再如:

*p++ = val;           /* 将val压入栈 */
val = *--p              /* 将栈顶元素弹出到val中 */

这里涉及到一个问题,就是优先级的问题。*,++,--,具有相同的优先级,按照从右到左的顺序结合。按照这个原则上叙的就不难理解。究竟是对地址改变,还是对地址所引用的值变换。
再如,命令行操作经常遇到的:argv[0]保存命令好的第一个单词,通常是命令。(*argv)[0]同*argv[0]就完全不一样。因为[ ]的优先级要比*的高,所以(*++argv)[0]可以看作是**++argv,是命令的第一个字母。而*++argv[0]就相当于增加argv[0]指针。可以借此来遍历命令行之后的参数的内容。 

2.指针和数组
    在c语言中,指针和数组的关系十分密切。通过数组下标能完成的任何操作都可以通过指针来实现。一般来说,用指针写的程序比用数组下标写的程序执行速度快一些,但另一方面,用指针实现的程序理解起来稍微困难一些。

  int a[10];
  int *pa;
pa = &a[0];         /* 指针pa指向数组a的第0个元素,也就是说,pa的值为数组a[0]的地址。*/

因为数组名所代表的就是该数组最开始的一个元素的地址。
所以 pa=&a[0];等价于:pa = a;
       a[i]          等价于:*(a+i);               /* a[i]在c语言内部表示为*(a+i) */
       &a[i]        等价于:a+i;
       pa[i]        等价于:pa+i;

但是,我们必须记住,数组名和指针之间有一个不同之处。指针是一个变量,因此,在c语言中,语句pa=a和pa++都是合法的。但数组名不是变量,因此,类似于a=pa和a++形式的语句是非法的。

3.地址运算
   有效的指针运算包括相同类型指针之间(也可以是两个指针之一是void*类型的情况)的赋值运算;指针同整数之间的加法或减法运算;指向相同数组中元素的两个指针间的减法或比较运算;将指针赋值为0或者指针与0之间的比较运算。其他所有形式的指针运算都是非法的。


4.字符指针
   字符串常量是一个字符数组。在字符串的内部表示中,字符数组以空字符'\0'结尾。所以,程序可以通过检查空字符找到字符数组的结尾。

   下面这两个定义有很大差别:
    char amessage[] = "now is the time";               /* 定义一个数组 */
    char *pmessage = "now is the time";               /* 定义一个指针 */

amessage是一个仅仅足以存放初始化字符串以及空字符'\0'的一维数组。数组中的单个字符可以进行修改,但amessage始终指向同一个存储位置。另一方面,pmessage 是一个指针,其初值指向一个字符串常量,之后他可以被修改为指向其他地址,但如果试图修改字符串的内容,结果是没有定义的。

5. 指针数组
  其实也不能理解。
  char *lineptr[MAXLINE];
他表示lineptr是一个具有MAXLINE个元素的一维数组,其中数组的每个元素是一个指向字符类型对象的指针。也就是说,lineptr[i]是一个字符指针,而*lineptr[i]是该指针指向的第i个文本行的首字符。
  所以lineptr本身就是一个数组名,只不过它保存的是一些指针。存储的内容不同而已。

再如:
int a[10][20];
int *b[10];
对a来说,是分配了200个int型的空间。
而对b来说,该定义仅仅分配了10个指针,并且没有初始化他们。他们的初始化必须显式进行。

其中[]的优先级高于*的优先级。
所以,int *b[10]; 同int (*b)[10];是完全不一样的。
对于int *b[10]; b是一个数组名,数组内有10个整型指针。
对于int (*b)[10],意味着b是一个指针,他指向具有10个整型元素的一维数组。
int b[2][10]; int b[][10]; int (*b)[10] ;等价的。
一般来说,除数组的第一维(下标)可以不指定大小,其余各维都必须明确指定大小。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics