【问题标题】:Segmentation fault when reading C-style string from scanf从 scanf 读取 C 样式字符串时出现分段错误
【发布时间】:2023-03-24 16:28: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::stringoperator&gt;&gt;std::getline
  • @Aashish 是的,我可以,但我对此代码有使用 scanf 和 printf 的具体说明。
  • @chris 我已经在使用它了。
  • 你的标题完全不符合标准:你不是使用scanf读入std::string,你正试图读入char *是一个 c 风格的字符串.
  • @crashmstr 谢谢,已解决。

标签: c++


【解决方案1】:

声明一些存储空间供scanf写入:

char ccmd[1000];

否则,*ccmd 是一个随机指针,(可能)没有足够的存储空间来写入要写入的字符。请注意,scanf 不会对该空间进行间接处理。

另外,ccmd 已经是一个指针,所以不需要额外的&amp;(地址):

 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。

您还需要包含标题&lt;string&gt;。否则,如果您尝试使用其他编译器编译您的程序,您可能会收到错误消息。

正如 @Maxim Yegorushkin 所指出的,即使函数 scanf 的调用也不正确。而不是

std::scanf("%s", &ccmd)

应该有

std::scanf("%s", ccmd)

【讨论】:

  • 请您说得更具体些吗?例如。究竟如何初始化该指针?
  • @Benji 它必须引用分配的内存,您将在其中读取字符串。现在这个指针有一些任意值了。
  • 您将char** 转换为%s 格式,这是不正确的。
  • 但是你可以做sscanf("%ms", &amp;ccmd),它会在使用glibc时为你分配一个缓冲区。这是一个非标准的扩展。
猜你喜欢
  • 1970-01-01
  • 2015-06-08
  • 1970-01-01
  • 2017-08-01
  • 2021-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-16
相关资源
最近更新 更多