C++ 类类型 含指针成员的浅拷贝问题

Sherlock_c787 2018-11-30 05:38:13
如题,小弟最近初次学习到了类的定义章节,今天下午在敲一个程序的时候,出现一个问题,单步调试没能自己解决,来问问各位大侠。
我定义了一个构造函数如下:

Student::Student()
{

name = new char[30];
if(name!=NULL)
{
strcpy(name,"c++ class study");
}
}


这里用到了动态数组,主函数中分别定义了两个Student类对象:s1、s2, s2用s1进行初始化,之后再改变s2的值,s1会随着s2的值改变,这是因为使用了默认的拷贝函数,因此s2改变时,s1也会改变。
主函数代码及输出截图如下


int main()
{
Student s1,s2(s1);
cout<<"输出s1"<<endl;
s1.outputName();
cout<<"输出s2"<<endl;
s2.outputName();
s2.setName("codeblock");
cout<<"输出s2"<<endl;
s2.outputName();
cout<<"输出s1"<<endl;
s1.outputName();
return 0;
}



现在出现的问题是,我将 上述代码中的 name = new char[30];改为 char xx[30];name = xx;
也是向name传递了地址,然而此时只能输出一个n,如下图所示:


这种错误该如何理解,拜托各位大侠帮忙看看
...全文
247 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
Sherlock_c787 2018-12-01
  • 打赏
  • 举报
回复
引用 13 楼 赵4老师 的回复:
VMMap 是进程虚拟和物理内存分析实用工具。http://technet.microsoft.com/zh-cn/sysinternals/dd535533
十分感谢您推荐的工具和方法,我在尝试着去用。
赵4老师 2018-12-01
  • 打赏
  • 举报
