显示乱码和缺失的操作
Displaying gibberish and missing operations
所以我是 C++ 的初学者,我正在尝试制作一个 Class,其中包含用于获取数据、计算平均总和并将它们除以分数的函数 (5),最终函数是用于显示有关 student.Here 的数据,这是我在控制台中获得的数据: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();
}
因此我希望程序显示输入的有关学生的信息。
#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;
}
首先:
Students in,out;
in.takingdata();
out.displaydata();
这应该如何运作?你这里有两个对象,写入第一个并从第二个读取。
应该是这样的:
Students students;
students.takingdata();
students.displaydata();
不过,了解您的代码版本中实际发生的情况仍然很重要。正如我们刚刚建立的那样,您从 std::cin
读取到 in
的所有内容稍后都会被丢弃。其中包含您从 out
中到底读到了什么的问题。让我们再次查看 class 定义的相关部分:
int br;
char Name[30];
int fakn,i;
float grades[5],sum;
char spec[25];
所有这些成员变量都是所谓的原始类型。这意味着,除其他事项外,如果您不显式初始化它们,它们将保持未初始化状态。例如,br
不会 "start at 0"。严格来说,在你给它赋值之前,它什么都不是。
任何输出这些未初始化值的尝试都会产生未定义的行为。未定义的行为意味着 C++ 语言规范 "gives up" 并且没有说明生成的程序应该做什么。
在像您这样的情况下,在实践中经常发生的情况是,您的程序读取一个或多或少的随机值,该值恰好位于内存中由变量表示的位置,并打印该值。这样做的危险之处在于,它可能看起来可以正常工作很长时间,因为内存位置恰好包含一个零值,诱使您认为您的程序没有错误,然后它突然崩溃或打印垃圾值.
因此,我们应该对您的代码应用的第一个明显修复是确保所有成员变量都已初始化。在我们这样做的同时,我还将:
- 在顶部添加
#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 个可见字符加上终止符 '[=25=]'
(用于 C 样式字符串)?为什么要在内存中占用 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 个元素后停止,您最终会得到一个没有终止 '[=25=]'
的数组,因此稍后的输出代码将再次离开数组的边界寻找它。除此之外,所有通过 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();
}
该程序可能需要更多修复。例如,你会想用 std::vector<float>
替换 float
数组,并且通常使用 double
而不是 float
。
简而言之:如果你想用 C++ 编程,你应该多用 C++,少用 C。
所以我是 C++ 的初学者,我正在尝试制作一个 Class,其中包含用于获取数据、计算平均总和并将它们除以分数的函数 (5),最终函数是用于显示有关 student.Here 的数据,这是我在控制台中获得的数据: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();
}
因此我希望程序显示输入的有关学生的信息。
#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;
}
首先:
Students in,out; in.takingdata(); out.displaydata();
这应该如何运作?你这里有两个对象,写入第一个并从第二个读取。
应该是这样的:
Students students;
students.takingdata();
students.displaydata();
不过,了解您的代码版本中实际发生的情况仍然很重要。正如我们刚刚建立的那样,您从 std::cin
读取到 in
的所有内容稍后都会被丢弃。其中包含您从 out
中到底读到了什么的问题。让我们再次查看 class 定义的相关部分:
int br; char Name[30]; int fakn,i; float grades[5],sum; char spec[25];
所有这些成员变量都是所谓的原始类型。这意味着,除其他事项外,如果您不显式初始化它们,它们将保持未初始化状态。例如,br
不会 "start at 0"。严格来说,在你给它赋值之前,它什么都不是。
任何输出这些未初始化值的尝试都会产生未定义的行为。未定义的行为意味着 C++ 语言规范 "gives up" 并且没有说明生成的程序应该做什么。
在像您这样的情况下,在实践中经常发生的情况是,您的程序读取一个或多或少的随机值,该值恰好位于内存中由变量表示的位置,并打印该值。这样做的危险之处在于,它可能看起来可以正常工作很长时间,因为内存位置恰好包含一个零值,诱使您认为您的程序没有错误,然后它突然崩溃或打印垃圾值.
因此,我们应该对您的代码应用的第一个明显修复是确保所有成员变量都已初始化。在我们这样做的同时,我还将:
- 在顶部添加
#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 个可见字符加上终止符 '[=25=]'
(用于 C 样式字符串)?为什么要在内存中占用 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 个元素后停止,您最终会得到一个没有终止 '[=25=]'
的数组,因此稍后的输出代码将再次离开数组的边界寻找它。除此之外,所有通过 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();
}
该程序可能需要更多修复。例如,你会想用 std::vector<float>
替换 float
数组,并且通常使用 double
而不是 float
。
简而言之:如果你想用 C++ 编程,你应该多用 C++,少用 C。