-3

I did not see this question already posted, or anything helpfully similar.

I'm in a 2nd semester C++ class and am only passing 5 of 10 test points. I can tell something is wrong with my try/catch setup. After scouring the internet I'm possibly more confused about the errors I'm getting:

main.cpp: In function ‘std::string FindID(std::string, std::ifstream&)’:
main.cpp:24:1: warning: control reaches end of non-void function [-Wreturn-type]
   24 | }
      | ^
main.cpp: In function ‘std::string FindName(std::string, std::ifstream&)’:
main.cpp:49:1: warning: control reaches end of non-void function [-Wreturn-type]
   49 | }
      | ^

Problem and my code below:


6.9 LAB: Student info not found

Given a program that searches for a student’s ID or name in a text file, complete the FindID() and FindName() functions. Then, insert a try/catch statement in main() to catch any exceptions thrown by FindID() or FindName(), and output the exception message. Each line in the text file contains a name and ID separated by a space.

Function FindID() has two parameters: a student's name (string) and the text file's contents (ifstream). The function FindID() returns the ID associated with the student's name if the name is in the file, otherwise, the function throws a runtime_error with the message "Student ID not found for studentName", where studentName is the name of the student.

Function FindName() has two parameters: a student's ID (string) and the text file's contents (ifstream). The function FindName() returns the name associated with the student's ID if the ID is in the file, otherwise, the function throws a runtime_error with the message "Student name not found for studentID", where studentID is the ID of the student.

The main program takes three inputs from a user: the name of a text file (string), the search option for finding the ID or name of a student (int), and the ID or name of a student (string). If the search option is 0, FindID() is invoked with the student's name as an argument. If the search option is 1, FindName() is invoked with the student's ID as an argument. The main program outputs the search result or the caught exception message.

Ex: If the input of the program is:

roster.txt 0 Reagan

and the contents of roster.txt are:

Reagan rebradshaw835
Ryley rbarber894
Peyton pstott885
Tyrese tmayo945
Caius ccharlton329

the output of the program is:

rebradshaw835

Ex: If the input of the program is:

roster.txt 0 Mcauley

the program outputs an exception message:

Student ID not found for Mcauley

Ex: If the input of the program is:

roster.txt 1 rebradshaw835

the output of the program is:

Reagan

Ex: If the input of the program is:

roster.txt 1 mpreston272

the program outputs an exception message:

Student name not found for mpreston272

my main.cpp code:

#include <string>
#include <iostream>
#include <stdexcept>
#include <fstream>
using namespace std;

string FindID(string name, ifstream &infoFS) {
   bool foundID = false;
   string input;
   infoFS >> input;
   while (infoFS) 
   {
      if (input == name)
      {
         infoFS >> input;
         return input;
      }
      else { infoFS >> input; }
   }
   if (foundID == false)  
   {
      throw name;
   }   
}

string FindName(string ID, ifstream &infoFS) {
   bool foundName = false;
   string previous;
   string input;
   infoFS >> previous;
   infoFS >> input;
   while (infoFS) 
   {
      if (input == ID)
      {
         foundName = true;
         return previous;         
      }
      else 
      { 
         previous = input;
         infoFS >> input; 
      }
   }
   if (foundName == false) 
   {
      throw ID;
   }   
}

int main() {
   int userChoice;
   string studentName;
   string studentID;
   string studentInfoFileName;
   ifstream studentInfoFS;
   
   // Read the text file name from user
   cin >> studentInfoFileName;
   
   // Open the text file
   studentInfoFS.open(studentInfoFileName);
   
   // Read search option from user. 0: FindID(), 1: FindName()
   cin >> userChoice;

   try 
   {
      if (userChoice == 0) {
         cin >> studentName;
         studentID = FindID(studentName, studentInfoFS);
         cout << studentID << endl;
      }
      else {
         cin >> studentID;
         studentName = FindName(studentID, studentInfoFS);
         cout << studentName << endl;
      }
   }
   catch (string name)
   {
      if (userChoice == 0) {
         cout << "Student ID not found for " << name << endl;
      }
   }  
   catch (char ID)
   {
      cout << "Student name not found for " << ID << endl;
   }
    
   studentInfoFS.close();
   return 0;
}

Compiler warnings when I submit:

main.cpp: In function ‘std::string FindID(std::string, std::ifstream&)’:
main.cpp:24:1: warning: control reaches end of non-void function [-Wreturn-type]
   24 | }
      | ^
main.cpp: In function ‘std::string FindName(std::string, std::ifstream&)’:
main.cpp:49:1: warning: control reaches end of non-void function [-Wreturn-type]
   49 | }
      | ^

PASSED TESTS:

1: Compare output

    Input
    roster.txt 0 Reagan
    Your output
    rebradshaw835

2: Compare output

    Input
    roster.txt 0 Mcauley
    Your output
    Student ID not found for Mcauley

3: Compare output

    Input
    roster.txt 1 rebradshaw835
    Your output
    Reagan
7: Unit test

    Test FindName("mpreston272", infoFS) with roster1.txt, should return Mcauley
    Your output
    FindName("mpreston272", infoFS) correctly returned Mcauley

8: Unit test

    Test FindID("Mcauley", infoFS) with roster1.txt, should return mpreston272
    Your output
    FindID("Mcauley", infoFS) correctly returned mpreston272

FAILED TESTS:

4: Compare output

    Input
    roster.txt 1 mpreston272
    Your output
    Your program produced no output
    Expected output
    Student name not found for mpreston272

5: Unit test

    Test FindID("John", infoFS) with roster1.txt, should throw an exception
    Returned unexpected error code (-6)

6: Unit test

    Test FindName("jsmith474", infoFS) with roster1.txt, should throw an exception
    Returned unexpected error code (-6)
