学习Linux C编程之数组与指针

1.    指针类型分析

分析指针,可以从变量名处起,根据运算符优先级结合,一步一步分析. 
int p;  //这是一个普通的整型变量 
int *p;  //首先从P处开始,先与*结合,所以说明P是一个指针,然后再与int结合,说明指针所指向的内容的类型为int 型.所以 P是一个返回整型数据的指针 
int p[3]; //首先从P处开始,先与[]结合,说明P 是一个数组,然后与int结合,说明数组里的元素是整型的,所以 P是一个由整型数据组成的数组 
int *p[3]; //首先从P处开始,先与[]结合,因为其优先级比*高,所以P是一个数组,然后再与*结合,说明数组里的元素是指针类型,然后再与 int结合,说明指针所指向的内容的类型是整型的,所以是一个由返回整型数据的指针所组成的数组 
int (*p)[3]; //首先从P处开始,先与*结合,说明P是一个指针然后再与[]结合(与"()"这步可以忽略,只是为了改变优先级),说明指针所指向的内容是一个数组,然后再与int 结合,说明数组里的元素是整型的.所以P是一个指向由整型数据组成的数组的指针 
int **p; //首先从 P开始,先与*结合,说明P是一个指针,然后再与*结合,说明指针所指向的元素是指针,然后再与 int结合,说明该指针所指向的元素是整型数据. 所以P是一个返回指向整型数据的指针的指针 
int p(int);  //从P处起,先与()结合,说明P是一个函数,然后进入()里分析,说明该函数有一个整型变量的参数然后再与外面的int 结合,说明函数的返回值是一个整型数据.所以P是一个有整型参数且返回类型为整型的函数 
int (*p)(int); //从P处开始,先与指针结合,说明P是一个指针,然后与()结合,说明指针指向的是一个函数,然后再与()里的int 结合,说明函数有一个int 型的参数,再与最外层的int 结合,说明函数的返回类型是整型,所以P是一个指向有一个整型参数且返回类型为整型的函数的指针 
int *(*p(int))[3]; //从 P开始,先与()结合,说明P是一个函数,然后进入()里面,与int结合,说明函数有一个整型变量参数,然后再与外面的*结合,说明函数返回的是一个指针,,然后到最外面一层,先与[]结合,说明返回的指针指向的是一个数组,然后再与*结合,说明数组里的元素是指针,然后再与int 结合,说明指针指向的内容是整型数据.所以P是一个参数为一个整数且返回一个指向由整型指针变量组成的数组的指针变量的函数 

2. 运算符&和* 
&是取地址运算符,*是间接运算符。 
&a的运算结果是一个指针,指针的类型是a的类型加个*,指针所指向的类型是a的类型,指针所指向的地址嘛,那就是a的地址。 
*p的运算结果就五花八门了,总之*p 的结果是 p 所指向的东西,这个东西有这些特点:它的类型是 p指向的类型,它所占用的地址是p所指向的地址。 

3.指针算数运算

 C的指针的算术运算只局限于两种形式。

第一种形式是:   指针+-整数  标准定义这种形式只能用于指向数组中某个元素的指针。对一个指针加1使它指向数组中的下一个元素,加5使它向右移动5个元素的位置,依次类推。把一个指针减去3使它向左移动3个元素的位置。

第二种类型的指针运算具有如下的形式:   指针—指针  两个指针相减的结果的类型是ptrdiff_t,它是一种有符合整数类型。减法运算的值是两个指针在内存中的距离(以数组元素的长度为单位,而不是以字节为单位),因为减法运算的结果将除以数组元素类型的长度。

4.常量指针和指针常量

指向常量的指针

constint *pa;
int const *pa;
两者等价。因为指向常量的指针有时候会指向常量,所以它具有这个性质:“不能靠解引用改变它指向的对象的值”,以此保护它所指向的常量的常量性:
*pa =d; // 不可行(d是已经声明过的整型)

但指针本身的值是可变的:
pa=& d; // 可行(d是已经声明过的整型)

而且指向常量的指针有时候也会指向变量,如下:
int t,u;
const int *pa;
pa =&t; //可行,指向变量t
pa =&u; //也可行,指向变量u

我们可以把它理解成:“为了指向常量而发明的指针”,这样比较贴切。

常量指针:

int*const pa =&n; // n是之前已经声明过的整型变量,注意必须是变量,理由见下

“常量指针”即指针本身的值是常量,但“能靠解引用改变它指向的对象的值”,如下:
pa=&d; // 不可行(d是已经声明过的整型)
*pa =d; // 可行(d是已经声明过的整型)

因为常量指针也是一种const常量,所以它同样必须在第一次声明时就初始化,不过它的初始值缩小为只能是变量(的地址),因为只有变量才能确保以后能靠解引用而改变它指向的对象的值。这使得常量指针不象一般的const常量,用变量或常量初始化都可以。
也就是说,常量指针反而总是指向变量的。

5.空指针及其使用

空指针常量,ANSI规定:<stdio.h>规定预处理宏NULL 为空指针常量,通常#define NULL 0或(void *)0

误区:有的机器不同类型的指针使用不同的内部表示,例如将字符指针的空指针常量定义为#define NULL ((char *)0),这样的NULL定义对于接受字符指针的函数没有问题,但对于其他类型的指针仍然需要进行显示的转换,本来合法的构造可能会失败,例如FILE *fp=NULL;

注意1:NULL只能用做指针,非指针变量中不能用NULL

注意2:运行时的整数0转化为指针不一定是空指针,只有常量整数0才能保证空指针

6.void指针

1.void指针是一种特别的指针
   void *vp
  //
说它特别是因为它没有类型
  //
或者说这个类型不能判断出指向对象的长度

2.任何指针都可以赋值给void指针
  type *p;
  vp=p;
  //
不需转换
  //
只获得变量/对象地址而不获得大小

3.void指针赋值给其他类型的指针时都要进行转换
   type *p=(type*)vp;
   //
转换类型也就是获得指向变量/对象大小
:http://icoding.spaces.live.com/blog/cns!209684E38D520BA6!130.entry

4.void指针不能复引用
  *vp//
错误
 
因为void指针只知道,指向变量/对象的起始地址
 
而不知道指向变量/对象的大小(占几个字节)所以无法正确引用

5.void指针不能参与指针运算,除非进行转换
   (type*)vp++;
  //vp==vp+sizeof(type)

因此,void*的作用大致如下:

1. 传参:通用类型

可以作为函数模板,链表等参数的通用参数。在使用时,只需要强制类型转换就可以。

2.强制类型转换

有时候由于重载等的干扰,导致需要转换成void*,来进行取地址。

例如,(void*)obj.member,就可以取到member的地址;直接&(obj.member)取到的实际上是obj的开始地址。

3.指向0的地址

(void *)0,指向全是0的地址,相当于NULL

void类型显式转换为void类型表达式,用于避免一些代码静态检查工具的警告。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值