[原创]C指针应用常见缪误

文章标题:C指针应用常见缪误
文章作者:半点闲
文章撰写日期:2005-10-18
发布日期:2005-10-18 12:10
 
  今天在写程序的时候,遇到了几个关于指针方面的问题,觉得很典型(对于初学者来讲)。所以决定把它写出来一来练练文笔,二来也存个档为以后查阅方便吧。工科不善文笔的我,就用代码来说明问题。

前言:
  一、文章中所说的C指的是ANSI C,是由ANSI/ISO 9899-1990[ANSI 90]进行定义并由[KERN 89]进行描述的。
  所有代码的执行环境如下:
  操作系统:中文版WindowsXP Professional+SP2
  编辑器:VC6或VC7

  文章中所举的例子在上述环境中编译通过,我也会尽量把问题表述清楚,但由于是第一次写东西,再加上本人也是一个初学者水平有限,文中难免有不清或错误的地方,在这里请大家多提意见!
  
 二、语法描述格式:
  关于const限定修饰符书写位置:
     C语言与ANS C中并未统一的标准。你可以写在数据类型符前面如:const int (变量名)或后面如:int  const (变量名)。我倾向于前者也就是const int (变量名)原因就是方便阅读吧(我们可以从右往左把这个定义读为“(变量名)是一个int类型的const(常量,值不能被更改)。

正文:
  问题1:当指针是函数参数时的误用。请先看一段代码:
#include <stdio.h>
#include <stdlib.h>

void u_p(char  *p);

void main (void)
{
  char *pstr = (char *) malloc (sizeof(char));
  *pstr = 'a';
 
  u_p (pstr);
 
  if ( pstr = NULL )
  {
    printf ("pstr == NULL");
  }
  else
  {
    printf ("pstr != NULL");
  }
  system ("pause");  //暂停。
}
void u_p(const char *p)
{
  free(p);
  p = NULL;
}
解释:
  程序的愿意是想在执行p = NULL后达到pstr = NULL。但实际上p是u_p()函数内,局部自动变量。当函数执行完后,其值将自动的销毁。p = NULL只是让p自己赋个NULL值罢了(在这个函数体内,p赋不赋NULL值都无所谓),而free(p)只是释放了pstr所指向动态生成的存储空间,pstr中的值(空间地址)依然存在,并不为空。所以在执行if (pstr == NULL) 判断时通不过。此时,如果访问pstr中的值,将会产生错误(因为值中所指地址,已经被系统回收不存在了)这种指针是很危险的,称为“悬挂”指针。
 
正确的方法:
void u_p(char **p)
{
  free (*p);
  *p = NULL;
}
void main (void)
{
  char *pstr = (char *) malloc (sizeof(char));
  *pstr = 'a';

  u_p (&pstr);

  if ( pstr == NULL )
  {
    printf ("pstr == NULL");
  }
  else
  {
    printf ("pstr != NULL");
  }
  system ("pause");  //暂停。
}

  问题2:const限定修饰符。请先看一段代码:
  const int ivalue = 5;
  int *pvalue = &ivalue;
 
  这是否可行?ivalue是一个常量对像,因此它不能被改写为一个新值。但是pvalue是一个普通指针,没有什么能阻止我们写出这新的代码:

  *pvalue += 1; //修改了ivalue!

  一般编译器不能跟踪指针在程序中任意一点指向的对象,[这种内部工作需要进行数据流分析(data flow analysis),通常由单独的优化器(optimizer)组件来完成。]允许非const对象的指针指向一个常量对象,把“试图通过该指针间接改变对象值”的动作标记为非法的,这种编译器来说是不可行的。因而任何“试图将一个非const对象的指针指向一个常量对象”的动作都将引起编译错误(此段话摘自<<c++primer>>中文第三版84页)。
这并不意味着我们不能间接地指向一个const对象,只意味着我们必须声明一个指向常量的指针来做这件事。

例如:
  const int *pvalue;  //这里会产生一个误区,下面将说到。
 
  pvalue是一个指向int类型的const对象指针,(我们可以从右往左把这个定义读为“pvalue是一个指向int类型的、被定义成const的对象指针”。)此中微妙在于pvalue本身不是常量。我们可以重新赋值给pvalue,使其指向不同对象,但不能修改pvalue指向的对像。例如:
  const int *pc = 0;
  const int value = 1;

  pc = &value; //OK:不能通过pc修改value。
 
  int value2 = 2;
 
  pc = &value2; //OK,不能通过pc修改value2,虽然value2本身不是一个常量。

  const对象的地址只能赋值给指向const对象的指针,例如:pc。但是,指向const对象的指针可以被赋以一个非const对象的地址。

  我们还可以定义一个"const指针"指向一个非const对象。例如:
  int errNumb = 0;
  int *const curErr = &errNumb;
 
  curErr是指向一个非const对象的const指针。(我们可以从右往左把定义读作"curErr是一个指向int类型对象的const指针。)这意味着不能赋给curErr其他的地址值,但可以修改curErr指向的值。指向const对象的const指针的定义就是前面两种定义结合起来。例如:
  const int value = 1;
  const int *const p = &value;
 
  这种情况下p指向的对象的值以及它的地址本身都不能被改变。(我们可以从右往左将定义读作:"p是指向被定义为const的int类型对象的const指针"。)

  今天就写到这里~~~,看过后,如果你发现文中有什么错误或者有什么意见请与我联系!QQ:15237415

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值