指针问题

一. 指针包含内容

    要搞清一个指针需要搞清指针的四方面的内容:

                           指针的类型,

                           指针所指向的类型,

                           指针的值或者叫指针所指向的内存区,

                           指针本身所占据的内存区。


二.指针的类型
  从语法的角度看,你只要把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。这是指针本身所具有的类型。

        (1)int*ptr;//指针的类型是int* 
  (2)char*ptr;//指针的类型是char* 
  (3)int**ptr;//指针的类型是int** 
  (4)int(*ptr)[3];//指针的类型是int(*)[3] 
  (5)int*(*ptr)[4];//指针的类型是int*(*)[4]

      若一个变量名是指针是指针变量,则必定紧跟一个*(考虑优先级情况)。例如:

           int (*p) [10]中,p紧跟一个*,他必定是指针,是一个int (*) [10]指针,而int* p[10]或者int *p[10]中,p都紧跟[10]而非*,故p为一个含10个int *元素的数组而非指针,int *p[10]由于[]优先级大于*,不能判定为p紧跟*。


三.指针所指向的类型
  当你通过指针来访问指针所指向的内存区时,指针所指向的类型决定了编译器将把那片内存区里的内容当做什么来看待。
        从语法上看,你只须把指针声明语句中的指针名字和名字左边的指针声明符*去掉,剩下的就是指针所指向的类型。

        (1)int*ptr;//指针所指向的类型是int 
  (2)char*ptr;//指针所指向的的类型是char 
  (3)int**ptr;//指针所指向的的类型是int* 
  (4)int(*ptr)[3];//指针所指向的的类型是int()[3] 
  (5)int*(*ptr)[4];//指针所指向的的类型是int*()[4]


四.指针的值,或者叫指针所指向的内存区或地址

        指针的值是指针本身存储的数值,这个值将被编译器当作一个地址,而不是一个一般的数值。在32位程序里,所有类型的指针的值都是一个32位整数,因为32位程序里内存地址全都是32位长。

        指针所指向的内存区就是从指针的值所代表的那个内存地址开始,长度为si zeof(指针所指向的类型)的一片内存区我们说一个指针的值是XX,就相当于说该指针指向了以XX为首地址的一片内存区域;我们说一个指针指向了某块内存区域,就相当于说该指针的值是这块内存区域的首地址。


五. 指针本身所占据的内存区

     指针本身占了多大的内存?你只要用函数sizeof(指针的类型)测一下就知道了。在32位平台里,指针本身占据了4个字节的长度


六.指针的算术运算

    一个指针ptr_old加上一个整数n后,结果是一个新的指针ptr_new,ptr_new的类型和ptr_old的类型相同,ptr_new所指向的类型和ptr_old所指向的类型也相同。ptr_new的值将比ptr_old的值增加了n乘sizeof(ptr_old所指向的类型)个字节。就是说,ptr_new所指向的内存区将比ptr_old所指向的内存区向高地址方向移动了n乘sizeof(ptr_old所指向的类型)个字节。

      一个指针ptr_old减去一个整数n后,指向的内存区向低地址方向移动了n乘sizeof(ptr_old所指向的类型)个字节。


七.数组和指针的关系

        在不同的表达式中数组名array可以扮演不同的角色。 
  在表达式sizeof(array)中,数组名array代表数组本身,故这时sizeof函数测出的是整个数组的大小。 
         在表达式*array中,array扮演的是指针,因此这个表达式的结果就是数组第0号单元的值。sizeof(*array)测出的是数组单元的大小。 
  表达式array+n(其中n=0,1,2,....。)中,array扮演的是指针,故array+n的结果是一个指针,它的类型是TYPE*,它指向的类型是TYPE,它指向数组第n号单元。故sizeof(array+n)测出的是指针类型的大小。 


1.指向数组的指针: TYPE (*) [10],表示一个指向TYPE [10]的数组指针。

2. 指针数组: TYPE*  [10]    (TYPE* ([10])定义的也为指针数组 ),表示一个含有10个TYPE* 元素的数组。

3.指向数组的指针的算术运算,取*运算和取**运算。

假设:

int arr[4] = {1,2,3,4};

int (*parr)[4] = &a; 

