const * char in struct in class - segmentation fault - c++

I have this code and it gives me segmentation fault.
struct TRecord {
const char * Id;
const char * Name;
};
class CClass {
CClass ();
~CClass ();
bool Add ( const char * id, const char * name);
TRecord ** m_record;
int m_count;
};
CClass::CClass (void) {
m_count = 0;
m_record = new TRecord * [1000];
}
CClass::~CClass(void) {
for(int i=0;i<m_count;i++){
delete m_record[i];
}
delete [] m_record;
}
bool CClass::Add (const char * id, const char * name) {
m_record[m_count] -> Id = new char[11];
m_record[m_count] -> Name = new char[strlen(name) + 1];
m_record[m_count] -> Id = id;
m_record[m_count] -> Name = name;
m_count++;
return true;
}
If I add for example const char haha[2222]; to struct TRecord, it works. I don't understand why. Can you help me?
P.S. I can't use string.

Add this line as to top of you Add function declaration, It will fix your Segmentation Fault problem.
m_record[m_count] = new TRecord;
But as you can see in answers and comments, your code has many problems. Most important problem is that you have not any good plan for your garbage objects. So your code have memory leakage.

One error is that you are not following the rule of three in your CRegister class. That often causes segfaults.
Another error is that you do not initialise your m_record[i] pointers. So you destructor may call delete[] on garbage values.
A third error is that you apparently dereference the same garbage values in CRegister::Add.

Related

Corrupted struct char arrays - sqlite C++

I am a bit puzzled by this one. Everything has been fine so far with using SQLite but now I am trying to store my query results in a simple struct. When I do this in my callback, all my data looks great in my SQLItems vector but as soon as the callback exits, my SQLItems vector holding my rows of data is suddenly corrupted. Any ideas what could be causing this?
// Simple struct to hold column name and row data
struct SQLrow {
char * Column;
char * Data;
};
// static Vector to hold SQL rows
static std::vector<SQLrow> SQLItems;
...
// static callback that handles placing query results into structs and into SQLItems vector
// SQLItems column/row data gets corrupted after this function exits
static int countTablesCallback(void *data, int count, char **rows, char **azColName) {
int i;
for (i = 0; i < count; i++) {
SQLrow newItem = { azColName[i] ,rows[i] };
SQLItems.push_back(newItem);
}
*static_cast<std::vector<SQLrow>*>(data) = SQLItems; // Tried this too but throws an exception
return 0;
}
I also thought maybe it is only possible to statically cast from the callback to save the vector but that is throwing an exception as well. Stumped here. Thanks for any advice!
Your vector is fine, the static_cast makes no sense there, unless data is actually used as an out parameter. Your problem is, most likely, that SQLrow holds char pointer and SQLite deletes the pointed-to strings after the callback returns. Changing your class to
struct SQLrow {
std::string Column;
std::string Data;
};
should solve the problem.
Just looking at the code, it appears that the data pointed to by rows will be invalidated/destroyed/changed once the callback returns. So you can't retain those pointers for later use, and will have to make a copy of the data.
One easy way is to change Column and Data from char * to std::string. Failing that, you'll have to do some sort of manual memory management (allocate space with new, then delete it later) which is error prone and not really advisable these days.
In my opinion, there are very few case in which you want/need to use raw string in c++ and yours isn't one of those. By the way I hope this will help you or someone else in some way:
#include <vector>
#include <stdio.h>
#include <string.h>
#include <iostream>
struct SQLrow {
char* Column;
char* Data;
};
void your_callback(int count, char **rows, char **azColName) {
std::vector<SQLrow> rows_list;
for (int i = 0; i < count; i++) {
/* Uncomment this if you want
your copy of the strings. If you
use this, don't forget to free the
memory yourself with delete[] s1 and
s2.
size_t s1_len = strlen(rows[i]);
size_t s2_len = strlen(azColName[i]);
char* s1 = new char [sizeof(char) * (s1_len + 1)];
char* s2 = new char [sizeof(char) * (s2_len + 1)];
memcpy(s1, rows[i], s1_len);
s1[s1_len] = '\0';
memcpy(s2, azColName[i], s2_len);
s2[s2_len] = '\0';
SQLrow r = { s1, s2 }; */
SQLrow r = { rows[i], azColName[i] };
rows_list.push_back(r);
}
// test the result
for (int i = 0; i < count; i++) {
SQLrow r = rows_list.at(i);
std::cout << "rows:" << r.Column << " azColName:" << r.Data << std::endl;
}
}
// this 2 lines are just for simulating the data
// you will get this 'warning: ISO C++ forbids converting a string constant to char*''
char* rows[] = {"row1", "row2" , "row3" };
char* colName[] = {"name1", "name2", "name3" };
int main()
{
your_callback(3, rows, colName);
return 0;
}

