文章标题: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