From reading other stackoverflow questions I am aware that this error means I am trying to dereference a null pointer. However, I cannot figure out where my code is dereferencing a null pointer. I am trying to set a char* (cstring) to a non-null value, but I get an access violation error. Here is the code:
void Data::setName(char const * const name)
{
if (this->name)
delete[] this->name;
this->name = new char[strlen(name) + 1]; // This is where my code breaks in debug mode
strcpy(this->name, name);
}
name is a char* variable that gets initialized to null. setName is being called by an overloaded assignment operator:
Data& Data::operator=(const Data& data2)
{
//if it is a self copy, don't do anything
if (this == &data2)
return *this;
else
{
setName(data2.name); // Here is the call to setName
return *this;
}
}
P.S. For the love of god please don't tell me I shouldn't be using cstrings! I know std::string is better, but this is for a homework assignment that requires cstrings.
If this is the line the code breaks:
this->name = new char[strlen(name) + 1];
then name must be a null pointer, since nothing else is being dereferenced. name is being dereferenced inside the strlen function. Just print the variable value in your debugger and you will be sure.
Also, using same name of variable in the setter like this:
struct A
{
void set(int a){this->a = a;}
int a;
};
is not a good practice. Just use:
struct A
{
void set(int na){a = na;}
int a;
};
or
struct A
{
void set(int a){a_ = a;}
int a_;
};
Related
When compiling this code, I get this warning:
Conditional jump or move depends on uninitialized value(s)
My set function is using a dynamic array and I wish to have it delete the dynamic space if it already exists.
The class:
class Name
{
char* m_name;
public:
Name();
Name(const char*);
~Name();
void set(const char*);
}
The constructor and setEmpty():
void Name::setEmpty()
{
m_name = nullptr;
}
Name::Name()
{
setEmpty();
}
The function:
void Name::set(const char* name)
{
if (name == nullptr || std::strlen(name) == 0)
{
setEmpty(); // <-- What my constructor has; sets 'm_name' to nullptr;
}
else
{
int length = std::strlen(name) + 1;
if (m_name != nullptr) // <-- gives warning because m_name is not initialized however it was created via constructor (?)
{
delete[] m_name;
}
m_name = new char[length]; // <-- No matter what I want to re-create the dynamic array
std::strcpy(m_name, name);
}
}
Main():
int main()
{
// constructors
Name s1("Sample");
Name s2, s3;
Name badData[] = {
Name ("Kappa"),
Name("Omega"),
Name(nullptr),
Name("", )
};
s1.set("Sample");
//...//
}
It's not terribly clear, but if your class has any constructors that don't call setEmpty(), possibly one of them does not initialise m_name. If that happens, a subsequent call of set() with a non-null pointer for which strlen() returns a non-zero value will test the value of m_name when it is uninitialised. You haven't shown how the constructor that accepts a const char * is defined, so it is possible that constructor is the culprit. – Peter 5 mins ago
This actually was the problem.
Solution:
Name::Name(const char* name)
{
setEmpty(); // <-- call safe state in all constructors
set(name, dob, power, level, super);
}
I didn't realize I needed to call either the function or the constructor that initializes values before I use my set function in the overloaded constructor.
Thank you Peter.
I am searching for a long time on net. But no use. Please help or try to give some ideas:
I found a reproductive error in template class when I tried to alloc more space for a dynamic array member managed by a pointer with a friend function. If I turn to another member function, or just in the Push(), to finish this process, error vanished.
Independent from private/public accessibility, Error cover all field of array member accession, once I tried to read or delete element in it, error happend.
No clear tips were given by GCC compiler. Error didn't affect basic types, like int.
Binding friend & Unbinding friend both suffer from this error
Is there anything wrong in my code, or there is some limitation I didn't know in using memory function?
Every opinion, link and anwser is appreciated.
PS: To make posted code more clearly, I simplify some unimportant code. But to provide enough imformation, it still looks so long, feel sorry to the
reading difficulty.
PS2:Guarantee can be made that code simplified is correct.
Error occurs both in Debug mode(x64 and x86),Visual Studio 2017
and cmake 3.13.4-GCC 7.2.0 toolchain debugging with gdb in VScode.
//Bizcard.hpp
class Bizcard
{
private:
char *name;
char *phone;
public:
Bizcard();
Bizcard(const char* n,const char* phone);//constructor
Bizcard(const Bizcard &b);//copy constructor
Bizcard& operator=(const Bizcard& b);//assignment operator
~Bizcard();
};
//Bizcard.cpp
#include"Bizcard.hpp"
#include<string.h>
#include<iostream>
Bizcard::Bizcard()
{
name = nullptr;
phone = nullptr;
}
Bizcard::Bizcard(const char* n ,const char* p)
{
//simplified...
}
Bizcard::Bizcard(const Bizcard &b)
{
//simplified...
}
Bizcard& Bizcard::operator=(const Bizcard& b)
{
if(this==&b)
return *this;
delete[] this->name;//Error would occur here if using
//friend func to expand array capacity
delete[] this->phone;
if(b.name==nullptr)
{
name = nullptr;
phone = nullptr;
return *this;
}
int nlen = strlen(b.name);
int plen = strlen(b.phone);
this->name = new char[nlen+1];
strcpy_s(name, nlen + 1, b.name);
this->phone = new char[plen+1];
strcpy_s(phone, plen + 1, b.phone);
return *this;
}
Bizcard::~Bizcard()
{
delete[] name;
delete[] phone;
}
//BagTemplate.hpp
#include<stdlib.h>
#include<algorithm>
#include<iostream>
#include"Bizcard.hpp"
template<typename Type>
void ChangeSize1D_binding(Type* array, int old_capacity, int new_capacity)
{
if(new_capacity<old_capacity)
throw "Paragram Error! New capacity must greater than the old one.";
Type* temp_array =new Type[new_capacity];
std::copy(array,array+old_capacity,temp_array);
delete[] array;
array = temp_array;//Point array to the dest of temp_array
}
template<typename T>
class Bag
{
public:
Bag(int bagCapability =3);
~Bag();
void Push(const T&);
void ChangeSize1D_self(int old_capacity, int new_capacity);
private:
T *array;
int capacity;
int top;
friend void ChangeSize1D_binding<T>(T* array, int old_capacity, int new_capacity);
template<typename Type>
friend void ChangeSize1D_unbind(Type* array, int old_capacity, int new_capacity);
};
template<typename T>
Bag<T>::Bag(int bagCapacity):capacity(bagCapacity)
{
if(capacity<1) throw "Capacity must be >0";
array = new T[capacity];
top = -1;
}
template<typename T>
Bag<T>::~Bag()
{
delete[] array;
}
template<typename T>
void Bag<T>::ChangeSize1D_self(int old_capacity,int new_capacity)
{
if(new_capacity<old_capacity)
throw "Paragram Error! New capacity must greater than the old one.";
T* temp_array =new T[new_capacity];
std::copy(array,array+old_capacity,temp_array);
delete[] array;
array = temp_array;
}
template<typename Type>
void ChangeSize1D_unbind(Type* array, int old_capacity, int new_capacity)
{
if(new_capacity<old_capacity)
throw "Paragram Error! New capacity must greater than the old one.";
Type* temp_array =new Type[new_capacity];
std::copy(array,array+old_capacity,temp_array);
delete[] array;
array = temp_array;
}
template<typename T>
void Bag<T>::Push(const T& x)
{
if(capacity ==top+1)
{
//this->ChangeSize1D_self(capacity,2*capacity);
ChangeSize1D_unbind(array,capacity, 2*capacity);
//ChangeSize1D_binding(array,capacity, 2*capacity);
/*T* temp_array = new T[2 * capacity];
std::copy(array,array+capacity,temp_array);
delete[] array;
array = temp_array;*/
capacity*=2;
}
array[++top]=x;
}
//main.cpp
int main()
{
Bag<int> IntBag;
IntBag.Push(1);
IntBag.Push(1);
IntBag.Push(1);
IntBag.Push(1);
Bag<Bizcard> BizcardBag;
BizcardBag.Push(Bizcard());
BizcardBag.Push(Bizcard());
BizcardBag.Push(Bizcard());
BizcardBag.Push(Bizcard());//Error may happen here since Push() it need
//expanding capacity(origin value: 3)
/*1.as predict, Push success if change size process is directly in Push()
2.when turn to ChangeSize1D(), same error occur
2.1 when change to private member func, no error
2.2 when change to public member func, no error
2.3 when change to private unbinding friend func, same error occur;means private or public doesnt effect behaviour
2.4 when change to private binding friend func, same error occur
*/
return EXIT_SUCCESS;
}
#CMakeLists.txt
cmake_minimum_required(VERSION 2.6)
project(BugReproduct)
include_directories("${PROJECT_SOURCE_DIR}/Bizcard")
add_subdirectory("${PROJECT_SOURCE_DIR}/Bizcard")
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED true)
add_executable(BugReproduct ArrayExpansion.cpp)
target_link_libraries(BugReproduct Bizcard)
#Bizcard/CMakeList.txt
add_library(Bizcard Bizcard.cpp)
Problem SOLVED, this error happened because I pass the pointer directly to friend func, thus friend func would hold a copy but not reference or pointer to it. When I changed the destination the copied "array" pointed to in friend func, which changed the address value it saved, such process do nothing to the real array pointer outside, leading to error when I access the extra alloc element.
This issue can be another footnote about how dangerous pointer is and how much effort should be made before using pointer prefectly.
Profound appreciate to all the help you ever gave. Thank you all.
I have a class that contains an array of object pointers as its member variable. I'm currently having an issue in getting the compiler to copy an object to the end of the array as when I step through the program the array of objects reads that its memory cannot be read. Anyone know what the issue might be?
void Notifications::operator+=(const iMessage& src) {
iMessage** temp2 = nullptr;
temp2 = new iMessage*[size+1];
if (size != 0){
for (int i = 0; i < size; i++) {
*temp2[i] = *messages[i];
}
}
*temp2[size] = src; //compiler states that it cannot read the data from temp2 after this point
delete[]messages;
for (int i = 0; i < size + 1; i++) {
*messages[i] = *temp2[i]; //Unhandled exception at 0x00C58F99 in w5.exe: 0xC0000005: Access violation reading location 0x00000000.
}
size++;
}
Notifications.h
#include "iMessage.h"
#include <vector>
namespace w5 {
class Notifications {
int size;
iMessage **messages;
public:
Notifications();
Notifications(const Notifications&);
Notifications& operator=(const Notifications&);
Notifications(Notifications&&);
Notifications&& operator=(Notifications&&);
~Notifications();
void operator+=(const iMessage&);
void display(std::ostream&) const;
};
}
IMessage.h
#ifndef _I_MESSAGE_H_
#define _I_MESSAGE_H_
// Workshop 5 - Containers
// iMessage.h
#include <iostream>
#include <fstream>
namespace w5 {
class iMessage {
public:
virtual void display(std::ostream&) const = 0;
virtual iMessage* clone() const = 0;
virtual bool empty() const = 0;
};
iMessage* getMessage(std::ifstream&, char);
}
#endif
Message.h
#include "iMessage.h"
namespace w5{
class Twitter : public iMessage {
std::string msg;
public:
Twitter(char, std::ifstream&);
virtual void display(std::ostream&) const;
virtual iMessage* clone() const;
virtual bool empty() const;
};
class Email : public iMessage {
std::string msg;
public:
Email(char, std::ifstream&);
virtual void display(std::ostream&) const;
virtual iMessage* clone() const;
virtual bool empty() const;
};
}
1) Just use vector.
2) You should always post exact compiler messages. "compiler states that it cannot read the data from temp2 after this point" is not good enough.
3) You allocate an array of pointers, and then dereference those pointers, but you never let the pointers point anywhere.
4) You delete the messages array and then proceed to copy back into it as if it was still there. (What you actually want to do is just assign messages = temp2.)
5) You're slicing objects all over the place, by using assignment to attempt to copy iMessage objects. There's a reason iMessage has a clone() function.
First you do
delete[]messages;
then you do
*messages[i] = *temp2[i];
attempting to access the array you've just deleted. I think you just want to take the pointer to the array you've just created:
messages = temp2;
You also do
*temp2[size] = src;
when temp2[size] doesn't point to anything. That should probably be
temp2[size] = src.clone();
to make a persistent copy of the argument and store it in the array.
It's rather tricky to follow this weird pointer-juggling; I think you also want to delete each element of messages before messages itself to avoid leaks. Why not just use std::vector to take care of memory allocation for you? That will reduce the whole insane dance to
std::vector<std::unique_ptr<iMessage>> messages;
void operator+=(const iMessage & src) {
messages.emplace_back(src.clone());
}
Also, _I_MESSAGE_H_ is a reserved name. You should remove the leading underscore.
You want to convert a const reference into a non-const pointer.
I wonder that the compiler doesn't throw errors. Which compiler you use?
Is something like this not possible?
void Notifications::operator+=(iMessage* src) {
I was not testing but this should also work:
void Notifications::operator+=(iMessage& src) {
*bar[foo] = &src;
I have written following piece of code
#include<iostream>
#include<cstring>
using namespace std;
///Driver class
class driver
{
char *name;
int age;
public:
//Default contructor
driver(){}
//Constructor for initialize
driver(int a, char* n)
{
age = a;
int len = strlen(n);
//Allocate memory for name
name = new char[len];
strcpy(name, n);
}
//Copy constructor
driver(const driver &d)
{
name = new char[strlen(d.name)];
strcpy(name, d.name);
age = d.age;
}
void print()
{
cout<<"Name: "<<name<<endl;
cout<<"Age: "<<age<<endl;
}
~driver()
{
if(name != NULL)
{
delete name;
}
}
};
class automobile
{
driver drv;
char* make;
int year;
public:
automobile(driver d, char* m, int y)
{
drv = d;
int len = strlen(m);
make = new char[len];
strcpy(make, m);
year = y;
}
void print()
{
drv.print();
cout<<"Make: "<<make<<endl;
cout<<"Year: "<<year<<endl;
}
~automobile()
{
if(make!=NULL)
{
delete[] make;
}
}
};
int main()
{
driver d(15, "Jakir");
automobile a(d, "Toyta", 1980);
a.print();
return 0;
}
I have to use char* not string and allocate memory dynamically. But when I run the code, there occurs an error of memory leaks. I think it's due to the copy constructor and de-allocation memory of driver class. How to fix the error? Any suggestion is appreciated. Thanks in advance.
There is a lot of stuff wrong with this code, but I will list a few of the big ones.
As smentioned by others, you new char's need to be one bigger than they are.
You default constructor should set name to nullptr.
you have a memory handling error whenever you do an assignment, eg on this line: drv = d; because it calls the default operator=, which is incorrect in your case. Ther eis the Law of the Big Three which loosely states that whenever you need either a (non-trivial) copy constructor, copy assignment operator, or destructor, you'll most likely need to implement the others, too. You need to write an operator=!
Based on existing code, I would expect your operator= to look vaguely like this:
//assignment operator
const driver&operator=(const driver &rhs)
{
if (this==&rhs) return *this;
delete[] this->name;
this->name = new char[strlen(rhs.name)+1];
strcpy(this->name, rhs.name);
this->age = rhs.age;
return *this;
}
Do all that, and your core dump goes away.
PS Please, please just learn to use std::strings, new-ing char arrays and managing the memory yourself is a bad bad move.
name = new char[len+1]; not name = new char[len];
name = new char[strlen(d.name) + 1]; not name = new char[strlen(d.name)];
delete[] not delete
Need to define an assignment operator driver& operator=(const driver &d) in order to follow the rule of three.
Similar changes need to automobile.
However I don't see a memory leak, what makes you think you have one?
In main method you need to do like this,
driver* d = new driver(15, "Jakir");
automobile* a = new automobile (d, "Toyta", 1980);
a->print();
if ( a ) delete a ;
if ( d ) delete d ;
return 0 ;
I have implemented a class string, similar to std::string one.
I have a problem when the destructor is called: the field length has the length of the characters allocated in field.
This is the class:
class indexException:public std::exception
{
public:
virtual const char* what()
{
return "Index is either too long, or negative";
}
};
class string
{
public:
static const unsigned int length_max=100;
string(const char* field=NULL)
{
if(field!=NULL)
{
const unsigned int length=strlen(field);
this->field=new char[length+1];
this->length=length;
for(unsigned int i=0;i<=length;i++)
this->field[i]=field[i];
}
else
{
this->field=NULL;
length=0;
}
}
string(string& str)
{
string(str.field);
}
~string()
{
if(length>0)
delete field;
}
char& operator[] (int i) const throw()
{
try
{
if(i<0 || i>=(int)length)
throw indexException();
}
catch(indexException& e)
{
std::cerr << e.what() << std::endl;
}
return field[i];
}
string& operator=(const char* field)
{
const unsigned int length=strlen(field);
if(this->length>0)
delete this->field;
this->field=new char[length];
this->length=length;
for(unsigned int i=0;i<length;i++)
this->field[i]=field[i];
return *this;
}
string& operator= (const string& str)
{
if(this!=&str)
*this=str.field;
return *this;
}
operator char* ()
{
return field;
}
friend std::ostream& operator<< (std::ostream& out, string& str);
friend std::istream& operator>> (std::istream& in, string& str);
public:
unsigned int length;
char* field;
};
std::ostream& operator<<(std::ostream& out, string& str)
{
out << str.field;
return out;
}
std::istream& operator>> (std::istream& in, string& str)
{
char temp[string::length_max];
in >> temp;
str=temp;
return in;
}
If I use the assignment operator, this doesn't cause a segmentation fault.
But it undirectly cause it.
I explain how:
int main(int argc,char** argv)
{
string str="hi";
string str2=str;
return 0;
}
Putting a breakpoint into the assignment operator overloading, I realized that the assigment operator doesn't cause segmentation fault.
The problem is after, when exiting from main.
If I remove the destructor I don't get this segmentation fault, but I would know why I get this problem.
Edit: I have understood where's the problem.
I followed your suggestions but it still goes to segmentation fault.
But now it doesn't crash anymore on the destructor method, but on the assignment operator overloading:
string& operator=(const char* field)
{
unsigned int length=0;
if(field!=NULL)
length=strlen(field);
else
field="";
if(this->length>0)
delete[] this->field;
this->field=new char[length+1];
this->length=length;
strcpy(this->field,field);
return *this;
}
The problem is when I delete this->field, the debugger stops there.
An example of segmentation fault:
string str("hi");
string str2=str;
This causes segmentation fault.I suppone it's because str2 is not initialized, and length has an undefined value.
If I instead do this:
string str("hi");
string str2;
str2=str;
There isn't any segmentation fault.Why?
I thought that calling :
string str2;
Was also calling the constructor, or is that the "=" operator has the precedence?
How to solve this?
PS: I also changed other things,like the copy constructor.
Full code is here:
http://pastebin.com/ubRgaVr8
Solved: I changed the copy constructor as suggested in the accepted reply:
string(const string& str)
{
length=str.length;
field=new char[str.length+1];
memcpy(field,str.field,length+1);
}
Your copy constructor doesn't initialise the object.
string(string& str)
{
string(str.field); // Does nothing
}
string(str.field)creates an unnamed stringand immediately throws it away.
It does not initialise this object using a different constructor.
Since your object now consists only of randomness, bad things will happen when you try to destroy it.
To make sure things are initialised, make a private member function
void initializeFromChars(const char* cString);
that does the work and use it in your constructors and assignment operator.
EDIT: Scrapped my previous answer, as it was incorrect.
The problem appears to be the copy constructor, you are passing the field from the source instance as though it is merely another null terminated char*, but it isn't.
You don't copy the null character at the end during the char* assignment invoked by the previous statement, you use an internal length field instead, and copy only that many bytes.
so your copy constructor should be:
string(string& str)
{
length = str.length;
field = new char[length];
memcpy(field, str.field, length);
}
or, if you want to preserve compatibility with null terminated functions, and you have ensured that the null is kept for all other assignments/constructors, etc:
string(string& str)
{
length = str.length;
field = new char[length + 1];
memcpy(field, str.field, length + 1);
}
In fact, the mixing null terminated, and specified length strings so much throughout your class appears to be confusing you.
I would create an internal, private, single disposal method, and an array of methods to set various source types, and have the constructors, assignment operators, and destructors use those instead.
That way you only have a single places where any given operation occurs, rather than juggling many minor variations on the same functionality. For example:
private:
void internalSet(const char *source) {
if (source == NULL) {
length = 0;
field = NULL;
}else{
length = strlen(source);
field = new char[length];
memcpy(field, source, length);
}
}
void internalSet(const string &source) {
length = source.length;
if (length > 0) {
field = new char[length];
memcpy(field, source.field, length);
}else{
field = NULL;
}
}
void internalDispose() {
delete[] field;
}
public:
string() : field(NULL), length(0) {}
string(const string& source) { internalSet(source); }
string(const char *source) { internalSet(source); }
~string() { internalDispose(); }
string& operator=(const char *source) {
internalDispose();
internalSet(source);
return *this;
}
string& operator=(const string &source) {
internalDispose();
internalSet(source);
return *this;
}
void clear() {
internalDispose();
length = 0;
}
Your destructor uses delete, when it should use delete[].
Once you allocate memory with
field = new char[length+1];
You should delete it with:
delete [] field;
And you're not checking whether your allocation was successful.
Another thing considered good practice is setting field to NULL after delete so it won't get deleted twice (if you start delivering classes) for example:
~string(){
delete [] field;
// field = NULL;
}
Note: according to Dietmar Kühl setting field=NULL isn't good practice (take a look at the comments) and choose your way, here's question specifically about this: Is it worth setting pointers to NULL in a destructor? .
Note 2: KerrekSB pointed out that delete [] field will do nothing if pointer is NULL and whole condition is unnecessary.
Than in string& operator=(const char* field) you probably want to allocate length + 1 and iterate to it too (to include terminating NULL).
And I don't like your string& operator= (const string& str), you have cached info on length of string and you're using strlen() and than manual copy char by char.
Your copy constructor also looks bad... You should "copy" manual allocation and copy byte by byte to it. Or rather build protected function like fromCString(const char *) and use it in both constructors and assign operators.
If those doesn't help ask in comment for more help.