指针学习误区:=

庄鱼 2012-04-07 07:50:30
= 符在C/C++里是最常见也最基本的操作符,通常解释为赋值,流程表达为←,即将符号右边的内容替换左边的内容。
然而,对于指针操作而言,= 符与其说成是赋值不如改称重定向更合适:因为赋值语义的限定性包含了变更与复制内容两个相似而行为相左的概念,使得很多初学者乃至一些有经验的编程人员都会落入指针操作陷阱,从而被一些不了解C/C++的人极力攻讦的对象。而这主要原因来自于早期引进翻译的人本身的认知局限,其后语言学家们不究明里的一味跟风所致(国外原版也好不到哪里,幸亏数学表达一直用←而不是含≌性质的<=)。
←指向是将目标地址直接替代原有地址,使新得到的数据与目标完全同一,即两者是不分彼此的关联关系,是一个对象。
<=复制则是在原空间内填写目标数据内的内容,对指针而言,原指针指向性不变,但指向的地址内容发生了变化,变化值与目标相同,左值与右值依然是两个独立存在的对象,相互间是全等关系。
←与<=的区别在哪呢?对于简单类型来说,没有任何的不同,当左值变更为右值时,其空间的实际情况也同时被复制成右值数据,因此说成赋值一点也不为过。但对指针或复杂类型而言,赋值一说就显得宽泛不严谨了。也就是许多人说的深拷贝浅拷贝问题。
在指针上,←是指指针定向,注意这里不包括复制功能!也就是说,当发生←操作时,原有的指向空间将会被新的地址所取代,从而实现左值与右值相同都指向同一地址情况,达到数据快速定位、调度、运算的目的。但是,毕竟是指针重定向,其原来指向的空间将因为没有指针管理回收而成为野指针,最终造成系统资源泄露,这也是许多人诟病指针难学的原因。通常意义上讲,很多使用指针赋值的人,大多会习惯性的认为 = 操作会令系统替其完成复制数据功能,从而依赖系统自动的做一些本来就应该是编程者做的事,而实际上系统远不会那么“智能”,这种情况下程序出错也就在所难免。
为了实现这种使用 = 作指针及复杂类型复制操作,有些“大能”想到了操作符重载,可这又是另一个陷阱:性能及资源循环。
其实,了解到了指针 = 的指向性,完全可以简化很多程序操作,大可以直接使用指针对所指向的对象进行操作,当且仅当需要产生与原对象独立的对象时才使用复制建立对象,如果完全遵循这个原则,将极大的杜绝内存泄露与野指针、垃圾数据问题。由此,也就可以理解,C语言为什么有那么多字符串、内存的复制函数了。
相关举例如下:

struct T{
Type a;
}

T fun(){
T a;
...
return a; //---- a 解析,内容不确定
}
T t1=fun() //----- 垃圾数据读取

T* fun1(T *a)
{
...
return a;
}
T fun2(T& a)
{
...
return a;
}
t1 = *(fun1(&a));
t1 = fun2(a);

T* f1()
{
T *a=0;
a = new T;
...
return a; //------ 不建议采用的指针创建,如无接受对象将引发资源问题,此种函数适用于初始化指针变量
}
T* f1(T **a)
{
if(!*a)
*a = new T;
...
return *a;
}
T* f2(T* &a)
{
T *t=0;
try{
t = new T;
}catch(...){goto Done;}
...
if(a){
delete a;}
a = t;
t = 0;
Done:
if(t)delete t;
return a;
}
T *t2=0;
f1 (&t2);
t2 = f1(&t2);
f2(t2);
t2 = f2(t2);
...全文
189 5 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
庄鱼 2012-04-08
  • 打赏
  • 举报
回复
单步调试去查看实际汇编流程,这正是又回到先实践再总结理论的老路上来,但针对问题的出现与解答时,总不能用这种方法去对待,若然则是另一种对事物本身性质的不了解:说错了没关系,可以逐步修正,但为了避免出错,而说些于事无补的放之四海而皆准的话,那就是滑头了。而用这种态度对初学者理解事物本质而言实在没有多大帮助,即便是再多的语重心长,不懂的依然不懂,看汇编也会陷于一大堆代码之中,这对没有混合编程经验的初学者而言不啻为一种灾难。
“不要迷信书、考题、老师、回帖;
要迷信CPU、编译器、调试器、运行结果。”比较适用于有一定编程经验的,但有些问题依然不甚了解的人,那就要用这种指导性的原则来深入探寻事物本质。
自信男孩 2012-04-07
  • 打赏
  • 举报
回复
嗯,挺好。知识学习后就应该总结一下。
Saingel 2012-04-07
  • 打赏
  • 举报
回复
=对于指针来说当然也是赋值,只不过是地址值而已
赵4老师 2012-04-07
  • 打赏
  • 举报
回复
VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
指针即地址。“地址又是啥?”“只能从汇编语言和计算机组成原理的角度去解释了。”

提醒:
“学习用汇编语言写程序”

“VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习C和汇编的对应关系。”
不是一回事!

不要迷信书、考题、老师、回帖;
要迷信CPU、编译器、调试器、运行结果。
并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。
任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实!

不要写连自己也预测不了结果的代码!

65,187

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