理解指针

指针是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] ;等价的。
一般来说,除数组的第一维(下标)可以不指定大小,其余各维都必须明确指定大小。
 
6.指向函数的指针
                              为完待续。。。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值