在 C++ 中使用 cin 时内存损坏
Memory corruption when cin in c++
我有 class "student.cpp"
#include <iostream>
#include "student.h"
using namespace std;
void student::setMarks(int m1, int m2) {
mark1 = m1;
mark2 = m2;
};
void student::setName(char *n) {
name = n;
};
int student::calc_media(void){
return (mark1+mark2)/2;
};
void student::disp(void){
cout << "Student:" << name << " \n media:"<< calc_media() <<"\n";
};
student::student(){
mark1 = 0;
mark2 =0;
name = "";
};
头文件"student.h":
ifndef CLASY_STUDENT_H
#define CLASY_STUDENT_H
#endif //CLASY_STUDENT_H
class student{
char *name;
int mark1, mark2;
public:
void setName(char *n);
void setMarks(int m1, int m2);
void disp(void);
int calc_media(void);
student();
};
和"main.cpp":
#include <iostream>
#include "student.h"
using namespace std;
int main() {
student s;
char* n;
int m1, m2;
cout << "Enter name:";
cin>> n;
cout << "Enter marks of two subjects:";
cin>> m1;
cin>> m2;
s.setName(n);
s.setMarks(m1, m2);
s.disp();
return 0;
}
我正在 运行使用 Clion 和 Cmake 是:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall")
set(SOURCE_FILES main.cpp student.cpp student.h student.cpp student.h)
但是当我 运行 时,它要求输入名称,但是当我键入内容时,我遇到了内存碎片错误。怎么了?
顺便说一句,有人能告诉我它对 C++ 来说是否合适吗?我正在尝试从 java 切换到 c++。
char* n;
...
cin>> n;
n
是一个指针,应该指向一块特定的内存。但是你从来没有设置它。所以它有一些未定义的值,指向你最终试图覆盖的一些内存中谁知道的地方。很可能是您不允许覆盖的内存,导致段错误。
如果您还不知道手动内存管理,请不要尝试使用 char*
(一旦了解,您就会明白为什么不这样做)。使用 std::string
.
快速浏览一下,您几乎可以用 std::string
替换任何地方的 char*
(只要您 #include <string>
)。
与其他人所说的类似,您的变量 n
是一个未初始化的指针。顾名思义,指针只是指向内存中特定位置的路标 - 告诉 CPU "go to this memory location for variable x".
假设你有一个整型变量 var
,声明如下:
int var;
那个变量占用内存,你可以这样赋值:
var = 5;
您也可以像这样声明一个指向整数的指针:
int * var_ptr;
现在假设 var_ptr
指向一个有效的整数,我可以像这样给它赋值:
*var_ptr = 5;
这表示 "put the number 5 at the memory location pointed to by var
"。但是,如果 var_ptr
尚未初始化,那么它将指向内存中的一个随机位置,该位置可能会覆盖重要内容,或者尝试写入受保护的内存地址,从而导致保护错误(段错误)。这就是您的代码中发生的情况。
要初始化var_ptr
指向var
的地址,我们可以这样做:
var_ptr = &var;
& 符号是 "address of" 运算符 - 它表示 "don't get me the value of var
but instead get me the address of the memory location where var
is stored"。
因此,为了防止出现问题,您必须将 n
初始化到某个有效的内存位置,您可以在其中安全地写入一些数据。
有几种方法可以做到这一点。正如@Stefan 指出的那样,您可以将 n
声明为字符数组:
char n[20];
正如@BobTFish 指出的那样,您需要一些方法来确保您的输入不超过数组的大小(在本例中为 20 个字节)。解决方案是std::cin.width(20)
.
正如@BobTFish 也提到的,您也可以使用 std::string
,像这样:
std::string n;
std:cin >> n;
std::string
对象将自动负责内存分配。
如果你真的必须使用char *
,你可以取char
数组的地址(这里我取数组第一个元素的地址):
char n_array[20];
char *n = &n_array[0];
std::cin.width(20);
std::cin >> n;
您也可以使用动态内存分配:
char *n = new char[20];
std::cin.width(20);
std::cin >> n;
delete n;
请注意,如果您使用动态内存分配,则必须在完成后使用 delete
释放内存,否则会发生内存泄漏。局部变量(如数组)分配在堆栈上,因此在函数 returns 时自动释放。由于这个原因,以及动态内存分配的开销,你在这里使用它会很疯狂。
我有 class "student.cpp"
#include <iostream>
#include "student.h"
using namespace std;
void student::setMarks(int m1, int m2) {
mark1 = m1;
mark2 = m2;
};
void student::setName(char *n) {
name = n;
};
int student::calc_media(void){
return (mark1+mark2)/2;
};
void student::disp(void){
cout << "Student:" << name << " \n media:"<< calc_media() <<"\n";
};
student::student(){
mark1 = 0;
mark2 =0;
name = "";
};
头文件"student.h":
ifndef CLASY_STUDENT_H
#define CLASY_STUDENT_H
#endif //CLASY_STUDENT_H
class student{
char *name;
int mark1, mark2;
public:
void setName(char *n);
void setMarks(int m1, int m2);
void disp(void);
int calc_media(void);
student();
};
和"main.cpp":
#include <iostream>
#include "student.h"
using namespace std;
int main() {
student s;
char* n;
int m1, m2;
cout << "Enter name:";
cin>> n;
cout << "Enter marks of two subjects:";
cin>> m1;
cin>> m2;
s.setName(n);
s.setMarks(m1, m2);
s.disp();
return 0;
}
我正在 运行使用 Clion 和 Cmake 是:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall")
set(SOURCE_FILES main.cpp student.cpp student.h student.cpp student.h)
但是当我 运行 时,它要求输入名称,但是当我键入内容时,我遇到了内存碎片错误。怎么了? 顺便说一句,有人能告诉我它对 C++ 来说是否合适吗?我正在尝试从 java 切换到 c++。
char* n;
...
cin>> n;
n
是一个指针,应该指向一块特定的内存。但是你从来没有设置它。所以它有一些未定义的值,指向你最终试图覆盖的一些内存中谁知道的地方。很可能是您不允许覆盖的内存,导致段错误。
如果您还不知道手动内存管理,请不要尝试使用 char*
(一旦了解,您就会明白为什么不这样做)。使用 std::string
.
快速浏览一下,您几乎可以用 std::string
替换任何地方的 char*
(只要您 #include <string>
)。
与其他人所说的类似,您的变量 n
是一个未初始化的指针。顾名思义,指针只是指向内存中特定位置的路标 - 告诉 CPU "go to this memory location for variable x".
假设你有一个整型变量 var
,声明如下:
int var;
那个变量占用内存,你可以这样赋值:
var = 5;
您也可以像这样声明一个指向整数的指针:
int * var_ptr;
现在假设 var_ptr
指向一个有效的整数,我可以像这样给它赋值:
*var_ptr = 5;
这表示 "put the number 5 at the memory location pointed to by var
"。但是,如果 var_ptr
尚未初始化,那么它将指向内存中的一个随机位置,该位置可能会覆盖重要内容,或者尝试写入受保护的内存地址,从而导致保护错误(段错误)。这就是您的代码中发生的情况。
要初始化var_ptr
指向var
的地址,我们可以这样做:
var_ptr = &var;
& 符号是 "address of" 运算符 - 它表示 "don't get me the value of var
but instead get me the address of the memory location where var
is stored"。
因此,为了防止出现问题,您必须将 n
初始化到某个有效的内存位置,您可以在其中安全地写入一些数据。
有几种方法可以做到这一点。正如@Stefan 指出的那样,您可以将 n
声明为字符数组:
char n[20];
正如@BobTFish 指出的那样,您需要一些方法来确保您的输入不超过数组的大小(在本例中为 20 个字节)。解决方案是std::cin.width(20)
.
正如@BobTFish 也提到的,您也可以使用 std::string
,像这样:
std::string n;
std:cin >> n;
std::string
对象将自动负责内存分配。
如果你真的必须使用char *
,你可以取char
数组的地址(这里我取数组第一个元素的地址):
char n_array[20];
char *n = &n_array[0];
std::cin.width(20);
std::cin >> n;
您也可以使用动态内存分配:
char *n = new char[20];
std::cin.width(20);
std::cin >> n;
delete n;
请注意,如果您使用动态内存分配,则必须在完成后使用 delete
释放内存,否则会发生内存泄漏。局部变量(如数组)分配在堆栈上,因此在函数 returns 时自动释放。由于这个原因,以及动态内存分配的开销,你在这里使用它会很疯狂。