how to fix 'Access violation reading location' in this code

run this code i got some error like this
' Exception thrown at 0x778D7FCB (ntdll.dll) in Project1.exe: 0xC0000005: Access violation reading location 0x00000014.'
This error occurs in this line
~UnivStudnet() {
delete[]major; // error
}
#include <iostream>
#include <cstring>
using namespace std;
class Person {
private:
char * name;
public:
Person(const char * myname) {
name = new char[strlen(myname) + 1];
strcpy_s(name, strlen(name), myname);
}
~Person() {
delete[]name;
}
void WhatYourName() const {
cout << "My name is " << name << endl;
}
};
class UnivStudnet : public Person {
private:
char * major;
public:
UnivStudnet(const char * myname, const char * const mymajor) :Person(myname) {
major = new char[strlen(mymajor) + 1];
strcpy_s(major, strlen(major), mymajor);
}
~UnivStudnet() {
delete[]major;
}
void WhoAreYou() const {
WhatYourName();
cout << "My major is " << major << endl;
}
};
int main(void) {
UnivStudnet st1("kim", "Mathenatics");
st1.WhoAreYou();
UnivStudnet st2("hong", "Physiscs");
st2.WhoAreYou();
return 0;
}
How do I fix this error?
There are bugs on the two strcpy_s lines.
strcpy_s(name, strlen(name), myname);
should be
strcpy_s(name, strlen(myname)+1, myname);
and likewise
strcpy_s(major, strlen(major), mymajor);
should be
strcpy_s(major, strlen(mymajor)+1, mymajor);
Calling strlen on the newly-allocated char arrays name and major which have indeterminate values, causes undefined behavior which is the cause of your crash.
Your strcpy_s usage is suspect.
major = new char[strlen(mymajor) + 1];
strcpy_s(major, strlen(major), mymajor);
The second parameter to strcpy_s is the allocated size of the buffer specified by the first parameter. (And I just now realized - based on another answer that strlen(major) is undefined before you copy to it!
You are allocating the buffer to be large enough to hold the string, but the subsequent call to strcpy_s is indicating that major isn't big enough to hold the entire string including the null char.
Better:
size_t len = strlen(mymajor) + 1;
major = new char[len];
strcpy_s(major, len, mymajor);
Repeat the above pattern for the base class name parameter as well.
You could go more C++-way:
You need to declare:
virtual ~Person()
destructor in base class and then:
class UnivStudnet : public Person {
private:
std::string major;
public:
UnivStudnet(const char * myname, const char * const mymajor) :Person(myname), major(mymajor) {
}
virtual ~UnivStudnet() {
}
...
This way you will achieve what you need and do not think about memory allocation/deallocation. Remember to #include <string> header.
Same way do it in Person class.

Dynamic memory allocation to array of pointers to object

I have a class named Student
class Student
{ string name;
unsigned long int ID ;
string email;
unsigned short int year;
public :
Student() // Constructor
string getName(void);
unsigned long int getID(void);
string getEmail(void);
unsigned short int getYear(void);
{
and another class named eClass
class eClass {
private:
string eclass_name;
Student* students[100];
unsigned int student_count;
public:
eClass(string name)
{
student_count =0 ;
eclass_name = name ;
}
bool exists(Student obj)
{
unsigned long int code = obj.getID();
bool flag = TRUE ;
for (unsigned int i = 0 ; i<=student_count ; i++ )
{
unsigned long int st = (*students[i]).getID();
if (code==st)
{
flag = FALSE;
}
}
return flag;
}
void add(Student& obj)
{
bool res = exists(obj);
if (res)
{
students[student_count] = new Student(); //probably the problem is here
*students[student_count] = obj ;
student_count++ ;
}
}
string getEclassName(void) { return eclass_name; }
unsigned int getStudentCount(void) { return student_count; }
Student getStudent(int i) { return *students[i-1]; }
};
The statement Student* students[100]; must look exactly like this . For example I can't write something like this: Student* students[100]={} ;
And main() looks like this
int main()
{
Student JohnDoe("John Doe", 12345, 2, "johndoe#gmail.gr");
eClass Cpp("C++");
Cpp.add(JohnDoe);
}
Basically I have an array of pointers to Student objects and I want to allocate dynamically memory every time I want to add a new Student object.
When I compile I get no errors but when I try to run the program the only thing I get is "Program_name.exe" stopped running...
I'm pretty sure the problem has to do with memory allocation but I'm not able to find it and solve it.
Any suggestions ?
The main bug in exists was the loop went one too far, using an uninitialized pointer. But also it is very bad style for exists to take its input by value. Fixing both of those:
bool exists(Student const& obj)
{
unsigned long int code = obj.getID();
bool flag = TRUE ;
for (unsigned int i = 0 ; i<student_count ; i++ )
{
unsigned long int st = (*students[i]).getID();
if (code==st)
{
flag = FALSE;
}
}
return flag;
}
You should declare getID() const inside student in order to be able to code exists correctly.
unsigned long int getID() const;
First, you should initialize all of your student pointers to either NULL or nullprt. This is not strictly needed but is a very good habit to get into. You'll thank yourself later.
Second, why are you returning false if the student exists? Kind of confusing I'd imagine. Also, you can use the break statement after you find your student exists; no need to check the rest of them.
Also, on your add, you may want to check to ensure you don't have MORE than 100 students. This will overwrite memory and bad things will happen.

c++ pointer being freed was not allocated error

I am practcing c++'s new/delete, hashfunction and linked.
I made a practice by myself.
I have a struct which is
typedef struct student
{
int id;
string fName;
string lName;
student * nextStudent;
}Student;
Then in main function, I define an array of student
Student * table = new Student [10];
I have my own hash function which takes the id, and change to 0-9.
I want to add a student I do following
void addStudent(int studentId, string firstName, string lastName, Student *table)
{
// using hash function, convert the id into hashed id
int hashedID = hashFunction( studentId );
Student * pointer = &table[hashedID];
while(pointer->nextStudent !=NULL){
pointer = pointer->nextStudent;
}
// once we reach to the student who has NULL in nextStudent
// add student
Student *tmp = new Student;
tmp->id = studentId;
tmp->fName = firstName;
tmp->lName = lastName;
tmp->nextStudent = NULL;
// link
pointer->nextStudent = tmp;
}
I tested it, it seems fine.
The problem is deletion.
Since student variables are stored in dynamic memeory,
I need to use delete.
The following is my code.
void deleteAll(Student *table, int len)
{
for (int i = 0; i < len; i++)
{
Student* tmp = &table[i];
// delete student info except the last one
while ( tmp -> nextStudent !=NULL){
Student* tmp2;
tmp2 = tmp;
tmp = tmp->nextStudent;
delete tmp2;
}
}
}
I visited every student varialbes ane do the deletion.
I cannot find any probelm in my deletion funtion...
This is what I got after run..
malloc: *** error for object 0x7f85f1404b18: pointer being freed was not allocated
I have no clue what I have done wrong..
Can you help me?
EDIT...
As you guys metion
I added "delete [] table" in the main funtion..
Also, I remove "delete tmp" in deleteAll function; i think "delete [] table" will handle that part.
Still does not work..
By the way I forgot to added initTable function in the initial post.
initTable initialize the table...
void initTable (Student *table, int len)
{
for (int i = 0; i < len; ++i)
{
table[i].nextStudent = NULL;
}
}
Thank you.
The nextStudent field is never initialized, so all 10 elements created here have it pointing to unknown values.
Student * table = new Student [10];
This causes addStudent to loop until some pointer->nextStudent hits a NULL value by chance, then overwrite memory it doesn't own (unless it hits the lucky NULL on the first iteration).
while(pointer->nextStudent !=NULL) { ... }
The 'student` struct (btw, why the typedef?) should have a constructor to at least do this.
student::student() : nextStudent(NULL) { }
[ EDIT ] The other issue that #JonathanPotter duly pointed in a comment is that the head of each of the 10 student lists is a member of the table array. It is not dynamically allocated, and should not be individually deleted.
The qucik/easy fix would be to add a student destructor to recursively delete child nodes:
student::~student() { if(nextStudent) delete nextStudent; }
Then deleteAll would reduce to:
void deleteAll(student *table, int len)
{
for (int i = 0; i < len; i++)
{
student *tmp = &table[i];
if(tmp->nextStudent) delete tmp->nextStudent;
}
// this leaves the dynamically allocated table[] in place
// to delete it as well, just `delete [] table;`
}
However, such recursion may become impracticable once the lists grow large, and should better be rewritten as an iteration (without the recursive destructor).
student::~student() { }
// ...
void deleteAll(student *table, int len)
{
for(int i = 0; i < len; i++)
{
student *tmp = &table[i];
// delete student info except the *first* one
for(student *tmp2; tmp2 = tmp->nextStudent; )
{
tmp->nextStudent = tmp2->nextStudent;
delete tmp2;
}
}
// this leaves the dynamically allocated table[] in place
// to delete it as well, just `delete [] table;`
}
Then in main function, I define an array of student
Student * table = new Student [10];
First of all you are creating array of Student not Student*. And late you are trying to delete not allocated values. This is the reason of your program behavior.
To create pointer of array of pointers Student* you need the following:
Student** table = new Student*[10];
Than change your functions arguments from Student* table to Student** table and continue research.
Also do not forget to delete table using delete[] table;
Good Luck.

Error reserving memory in the heap c++

#include<iostream>
using namespace std;
#include<cstring>
struct stringy
{
char * str;
int ct;
};
void set(stringy & stringa, char ar[]);
void show(stringy & stringa);
int main()
{
stringy beany;
char testing[] = "Reality isn't what is used to be.";
set(beany, testing);
show(beany);
return 0;
}
void set(stringy & stringa, char * ar)
{
char * ps = new char[strlen(ar) + 1];
stringa.str = ps;
strcpy(ar,ps);
cout << strlen(stringa.str);
stringa.ct++;
delete [] ps;
}
void show(stringy & stringa)
{
for(int i = 0; stringa.str[i] != '\0'; i++)
{
cout << stringa.str[i];
}
}
This is my code. It's part of an exercise. I was given the body of the main function as asked to write functions that did the requested task.
locates space to hold copy of testing,
sets str member of beany to point to the
new block, copies testing to new block,
and sets ct member of beany
My issue is with the set function. I feel as though i have satisfied the criteria, the strlen is there because i am trying to figure out what is going on... it returns 0. then the program exits.
There are a lot of problems with this code, among which:
strcpy(ar, ps);
This copies ps to ar, not the other way around. You want:
strcpy(ps, ar);
This error would have been detected by the compiler if the const qualifier were used as it should have been.
Additionally, the delete[] ps at the end of set() should not be there.
Finally, I'm not sure what the purpose of the ct field is, so I can't tell you what it should be, but incrementing an uninitialized field is certainly wrong.