一段很简单的,困惑的程序

王嗣钧 2013-11-29 11:21:21
#include <iostream>
using namespace std;

class A
{
public:
void Func(void){ cout << "Func of class A" << endl; }

};

A* Test(void)
{
A *p;
A a;
p = &a; // 注意 a 的生命期
return p;
}

void main()
{
// 这段程序搞笑了
A *q;
/*q = Test();*/
q = NULL;
q->Func();
system("pause");
}

代码如上,输出结果为“Func of class A”,可是我明明将q变为空指针了。
如果去掉代码“q = NULL;”,编译出错。
如果取消注释/*q = Test();*/,不论是否注释“q = NULL;”,结果还是输出“Func of class A”,可是栈里面的a对象明明已经被自动销毁了,这个时候返回的q应该是野指针才对吧?

这一切的一切,是为啥呢?难道C++和C的底层原理不同?

请各路大神指教,谢谢。
...全文
247 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
赵4老师 2013-12-02
  • 打赏
  • 举报
回复
计算机组成原理→DOS命令→汇编语言→C语言(不包括C++)、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言(包括C++)、架构…… 对学习编程者的忠告: 眼过千遍不如手过一遍! 书看千行不如手敲一行! 手敲千行不如单步一行! 单步源代码千行不如单步对应汇编一行! 单步类的实例“构造”或“复制”或“作为函数参数”或“作为函数返回值返回”或“参加各种运算”或“退出作用域”的语句对应的汇编代码几步后,就会来到该类的“构造函数”或“复制构造函数”或“运算符重载”或“析构函数”对应的C/C++源代码处。 VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。 对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。 (Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
王嗣钧 2013-12-01
  • 打赏
  • 举报
回复
引用 11 楼 Adol1111 的回复:
[quote=引用 8 楼 wsj998689aa 的回复:] 那为何,必须至少先为对象指针q赋值为NULL呢? 既然函数地址已经是固定的了,为何我q是野指针的时候,就不能调用Func()函数了?
那个报错不是语法的问题,是C++编译器不允许直接使用未初始化的变量。当然有些情况下编译器也无法处理这个问题,比如:
int i;
cin>>i;//你故意输入错误格式,比如字符,导致i仍未初始化,但是i却可以使用了
编译器是为了用户考虑,避免你犯这种低级错误之后,找不到是哪里的问题。[/quote] 你对!还很详细,3Q
王嗣钧 2013-12-01
  • 打赏
  • 举报
回复
引用 10 楼 tigertianx 的回复:
[quote=引用 8 楼 wsj998689aa 的回复:] 那为何,必须至少先为对象指针q赋值为NULL呢? 既然函数地址已经是固定的了,为何我q是野指针的时候,就不能调用Func()函数了?
楼主有没有在出现错误之后继续执行程序呢,若继续执行也会出现Func()的调用结果,和将q赋值为null的输出结果是一样的,也就是说出现错误,只是编译器要检查p又没定义,至于p指向的A对象存不存在并不重要,至于原因,上面讲了很多。[/quote] 你对!3Q
Adol1111 2013-11-29
  • 打赏
  • 举报
回复
这个问题属于C++的对象模型问题,其实这个问题并不是那么简单的。如果感兴趣的话可以看看Lippman的杰作《 深度探索C++对象模型》(Inside The C++ Object Model)里面解释的很清楚了。 简单的说C++的对象模型中只有成员数据,而没有成员函数,成员函数是用一个函数表来维护的,里面有一个用来查找的函数指针。你可以在VS下或gcc中打印一下这个类的结构,就可以证实了。简单的说,函数的地址其实已经固定了,只要你这个指针类型仍然是这个类,就可以直接访问这个函数,而不需要管是否实例化(指针会自己调用类内部的函数表寻找成员函数地址)
Uron 2013-11-29
  • 打赏
  • 举报
回复
类中定义点成员变量试试看。
晓敬 2013-11-29
  • 打赏
  • 举报
回复
代码好难看....
w195438178 2013-11-29
  • 打赏
  • 举报
回复
q->Func(); 这是方法调用啊 只要q是A的对象,就肯定会输出那样的结果
AndyStevens 2013-11-29
  • 打赏
  • 举报
回复
不是未定义行为,Func()里没有用到非静态的成员变量,也就是跟本不需要用到this指针,所以你完全可以这样调用
((A*)0)->Func()
j8daxue 2013-11-29
  • 打赏
  • 举报
回复
又是老问题, 建议多看看CSDN上一些历史帖子再发 http://bbs.csdn.net/topics/390626644 http://bbs.csdn.net/topics/390274839
可乐崽 2013-11-29
  • 打赏
  • 举报
回复
未定义行为,能输出完全是靠运气,你在A *q;后面再定义几个其他变量,估计会导致出错了,这个看编译器的
Adol1111 2013-11-29
  • 打赏
  • 举报
回复
引用 8 楼 wsj998689aa 的回复:
那为何,必须至少先为对象指针q赋值为NULL呢? 既然函数地址已经是固定的了,为何我q是野指针的时候,就不能调用Func()函数了?
那个报错不是语法的问题,是C++编译器不允许直接使用未初始化的变量。当然有些情况下编译器也无法处理这个问题,比如:
int i;
cin>>i;//你故意输入错误格式,比如字符,导致i仍未初始化,但是i却可以使用了
编译器是为了用户考虑,避免你犯这种低级错误之后,找不到是哪里的问题。
tigertianx 2013-11-29
  • 打赏
  • 举报
回复
引用 8 楼 wsj998689aa 的回复:
那为何,必须至少先为对象指针q赋值为NULL呢? 既然函数地址已经是固定的了,为何我q是野指针的时候,就不能调用Func()函数了?
楼主有没有在出现错误之后继续执行程序呢,若继续执行也会出现Func()的调用结果,和将q赋值为null的输出结果是一样的,也就是说出现错误,只是编译器要检查p又没定义,至于p指向的A对象存不存在并不重要,至于原因,上面讲了很多。
dllg1988 2013-11-29
  • 打赏
  • 举报
回复
不是很明显么,使用的变量没有初始化,VS报错了。 比如这样

int GetX()
{
  int X;
  return X;
}
int n = GetX();
如果你要问为什么我不初始化编译器会弹框报错,我只能说这应该是编译器规定的吧,记得以前VC6.0好像不会,那时候还经常因为变量没赋值导致结果不对调试了半天。
王嗣钧 2013-11-29
  • 打赏
  • 举报
回复
那为何,必须至少先为对象指针q赋值为NULL呢? 既然函数地址已经是固定的了,为何我q是野指针的时候,就不能调用Func()函数了?

64,642

社区成员

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

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