从 scanf 读取 C 样式字符串时出现分段错误
Posted
技术标签:
【中文标题】从 scanf 读取 C 样式字符串时出现分段错误【英文标题】:Segmentation fault when reading C-style string from scanf 【发布时间】:2014-02-27 19:04:01 【问题描述】:我有以下简单代码:
#include <cstdio>
#include <queue>
#include <iostream>
struct Pacient
int ill_state;
int ev_num;
bool operator==(const Pacient& other) const
return ill_state == other.ill_state && ev_num == other.ev_num;
bool operator<(const Pacient& other) const
return (ill_state < other.ill_state) || (ill_state == other.ill_state && ev_num > other.ev_num); // má menšiu prioritu, ak čaká kratšie (vyššie číslo na kartičke pri vstupe do ambulancie
bool operator>(const Pacient& other) const
return (ill_state > other.ill_state) || (ill_state == other.ill_state && ev_num < other.ev_num);
;
int main()
char* ccmd;
std::priority_queue<Pacient> ps;
int ev_num, ill_state;
while (std::scanf("%s", ccmd))
std::string cmd(ccmd);
if (cmd == "dalsi")
if (ps.empty())
std::printf("-1\n");
else
std::printf("%d\n", ps.top().ev_num);
ps.pop();
else if (cmd == "pacient")
std::scanf("%d%d\n", &ev_num, &ill_state);
Pacient new_ps;
new_ps.ev_num = ev_num;
new_ps.ill_state = ill_state;
ps.push(new_ps);
else if (cmd == "koniec")
break;
return 0;
编译并输入一些内容到标准输入后,我有以下段错误:
Program received signal SIGSEGV, Segmentation fault.
__strlen_sse2_pminub () at ../sysdeps/x86_64/multiarch/strlen-sse2-pminub.S:38
38 ../sysdeps/x86_64/multiarch/strlen-sse2-pminub.S: No such file or directory.
我使用的是 Ubuntu 13.10 64 位。 有人可以解释一下,是什么导致了这个问题?
注意:我使用的是 scanf 而不是 cin,因为我有使用 scanf、printf 而不是 cin、cout 的具体说明(来自学校)。否则我不会使用它。
【问题讨论】:
当您使用“%s”时,scanf
需要 char *
。也就是说,使用std::string
和operator>>
或std::getline
。
@Aashish 是的,我可以,但我对此代码有使用 scanf 和 printf 的具体说明。
@chris 我已经在使用它了。
你的标题完全不符合标准:你不是使用scanf
读入std::string
,你正试图读入char *
,是一个 c 风格的字符串.
@crashmstr 谢谢,已解决。
【参考方案1】:
声明一些存储空间供scanf
写入:
char ccmd[1000];
否则,*ccmd
是一个随机指针,(可能)没有足够的存储空间来写入要写入的字符。请注意,scanf
不会对该空间进行间接处理。
另外,ccmd
已经是一个指针,所以不需要额外的&
(地址):
std::scanf("%s", ccmd)
【讨论】:
防止堆栈溢出:std::scanf("%999s", ccmd)
@MaximYegorushkin:已更新为地址(更优雅一些)。
您确定*
允许您指定最大字段宽度吗?此外,%s
的字段宽度不应包含\0
的空格,即sizeof ccmd - 1
。
@MaximYegorushkin:哦,你说的很对。已收回。
@wallyk 我希望它确实允许这样做(。【参考方案2】:
你不需要使用std::scanf
来读取字符串,你可以使用安全的C++:
std::string cmd;
while(std::cin >> cmd)
// ...
【讨论】:
我有具体的指令(来自学校)在这段代码中使用 scanf 和 printf。 @Benji 他们要求你使用 C++ 和 C 风格的输入/输出,这很奇怪。 听说是因为这个程序的输入会很大,scanf应该比cin快。 @Benji 哦不,浪费了几毫秒!说真的,他们应该教你正确的惯用 C++ 代码,然后担心性能。 @Benji 请注意scanf
系列函数很容易将堆栈溢出引入您的应用程序,就像scanf("%s")
肯定会这样做,因为您没有指定要读取的最大字符串长度。换句话说,scanf
系列函数更难正确使用。【参考方案3】:
你没有初始化指针ccmd
char* ccmd;
并且没有在你要读取字符串的地方分配内存
while (std::scanf("%s", &ccmd))
所以程序有未定义的行为。
完全不清楚为什么您不想将运算符 >> 与流 std::cin
一起使用,而是使用不安全的函数 scanf。
您还需要包含标题<string>
。否则,如果您尝试使用其他编译器编译您的程序,您可能会收到错误消息。
正如 @Maxim Yegorushkin 所指出的,即使函数 scanf 的调用也不正确。而不是
std::scanf("%s", &ccmd)
应该有
std::scanf("%s", ccmd)
【讨论】:
请您说得更具体些吗?例如。究竟如何初始化该指针? @Benji 它必须引用分配的内存,您将在其中读取字符串。现在这个指针有一些任意值了。 您将char**
转换为%s
格式,这是不正确的。
但是你可以做sscanf("%ms", &ccmd)
,它会在使用glibc时为你分配一个缓冲区。这是一个非标准的扩展。以上是关于从 scanf 读取 C 样式字符串时出现分段错误的主要内容,如果未能解决你的问题,请参考以下文章