显示乱码和缺失操作

时间:2015-03-06 21:37:46

标签: c++ class object

所以我是C ++的初学者,我正在尝试创建一个包含获取数据的函数的类,计算平均总和并将它们除以等级数(5),最后的函数用于显示有关数据的数据。这是我在控制台里得到的:Click for image 我很乐意从你们那里得到一些建议。 这是代码:

class Students{
int br;
char Name[30];
int fakn,i;
float grades[5],sum;
char spec[25];
public:
void takingdata();
float avarage();
void displaydata();
};

void Students::takingdata(){
cout << "Enter name of the student: "; cin.getline(Name, 20);
cout << "Enter his faculty number: "; cin >> fakn;
cout << "specialty: "; cin.getline(spec, 10);
cout << "Enter grades : ";
for (i = 0; i < 5; i++){
    cout << "Enter his grades(5 classes): "; cin >> grades[i];

}


}

float Students::avarage(){
sum = 0;
br = 0;
for (i = 0; i < 5; i++){
    sum = sum + grades[i];


}
return sum / 5;
}


void Students::displaydata(){
cout << "Name of student: " << Name;
cout << "Student faculty number: " << fakn;
cout << "Student specialty: " << spec;
for (i = 0; i < 5; i++){
    cout << "His " << i << " grade: " << grades[i];
}
cout << "His avarage grade: " << avarage();

}

void main(){
Students in,out;
in.takingdata();
out.displaydata();



_getch();
}

因此,我希望程序显示有关学生的输入信息。

2 个答案:

答案 0 :(得分:0)

首先:

Students in,out;
in.takingdata();
out.displaydata();

这应该如何运作?这里有两个对象,写入第一个对象,然后从第二个对象读取。

应该是这样的:

Students students;
students.takingdata();
students.displaydata();

但是,理解您的代码版本中真正发生的事情仍然很重要。正如我们刚刚建立的那样,您从std::cin读到in的所有内容都会在以后被丢弃。这就是你从out读到的内容的问题。让我们再次查看类定义的相关部分:

int br;
char Name[30];
int fakn,i;
float grades[5],sum;
char spec[25];

所有这些成员变量都是所谓的原始类型。这意味着,除其他外,如果你没有明确地初始化它们,它们将保持未初始化状态。例如,br不会在0&#34;开始。严格来说,除非你给它分配一些东西,否则就没什么了。

任何输出这些未初始化值的尝试都会产生未定义的行为。未定义的行为意味着C ++语言规范&#34;放弃&#34;并且没有说出由此产生的程序应该做什么。

在像你这样的情况下,在实践中经常发生的事情是你的程序读取一个或多或少的随机值,该值恰好位于由变量表示的内存中的位置,并打印出一个。关于这一点的危险之处在于,它似乎可以正常工作很长一段时间,因为内存位置恰好包含零值,诱使您认为您的程序没有错误,然后它突然崩溃或打印垃圾值

因此,我们应该对您的代码应用的明显的第一个修复是确保所有成员变量都已初始化。虽然我们这样做,但我也会:

  • 在顶部添加#include <iostream>
  • 在所有标准库功能前添加std::(这是一种很好的做法)。
  • 将非法void main更改为int main
  • 删除不必要的_getch电话。

这是第一次修复迭代后的结果:

#include <iostream>

class Students{
int br;
char Name[30];
int fakn,i;
float grades[5],sum;
char spec[25];
public:

Students() :
    br(0),
    Name(),
    fakn(0),
    i(0),
    grades(),
    sum(0.0),
    spec()
{}

void takingdata();
float avarage();
void displaydata();
};

void Students::takingdata(){
std::cout << "Enter name of the student: "; std::cin.getline(Name, 20);
std::cout << "Enter his faculty number: "; std::cin >> fakn;
std::cout << "specialty: "; std::cin.getline(spec, 10);
std::cout << "Enter grades : ";
for (i = 0; i < 5; i++){
    std::cout << "Enter his grades(5 classes): "; std::cin >> grades[i];

}


}

float Students::avarage(){
sum = 0;
br = 0;
for (i = 0; i < 5; i++){
    sum = sum + grades[i];


}
return sum / 5;
}


void Students::displaydata(){
std::cout << "Name of student: " << Name;
std::cout << "Student faculty number: " << fakn;
std::cout << "Student specialty: " << spec;
for (i = 0; i < 5; i++){
    std::cout << "His " << i << " grade: " << grades[i];
}
std::cout << "His avarage grade: " << avarage();

}

int main(){
Students students;
students.takingdata();
students.displaydata();

}

注意:如果使用Visual C ++,则应阅读以下有关数组成员初始化的内容:

https://msdn.microsoft.com/en-us/library/1ywe7hcy.aspx

