#include"iostream"
using namespace std;
class xxx
{
public:
char **a;
xxx();
~xxx();
};
xxx :: xxx()
{
a=new char*;
*a="10";
cout<<endl<<*a; // works fine
cout<<"Enter name:";
cin>>*a; // segmentation fault??
}
xxx :: ~xxx()
{
delete a;
}
main()
{
xxx x;
cout<<*x.a;
}
为什么我不能使用cin更改名称字段? 当我调用构造函数时,它将值赋给变量但在编辑它时显示以下错误: 程序已停止工作。 方法也出现了同样的问题。我错过了什么。
答案 0 :(得分:1)
在xxx
的构造函数中,*a
被初始化,因此它指向字符串文字的(第一个字符)。
语句cin >> *a
然后尝试修改字符串文字。这给出了未定义的行为。您描述的症状是未定义行为的一种可能结果。
一个更简单的例子,没有类xxx
的模糊细节将是
#include <iostream>
int main()
{
char **a = new char *;
*a = "10";
std::cout << std::endl << *a; // works fine
std::cout << "Enter name:";
std::cin >> *a; // undefined behaviour here
}
尽管与任何形式的未定义行为一样,但不能保证特定的结果/症状。
您可能会尝试调高编译器的警告级别,结果可能是语句*a = "10"
中有关可疑转换的警告(例如将某些内容const
转换为const
) 。大多数现代C ++编译器(以及相当多的旧编译器)被配置为默认情况下不会警告这些事情,但可以配置为发出此类警告。打开编译器警告并注意它们有助于减少此类未定义的行为。
答案 1 :(得分:1)
就此而言,代码的问题非常简单。在你的构造函数中:
xxx :: xxx()
{
a=new char*;
*a="10";
cout<<endl<<*a; // works fine
cout<<"Enter name:";
cin>>*a; // segmentation fault??
}
您正在尝试读入已初始化的字符串文字,然后导致Undefined Behavior。如果你想做这样的事情,并且你正在使用C ++,你应该切换到std::string
,这将使你的代码更简单,而无需处理原始字符串文字和指针,如下所示:
#include <iostream>
#include <string>
class xxx
{
public:
std::string a;
xxx();
~xxx();
};
xxx :: xxx()
{
a = "10";
std::cout << std::endl << a;
std::cout << "Enter name:";
std::cin >> a;
}
int main()
{
xxx x;
std::cout<< x.a;
}
在此示例中,a=new char*;
和delete a;
等代码与析构函数本身一起被删除。我所做的其他更改包括将您的代码更改为不使用using namespace std;
(Read为何被视为不良做法)并将int
的返回类型用于main()
。此外,我还为<string>
添加了std::string
库。最后,作为另一个建议,由于std::cin
只会读取传递给它的第一个单词并忽略其余单词,如果您想要读取全名,那么您可以使用getline()
如下:
//std::cin >> a; becomes...
getline(std::cin, a);
答案 2 :(得分:0)
您的代码中的问题可以最小化到此无效代码片段:
char *p = "foobar"; // should not compile, but would on many compilers due to backward compatibility
p[0] = 'F';
问题是你正在尝试修改字符串文字所在的内存,即UB。