回复
栈中的变量通常包括函数参数和函数里声明的临时变量。 栈中的基本变量退出其作用域时,没有谁执行一段代码去释放/销毁/析构它所占用的内存,仅仅是没人再去理会的留在当前栈顶上方的若干遗留下来可被后续压栈操作覆盖的无用数据而已。 而栈中的类变量退出其作用域时,会自动执行其析构函数,…… 计算机组成原理→DOS命令→汇编语言→C语言(不包括C++)、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言(包括C++)、架构…… 对学习编程者的忠告: 多用小脑和手,少用大脑、眼睛和嘴,会更快地学会编程! 眼过千遍不如手过一遍! 书看千行不如手敲一行! 手敲千行不如单步一行! 单步源代码千行不如单步Debug版对应汇编一行! 单步Debug版对应汇编千行不如单步Release版对应汇编一行! 不会单步Release版对应汇编?在你想单步Release版C/C++代码片断的前面临时加一句DebugBreak();重建所有,然后在IDE中运行。(一般人我不告诉他!单步类的实例“构造”或“复制”或“作为函数参数”或“作为函数返回值返回”或“参加各种运算”或“退出作用域”的语句对应的汇编代码几步后,就会来到该类的“构造函数”或“复制构造函数”或“运算符重载”或“析构函数”对应的C/C++源代码处。 VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。 对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。 《深度探索C++对象模型》 《C++反汇编与逆向分析技术揭秘》
赵4老师 2018-12-01
  • 打赏
  • 举报
回复
VMMap 是进程虚拟和物理内存分析实用工具。http://technet.microsoft.com/zh-cn/sysinternals/dd535533
mirro 2018-12-01
  • 打赏
  • 举报
回复
浅拷贝就是拷贝数值,不改变地址
Sherlock_c787 2018-11-30
  • 打赏
  • 举报
回复
引用 11 楼 _sseakom 的回复:
[quote=引用 4 楼 Sherlock_c787 的回复:]
我可能没表达清楚。浅拷贝我是能理解的。我无法理解的是在上述构造函数中

name = new char[30];



char xx[30];
name = xx;//或者 name = &xx;

这两种写法为什么运行结果不同
new 是在堆上分配内存,没有手动释放这片内存或者进程没有结束。那么这片内存一直属于当前进程。而不使用 new 是在栈上分配内存,在当前函数结束就将内存归还系统,进程不再有这片内存的使用权。[/quote]

十分感谢你的回复,我明白了,结帖答案属于你。
看到你也是学生,可否加你好友。
李财日记 2018-11-30
  • 打赏
  • 举报
回复
引用 4 楼 Sherlock_c787 的回复:
我可能没表达清楚。浅拷贝我是能理解的。我无法理解的是在上述构造函数中

name = new char[30];



char xx[30];
name = xx;//或者 name = &xx;

这两种写法为什么运行结果不同
new 是在堆上分配内存,没有手动释放这片内存或者进程没有结束。那么这片内存一直属于当前进程。而不使用 new 是在栈上分配内存,在当前函数结束就将内存归还系统,进程不再有这片内存的使用权。
李财日记 2018-11-30
  • 打赏
  • 举报
回复
引用 8 楼 Sherlock_c787 的回复:
@zjq9931 如你所述,我改成你的写法,输出就正常了。

不过我还有一点不明白,我那种定义方法。在单步调试过程中,我发现在执行第一个cout语句前,即主函数中

cout<<"输出s1"<<endl;

在运行这条语句之前s1、s2中的值确实变成了 "c++ class study",在执行cout后,s1、s2突然就没了,然后还有可能会卡死,这是为什么呢?
因为char xx[30]这片内存在构造函数内时才属于当前进程,当离开构造函数,这片内存归还给系统,不在属于当前进程。再访问这片内存将是非法访问。
Sherlock_c787 2018-11-30
  • 打赏
  • 举报
回复
我刚才又单步调试了一遍,在第一条声明语句处加断点,调试结果如下

这是执行完语句语句1后,即将执行语句2时,s1、s2的状态




这是继续执行,s1、s2突然消失时的屏幕截屏,最下面蓝色划线部分是codeblocks 输出的调试信息:


Sherlock_c787 2018-11-30
  • 打赏
  • 举报
回复
@zjq9931 如你所述,我改成你的写法,输出就正常了。 不过我还有一点不明白,我那种定义方法。在单步调试过程中,我发现在执行第一个cout语句前,即主函数中 cout<<"输出s1"<<endl; 在运行这条语句之前s1、s2中的值确实变成了 "c++ class study",在执行cout后,s1、s2突然就没了,然后还有可能会卡死,这是为什么呢?
  • 打赏
  • 举报
回复
局部变量的问题,给了你正确的错误的对比。

#include <iostream>
#include <string.h>

using namespace std;

class Student
{
public:
	Student();
	void setName(char *n){};
	void outputName()
	{
		cout << "name_part  " << name_part << endl;
		cout << "name_mem   " << name_mem << endl;
	};
private:
	char *name_part;
	char *name_mem;
	char m_xx[30];
};

Student::Student()
{
	char xx[30];	//局部变量,初始化结束后就销毁了,所以初始化完成后name指向的是被销毁的内存
	name_part = xx;
	name_mem = m_xx;
	//    name = new char[30];
	if(name_part!=NULL &&name_mem!=NULL)
	{
		strcpy(name_part,"c++ class study");
		strcpy(name_mem,"c++ class study");
	}
}

int main()
{
	Student s1,s2(s1);
	cout<<"输出s1"<<endl;
	s1.outputName();
	cout<<"输出s2"<<endl;
	s2.outputName();
	s2.setName("codeblock");
	cout<<"输出s2"<<endl;
	s2.outputName();
	cout<<"输出s1"<<endl;
	s1.outputName();
	return 0;
}
Sherlock_c787 2018-11-30
  • 打赏
  • 举报
回复
十分抱歉,第二张图片我上传错了。 正确的是
AlbertS 2018-11-30
  • 打赏
  • 举报
回复
只能输出一个n是什么意思,没有看到两次图片有什么不同啊
Sherlock_c787 2018-11-30
  • 打赏
  • 举报
回复
我可能没表达清楚。浅拷贝我是能理解的。我无法理解的是在上述构造函数中 name = new char[30]; 和 char xx[30]; name = xx;//或者 name = &xx; 这两种写法为什么运行结果不同
云山大侠 2018-11-30
  • 打赏
  • 举报
回复
指针本质上也只是一个数据类型,我们常说指针保存的是地址,浅拷贝就是拷贝的这个地址,并不会重新开辟一段空间。
Sherlock_c787 2018-11-30
  • 打赏
  • 举报
回复
引用 1 楼 zjq9931 的回复:
name = xx; name是什么类型的?XX的内容是什么?
1.name时字符指针,作为类的成员变量; 定义如下:

class Student
{
public:
    Student();
    void setName(char *n);
    void outputName();
private:
    char *name;
};
2.xx作为数组名,理应该会把地址传给name

Student::Student()
{
    char xx[30];
    name = xx;
//    name = new char[30];
    if(name!=NULL)
    {
        strcpy(name,"c++ class study");
    }
}
  • 打赏
  • 举报
回复
name = xx; name是什么类型的?XX的内容是什么?

65,210

社区成员

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

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