指针加减运算
大家已经知道,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;这里的1是1个单位长度,这里由于p是int
//所以,是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+1,a的值将变为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;
}