首页 > C > 指针 阅读:57,774

指针加减运算

大家已经知道,C语言最适合于底层的开发,一个重要的原因就是因为它支持指针,能够直接访问内存和操作底层的数据,可以通过指针直接动态分配与释放内存:

 

//下面是用typedef定义一个新结构最常用的定义形式

//在微软的面试中,在考查你某个算法前,一般会让你先定义一个与算法相关的结构。

//比如链表排序的时候,让你定义一个链表的结构。

typedef struct _node

{

     int  value;

     struct _node * next;

}node, *link;

 

node *pnode = NULL; //声明变量都应该初始化,尤其是指针

pnode = (node *)malloc(sizeof (node)); //内存分配

//务必检测内存分配失败情况,程序健壮性的考查

//加上这样的判断语句,会让你留给面试官一个良好的印象

//不加这样的判断,如果分配失败,会造成程序访问NULL指针崩溃

if (pnode == NULL)

{

     //出错处理,返回资源不足错误信息

}

memset(pnode, 0, sizeof(node));  //新分配的内存应该初始化,否则内存中含有无用垃圾信息

pnode->value = 100;

printf(“pnode->value = %d\n”, pnode->value);

node * ptmp = pnode;

ptmp += 1;    //指针支持加减运算,但须格外小心

free(pnode);  //使用完内存后,务必释放掉,否则会泄漏。一般采取谁分配谁释放原则

pnode = NULL;//释放内存后,需要将指针置NULL,防止野指针

 

上面的这段代码演示了指针的基本使用方式。在指针声明的时候,最好将其初始化为NULL,否则指针将随机指向某个区域,访问没有初始化的指针,行为为未定义而为程序带来预想不到的结果;指针释放之后,也应该将指针指向NULL,以防止野指针。因为指针所指向的内存虽然释放了,但是指针依然指向某一内存区域。

指针的运算最容易出错。指针支持加减运算。上面代码中ptmp += 1运算结束之后,指针指向的区域不是向前移动了一个字节,而是向前移动了sizeof  (node)个字节,也就是说“1”代表了指针指向的数据结构(node)大小个字节。如果要让指针向前移动一个字节,那么需要先对指针进行类型转换:(char *)ptmp + 1或者(unsigned long)ptmp+1

也就是说,对于指针p,指针的加法运算p = p + n中,p向前移动的位置不是n个字节,而是n * sizeof(*p)个字节,指针的减法运算与此类似。

现在为了让大家对指针有深刻的理解和牢固的掌握,重点研究一些与指针相关的典型问题。这些问题频繁出现在各大知名IT企业的笔试或者技术面试中。当然,这也是学习C语言必须掌握的问题。

一组易混淆的指针表达式:

1.         *p++;//*p,p++

2.         (*p)++;//(*p)++,即*p = *p+1或者*p += 1;

3.         b=*p++;//b=*p;p++

4.         b=(*p)++;//b=*p;(*p)+=1;

5.         b=++*p;//(*p)+=1;b=*p;

6.         b=++(*p);//(*p)+=1;b=*p;

7.         b=*++p;//p+=1;b=*p;

8.         b=*(++p);//p+=1;b=*p

 

//有关于*p++,(*p)++,++*p,++(*p),*++p;的区别

 

int _tmain(int argc, _TCHAR* argv[])

{

       int a=1;

       int *p=&a;

 

       int res=0;

 

       //一,*p++

 

       //*p++,由于单目运算符是右结合律,所以p先与++结合,即等价于:

       //*(p++)

       //由于p++在表达式里是先取值,再加1,因此等价于:

       //res = *p;

       //p= p+1;这里的11个单位长度,这里由于pint

       //所以,是4个字节的长度

       //验证如下:

       res = *p++;

       printf("res:%d,p:%p,&a:%p\n",res,p,&a);

      

       //二,(*p)++

       a=1;

       p = &a;

       //这里(*p)++等价于先将*p的值给了res,然后,再将(*p)进行加1

       //即等价于:

       //res = *p;

       //*p = *p+1,因为*p即为a,所以也就是a=a+1a的值将变为2

       //验证如下:

       res = (*p)++;

       printf("res:%d,p:%p,&a:%p,a:%d\n",res,p,&a,a);

 

       //三,++(*p)

       a=1;

       p = &a;

       //++(*p),也就是先把*p对应的值加1,再把加1后的*p的值传给res

       //也就是等价于:

       //*p=*p+1,因为*p就是a,所以也就是a=a+1

       //res = *p;

       //验证如下:

       res= ++(*p);

       printf("res:%d,p:%p,&a:%p\n",res,p,&a);

 

       //四,*++p

       a=1;

       p=&a;

       //*++p,先将p的地址加1,然后再将p的值给res,即:

       //p = p+1;

       //res = *p;

       //验证如下:

       res = *++p;

       printf("res:%d,p:%p,&a:%p\n",res,p,&a);

 

       //五,++*p

       a=1;

       p=&a;

 

       //++*p等价于++(*p),参见上面的三

       //验证如下:

       res = ++*p;

       printf("res:%d,p:%p,&a:%p\n",res,p,&a);

 

       return 0;

}

周哥教IT,分享编程知识,提高编程技能,程序员的充电站。跟着周哥一起学习,每天都有进步。

通俗易懂,深入浅出,一篇文章只讲一个知识点。

当你决定关注「周哥教IT」,你已然超越了90%的程序员!

IT黄埔-周哥教IT技术交流QQ群:213774841,期待您的加入!

二维码
微信扫描二维码关注