I have a char pointer as a private member of a class. I need to read record from a file and insert it into class array. First, I need to get number of record first then create a myStudent array during runtime. Then insert all the record in. But when I tried to initialize the name field using set method, it gave me Practise1(3278,0x7fff7287e300) malloc:error for object 0x100105578: incorrect checksum for freed object - object was probably modified after being freed. set a breakpoint in malloc_error_break to debug error
if i use debugger to run the program step-by-step, it works perfectly fine with no error, however if i run it normally, it gave me the above error. (Sometimes it works, sometime it doesn't)
Here is a small portion of my code:
myClass.h:
class myClass{
private:
char *name;
public:
myClass();
void setName(string);
}
myClass.cpp
myClass:: myClass(){}
void myClass::setName(string x){
name = new char[x.length()+1]; //my xcode give me signal SIGBART here
strcpy(name, x.c_str());
}
main.cpp
int main(){
myClass *classArr;
int amountRecord = getRecord(); //check the number of record and return it(assuming it return 5)
classArr = new myClass[amountRecord];
loadClassData("test.dat",classArr);
}
void loadClassData(string filename,myClass *classArr){
ifstream ins(filename,ios::in);
int counter = 0;
string className;
string temp;
if(ins.good()){
while(!ins.eof()){
className = "";
getline(ins, className,'\n');
classArr[counter].setName(className);
counter++;
}
ins.close();
}
The problem is in how you loop when reading (see Why is “while ( !feof (file) )” always wrong? for why).
This causes the loop to iterate one extra time leading you to use an out-of-bounds index into the classArr array, which leads to undefined behavior and the crash.
Instead do e.g. while (std::getline(ins, className))
In function void myClass::setName(string x) you are using some variable called sName.
I have no idea where it's declared, but you should be using the variable x that is passed in the function.
Where sName is come from? I think it should be like this.
myStudent::myStudent(){}
void myStudent::setName(string x){
name = new char[x.length()+1]; //my xcode give me signal SIGBART here
strcpy(name, x.c_str());
}
Related
Multiple students can associate with a single Department and single student can
associate with multiple Departments, but there is no ownership between the objects
and both have their own lifecycle. Both can create and delete independently.
WAP in C++ to model the relationships.
I have implemented this code as follows
#include<iostream>
#include<cstring>
using namespace std;
class Student
{
char* name_p;
public:
Student(char *sName)
{
cout<<"Student constructor called\n";
name_p=new char(sizeof(strlen(sName)));
name_p=sName;
}
~Student()
{
cout<<"Student destructor called\n";
delete name_p;
};
char* sName()
{
return name_p;
}
};
class Department
{
char* name_p;
public:
Department(char *dName)
{
cout<<"Department destructor called\n";
name_p=new char(sizeof(strlen(dName)));
name_p=dName;
}
~Department()
{
cout<<"Department destructor called\n";
delete name_p;
}
char* dName()
{
return name_p;
}
};
class Course
{
Student* std_p;
Department* dept_p;
char* courseName_p;
static unsigned int index;
static Course *courseList_p[4];
public:
Course(char* crseName,Student* student,Department* dept)
{
cout<<"Course constructor called\n";
std_p=student;
dept_p=dept;
if(index<4)
{
courseName_p=new char(sizeof(strlen(crseName)));
courseName_p=crseName;
courseList_p[index]=this;
++index;
}
else
{
cout<<"Cannot accomodate any more Course\n";
}
};
~Course()
{
cout<<"Course destructor called\n";
delete courseName_p;
};
static char* findStudent(char *crseName, char* deptName)
{
for(int i=0; i<index; i++)
{
if ( (courseList_p[i]->getCourseName() == crseName) &&
(courseList_p[i]->getDeptName() == deptName) )
{
return(courseList_p[i]->getStdName());
}
}
}
char* getStdName()
{
return std_p->sName();
};
char* getDeptName()
{
return dept_p->dName();
};
char* getCourseName()
{
return courseName_p;
};
};
unsigned int Course::index =0;
Course* Course::courseList_p[4]={0,0,0,0};
int main()
{
int i;
cout<<"\nExample of Association class\n";
cout<<"-----------------------------------\n\n";
cout<<"We have got 4 students\n";
Student *studentNames[4] = {new Student("Meera"), new Student("Moina"), new Student("Teena"), new Student("Mridula")} ;
cout<<"\n";
cout<<"We have got 2 Departments\n";
Department *departNames[2] = {new Department("Mathematics"), new Department("ComputerSceince")} ;
cout<<"\n";
cout<<"Here class Course Associates Student and Department, with a Course name\n";
Course course1("DataStructure",studentNames[0], departNames[1]);
Course course2("Maths",studentNames[3], departNames[0]);
Course course3("Geometry",studentNames[2], departNames[0]);
Course course4("CA",studentNames[1], departNames[1]);
cout<<"\n";
cout<<"Finding a Student using Course and Department\n";
cout<<"Student who has taken Maths Course in Mathematics Department is:"<<Course::findStudent("Maths", "Mathematics")<<endl;
cout<<"\n";
cout<<"Deletion of objects\n\n";
for(i=0;i<4;i++)
{
delete studentNames[i];
}
cout<<"\n";
for(i=0;i<2;i++)
{
delete departNames[i];
}
cout<<"\n";
return 0;
}
The code is showing warnings in main function i.e. ISO C++ forbids converting a string constant to char* and also the main() function is not returning 0 but a garbage value. Please help me in rectify these errors and warnings.
Also I don't want to use this pointer in class course, can I implement the code without using this pointer.
There are a couple of problems with your code. Mostly they are related to the use of char* instead of string. I'm amazed to see that some teacher still are found of this practice.
c-string allocation problems
The first problem causes memory corruption. This could explain that your main() returns garbage instead of 0. For example:
name_p=new char(sizeof(strlen(dName))); // OUCH!!!
In the statement you allocate it wrong. If you want to allocate an array, you must use new[...]. Moreover, keep in mind that a c-string allways needs 1 char more for the trailing null. So it should be:
name_p=new char[strlen(dName)+1];
would already improve the situation.
Last but not the least, if you allocate an array you must delete an array with delete[]
c-string copying issue
Then, you can copy C++ string with an assignment operator just as in:
name_p=sName; // OUCH
However, for char*, this just overwrites the pointer that new returned and you are not sure that the c-string it points to will still be valid when it's used.
If you want to assign a c-string, you need to go for:
strcpy (name_p, sName); // C-style
copy (sName, sName+strlen(sName)+2, name_p); // Safer C++ alternative
c-string comparison issue
Suppose you have two pointers to c string, say pa and pb. Comparing the pointers looks at the memory address, not at the content. So yu could have two identical strings but the comparison could nevertheless fail. THis kind of comparison would work perfectly well for c++ string, but for cstring, you need to to
strcmp(pa, pb)==0 // instead of pa == pb
c-strings in classes and structures
Whenever you have some pointers that you allocate in a class, you need to think of the rule of 3. Meaning that you'd need to add a copy constructor and an assignment operator. Fortunately, at first sight it seems that you don't need them here. Of couse, if you'd use c++ string you wouldn't have to worry about such details.
c-string conversion issues?
ANother issue in your code is the use of string literals with constructors. For example:
new Student("Meera").... // c-string literals (constant)
Student(char*...) // constructor using a c-string pointer (non constant)
You can easily get rid of this complaint, by making the constructor's pointer argument as constant:
Student(const char *sName)...
The same applies to function arguments, such as in find.
Other problems
The static member findStudent() works well, but only if a result is found. If nothing is found, it's UB, since there is no return statement (put a return nullptr; at the end of this function?)
Moreover, the wya you use this function, directly printing its result is dangerous, because dereferencing an invalid pointer will lead to UB.
Here the corrected code. It compiles and seem to run. I didn't analyse for more issues.
I have this struct:
struct event_ {
bool is_crossover = false;
bool is_birth = false;
bool is_repetitive = false;
int eID = 0;
bool inicio_fin = false;
fecha inicio_fecha;
fecha fin_fecha;
locacion inicio_l;
string eLatitud_i = 0;
string eLongitud_i = 0;
locacion fin_l;
string eLatitud_f = 0;
string eLongitud_f = 0;
personaje_info personajes_evento; //This is a class
int cantidad_personajes = 0;
string nombre;
string descripcion;
string tipo_evento;
event_ *sig, *ant;
};
And then, when I call the function:
event_ *n = new event_;
it sends me an Access Violation Error:
Exception thrown at 0x0F69F6E0 (ucrtbased.dll) in Auxiliar Libros.exe: 0xC0000005: Access violation reading location 0x00000000.
Anyone knows why is this happening?
As additional information, I ran a Code Metrics Analysis, and before this, the program worked perfectly fine. And also it tells me about exceptions, what should I do?
This code
string eLongitud_f = 0;
calls the string constructor with a NULL pointer (0 is another way of writing the NULL pointer), resulting in your access validation error.
What do you think that code is doing? Obviously 0 is an integer not a string. Did you mean this?
string eLongitud_f = "0";
Or did you mean this?
string eLongitud_f = "";
Maybe you even meant this
double eLongitud_f = 0.0;
You can also just have this
string eLongitud_f;
which is the same as the second alternative above. All these are possible, it's hard to know which you really want, but the fundamental problem is that you are have a string variable and you are trying to give it a value which is not a string.
To solve your problem, I think that the best thing to do is to reduce your code and try some combinaison.
First, you must try a little struct with only one bool variable to see if your new function is correct
struct event_
{
bool is_crossover = false;
};
event_ *n = new event_;
If your program continue to crash, your error is there, in new().
Else you can try then to reduce your structure removing what you think is correct.
Personnaly, I think that all your bool, int and event_ declaration are correct, so I remove them.
I think that similar object declaraction can also be removed and I remove them.
I have following structure:
struct event_
{
fecha fin_fecha;
locacion inicio_l;
string eLatitud_i = 0;
personaje_info personajes_evento;
};
What happens when you build and run this code ?
If you program has stopped to crash, the error is in removed code ?
Else, one (or more) declaration's line of this new structure is incorrect.
If changing your struct has too much impact in your code, your create a similar structure (other name not yet used) and you test it.
Please, can you try ? I think that you will find very quickly solve the problem yourself !
There are too much variables in your first code that can produce your crash ?
#include <iostream>
using namespace std;
const int ALPHABET = 26;
const int LANG = 4;
const double TOLK[LANG][ALPHABET]= {{0}};
class Text
{
private:
string sample;
int* histogram;
double* rel_histogram;
int sample_size;
public:
Text();
~Text();
string parse();
};
string parsing(const double TOLK[][ALPHABET], double rel_occurence_arr[]);
int main()
{
Text myText;
myText.parse();
return 0;
}
Text::Text(){
sample = "";
histogram = new int[ALPHABET];
rel_histogram = new double[ALPHABET];
sample_size = 0;
}
Text::~Text(){
delete[] histogram;
delete[] rel_histogram;
}
string Text::parse(){
parsing(TOLK, rel_histogram);
//Invalid pointer here
}
string parsing(const double TOLK_HJALP[][ALPHABET], double rel_occurence_arr[]){
return "test";
}
This is part of a larger code, but I've peeled of everything I could till only the parts causing the error remains. Running it like this results in a invalid pointer error, running it with all the extra bits causes a double free/corruption error. But I think that if I can figure it out at this level I can probably figure it out at the larger scale.
From what I've gathered, I think that the Text class is trying to delete something which has already been deleted when the parsing function returned. I don't know if that is correct, but if it was, I have no idea on how to stop it from happening. It doesn't matter if I send a copy(in the way I tried, maybe there are more ways than one?).
And also, removing iostream from the include seems to remove the error, for whatever reason. Why is that? It isn't even used here?
Thanks in advance.
There are two issues with your code that I can see.
(1) This should be what is causing your error. You are not including string, and iostream doesn't need to include it. This means you are returning a pointer to a char from parsing, but the pointer is deleted when parsing returns. This results in undefined behavior.
(2) parse doesn't return a value, but it promises to in its declaration. That could cause some issues.
Note: You should try using -Wall when you run into a problem (or just all the time). That would have caught both of those errors for you.
I have been given this definitions, the function should return what is in info->phrase. However info->phrase can contain a string in which case I can only make it return the first char on info->phrase. Is there a way to make a string compatible with the char type? I am new to c++.
struct rep_info {
int num;
char *phrase;
};
I´ve tried few thing but get type errors, this was my latest attempt
char *phrase_info(rep_info info) {
char text[std::strlen(info->phrase) + 1];
text = info->phrase;
return text;
}
Since you said you have been given these definitions, let's fix the problem with the current setup first. Looking at your function, you are trying to copy into this local array (incorrectly I might add), and return this local variable. There are a number of things wrong with this, including the syntax and the fact that the local variable is destroyed when the function exits.
If you just need to get the value of the phrase member variable, the simplest solution would be to just access the member variable directly and return it:
char *phrase_info(rep_info info) {
return info.phrase; //since info is not a pointer, use the '.' accessor
}
If you mean to pass a pointer to the function, you would re-write it like this:
char *phrase_info(rep_info *info) {
return info->phrase;
}
But it seems like you feel the need to copy the contents of info->phrase into a new memory space? If so, then you would do something like this where you first allocate new memory and return this buffer:
char *phrase_info(rep_info *info) {
char *buf = new char[std::strlen(info->phrase) + 1];
std::strcpy(buf,info->phrase); //copies info->phrase into buf
return buf;
}
You would then need to use delete on the returned memory value to clean up the memory allocated by new, otherwise you will have a memory leak.
Overall, all the above solution would potentially solve the problem given some parameters you haven't made clear. To round this out, this should be written more like:
class rep_info {
private:
int num;
std::string phrase;
public:
rep_info(int n, std::string p) : num(n), phrase(p) {}
std::string get_phrase() { return phrase; }
// other functions
};
//later in the code
rep_info info(...);
info.get_phrase();
Ideally, you would wrap these member variables into their own object with corresponding member functions that can get and set these values. Moreover, for handling strings in C++, std::string is the preferred option for storing, copying, modifying, etc. strings over the older char * C-style string.
Hello i am building a project and today after 500 lines of code i am going to shoot my self. Today i started a new class and some very strange things are happening:
class Target {
public:
Target(const int port);
virtual ~Target();
private:
const char* initialize_port(const int port) const;
const char *const port;
};
and cpp file:
Target::Target(const int port)
:
port(initialize_port(port))
{
cout<<this->port<<endl; //this cout 80
string test3="Target2";//when i replace with char * test3="Target2" then both couts in the constructor are working ok.
cout<<this->port<<endl; //this cout Target2!!!!!!
}
const char* Target::initialize_port(const int port) const {
string port_str = std::to_string(port);
const char* port_char=port_str.c_str();
return port_char; // OR/and when i replace with something like return "80" then both couts in the constructor are working ok.
}
Target::~Target() {
}
Like you can see in the cpp file, while the default constructor is being called it couts the "this->port", then i create a string, and then i print it again. How is it even possible to get a different response??
From netbeans:
80
Target2
RUN FINISHED; exit value 0; real time: 20ms; user: 0ms; system: 0ms
PS:When in the function initialize_port(const int port) i am giving a standard return, for example return "80"; everything is ok. When in the constructor i am replacing the string with char *, again everything is ok.
PS2:I know that i have some problems with my RAM. If someone will compile and there is no problem with the outputs (cout) please let me know.
Thanks in advance.
The problem comes from:
{
string port_str = std::to_string(port);
const char* port_char=port_str.c_str();
return port_char;
}
When the return happens, port_str is destroyed because it is a locale variable to that code block. Then port_char is a dangling pointer (a pointer that used to point to an object that has now been destroyed).
Using that pointer causes undefined behaviour and that explains your weird effects when you use the pointer.
To fix this, stop using raw pointers. The simplest fix is to use std::string instead.
The problem is that the return value of port_str.c_string() is only valid for the lifetime of port_str. Since that is allocated on the stack in initialize_port it becomes invalid once that function returns.
In your constructor, when you initialize the test3 string it ends up (mostly by chance) occupying the same memory as port_str did.
If you need to use a const char * you will need to allocate new memory for the string inside initialize_port (and deallocate it in your constructor!). Alternatively just stick with using std:string objects.