关于C++指针Word格式.docx
《关于C++指针Word格式.docx》由会员分享,可在线阅读,更多相关《关于C++指针Word格式.docx(21页珍藏版)》请在冰豆网上搜索。
声明变量:
int
nNumber;
*pPointer;
现在给它们赋值:
nNumber
15;
pPointer
//打印出变量nNumber的值:
cout<
"
is
equal
to
:
nNumber<
endl;
现在通过指针改变nNumber的值:
*pPointer
25;
//证明nNumber已经被上面的程序改变
//重新打印出nNumber的值:
}
通读一下这个程序,编译并运行它,务必明白它是怎样工作的。
如果你完成了,准备好,开始下一小节。
陷井!
试一下,你能找出下面这段程序的错误吗?
SomeFunction();
//让指针指向nNumber:
//为pPointer赋值
//为什么这里失败了?
为什么没有得到25
Value
of
*pPointer:
*pPointer<
这段程序先调用了SomeFunction函数,创建了个叫nNumber的变量,接着让指针pPointer指向了它。
可是问题出在哪儿呢?
当函数结束后,nNumber被删掉了,因为这一个局部变量。
局部变量在定义它的函数执行完后都会被系统自动删掉。
也就是说当SomeFunction
函数返回主函数main()时,这个变量已经被删掉,但pPointer还指着变量曾经用过的但现在已不属于这个程序的区域。
如果你还不明白,你可以再读读这个程序,注意它的局部变量和全局变量,这些概念都非常重要。
但这个问题怎么解决呢?
答案是动态分配技术。
注意这在C和C++中是不同的。
由于大多数程序员都是用C++,所以我用到的是C++中常用的称谓。
动态分配
动态分配是指针的关键技术。
它是用来在不必定义变量的情况下分配内存和让指针去指向它们。
尽管这么说可能会让你迷惑,其实它真的很简单。
下面的代码就是一个为一个整型数据分配内存的例子:
*pNumber;
pNumber
new
int;
第一行声明一个指针pNumber。
第二行为一个整型数据分配一个内存空间,并让pNumber指向这个新内存空间。
下面是一个新例,这一次是用double双精型:
double
*pDouble;
pDouble
double;
这种格式是一个规则,这样写你是不会错的。
但动态分配又和前面的例子有什么不同呢?
就是在函数返回或执行完毕时,你分配的这块内存区域是不会被删除的所以我们现在可以用动态分配重写上面的程序:
SomeFunction()
让指针指向一个新的整型
为pPointer赋值
}
通读这个程序,编译并运行它,务必理解它是怎样工作的。
当SomeFunction
调用时,它分配了一个内存,并让pPointer指向它。
这一次,当函数返回时,新的内存区域被保留下来,所以pPointer始终指着有用的信息,这是因为了动态分配。
但是你再仔细读读上面这个程序,虽然它得到了正确结果,可仍有一个严重的错误。
分配了内存,别忘了回收
太复杂了,怎么会还有严重的错误!
其实要改正并不难。
问题是:
你动态地分配了一个内存空间,可它绝不会被自动删除。
也就是说,这块内存空间会一直存在,直到你告诉电脑你已经使用完了。
可结果是,你并没有告诉电脑你已不再需要这块内存空间了,所以它会继续占据着内存空间造成浪费,甚至你的程序运行完毕,其它程序运行时它还存在。
当这样的问题积累到一定程度,最终将导致系统崩溃。
所以这是很重要的,在你用完它以后,请释放它的空间,如:
delete
pPointer;
这样就差不多了,你不得不小心。
在这你终止了一个有效的指针(一个确实指向某个内存的指针)。
下面的程序,它不会浪费任何的内存:
}
只有一行与前一个程序不同,但就是这最后一行十分地重要。
如果你不删除它,你就会制造一起“内存漏洞”,而让内存逐渐地泄漏。
(译者:
假如在程序中调用了两次SomeFunction,你又该如何修改这个程序呢?
请读者自己思考)
传递指针到函数
传递指针到函数是非常有用的,也很容易掌握。
如果我们写一个程序,让一个数加上5,看一看这个程序完整吗?
:
AddFive(int
Number)
Number
+
5;
nMyNumber
18;
My
original
number
nMyNumber<
AddFive(nMyNumber);
//得到了结果23吗?
问题出在哪儿?
问题出在函数AddFive里用到的Number是变量nMyNumber的一个副本而传递给函数,而不是变量本身。
因此,
5"
这一行是把变量的副本加了5,而原始的变量在主函数main()里依然没变。
试着运行这个程序,自己去体会一下。
要解决这个问题,我们就要传递一个指针到函数,所以我们要修改一下函数让它能接受指针:
把'
Number)'
改成
'
AddFive(int*
。
下面就是改过的程序,注意函数调用时要用&号,以表示传递的是指针:
*Number
AddFive(&
nMyNumber);
试着自己去运行它,注意在函数AddFive的参数Number前加*号的重要性:
它告诉编译器,我们是把指针所指的变量加5。
而不并指针自己加5。
最后,如果想让函数返回指针的话,你可以这么写:
*
MyFunction();
在这句里,MyFunction返回一个指向整型的指针。
指向类的指针
指针在类中的操作要格外小心,你可以用如下的办法定义一个类:
class
MyClass
public:
int
m_Number;
char
m_Character;
};
接着你就可以定义一个MyClass
类的变量了:
MyClass
thing;
你应该已经知道怎样去定义一个指针了吧:
*thing;
接着你可以分配个内存空间给它:
thing
MyClass;
注意,问题出现了。
你打算怎样使用这个指针呢,通常你可能会写'
thing.m_Number'
,但是thing是类吗,不,它是一个指向类的指针,它本身并不包含一个叫m_Number的变量。
所以我们必须用另一种方法:
就是把'
.'
(点号)换成
->
来看下面的例子:
public:
char
pPointer->
m_Number
10;
m_Character
s'
;
指向数组的指针
你也可以让指针指向一个数组,按下面的方法操作:
*pArray;
pArray
int[6];
程序会创建一个指针pArray,让它指向一个有六个元素的数组。
另外一种方法,不用动态分配:
MyArray[6];
MyArray[0];
注意,&
MyArray[0]
也可以简写成
MyArray
,都表示是数组的第一个元素地址。
但如果写成pArray
MyArray可能就会出问题,结果是
指向的是指向数组的指针(在一维数组中尽管与&
MyArray[0]相等),而不是你想要的,在多维数组中很容易出错。
在数组中使用指针
一旦你定义了一个指向数组的指针,你该怎样使用它呢?
让我们来看一个例子,一个指向整型数组的指针:
Array[3];
Array[0]
Array[1]
20;
Array[2]
30;
Array[0];
points
the
value
%d\n"
*pArray<
如果让指针指向数组元素中的下一个,可以用pArray++.也可以用你应该能想到的pArray
1,都会让指针指向数组的下一个元素。
要注意的是你在移动指针时,程序并不检查你是否已经移动地超出了你定义的数组,也就是说你很可能通过上面的简单指针加操作而访问到数组以外的数据,而结果就是,可能会使系统崩溃,所以请格外小心。
当然有了pArray
1,也可以有pArray
-
1,这种操作在循环中很常用,特别是while循环中。
另一个需要注意的是,如果你定义了一个指向整型数的指针:
pNumberSet
,你可以把它当作是数组,如:
pNumberSet[0]
和
*pNumberSet是相等的,pNumberSet[1]与*(pNumberSet
1)也是相等的。
在这一节的最后提一个警告:
如果你用
动态地分配了一个数组,
别忘了回收,
delete[]
pArray;
这一句是告诉编译器是删除整个数组而不一个单独的元素。
千万记住了。
后话
还有一点要小心,别删除一个根本就没分配内存的指针,典型的是如果没用new分配,就别用delete:
number;
*pNumber
delete
pNumber;
错误
-
没有用new动态分配内存.
常见问题解答
Q:
为什么我在编译程序时老是在
delete语句中出现'
symbol
undefined'
错误?
A:
delete都是C++在C上的扩展,这个错误是说编译器认为你现在的程序是C而不C++,当然会出错了。
看看你的文件名是不是.cpp结尾。
malloc有什么不同?
是C++中的关健字,用来分配内存的一个标准函数。
如果没有必要,请不要在C++中使用malloc。
因为malloc是C中的语法,它不是为面向对象的C++而设计的。
我可以同时使用free
delete吗?
你应该注意的是,它们各自所匹配的操作不同。
free只用在用malloc分配的内存操作中,而delete只用在用new分配的内存操作中。
引用(写给某些有能力的读者)
这一节的内容不是我的这篇文章的中心,只是供某些有能力的读者参考。
有些读者经常问我关于引用和指针的问题,这里我简要地讨论一下。
在前面指针的学习中,我们知道(&)是读作“什么的地址”,但在下面的程序中,它是读作“什么的引用”
int&
myOtherNumber;
引用有点像是一个指向myOtherNumber的指针,不同的是它是自动删除的。
所以他比指针在某些场合更有用。
与上面等价的代码是:
指针与引用另一个不同是你不能修改你已经定义好的引用,也就是说你不能改变它在声明时所指的内容。
举个例子:
myFirstNumber
mySecondNumber
myReference
myFirstNumber;
mySecondNumber;
//这一步能使myReference
改变吗?
myFristNumber<
//结果是20还是25?
当在类中操作时,引用的值必须在构造函数中设定,例:
CMyClass:
CMyClass(int
variable)
m_MyReferenceInCMyClass(variable)
//
constructor
code
here
总结
这篇文章开始可能会较难掌握,所以最好是多读几遍。
有些读者暂时还不能理解,在这儿我再做一个简要的总结:
指针是一个指向内存区域的变量,定义时在变量名前加上星号(*)(如:
*number)。
你可以得到任何一个变量的地址,只在变量名前加上&(如:
my_number)。
你可以用'
new'
关键字动态分配内存。
指针的类型必须与它所指的变量类型一样(如:
*number
就不能指向
MyClass)。
你可以传递一个指针到函数。
必须用'
delete'
删除你动态分配的内存。
你可以用&
array[0]而让指针指向一个数组。
你必须用delete[]而不是delete来删除动态分配的数组。
文章到这儿就差不多结束了,但这些并不就是指针所有的东西,像指向指针的指针等我还没有介绍,因为这些东西对于一个初学指针的人来说还太复杂了,我不能让读者一开始就被太复杂的东西而吓走了。
好了,到这儿吧,试着运行我上面写的小程序,也多自己写写程序,你肯定会进步不小的!
C/C++中的指针的应用及注意问题
指针是c/c++学习一个比较让人头痛的问题,在程序设计过程中,指针也往往是产生隐含bug的原因。
下面就来谈谈指针的应用以及需要注意的一些问题,里面也许就有你平时没有注意到的问题,希望能帮助各位读者理解好指针。
一、我们先来回忆一下指针的概念吧,方便下面的介绍
指针是存放地址值的变量或者常量。
例如:
inta=1;
a就表示指针常量(“&
”表示取地址运算符,也即引用)。
int*b,b表示的是指针变量(注意,是b表示指针变量而不是*b),*表示要说明的是指针变量。
大家注意int*b[2]和int(*b)[2]是不同的,int*b表示一个指针数组,而int(*b)[2]表示含有两个元素的int指针,这里要注意运算优先级问题,有助于理解指针问题。
在这里大概介绍基本概念就够了,至于具体使用方法,如赋值等,很多书都有介绍,我就不多说了。
二、应用以及注意的问题
1、理解指针的关键所在——对指针类型和指针所指向的类型的理解//内容来自技术世界专业技术//
①、指针类型:
可以把指针名字去掉,剩下的就是这个指针
例如:
int*a;
//指针类型为int*
int**a;
//指针类型为int**
int*(*a)[8];
//指针类型为int*(*)[8]
②、指针所指向的类型:
是指编译器将把那一片内存所看待成的类型。
这里只要把
指针声明语句中的指针名字和名字右边的“*”号去掉就可以了,剩下的就是指针所指向
的类型。
我之所以把他们放在第一位,是因为弄清楚他们是学c/c++指针的重点,正确理解他
们才能使你打好c/c++的编程基础。
2、指针的应用——传递参数。
其实它可以相当于隐式的返回值,这就比return的方法更加灵活了,可以返回更多的值,看看下面的例子自然就明白了:
#include"
iostream.h"
voidexample(int*a1,int&
b1,intc1)
{
*a1*=3;
++b1;
++c1;
}
voidmain()
//来自技术BBS论坛//
int*a;
intb,c;
*a=6;
b=7;
c=10;
example(a,b,c);
cout《"
*a="
《*a<
b="
c="
输出:
*a=18
b=8
c=10
注意到没有,*a和b的值都改变了,而c没有变。
这是由于a1是指向*a(=6)的指针,也即与a是指向同一个地址,所以当a1指向的值改变了,*a的值也就改变了。
在函数中的参数使用了引用(int&
b1),b1是b的别名,也可以把它当作特殊的指针来理解,所以b的值会改变。
函数中的参数intc1只是在函数中起作用,当函数结束时候便消失了,所以在main()中不起作用。
3、关于全局变量和局部变量的一个问题
先不废话了,先看看程序:
#include“iostream.h”
inta=5;
int*example1(intb)
a+=b;
return&
a;
int*example2(intb)
intc=5;
b+=c;
b;
int*a1=example1(10);
//本文来自技术世界技术论坛//
int*b1=example2(10);
cout《”a1=”《*a1<
cout《”b1=”《*b1<
输出结果:
a1=15
b1=4135
*b1怎么会是4135,而不是15呢?
是程序的问题?
没错吧?
由于a是全局变量,存放在全局变量的内存区,它一直是存在的;
而局部变量则是存在于函数的栈区,当函数example2调用结束后便消失,是b指向了一个不确定的区域,产生指针悬挂。
下面是对example1和example2的反汇编(用TC++3.0编译):
example1:
pushbp;
入栈
movbp,sp
movax,[bp+04];
传递参数
add[00AA],ax;
相加
movax,00AA;
返回了结果所在的地址
.
popbp;
恢复栈,出栈
ret;
退出函数
example2:
subsp,02
//本文来自技术世界专业技术门户网站//
movwordptr[bp-02],0005
movax,[bp-02];
add[bp+04],ax;
leaax,[bp+04];
问题就出在这里
movsp,bp
对比之后看出来了吧?
ax应该是存储的是结果的地址。
而在example2中,返回的却是[bp+04]的内容,因此指针指向了一个不确定的地方,由此产生的指针悬挂。
example1中,ax返回了正确的结果的地址。
4、内存问题:
使用指针注意内存的分配和边界。
使用指针过程中应