C++:尝试打印 const char* 数组时程序崩溃

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

我有一个程序,让用户输入他们的姓名、年龄和他们所参加的 classes。这些 classes 作为二维字符数组存储在 main() 函数中,然后将它们传递给 Student class 中的函数,该函数将此数组复制到 public 成员中名为 m_CourseNames 的 const char* 数组。我已使用 CLion 中的调试器验证此过程已成功完成。

但是,每当我尝试遍历 m_CourseNames 数组并将其内容打印到屏幕时,我得到 exit code 11 并且程序崩溃。

我已经尝试通过以下方式将数组打印到屏幕上:

  1. 在主函数中:

    for (int count = 0 ; count < 9 ; count++)
        cout << student.m_CourseNames[count] << " ";
    
  2. 在学生class的一个成员函数中通过调用via student.getCourses();:

    for (int count = 0 ; count < 9 ; count++)
        cout << m_CourseNames[count] << " ";
    
  3. 在重载运算符函数中使用与 1) 中相同的方法(查看代码以了解我在这里尝试的原因)

尝试将 const char* 数组打印到屏幕的所有三种方法在程序完成之前都导致了以下错误代码:

如果数组是public的成员变量,不知道为什么不会迭代。调试器验证所有 classes 都正确存储在其中,因此它不是 addCourses() 函数的责任。

查看下面的整个程序(所有被注释掉的都是试图将数组打印到屏幕上):

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

Student::Student(const char* m_CourseNames[])中,你越界了m_CourseNames[10] = {0}; //Index is in [0..9] range

此外,您在哪里为 const char * m_CourseNames 指针数组分配 space?

请考虑使用 std::arraystd::string 而不是 C 类型数组和指针。

您正在循环访问数组中您尚未填充的条目。你想要这样的东西:

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

此外,正如 Arun 所指出的,您正在越界访问数组。您无法访问十条目数组的第十一个元素,条目 10 是第十一个元素(因为 0 是第一个)。

尽管出于很多原因,您的代码确实很糟糕。主要问题是您的 Person class 将 指针 存储到它不拥有的内存中,这使得 class 很难使用。为什么不使用 std::string

student.m_CourseNames 是指向 char 的指针数组。这意味着你得到了一堆指针。您没有任何存储指向,因此如果指针未指向某个有效存储,程序将 运行 掉入杂草中。在那里谁知道会发生什么。也许找到丢失的海盗宝藏。可能会被龙吃掉。可能会导致程序崩溃。

student.m_CourseNamesstudent.addCourse(input[count], count); 设置,它提供了一个指针(它将被下一个学生覆盖,所以这是一个坏主意)和 m_CourseNames 所在的索引被更新。这也是一个糟糕但不致命的想法。 classes 的目的之一是他们控制自己的数据,因此 Student 应该维护该索引。

假设我们添加了三个课程:A、B 和 C。for (int count = 0 ; count < 9 ; count++) 将尝试打印 9(索引 0 到 8),这意味着至少有 6 个镜头进入未定义的行为使程序崩溃。

解决方案:

不要使用字符数组。使用 std::string.

如果必须使用字符数组,请提供存储并将源复制到存储中。这样你就知道它是安全的,除非你想或做一些愚蠢的事情,否则不会被覆盖。

不要使用指针数组。使用 std::vector(并且指向真实数据,而不是指向数据的指针)。当您添加更多时,矢量会调整大小,并且始终知道它包含多少项目。如果您不能使用向量,请坚持使用数组,但不要使用指针数组。如果可能,使用 std::string 数组。

跟踪存储在列表中的项目数量,这样您就不会越界。 Vector 为您做这件事。

封装您的 class 数据。学生应该了解和管理学生的所有事情。没有人应该告诉学生在哪里放置它的课程,只是它有课程。当你想打印学生的数据时,让学生为你打印。