0

Trying to create a program that reads words from a text file and outputs 20 password combinations with 4 words in each and with certain conditions such as no punctuation in word, no digits, and no characters other than the first may be uppercase. However, I am getting an exception thrown at ispunct(b[i]) and I think it has to do with the changing sizes of the words but I am not sure. Any help would be appreciated as my knowledge with C++ is rudimentary at best.

#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;
}
Henry Ecker
  • 34,399
  • 18
  • 41
  • 57
  • 2
    Clearly, telling us *what* exception you get would be helpful... – Marcus Müller Nov 20 '21 at 21:26
  • All it says is that the program has triggered a breakpoint at ispunct(b[i]) when I try to run it. – user17466917 Nov 20 '21 at 21:31
  • In `acceptWord`, the second loop starts with its index at `b.length()`; that's not a valid index into `b`, so `isupper(b[I])` is probably the culprit. – Pete Becker Nov 20 '21 at 21:36
  • 1
    This doesn't address the question, but get in the habit of initializing objects with meaningful values rather than default-initializing them and immediately overwriting the default values. In this case, that means changing `fstream file; ... file.open(filename.c_str());` to `... fstream file(filename.c_str());` or, even better, `... fstream file(filename);`. – Pete Becker Nov 20 '21 at 21:38
  • 1
    What word is in `b` when the error occurs? [`ispunct`](https://en.cppreference.com/w/c/string/byte/ispunct) does not support signed characters with negative values (other than EOF), so if there is an extended-ASCII character in your string, and the `char` type is signed with your compiler, you can run into problems. – 1201ProgramAlarm Nov 20 '21 at 21:40
  • 1
    "triggers a breakpoint": do you have any breakpoints set? – Marcus Müller Nov 20 '21 at 21:45
  • Q: What word is in b when the error occurs? Q: "triggers a breakpoint": do you have any breakpoints set? Q: What C++ compiler/IDE are you using? Q: (most important): *WHAT WAS THE ERROR MESSAGE*? Surely there was *some* error message printed *somewhere* when the fault occurred. Look carefully, and try to find it. – paulsm4 Dec 26 '21 at 21:08
  • Solving an individual's problem is a side effect of the mission of Stack Overflow which is to "build a library of detailed, high-quality answers to every question about programming" ([tour](/tour)). For this reason, your question should remain visible so it can be helpful to future visitors. If an existing answer solves your problem you may choose to [accept an answer](https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work). Otherwise, you can post your own answer and accept that instead. Either way, please do not remove meaningful content from your post. – Henry Ecker Jan 02 '22 at 00:31

2 Answers2

0

Your bug is here:

    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;
            }
        }

BUT... There are some questions anyone who has to maintain this code in the future will be asking (to put it gently):

Why do your check the syntax of a word starting from the end? There is nothing special in there that demands this kind of complexity.

What is the purpose of parameter a? It is passed by value, so the statement a = b; has no effect. Even if it waas passed by reference, it would have no real purpose... The caller already knows the string it wants validated.

For some reason, words that start with a non-alphabetic character pass the validaton with flying colors.... I doubt that's what you wanted.

Just for illustration, here is a sample validation for tokens that must start with an alpha character, and then contain only alphanumeric characters. I.e.: "hello", "is42", etc...

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;
} 

This is only a suggestion. People are used to think in a forward manner. It is much easier to reason that way, and that keeps the bugs away.

Michaël Roy
  • 6,338
  • 1
  • 15
  • 19
0

There are a number of fundamental errors in your code (and your reasoning) that make it seem like your textbook isn't working out so well for you. For example, your diagnosis is only half correct:

I think it has to do with the changing sizes of the words but I am not sure

That's just a guess. In fact, if we stop being unguided and instead form guesses from the manual for ispunct we find that it accepts an int argument that is expected to be an unsigned char value. As we can see from similar previous questions, assertions are commonly raised for negative char values such as those glyphs from non-English languages.

If anything, you need a book such as K&R2e so you establish common idioms that work around these issues rather than wasting months trying to guess why your code throws assertions from within the C standard library, and only getting wrong answers from others who also don't read manuals or textbooks or the like. I strongly recommend less guessing and more reading and doing exercises from your textbook.

autistic
  • 1
  • 3
  • 35
  • 80
  • Thank you! I have been able to solve my issue since posting this from your guys' helpful comments/answers. The problem did in fact come from unsigned char issues and I had to use a different function than ispunct(). – user17466917 Jan 02 '22 at 00:39
  • @user17466917 no, you just need the idiomatic cast from the question & answer I liked to: `isalpha((unsigned char)value)` except your function is `ispunct` instead. – autistic Jan 03 '22 at 21:25