使用 c++ 标准库中的堆栈反转句子的单词

Reverse words of a sentence using stack from c++ standard library

我正在尝试使用 c++ 标准库中的 std::stack 来反转每个句子的单词。

输入文件内容为:

3
foobar
this is a test
all your base

所以答案应该是:

foobar
test a is this
base your all

但是答案是:

foobar
test test test test
base base base base

我不明白为什么。以下是代码:

#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <cstring>
#include <stack>

using namespace std;

int main() {
  FILE *fp, *fpo;
  fp = fopen("test.in", "r");
  int tests;
  fscanf(fp, "%d", &tests);
  char ch;
  fscanf(fp, "%c", &ch); 
  for (int i = 0; i < tests; i++) {
    char *letters;
    letters = (char*)calloc(1000, sizeof(char));
    stack <char*> words;
    fscanf(fp, "%s", letters); fscanf(fp, "%c", &ch);

    while (ch != '\n' && ch != EOF) {
      words.push(letters); printf(" %s", words.top());
      fscanf(fp, "%s", letters); fscanf(fp, "%c", &ch);
    }
    words.push(letters); printf(" %s", words.top());
    printf("  --  ");
    while (!words.empty()) {
      printf(" %s", words.top());
      words.pop();
    }
    printf("\n");
    free(letters);
  }
  fclose(fp);  
}

请不要以这种方式混合使用 CC++。它几乎不可读。一些准则:

  • 不要对字符串使用原始字符数组,请使用:std::string
  • 使用 C++ 工具读取行:std::getline
  • 要使用之前的函数,您需要使用 C++ 文件流 std::ifstream .
  • 阅读一行后,您可以使用 std::stringstreamstd::string 从该行中提取每个单词。
  • 然后您可以将每个单词压入堆栈,然后弹出以反转整个字符串。

正如其他人在评论中所说,您的代码不好:

  • 您使用高级 c++ 堆栈,但只在其中存储 char *,而您可以使用 std::string
  • 当您可以使用 C++ 库时,您将 C 标准库用于 IO(std::stringstream 在这里会有所帮助)
  • 你的输入是面向行的,你使用 fscanf 而不是 fgets (或者更好的 getline 因为你的问题被标记为 c++)

但您的错误的实际原因很简单,就是您在堆栈中存储了一个 char *,它始终指向同一个字符数组,而不是为每个单词分配一个新数组。所以:

  • 你在字母中找到一个词
  • 你只存储字母的地址而不是它的内容
  • 你用下一个单词擦掉字母

并且您的堆栈包含字母地址的 n 个副本,每个字母都指向相同的最后一个单词数组。

您应该:

  • 使用 malloc 或 strdup 为每个单词分配一个新数组(C 方式)——并持续释放每个分配的数组
  • 使用 std::string,最好使用 stack<string>(C++ 方式)让 C++ 库为您管理分配和释放。

在 C++ 程序中使用 C 库函数可能有充分的理由(已经使用 C 代码的程序中的大小或性能限制,分配这样做),但除非是这种情况,否则高级 C++库比低级别的 C 库更易于使用,出错风险更小。

TL/DR:如果您使用了 C++ 库(getline、std::string、iostream、stringstream、stack),库本身就可以避免您出现该错误。