但那还不是很令人满意。为什么学生的姓名不应超过29个字符(您的数组最多包含29个可见字符加上C样式字符串的终止'\0')?为什么当它变得更短时,它在内存中需要30个字符?

事实上,如果您输入超过29个字符会发生什么?我们试一试:

Enter name of the student: Long name that does not fit any more in 30 characters
Enter his faculty number: specialty: Enter grades : Enter his grades(5 classes): Enter his grades(5 classes): Enter his grades(5 classes): Enter his grades(5 cl
asses): Enter his grades(5 classes): Name of student: Long name that doesStudent faculty number: 0Student specialty: His 0 grade: 0His 1 grade: 0His 2 grade: 0H
is 3 grade: 0His 4 grade: 0His avarage grade: 0

那不好。 std::istream::getline尝试将30个以上的字符写入30个元素的数组中。这已经产生了未定义的行为。即使它在30个元素之后神奇地停止了,你最终会得到一个没有终止'\0'的数组,所以后来输出代码会再次让数组的边界找到它。除此之外,所有通过std::cin读取数字的尝试都会失败,因为第30个字符后面的流内容不能被解释为数字,而是它应该写入以前状态的变量。

正如您所看到的,以您的方式阅读固定大小的char数组是一项几乎无望的任务。幸运的是,C ++并没有强迫你跟上所有这些。它为动态大小的字符串提供std::string,并提供独立的std::getline函数以安全地读取它们。

这是修复的第二次迭代。请注意,std::string不是基本类型,因此它知道如何正确初始化自身。我仍然将两个变量添加到初始化列表中以与其他成员保持一致。

#include <iostream>
#include <string>

class Students{
int br;
std::string Name;
int fakn,i;
float grades[5],sum;
std::string spec;
public:

Students() :
    br(0),
    Name(),
    fakn(0),
    i(0),
    grades(),
    sum(0.0),
    spec()
{}

void takingdata();
float avarage();
void displaydata();
};

void Students::takingdata(){
std::cout << "Enter name of the student: "; std::getline(std::cin, Name);
std::cout << "Enter his faculty number: "; std::cin >> fakn;
std::cout << "specialty: "; std::getline(std::cin, spec);
std::cout << "Enter grades : ";
for (i = 0; i < 5; i++){
    std::cout << "Enter his grades(5 classes): "; std::cin >> grades[i];

}


}

float Students::avarage(){
sum = 0;
br = 0;
for (i = 0; i < 5; i++){
    sum = sum + grades[i];


}
return sum / 5;
}


void Students::displaydata(){
std::cout << "Name of student: " << Name;
std::cout << "Student faculty number: " << fakn;
std::cout << "Student specialty: " << spec;
for (i = 0; i < 5; i++){
    std::cout << "His " << i << " grade: " << grades[i];
}
std::cout << "His avarage grade: " << avarage();

}

int main(){
Students students;
students.takingdata();
students.displaydata();

}

该计划可能需要更多修复。例如,您需要将float数组替换为std::vector<float>,并且通常使用double代替float

简而言之:如果你想用C ++编程,你应该使用更多的C ++和更少的C.

答案 1 :(得分:-1)

#include <iostream>
#include <cstdio>

using namespace std;

class Students {
private:
    static const int CLASSES = 5;
    static const int NAME = 30;
    static const int SPEC = 15;

    char name[NAME], spec[SPEC];
    int fakn;
    float grades[CLASSES],sum;

public:
    Students();
    void takingdata();
    void avarage();
    void displaydata();
};

//constructor
Students::Students(){
    takingdata();
    avarage();
    displaydata();
}

//user innput
void Students::takingdata(){

    cout << "Enter name of the student: "; 
    cin.getline(name, NAME);

    cout << "Enter his faculty number: ";
    cin >> fakn;
    cin.ignore();

    cout << "specialty: ";
    cin.getline(spec, SPEC);

    printf("\nEnter Grades (%u classes)\n", CLASSES);
    for (int i = 0; i < CLASSES; i++){
        printf("Grade 0%u: ", i+1);
        cin >> grades[i];
    }
}

//calculations
void Students::avarage(){
    sum = 0;

    for (int i = 0; i < CLASSES; i++){
        sum = sum + grades[i];
    }

    sum /= CLASSES;
}

//display
void Students::displaydata(){
    printf("\n\nStudent Name: %s\nFaculty Number: %u\nSpecialty: %s\nGrade Average: %f", name, fakn, spec, sum);

    for (int i = 0; i < CLASSES; i++){
        printf("\nGrade 0%u: %f", i+1, grades[i]);
    }
}

//main
int main(){
    //all other functions now called in constructor
    Students in;

    return 0;
}