【问题标题】:Exception thrown at ispunct() when reading words from a text file - C++从文本文件中读取单词时在 ispunct() 引发异常 - C++
【发布时间】:2021-11-20 21:22:09
【问题描述】:

尝试创建一个程序,该程序从文本文件中读取单词并输出 20 个密码组合,每个密码组合 4 个单词,并且具有某些条件,例如单词中没有标点符号,没有数字,并且除第一个以外的字符不能为大写。但是,我在 ispunct(b[i]) 处抛出异常,我认为这与单词大小的变化有关,但我不确定。任何帮助都将不胜感激,因为我对 C++ 的了解充其量只是初级知识。

#include <iostream>
#include <fstream>
#include <vector>
using namespace std;

bool acceptWord(string a, string b) {
    
    if (b.length() > 3) {
        for (int i = b.length() - 1; i; --i) {
            if (ispunct(b[i])) {
                return false;
            }

            if (isdigit(b[i])) {
                return false;
            }
        }
        if (isalpha(b[0]) && isupper(b[0])) {
            for (int i = b.length(); i; --i) {
                if (isupper(b[i])) {
                    return false;
                }
            }
        }
        a = b;
        return true;
    }

    else {
        return false;
    }
}

int main()
{
  
   
    fstream file;
    string word, filename;
    vector<string> tokens;
    int random = rand() % 81;

    
    filename = "input.txt";

    
    file.open(filename.c_str());

    if (!file.is_open()) {
        cout << "File not found" << endl;
        exit(1);
    }

    
    while (file >> word)
    {
        string token = "";
        if (acceptWord(token, word)) {
            for (int i = 0; i < 80; ++i) {
                tokens[i] = token;
            }
        }

        for (int i = 0; i < 20; ++i) {
            cout << tokens[random] + " " + tokens[random] + " " + tokens[random] + " " + tokens[random] + "1" << endl;
        }
    }

    return 0;
}

【问题讨论】:

  • 很明显,告诉我们您遇到的什么异常会很有帮助...
  • 它只是说,当我尝试运行程序时,它在 ispunct(b[i]) 处触发了断点。
  • 这并没有解决问题,而是养成使用有意义的值初始化对象的习惯,而不是默认初始化它们并立即覆盖默认值。在这种情况下,这意味着将fstream file; ... file.open(filename.c_str()); 更改为... fstream file(filename.c_str());,或者更好的是... fstream file(filename);
  • 出现错误时b中的单词是什么? ispunct 不支持带负值的带符号字符(EOF 除外),因此如果您的字符串中有扩展 ASCII 字符,并且您的编译器对 char 类型进行了签名,您可能会遇到问题。跨度>
  • “触发断点”:你有设置断点吗?

标签: c++


【解决方案1】:

您的代码(以及您的推理)中存在许多基本错误,这使得您的教科书看起来不太适合您。例如,您的诊断只对了一半:

我认为这与单词大小的变化有关,但我不确定

这只是一个猜测。事实上,如果我们不再不受指导,而是从手册中对ispunct 进行猜测,我们会发现它接受了一个int 参数,该参数预计是一个unsigned char 值。从之前的类似问题中我们可以看到,assertions are commonly raised for negative char values such as those glyphs from non-English languages

如果有的话,您需要一本诸如 K&R2e 之类的书,这样您就可以建立解决这些问题的常用习语,而不是浪费数月时间去猜测为什么您的代码会从 C 标准库中抛出断言,而只会从其他人那里得到错误的答案也不要阅读手册或教科书等。我强烈建议您减少猜测,多阅读和练习您的教科书。

【讨论】:

  • 谢谢!自从从你们有用的 cmets/answers 发布此问题以来,我已经能够解决我的问题。问题确实来自 unsigned char 问题,我不得不使用与 ispunct() 不同的函数。
  • @user17466917 不,你只需要我喜欢的问题和答案中的惯用演员:isalpha((unsigned char)value),除了你的函数是ispunct
【解决方案2】:

你的错误在这里:

    if (isalpha(b[0]) && isupper(b[0])) {
        for (int i = b.length(); i; --i) {  // BUG!!! Should read b.length() - 1
            if (isupper(b[i])) {
                return false;
            }
        }

但是...任何人都必须在 未来会问(委婉地说):

为什么要从末尾开始检查单词的语法?没有什么特别之处需要这种复杂性。

参数a的作用是什么?它是按值传递的,所以语句a = b; 没有任何作用。即使它是通过引用传递的,它也没有真正的目的......调用者已经知道它想要验证的字符串。

出于某种原因,以非字母字符开头的单词通过了验证,并且非常成功......我怀疑这就是你想要的。

只是为了说明,这里是一个必须以字母字符开头,然后只包含字母数字字符的标记的示例验证。即:“你好”、“is42”等......

bool is_token(const std::string& s)  // Pass strings by reference.
{
    if (s.empty())            // check length
        return false;

    if (!isalpha(s[0]))       // first char alpha ?
       return false;

    for (size_t i = 1; i < s.length(); ++i)
         if (!isalnum(s[i]))  // subsequent chars all alnum ?
             return false;

    return true;
} 

这只是一个建议。人们习惯于向前思考。以这种方式推理要容易得多,并且可以避免错误。

【讨论】:

    猜你喜欢
    • 2012-10-07
    • 1970-01-01
    • 1970-01-01
    • 2011-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-06
    相关资源
    最近更新 更多