Part of a larger program I am making requires a path to be read in from the command line and stored in a class. Because paths can be an arbitrary size and it's needed in multiple functions, I store it in a char* in the header file. But, for some reason, when I assign a value to it, the program segfaults.
The debugger (gdb) shows the following:
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7b4828a in std::basic_istream<char, std::char_traits<char> >& std::operator>><char, std::char_traits<char> >(std::basic_istream<char, std::char_traits<char> >&, char*) ()
from /usr/lib/libstdc++.so.6
Here's the program I wrote to demonstrate the problem:
test.cpp:
#include "test.h"
#include <iostream>
#include <cstring>
Test::Test() {
filepath = NULL;
}
void Test::set_path(char* string) {
char temp[strlen(string) + 1];
strcpy(filepath, temp);
}
char * Test::get_path() {
return filepath;
}
int main(int argc, char *argv[]) {
std::cout << "Enter a file path: ";
char *temp;
std::cin >> temp;
Test *temp2 = new Test();
temp2->set_path(temp);
std::cout << "Path: " << temp2->get_path() << std::endl;
}
test.h:
#ifndef TEST_H
#define TEST_H
class Test {
private:
char *filepath;
public:
Test();
void set_path(char *);
char * get_path();
};
#endif // TEST_H
I'm not sure why it crashes. Is there something wrong with the method I'm doing this? Also, rather than just switching to strings, I'd like to find out more about this problem.
Thanks in advance!
temp (inside main) is uninitialized and not pointing to any valid allocated block of memory, therefore the line:
std::cin >> temp;
is causing input to be written into some unknown part of memory, causing undefined behaviour. You should either:
Make temp a char[] and only read in an amount of characters that will fit in the buffer.
Point temp to a valid buffer.
Better yet, make temp an std::string, and let the std::string class worry about the memory management.
You're also going to be having a similar problem with filePath after you fix the above problem. filePath is being set to NULL in the Test constructor, and then you're copying temp to the block of memory pointed by filePath in Test::set_path:
strcpy(filepath, temp);
NULL refers to an address that you're not allowed to dereference. You should change all of your C-strings to std::strings and use the std::string member functions and overloaded operators to deal with strings in C++.
You call strcpy without allocating memory for the string to be copied in set_path. The manual page clearly states that dest must be large enough to contain the string in src. Besides you copy from an empty temporary. Although, your crash appears early, when you read from cin into an uninitialized pointer.
Use std::string.
#include <iostream>
class Foo
{
public:
Foo(const std::string& s) : s_(s) {} ;
private:
std::string s_;
};
int main()
{
std::string f;
std::cin >> f;
std::cout << f << std::endl;
Foo foo = Foo(f);
return 0;
}
If you really preffer what you are doing:
class Foo
{
public:
Foo(const char* s) {
size_t size = strlen(s);
s_ = new char[size + 1];
// safer
strncpy(s_, s, size + 1);
} ;
private:
char* s_;
};
int main()
{
char buffer[1024];
// be save
buffer[1023] = '\0';
Foo foo = Foo(buffer);
return 0;
}
The second example is still broken. It is missing a proper destructor, copy constructor and assignment operator. I'll leave this as an exercise.
Test::Test() {
filepath = NULL;
}
void Test::set_path(char* string) {
char temp[strlen(string) + 1];
strcpy(filepath, temp);
}
I'm not sure what you thought that strcpy was going to do, but what it does is copy from temp, which is uninitialized, to filepath, which is NULL. So neither parameter makes any sense.
Related
I have a class IStream2:
class IStream2 {
private:
char* fn;
public:
IStream2(char* filename);
char* get_filename();
};
IStream2::IStream2(char *filename) {
strcpy(fn, filename);
}
char * IStream2::get_filename() {
return fn;
}
And here is the main code:
vector<IStream2> istreams;
char fn[] = "file1.txt";
IStream2 reader2 = IStream2(fn);
istreams.push_back(reader2);
char fn2[] = "file2.txt";
IStream2 reader3 = IStream2(fn2);
istreams.push_back(reader3);
cout << istreams[0].get_filename() << endl;
It prints file2.txt but I expected file1.txt.
I know that I should use string but I would like to resolve this problem.
IStream2::IStream2(char *filename) {
strcpy(fn, filename);
}
Allocates no storage for fn. strcpy(fn, filename); invokes undefined behaviour writing into whatever storage fn points at, and after that all bets are off. The program could do anything.
The right answer is to use std::string
class IStream2 {
private:
std::string fn;
public:
IStream2(const char* filename); // note const. if not modifying a passed rference,
// mark it const. The compiler can make optimizations
// and can catch mistakes for you
// also the function can now receive string literals
const char* get_filename(); // another const this is because a string won't
// easily give you a non const pointer
}; <-- note the added ;
IStream2::IStream2(const char *filename): fn(filename) {
}
const char * IStream2::get_filename() {
return fn.c_str(); // get the char array from the string
}
But I suspect this is an exercise in writing C with Classes, so back into the stone ages we go. This is a LOT more work because we have to manage all of the memory ourselves. For example, We need to observe the Rule of Three. What is The Rule of Three?
Sigh.
class IStream2 {
private:
char* fn;
public:
IStream2(const char* filename); // note const char *
~IStream2(); // need destructor to clean up fn. This means we need to
// comply with the Rule of Three
IStream2(const IStream2 & src); // copy constructor
IStream2 & operator=(IStream2 src); // assignment operator
char* get_filename(); // Note: by returning a non const pointer here we
// allow the caller to tamper with the contents of
// fn and even delete it. This defeats the point
// of declaring fn private, so avoid doing this.
};
IStream2::IStream2(const char *filename) {
fn = new char[strlen(filename) +1]; // allocate storage.
// The +1 is to hold the string's NULL terminator
strcpy(fn, filename);
}
// implement copy constructor
IStream2::IStream2(const IStream2 & src) {
fn = new char[strlen(src.fn) +1];
strcpy(fn, src.fn);
}
// implement destructor
IStream2::~IStream2()
{
delete[] fn;
}
// implement assignment operator. Using Copy And Swap Idiom
IStream2 & IStream2::operator=(IStream2 src)
{
std::swap(fn, src.fn);
return *this;
}
char * IStream2::get_filename() {
return fn;
}
int main()
{
vector<IStream2> istreams;
const char* fn = "file1.txt"; // note const char *. string literals may be
// read-only memory and can't be changed
IStream2 reader2 = IStream2(fn);
istreams.push_back(reader2);
const char* fn2 = "file2.txt"; // and again const char *
IStream2 reader3 = IStream2(fn2);
istreams.push_back(reader3);
cout << istreams[0].get_filename() << endl;
return 0;
}
Since we are wresting with dinosaurs, I won't bother with the Rule of Five and move operations, but see how much more annoying it is to have to do this the wrong way?
More on Copy And Swap Idiom
I have a class:
class MyClass
{
char *filename1;
char *filename2;
public:
void setFilename1(std::string str)
{
filename1 = const_cast<char*>(str.c_str())
}
void setFilename2(std::string str))
{
filename2 = const_cast<char*>(str.c_str())
}
void function()
{
// do semthing
}
void printFilename1()
{
std::cout<<filename1<<std::endl;
}
}
This is my main function:
MyClass *p = new MyClass();
p->setFilename1("first_string");
p->printFilename1();
p->setFilename2("second_string");
p->printFilename1();
The output is very surprising to me:
first_string
second_string
I swear I have no typo in my function MyClass::setFilename2 and I'm not setting the filename2 variable twice.
I'm using the g++ compiler version 4.8.4. Here is how I compile my class:
g++ -g -O -Wall -fPIC -pthread -std=c++11 -Wno-deprecated-declarations -m64 -I/home/user/root-6.06.00/include -c myClass.cxx
Now, another surprise: when I altered the MyClass::setFilename function:
void setFilename2(char* str))
{
filename2 = str;
}
I got the output I expected:
first_string
first_string
Executing the function MyClass::function() doesn't change the value of any of my strings.
So what is going on? This contradicts what I know about C++. How can one function have impact on another if they don't refer to the same variables and have nothing to do with each other?
I suppose it may have something to do with the compiler version or some compiler options. But I have no clue what's going on.
Edit: Could you please explain to me why the piece of code behaves the way it does?
c_str() returns a pointer to a char array which is stays valid as long as the std::string is not modified; in your case, the std::string object over which you called c_str() is destroyed immediately after your method returns (it's a temporary object created on the fly from the string literal), so you are effectively storing a pointer to memory that has been deallocated. The fact that you see the new value when you do printFileName1 is just a side effect of the fact that the allocator is recycling the memory location used before for the other string; as far as the standard is concerned, this all is undefined behavior (and you can expect tragic crashes).
The correct way to go is to store an std::string directly inside your class, it will manage its own memory correctly for the whole lifetime of your MyClass instance.
class MyClass
{
std::string filename1;
std::string filename2;
public:
void setFilename1(std::string str)
{
filename1 = str;
}
void setFilename2(std::string str))
{
filename2 = str;
}
void function()
{
// do semthing
}
void printFilename1()
{
std::cout<<filename1<<std::endl;
}
}
MyClass *p;
p->setFilename1("first_string");
p->printFilename1();
p->setFilename2("second_string");
p->printFilename1();
You never allocate memory for what p points to so anything you call on *p will be undefined behavior
I think this is also wrong for example.
void setFilename1(char* str)
{
std::string buf = str;
filename1 = const_cast<char*>(buf.c_str())
}
Because 'buf' is deleted out of scope.
This is OK.
void setFilename1(std::string str)
{
static std::string buf = str;
filename1 = const_cast<char*>(buf.c_str())
}
other method:
class MyClass
{
char *filename1;
char *filename2;
public:
void setFilename1(std::string& str)
{
filename1 = const_cast<char*>(str.c_str())
}
void setFilename2(std::string& str))
{
filename2 = const_cast<char*>(str.c_str())
}
void function()
{
// do semthing
}
void printFilename1()
{
std::cout<<filename1<<std::endl;
}
}
MyClass *p = new MyClass();
string str1 = "first_string";
p->setFilename1(str1);
p->printFilename1();
string str2 = "second_string";
p->setFilename2(str2);
p->printFilename1();
delete p;
I run in to segmentation faults when running this code (no compiler warnings or errors).
It occurs when trying to assign "Test" to str->sString
MyClass.cpp
//Constructor
MyClass::MyClass( MyStruct *pDesc )
{
pDesc = new MyStruct();
//This is where I get a segmentation fault
pDesc->bar= 0xFF;
}
MyClass.hpp
class ClGadgetFs
{
public:
struct MyStruct{
int bar;
};
MyClass(MyStruct *pDesc = NULL);
};
I thought when calling new I would be aalocating memory for the struct? Like malloc(sizeof(myStruct))
Where am I wrong?
void setStruct(myStruct *str)
{
str->sString = "Test";
str->nNo = 4;
}
int main()
{
myStruct p;
setStruct(&p);
return 0;
}
you can do this instead
Edit
int main()
{
MyStruct *pDesc;
MyClass myClassInstance( pDesc );
std::cout<< pDesc->bar << std::endl;
return 0;
}
and
MyClass::MyClass( MyStruct *pDesc )
should be changed to
MyClass::MyClass( MyStruct *& pDesc )
void setStruct(myStruct*& str)
The above is probably what you want: changing the passed pointer, as output parameter.
#include <string>
struct myStruct
{
std::string sString;
int nNo;
};
void setStruct(myStruct **str)
{
*str = new myStruct();
(*str)->sString = "Test";
(*str)->nNo = 4;
}
int main()
{
myStruct *p;
setStruct(&p);
}
should be what you want, this is the C-style of passing the pointer; since you're allocating memory for the passed pointer, passing the pointer alone doesn't work, you should pass the pointer's address. Another way would be a reference to the pointer that Joop Eggen's answer points out.
str in the function setStruct is a local variable, whose life time is limited in this function.
So when new returns the address, there is no effect on the actual parameter. It is just the same to
void func(int a){
a = 4
}
You should use pointer to pointer or reference
void setStruct(myStruct ** str){
(*str) = new myStruct();
(*str)->sString = "Test";
(*str)->nNo = 4;
}
void setStruct(myStruct *& str){
str = new myStruct();
str->sString = "Test";
str->nNo = 4;
}
You should use a reference to your pointer to modify it in your function:
struct myStruct{
std::string sStrnig;
int nNo;
};
void setStruct(myStruct* &str){
str = new myStruct();
str->sString = "Test";
str->nNo = 4;
}
main(){
struct myStruct *str = 0;
setStruct( str );
}
It's likely that the caller of setStruct is allocating a myStruct on the stack:
myStruct value;
and you are calling setStruct(&value);
That would cause the segmentation fault as you would be attempting to rearrange the stack memory.
It's difficult to say anything else without the complete example though.
There's nothing wrong with the code as it stands aside from the fact that the value of the pointer following str = new myStruct(); is not passed back to the caller: the caller would be still referring to the pointer pointing to unallocated memory which would result in undefined behaviour. But that is not causing your crash since given where you say the error happens.
A simple fix would be to change the function prototype to
void setStruct(myStruct*& str)
i.e. pass the pointer by reference so the caller get's the modified pointer value back.
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.
I need to store a char array inside a class and then return it. I have to admit that I'm a bit confused about pointers and have tried everything I can think of but can't get it to work. Here's what I have:
#include <iostream>
using namespace std;
class Test {
public:
void setName(char *name);
char getName();
private:
char m_name[30];
};
void Test::setName(char *name) {
strcpy(m_name, name);
}
char Test::getName() {
return *m_name;
}
void main() {
Test foobar;
char name[] = "Testing";
foobar.setName(name);
cout << foobar.getName();
}
Of course, I expect setName() to store the string "Testing" inside the class, and getName() should return "Testing". But instead, I get only the first letter T. What am I doing wrong?
I guess I should be using std strings but first I would like to understand why this does not work. As far as I know, this should work with char arrays as well?
Just return a pointer:
const char* Test::getName() const
{
return m_name;
}
and add a constructor for the class Test that would null-terminate the encapsulated array:
Test::Test()
{
m_name[0] = 0;
}
so that you don't ask for trouble if someone instantiates class Test and doesn't call setName() on the instance.
In Test::getName() you are just returning one character (first character). Instead you should return the address of the first character from where the string begins i.e. change the return type to char* and the return statement to return m_name;
If you want this to be C++ simply dont use char pointers unless you have a very, very specific reason to do so!
Switch from char pointer to std::string and see if that solves your problem:
#include <iostream>
#include <string>
using namespace std;
class Test {
public:
void setName(std::string name);
std::string getName();
private:
std::string m_name;
};
void Test::setName(std::string name) {
m_name = name;
}
std::string Test::getName() {
return m_name;
}
void main() {
Test foobar;
foobar.setName("Testing");
cout << foobar.getName();
}
For bonus points, make the parameter type in setName a const std::string&.
When you have a pointer, p, the pointer dereferencing operator * "follows" the pointer so the expression *p evaluates to whatever object the pointer is pointing at.
In many situations, the name of an array such as m_name, can behave like a pointer. Thus, *m_name evaluates to the first char in the array, since that is the type the array name, when interpreted as a pointer, points at.
Since strings in C are represented as pointers to characters, you should not dereference the pointer, but return it intact.
Many have suggested you use strncpy() to write the input string into your array, since it does (sort of) bounds checking. However, it is not optimal, it's semantics are odd and copying a string into a limited buffer is really not what it was designed for. It is better to investigate if you have a variety of the snprintf() function in your environment, and use that like so:
snprintf(m_name, sizeof m_name, "%s", name);
use this code to get name:
void Test::getName()
{
std::cout << "\nYour name is: ";
for (int i = 0; i < 30; i++)
{
if (Name[i] !=NULL)
std::cout << Name[i];
else break;
}
std::cout << "\n";
}