指向数组指针的加法或减法等算术运算,其单位偏移量是其指向数组的字节大小,例如parr的单位偏移量为sizeof(arr),即4*4=16;

指向数组指针的取*运算将取得它所指向数组的首地址,对取*后指向数组指针的算术运算的偏移量将为sizeof(int ),对*parr的所有使用情形与arr相同

指向数组指针的取**运算,是它所指向数组的首地址的取值运算,即为它所指向数组的首元素值,故**parr 为 1。


八.指针和结构体

        struct MyStruct 
       { 
         inta; 
         intb; 
         intc; 
       } 
     MyStruct ss={20,30,40};
        //声明了结构对象ss,并把ss的三个成员初始化为20,30和40。 
       MyStruct*ptr=&ss;


请问怎样通过指针ptr来访问ss的三个成员变量? 
  答案: 
ptr->a; 
ptr->b; 
ptr->c;


int*pstr=(int*)&ss;

又请问怎样通过指针pstr来访问ss的三个成员变量? 
  答案: 
          *pstr;//访问了ss的成员a。 
          *(pstr+1);//访问了ss的成员b。 
          *(pstr+2)//访问了ss的成员c。
      虽然我在我的MSVC++6.0上调式过上述代码,但是要知道,这样使用pstr来访问结构成员是不正规的。

      所有的C/C++编译器在排列数组的单元时,总是把各个数组单元存放在连续的存储区里,单元和单元之间没有空隙。但在存放结构对象的各个成员时,在某种编译环境下,可能会需要字对齐或双字对齐或者是别的什么对齐,需要在相邻两个成员之间加若干个"填充字节",这就导致各个成员之间可能会有若干个字节的空隙。所以,即使*pstr访问到了结构对象ss的第一个成员变量a,也不能保证*(pstr+1)就一定能访问到结构成员b。因为成员a和成员b之间可能会有若干填充字节,说不定*(pstr+1)就正好访问到了这些填充字节呢。


九.指针类型转换

      指针类型转换需要通过强制转换来实现。

        1、floatf=12.3; 
  2、float*fptr=&f;
        3、p=(int*)&f;


十.直接为指针写整数地址值

      如下所示直接为一个指针赋整型数或者赋整型变量是非法的。

      unsigned int a; 
      TYPE *ptr;
      a=0x20345686; 
      ptr=20345686;//非法
      ptr=a;//非法

      但是可以通过将一个非负整型变量强制转换为指针类型变量,实现对于指针的值的直接赋值,如下所示:

      unsigned int a; 
      TYPE *ptr;
      a=0x20345686;
      ptr=(TYPE*)a;// ptr将指向0x20345686内存

     通过类似的强制转换可以将一个指针的值取出来,如下所示:

     int a=123,b; 
     int *ptr=&a; 
     char *str; 
     b = (int)ptr;//把指针ptr的值当作一个整数取出来。 


十一.指针安全问题

      由于指针可能出现访问越界的情况,从而访问与修改别的进程内存空间,甚至是系统内存空间,故存在安全问题。


十二.函数指针问题

       函数名是指向函数的常指针。故函数指针是对函数通过函数名调用方式的一种推广。

       函数指针是一个指向函数的指针变量,并且可以通过这个指针来调用其他函数,只要被调函数的返回值类型与参数列表值类型和函数指针声明的形式一致即可。

函数指针数组的定义中,确定数组维数的数字必须写在函数指针名所在括号内。

返回函数指针的函数的定义,一般使用typedef实现。

以下为一个函数指针的简单示例:

int FindMax(int a,int b)
{
	return a>b?a:b;
}

typedef int (*pfunc)(int,int);
pfunc ReturnPtrToFindMax(void) // 返回函数指针的函数
{
	return &FindMax;
}

int main(int argc, char **argv)
{
	int (*pf)(int,int) = &FindMax; //函数名为指向函数的常引用
	int (*pfarr[10])(int,int) ={NULL}; //函数指针数组的定义中,数组维数需写在函数指针名字所在括号中
	pfunc (*pp1)(void) = &ReturnPtrToFindMax;

	int res = (*pf)(3,43);
	res = ( *(*pp1)() )(3,44);
	
	return 0;
}






引用:

http://bbs.csdn.net/topics/100021521

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值