简体   繁体   中英

C++: Program crashes when trying to print const char* array

I have a program that has a user enter their name, age, and the classes that they have taken. These classes are stored in the main() function as two-dimensional array of chars and then they are passed to a function within a Student class that copies this array into a public member const char* array called m_CourseNames. I have verified with a debugger in CLion that this process completes successfully.

However, I get exit code 11 and the program crashes whenever I try to iterate through the m_CourseNames array and print it contents to the screen.

I have tried printing the array to the screen the following ways:

  1. In the main function:

     for (int count = 0 ; count < 9 ; count++) cout << student.m_CourseNames[count] << " "; 
  2. In a member function of the student class by calling via student.getCourses(); :

     for (int count = 0 ; count < 9 ; count++) cout << m_CourseNames[count] << " "; 
  3. Inside an overloaded operator function with the same method as in 1) (see code to understand why I tried it here)

All three ways of trying to print the const char* array to the screen have resulted in the following error code before the program is finished:

If the array is a public member variable, I do not know why it will not iterate. The debugger verified that all the classes are properly being stored in it, so it is not the responsibility of the addCourses() function.

See entire program below (everything that is commented out is an attempt at achieving printing the array to the screen):

--main.cpp--

#include <iostream>
#include "Student.h"

using namespace std;

int main()
{
    char input[10][128] = {(0),(0)};
    char name[128] = {0}, student_check = ' ';
    int age = 0, count = 0;

    cout << "\nPlease state your name and age:\n\n";
    cout << "Name: ";
    cin.getline(name, 128);
    cout << "Age: ";
    cin >> age;

    cin.clear();
    cin.ignore();

    cout << "\n\nThanks!\n\nAre you a student? (Y/N): ";
    cin.get(student_check);

    switch (student_check)
    {
        case 'y':
        case 'Y':
        {
            Student student;
            student.setName(name);
            student.setAge(age);
            char course_check = ' ';
            cout << "\n\nWhat course(s) are you taking?"
            << " (Enter the course prefix and number without any spaces): \n\n";


            while (tolower(course_check) != 'n') {
                cin.clear();
                cin.ignore();

                cout << "Course #" << count + 1 << ": ";
                cin.getline(input[count], 128);
                student.addCourse(input[count], count);


                if (student.addCourse(input[count], count))
                {
                    cin.clear();

                    cout << "Do you want to enter another course? (Y/N): ";
                    cin.get(course_check);

                    count++;
                }
                else
                {
                    cout << "You have exceeded the number of courses you are allowed to enter" << endl << endl;
                    course_check = 'n';
            }
            cout << student;
            student.getCourses();
            //for (int count = 0 ; count < 9 ; count++)
              //  cout << student.m_CourseNames[count] << " ";
        }


        }
        default:
            break;

    }
}

--Student.h---

#ifndef PA2_STUDENT_H
#define PA2_STUDENT_H
#include "Person.h"
#include <ostream>

class Student : public Person
{
    public:
        Student();
        Student(const char* []);
        bool addCourse(const char*, int);
        void getCourses();
        friend std::ostream& operator <<(std::ostream& os, const Student& student);
       const char* m_CourseNames[10];
};

#endif

--student.cpp--
#include "Student.h"
#include <iostream>

using namespace std;

Student::Student() {}

Student::Student(const char* m_CourseNames[])
{
    m_CourseNames[10] = {0};
}

bool Student::addCourse(const char* course, int index)
{
    if (index < 9)
    {
        m_CourseNames[index] = course;
        return true;
    }
    if (index >= 9)
        return false;
}

void Student::getCourses()
{
    cout << ", Courses: ";
    for (int count = 0 ; count < 9 ; count++)
        cout << m_CourseNames[count] << " ";
}

std::ostream &operator<<(std::ostream& os, const Student& student) {
    os << "Name: " << student.m_Name << ", Age: " << student.m_Age;// << ",     Courses: " << Student::m_CourseNames;

//cout << ", Courses: ";
   // for (int count = 0 ; count < 9 ; count++)
       // cout << m_CourseNames[count] << " ";
return os;
}

You are iterating into entries in the array that you have not populated. You want something like:

void Student::getCourses()
{
    cout << ", Courses: ";
    for (int count = 0 ; count < index ; count++)
        cout << m_CourseNames[count] << " ";
}

Also, as Arun pointed out, you are accessing the array out of bounds. You can't access the eleventh element of a ten entry array, and entry 10 is the eleventh element (since 0 is the first).

Your code is really bad though for a lot of reasons. The main issue is that your Person class stashes pointers to memory it doesn't own, which makes the class very hard to use. Why not use std::string ?

In Student::Student(const char* m_CourseNames[]) , you are overstepping the array m_CourseNames[10] = {0}; //Index is in [0..9] range m_CourseNames[10] = {0}; //Index is in [0..9] range

Moreover where do you allocate space for array of const char * m_CourseNames pointers?

Please consider using std::array and std::string instead of C-type array and pointers.

student.m_CourseNames is an array of pointers to char. This means you get a bunch of pointers. You do not get any storage to point at, so if the pointer is not pointed at some valid storage the program is going to run off into the weeds. Out there who knows what'll happen. Maybe find lost pirate treasure. Maybe get eaten by dragons. Probably crash the program.

student.m_CourseNames is set by student.addCourse(input[count], count); which provides a pointer (which will be overwritten by the next student, so this is a bad idea) and the index at which m_CourseNames will be updated. This is also a bad, but not fatal, idea. One of the purposes of classes is they control their own data, so Student should be maintaining that index.

So say we add three courses: A, B and C. for (int count = 0 ; count < 9 ; count++) is going to try to print 9 (indexes 0 through 8) so that means there are at least six shots off into undefined behaviour to crash the program with.

Solutions:

Don't use char arrays. Use std::string.

If you have to use char arrays, provide storage and copy the source into the storage. That way you know it's safe and not going to be overwritten unless you want to or do something dumb.

Don't use arrays of pointers. Use std::vector (and to real data, not to pointers to data). Vector resizes as you add more and always know how many items it contains. If you can't use vectors, stick to using arrays, but not arrays of pointers. Use arrays of std::string if possible.

Keep track of the number of items stored in your lists so you don't go marching out of bounds. Vector does this for you.

Encapsulate your class data. Student should know and manage all things Student. No one should be telling Student where to put it's courses, just that it has courses. When you want to print student's data, ask Student to print it for you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM