指针

在c语言系列中,指针使得使用这种语言编写程序灵活。然而,灵活的另一面常常会带来多变,多变则容易出错。这篇将就指针进行深入理解和学习。

指针的定义是指向某一数据类型或者类的变量。也可以理解为地址。但是地址在一般意义上是一种常量,严格意义上这样理解指针是不对的。指针根据指向的类型来区分。比如说int型指针p,就是int *p。随着指针指向的类型复杂而变得复杂。比如说,指向类A派生类B的指针p,那么p在调用函数的时候,调用的是哪个类中函数将会变得复杂,基类的指针又如何过渡到子类,这涉及的是类的多态型,这里不展开说明。那么指针为什么常常会出错呢?这里主要总结两点。

第一、指针在没有初始化的情况下就调用指向对象的成员变量。在程序比较小的时候,我们很容易发现。但是一旦程序比较大,初始化和声明往往分开。如果在初始化之前调用,那么就很容易引起程序编译出错。在C++中,声明和定义可以同时进行。在指针未进行初始化时,往往都需要将指针初始化为NULL。那么指针在未初始化之前直接调用成员函数是否一定会出错呢?我自己测试了一下。

struct MyTest{
	void funa(){
		cout << "you are welcom!";
		return;
	}
	int funb()
	{
		return m_a;
	}
	int m_a;
	MyTest(int a)
	{
		m_a = a;
	}
};
void TestPointer()
{
	MyTest *p;
	p->funa();
	return;
}

这里定义了一个MyTest的类,在TestPointer中声明了一个MyTest型指针p,然后用该指针进行调用指向类的成员函数。结果在编译时出现如下错误:

cpp(27): error C4700: 使用了未初始化的局部变量“p”

这是因为p为进行初始化。如果我将p初始化为NULL呢?

void TestPointer()
{
	MyTest *p = NULL;
	p->funa();
	return;
}

那么程序将编译通过,并且正确执行funa()函数。接下来我调用funb()函数。

void TestPointer()
{
	MyTest *p = NULL;
	p->funa();
        p->funb();
	return;
}

这时编译能够通过,但是在执行时会出现错误。我们发现funa()与funb()的区别在于前者没有调用类的成员变量,后者调用了成员变量。而成员变量要依附于类的对象才能存在,在这里对象没有。成员变量就不存在,这会导致错误出现。

第二、指针的指向对象没有释放,直接将指针删除。这是最容易出现的,并且常常难以发现。比如在函数中变量的声明周期随着函数的结束而自动销毁。

测试实例如下:

void TestPointer(int *p)
{
	int a[10] = { 0 };
	p  = a;
	return;
}

int _tmain(int argc, _TCHAR* argv[])
{
	int *p_test = NULL;
	TestPoint(p_test);
	cout << *p_test<< endl;
	return 0;
}

这里编译将不会出错,但是在执行时却会出现错误。具体原因就是在TestPointer()中是值传递,传递的是指针本身的值NULL给p,指针p随着函数的结束而生命周期结束,而p_test仍为NULL,这时输出*p_test将会出错。

指针和数组往往联系密切,这里又会增加指针的难度。

我们称int *(p)[10]这样类似的指针p代表的是数组指针。假如用new来为这样的p初始化,在对p进行析构时,利用delete [] p。

int *(p[10])就称为指针数组。假如用new来初始化p,那么对这些申请的内存释放用的是delete [] *p。

如果我们想申请一个二维数组的指针p,那么p如何初始化呢?

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值