使用 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);
}
请不要以这种方式混合使用 C 和 C++。它几乎不可读。一些准则:
- 不要对字符串使用原始字符数组,请使用:std::string
- 使用 C++ 工具读取行:std::getline
- 要使用之前的函数,您需要使用 C++ 文件流 std::ifstream .
- 阅读一行后,您可以使用 std::stringstream 和
std::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),库本身就可以避免您出现该错误。
我正在尝试使用 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);
}
请不要以这种方式混合使用 C 和 C++。它几乎不可读。一些准则:
- 不要对字符串使用原始字符数组,请使用:std::string
- 使用 C++ 工具读取行:std::getline
- 要使用之前的函数,您需要使用 C++ 文件流 std::ifstream .
- 阅读一行后,您可以使用 std::stringstream 和
std::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),库本身就可以避免您出现该错误。