-3

I'm new to C++, and I am having trouble doing this exercise given by the lynda.com instructor.

I am supposed to create a txt file that has lines of words in it. And we read it using ifstream line by line and store the strings into a string array. (Note: This assignment has other parts which are irrelevant to my question.)

So, I have three questions:

  1. When I am running the solutions given by the instructor, though it compiles and runs, it has the EXC_BAD_ACCESS.

    Here is her code:

    #include <iostream>
    #include <cstdlib>
    #include <ctime>
    #include <cstring>
    #include <fstream>
    using namespace std;
    
    string getRandomReply(string [], int);
    
    int main()
    {
        ifstream inputfile;
    
        // Declare an input file
        inputfile.open("replies.txt", ios::in);
    
        char answer[30];
        string answers[20];
        int pos = 0;
    
        // Read from the file until end of file (eof)
        while (!inputfile.eof())
        {
            inputfile.getline(answer, 30);
            answers[pos] = answer;
            pos++;
        }
    
        cout << "Think of a question for the fortune teller, "
        "\npress enter for the answer " << endl;
        cin.ignore();
        cout << getRandomReply(answers, 20) << endl;
        return 0;
    
    }
    string getRandomReply(string replies[], int size)
    {
        srand(time(0));
        int randomNum = rand()%20;
        return replies[randomNum];
    }
    
  2. Even if this program is functional, I don't understand the need to create char [] and to assign values into the string array through it.

  3. I've written my own version of the code while I was doing the exercise, which compiles and runs but returns with lines of white spaces.

    #include <iostream>
    #include <cstdlib>
    #include <ctime>
    #include <cstring>
    #include <fstream>
    
    int main(int argc, const char * argv[]) {
        std::ifstream inputfile;
        inputfile.open("replies.txt", std::ios::in);
        std::string answers[20];
        int pos = 0;
    
        // Read from the file until end of file (eof)
        while (inputfile.good())
        {
            getline(inputfile, answers[pos], '\n');
            pos++;
        }
        for (int i=0; i<20; i++)
        {
            std::cout << answers[i] << std::endl;
        }
        /*
            srand(time(0));
            std::cout << "Think of a question that you would like to ask fortune teller." << std::endl;
            int ranNum = rand()%20;
            std::string answer = answers[ranNum];
            std::cout << answer << std::endl;
         */
        return 0;
    }
    
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Y.Yang
  • 13
  • 5
  • 5
    [Do not use `while(!inputfile.eof())`](https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong) – NathanOliver Aug 31 '17 at 18:53
  • If getline fails you still increment pos. You never use the calculated pos in the second loop. instead of raw array use std::vector - you can call push_back and it will grow as you read your file – Artemy Vysotsky Aug 31 '17 at 18:53
  • 2
    I believe stepping through your code line by line with the debugger and check whats going on would serve you better than asking such a question at Stack Overflow. – user0042 Aug 31 '17 at 18:55
  • @NathanOliver, even if I do change the while loop to something like while (inputfile.good), it just returns with empty white spaces. That is also my third question. – Y.Yang Aug 31 '17 at 19:01
  • @Y.Yang That is the same thing. If you read the link it will show you the right way to read from a file. – NathanOliver Aug 31 '17 at 19:02
  • @user0042 I agree that this question must be obvious if I can use a debugger to check it step by step. But as I said, I am new to programming in general. Thus the Xcode debugger's output such as this: "0x100001610 <+1600>: leaq -0x450(%rbp), %rsi" – Y.Yang Aug 31 '17 at 19:06
  • @Y.Yang Learn how to use the debugger. It's pretty intuitive to use with any decent IDE, and an essential skill for any developer. – user0042 Aug 31 '17 at 19:14
  • Prefer to use `std::vector` in your programs. Arrays require checking for overflow or accessing beyond the capacity of the array. – Thomas Matthews Aug 31 '17 at 19:40

1 Answers1

0

Eesh, I don't think I'd continue with this particular course.

In your teacher's code, I'm guessing (but can't be sure, because you haven't given the input) that your array for answers index (pos) is running off the end of the array and giving you the EXEC_BAD_ACCESS in the teacher's code.

http://www.cplusplus.com/reference/istream/istream/getline/

The failbit flag is set if the function extracts no characters, or if the delimiting character is not found once (n-1) characters have already been written to s. Note that if the character that follows those (n-1) characters in the input sequence is precisely the delimiting character, it is also extracted and the failbit flag is not set (the extracted sequence was exactly n characters long).

inputfile.getline(answer, 30) in this form will set the failbit on the ifstream if any of the questions are over 30 characters long, because it has not reached the delimiter (defaults to newline).

Without changing any of the data structures (there are better ones for this in C++), if you add something like, it may work:

// Read from the file until end of file (eof)
while (!inputfile.eof())
{
  inputfile.getline(answer, 30);
  answers[pos++] = answer;

  while (!inputfile)
  {
    inputfile.clear();
    inputfile.getline(answer, 30);
  }
}

This clears the failbit after every call to getline and attempts to finish reading the line if there were more than 30 characters. The issue is that, if the failbit gets set, the loop will run forever, because !ifstream.eof() while condition is never met. This means your pos index will increment forever and run off the end of the array.

It could also be there are more questions in the file than the fixed size array answers can store.

The comments to use the debugger are not being facetious. This is the way you figure these problems out. You need some beginner reading material on the Xcode debugger (maybe this?). For almost any beginner operations (checking the value of a variable, setting breakpoints and so on) it can all be done via the GUI and should be pretty straightforward.

Regarding your code (which is best not to mix two questions on Stack Overflow), it runs for me just fine after adding include <string> which contains the std::string and getline overload for string. However, I don't have the same input as you. Set a breakpoint inside the loop that calls getline. If you have the path wrong or something is going wrong with reading the input, you won't even enter that loop, and you'll be iterating through a bunch of empty strings and printing them out.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Josh
  • 12,602
  • 2
  • 41
  • 47