Yun
  • 3,056
  • 6
  • 9
  • 28
Koon W
  • 95
  • 5
  • 1
    The functions expect you to return a string, you're not returning anything. – Bib Oct 03 '21 at 18:59
  • What `C++` standard version are you using? – WBuck Oct 03 '21 at 19:35
  • What should you be returning when `foundID` or `foundName` is `true`? – jkb Oct 03 '21 at 20:00
  • 1
    You're getting the warnings because of your `if (foundID == false)`. Remove the conditional as it is useless anyway. – WBuck Oct 03 '21 at 20:00
  • `foundID`, in particular, is set to `false` and then _never changed_. Later, you check if it equals `false`. Why? Of course it's false. That variable is never needed. If you reach that line of code, you already know the ID wasn't found. – Drew Dormann Oct 03 '21 at 20:02
  • 2
    Also, don't `throw` an `std::string`, `throw` and `std::runtime_error` instead. Then, change your `exception` handler to: `catch ( const std::exception& error )` – WBuck Oct 03 '21 at 20:05
  • @WBuck i tried to see which version, but nowhere listed. its a HTML5 built-in compiler in the ZyBooks site... im not very advanced though – Koon W Oct 05 '21 at 02:21

2 Answers2

0

I finally got it to work and pass all 10 tests. Thank you @WBuck for the comment that had me looking closer at try/catch syntax: "don't throw an std::string, throw and std::runtime_error instead. Then, change your exception handler to: catch ( const std::exception& error ) – WBuck"

I found this post to be helpful: How to throw a C++ exception

And the cpp reference site: https://en.cppreference.com/w/cpp/language/function-try-block

I was trying to pass the generic error string, then add the variable name/ID input in the catch statement, but that doesn't work unless the variable gets passed. So I had to create a new string with the default message + the input variable, then pass that as one string into the thrown runtime_error.

The compiler is built into ZyBooks' website and it doesn't say anywhere what version of C++ it uses.

Here is the code that passes all tests, in case anyone else runs into a similar problem.

#include <string>
#include <iostream>
#include <stdexcept>
#include <fstream>
using namespace std;

string FindID(string name, ifstream &infoFS) {
   bool foundID = false;
   string input;
   infoFS >> input;
   while (infoFS) 
   {
      if (input == name)
      {
         foundID = true;
         infoFS >> input;
         return input;
         break;
      }
      else { infoFS >> input; }
   }
   if (foundID == false)  
   {
      string NoNameMsg = "Student ID not found for " + name;
      throw runtime_error(NoNameMsg);
   }   
   return "";
}

string FindName(string ID, ifstream &infoFS) {
   bool foundName = false;
   string previous;
   string input;
   infoFS >> previous;
   infoFS >> input;
   while (infoFS) 
   {
      if (input == ID)
      {
         foundName = true;
         return previous;
         break;
      }
      else 
      { 
         previous = input;
         infoFS >> input; 
      }
   }
   if (foundName == false) 
   {
      string NoIDMsg = "Student name not found for " + ID;
      throw std::runtime_error(NoIDMsg);
   }  
   return "";
}

int main() {
   int userChoice;
   string studentName;
   string studentID;
   string studentInfoFileName;
   ifstream studentInfoFS;
   
   // Read the text file name from user
   cin >> studentInfoFileName;
   
   // Open the text file
   studentInfoFS.open(studentInfoFileName);
   
   // Read search option from user. 0: FindID(), 1: FindName()
   cin >> userChoice;

   try 
   {
      if (userChoice == 0) {
         cin >> studentName;
         studentID = FindID(studentName, studentInfoFS);
         cout << studentID << endl;
      }
      else {
         cin >> studentID;
         studentName = FindName(studentID, studentInfoFS);
         cout << studentName << endl;
      }
   }
   catch ( const std::runtime_error& e )
   {
      cout << e.what() << endl;
   } 
         
   studentInfoFS.close();
   return 0;
}
Koon W
  • 95
  • 5
  • While this is technically working, it's a bit surprising to see you try to use `throw`/`catch` onn strings around in your program. Usually, `throw` / `catch` is for handling exceptions, which is useful for handling unexpected errors. In your case, you want to define a new exception type for your errors, so you could define your own exception class that is initialized with a string describing the error – Florian Castellane Oct 05 '21 at 05:15
0

Here is a solution for that problem in Python:

# Define custom exception
class StudentInfoError(Exception):
    def __init__(self, message):
        self.message = message  # Initialize the exception message


def find_ID(name, info):
    # Type your code here.
    if name not in info.keys():
        raise StudentInfoError('Student ID not found for {}'.format(name))
    the_id = info[name]
    return the_id
    
def find_name(ID, info):
    # Type your code here.
    if ID not in info.values():
        raise StudentInfoError('Student name not found for {}'.format(ID))
    the_name = list(info.keys())[list(info.values()).index(ID)]
    return the_name

if __name__ == '__main__':
    # Dictionary of student names and IDs
    student_info = {
        'Reagan' : 'rebradshaw835',
        'Ryley' : 'rbarber894',
        'Peyton' : 'pstott885',
        'Tyrese' : 'tmayo945',
        'Caius' : 'ccharlton329'
    }
    
    userChoice = input()    # Read search option from user. 0: find_ID(), 1: find_name()
    
    # FIXME: find_ID() and find_name() may throw an Exception.
    #        Insert a try/except statement to catch the exception and output any exception message.
    if userChoice == "0":
        try:
            name = input()
            result = find_ID(name, student_info)
            print(result)
        except StudentInfoError as e:
            print(e)
        
    else:
        try:
            ID = input()
            result = find_name(ID, student_info)
            print(result)
        except StudentInfoError as e:
            print(e)
Joseph M
  • 26
  • 2