I'm new to c++ and am still struggling with the whole pointer thing.
Let's say I have a function that returns a char* pointing to the start of an array of characters / a string.
char* read() {
char data[] = "this for example";
return *data;
}
then later I want to access this data, but I don't think I can do something like this:
char* data = read();
if(data[3] == 's')
return true;
what is the right way to use the data returned by read() in this example?
In this case it is better to use standard class std::string
std::string read()
{
char data[] = "this for example";
return data;
}
//...
std::string data = read();
if( data[3] == s )
return true;
As for your code snippet then if to rewrite it without errors it would have undefined behaviour because you return a pointer to a local array that will be destroyed after exiting the function.
In your read() function, return *data; returns a char not a char*. Also stack memory is not supposed to be accessed after your function returns. Make it static. It should be:
char* read()
{
static char data[] = "this for example";
return data;
}
You can't return pointer to an automatic variable. It invokes undefined behavior. Allocate data dynamically.
char *data = new char[20];
Do not forget to delete the allocated memory when you are done by using
delete[] data;
Better to use std::vector or std::string instead.
Related
I'm trying out a C# style string implementation in C++.
I have created an object and a pointer for class String, and assigned the object to the pointer. When i try to modify the object via the pointer instead of modifying the existing object i want to create a new object and make the pointer point it.
So i have overloaded the "=" operator, and creating a new object in the operator overloaded method. In order to reflect the change i need to use ss=*ss = "name";
Any suggestion to improve this code.
Below is my sample code
class String
{
char *str;
public:
String(char* str_in)
{
str = new char[strlen(str_in)];
strcpy(str, str_in);
}
String* operator=(char* s)
{
return new String(s);
}
};
int main()
{
String s="sample";
String *ss;
ss = &s;
ss=*ss = "name";
return 0;
}
I also tried to modify the this pointer, but not working as expected
String *ptr;
ptr = const_cast<String*>(this);
ptr = new String(s);
I would recommend some changes like this:
#include <string.h>
class String
{
char *str;
public:
String(const char* str_in)
{
str = new char[strlen(str_in)];
strcpy(str, str_in);
}
~String()
{
delete [] str;
}
String& operator=(const char* s)
{
char* tmp = new char[strlen(s)];
strcpy(tmp, s);
delete [] str;
str = tmp;
return *this;
}
};
int main()
{
String s("sample");
String *ss;
ss = &s;
ss = new String("name");
delete ss;
return 0;
}
First of all, you need an appropriate destructor or you are going to have a memory leak when String gets destroyed. Deleting the char* fixes this (since it is an array, we use the array delete).
Secondly, in C++, we almost always return a reference for operator= (not a pointer). So this revised operator= function is probably better - it deletes the old string, allocates memory for the new string, copies the new string, and returns *this.
Third, you can use const char* instead of char* for the constructor and assignment operator since you are not editing it.
In main(), I also created a new object for the pointer to point to since you requested that in the original post (and then it is deleted afterwards to avoid a memory leak).
Let me know if you have any questions with those changes.
I've been scratching my hair out but can't seem to find what is wrong with the following code. Here is the small snippet of valgrind output that it generates
Invalid read of size 1 at 0x4c22d82: strlen (mc_replace_strmem.c:242)
by 0x5E65CA: Application::readConfigurationFile() (char_traits.h:262)
by 0x5694BD: main Address 0xafc9660 is 24 bytes inside a block of size
39 free'd at 0x4C20E0D: operator delete(void*)
(vg_replace_malloc.c:342) by 0x635618:
Configurator::getParameterValue(char const*, char**) by 0x5E65B2:
Application:readConfigurationFile() (Application.cpp:77) by 0x5694BD:
main
bool Configurator::getParameterValue(const char *p_pParameterName, char** p_pParameterValue)
{
bool blReturnValue = false;
QDomElement element;
QDomNode node;
QDomNodeList list;
list = doc.elementsByTagName(p_pParameterName);
if (!list.isEmpty())
{
node = list.item(0);
element = node.toElement();
QString qs = element.text().toUtf8();
*p_pParameterValue = (char *)(qs.toStdString().c_str());
blReturnValue = true;
}
else
{
char sMessage[200];
sprintf(sMessage, "<Configurator::getParameterValue> Error! Parameter %s could not be found\n", p_pParameterName);
m_outputFunction(sMessage);
}
return blReturnValue;
}
bool Configurator::parseFile()
{
bool blReturnValue = false;
QString errorStr;
int errorLine;
int errorColumn;
if (!doc.setContent((QIODevice*)(&file), true, &errorStr, &errorLine, &errorColumn))
{
char aTemp[512];
sprintf(aTemp, "<Configurator::parseFile> error! can not read the file row: %d, column: %d:\n",errorLine, errorColumn);
m_outputFunction(aTemp);
}
else
{
closeFile();
blReturnValue = true;
}
return blReturnValue;
}
bool Application::readConfigurationFile()
{
bool blReturnValue = false;
m_outputFunction("<Application::readConfigurationFile> Reading configuration..\n");
if(m_configurator.parseFile())
{
blReturnValue = true;
m_configurator.writeParameters();
char *pTemp = 0;
if(!m_configurator.getParameterValue("center_no", m_bCenterNo))
m_bCenterNo = 1;
if(m_configurator.getParameterValue("highway_header", &pTemp))
m_strHighwayHeader.assign(pTemp);
else
m_strHighwayHeader.assign("... HIGHWAY"); // Default value
}
return blReturnValue;
}
Can somebody please tell me why I see invalid reads, I don't even use malloc/calloc in this code snippet.
*p_pParameterValue = (char *)(qs.toStdString().c_str());
Why you did so? QString is local variable and toStdString return new std::string
std::string QString::toStdString () const
So, returned std::string will be deleted. c_str() returns pointer to const char*. Quote from n3337 draft:
const charT* c_str() const noexcept;
const charT* data() const noexcept;
1 Returns: A pointer p such that p + i == &operator[](i) for
each i in [0,size()]. 2 Complexity: constant time. 3 Requires: The
program shall not alter any of the values stored in the character
array.
if(m_configurator.getParameterValue("highway_header", &pTemp))
m_strHighwayHeader.assign(pTemp);
Wrong. Since value in pTemp was deleted, when temporary object qs.toStdString() was deleted.
You are in effect returning a pointer to a local variable. In getParameterValue the variable qs is local inside a block, and you assign that strings pointer to p_pParameterValue. When getParameterValue the stack space formerly occupied by qs is now reclaimed and the pointer pTemp now points to unused memory. This is undefined behavior, and can cause lots of bad stuff to happen.
The temporary string object returned from qs.toStdString() allocates memory for the string, which is freed when the temporary is destroyed (after evaluation of the full expression). If you are compiling with optimization, it is likely that the std::string d'tor is inlined into your function, so it doesn't show up in your call stack.
When you want to continue using the string data after the function is done, you need to make it persist. The (in my opinion) sanest way is to return a std::string object rather than a char *, so the last parameter could be a std::string ** (which is filled by new std::string(qs.toStdString())), or a std::string & which is assigned to.
If you have the Boost libraries, you can also use boost::optional<std::string> as the return type, which provides a "string with a valid flag" data type.
char *recvmsg(){
char buffer[1024];
return buffer;
}
int main(){
char *reply = recvmsg();
.....
}
I get a warning:
warning C4172: returning address of local variable or temporary
I would suggest std::vector<char>:
std::vector<char> recvmsg()
{
std::vector<char> buffer(1024);
//..
return buffer;
}
int main()
{
std::vector<char> reply = recvmsg();
}
And then if you ever need char* in your code, then you can use &reply[0] anytime you want. For example,
void f(const char* data, size_t size) {}
f(&reply[0], reply.size());
And you're done. That means, if you're using C API, then you can still use std::vector, as you can pass &reply[0] to the C API (as shown above), and reply to C++ API.
The bottomline is : avoid using new as much as possible. If you use new, then you've to manage it yourself, and you've to delete when you don't need it.
You need to dynamically allocate your char array:
char *recvmsg(){
char* buffer = new char[1024];
return buffer;
}
for C++ and
char *recvmsg(){
char* buffer = malloc(1024);
return buffer;
}
for C.
What happens is, without dynamic allocation, your variable will reside on the function's stack and will therefore be destroyed on exit. That's why you get the warning. Allocating it on the heap prevents this, but you will have to be careful and free the memory once done with it via delete[].
The warning message is correct. You're returning the address of a local array which disappears after the function returns.
You can do this using dynamic memory allocation:
char *recvmsg(){
char *buffer = (char*)malloc(1024);
return buffer;
}
The catch is that you need to make sure you free() the pointer later on to avoid a memory leak.
Alternatively, you can pass the buffer into the function.
void recvmsg(char *buffer,int buffer_size){
// write to buffer
}
void main(){
char buffer[1024];
recvmsg(buffer,1024);
}
This avoids the need for a memory allocation. This is actually the preferred way to do it.
The problem is that buffer lives on the stack and goes out of scope the moment you exit recvmsg.
You could allocate buffer on the heap:
char *recvmsg(){
char *buffer = malloc(1024);
return buffer;
}
Note that now the caller is responsibe for disposing of the allocated memory:
void main(){
char *reply = recvmsg();
free(reply);
}
You have a few options...The way you're doing it now is going to cause undefined behavior as the array will go out of scope once hte function returns. So one option is to dynamically allocate the memory..
char * recmsg()
{
char * array = new char[128];
return array;
}
Just remember to clean it up with delete this way (or free if you used malloc). Second, you could use a parameter...
void recmsg(char * message, int size)
{
if (message == 0)
message = new char[size];
}
Again, the same thing goes for clean up here as with the previous. Also note the check for 0 to make sure you don't call new on a pointer that's been allocated already.
Last, you could use a vector..
std::vector<char> recmsg()
{
std::vector<char> temp;
//do stuff with vector here
return temp;
}
char *recvmsg(){
char *buffer = new char;
cout<<"\nENTER NAME : ";
cin>> buffer;
return buffer;
}
int main(){
char *reply = recvmsg();
cout<<reply;
}
Just to complete the picture:
It is not necessary, to allocate memory with malloc. You can also create the buffer on the stack, but you must create it on a stack frame that lives as long as the consumer of the buffer lives. That was the error of the OP -- when the callee was finished, the buffer was deleted and the caller got a invalid pointer.
So what you can do is this:
void recvmsg(char *buffer, size_t size) {
... do what you want ...
}
void main(void) {
char buffer[1024];
recvmsg(buffer, sizeof(buffer));
}
You could dynamically create the buffer, but then the caller needs to know to free it.
I think it's better to pass in a buffer (assuming recvmsg also fills it)
void recvmsg(char *buffer, size_t size){
}
void main(){
char buffer[1024];
recvmsg(buffer, sizeof(buffer));
}
Even if the caller decides dynamic is better, they will know that they need to free it, and the specific way to do that (free(), delete, delete[], or perhaps something special from a custom allocator)
The problem is that you are returning a pointer to a buffer allocated on the stack. Once the function returns, that buffer is no longer valid.
You are allocating the array on the stack inside of your recvmsg function. Returning a pointer to that memory will at some point lead to undefined behavior if it is dereferenced as the memory will be cleaned up when the function exits.
If you want to return a pointer to memory you will need to allocate it dynamically using malloc.
when you are returning the buffer then as it acting as a pointer to the first location of the array so it will return its address.And the place where you are calling the function there you can make a character pointer which will store this returned address value .After which you can move your pointer and can access all the elements of your array.
how about passing by ref
char buf[1024];
PutStuffInBuff(&buf);
In my program, i have line like this:
const char * str = getStr();
Do i need to call destructor on str [] at the end of function to prevent memory leaks?
Question does not contain enough information to tell, it depends what getStr() does. For example:
const char *getStr() {
return "boo";
}
then you must not call delete.
const char *getStr() {
return new char;
}
then you should call delete str; to avoid a memory leak (and must not call delete[]).
const char *getStr() {
return new char[10];
}
then you should call delete[] str; to avoid a memory leak (and must not call delete).
const char *getStr() {
return 0;
}
then it doesn't matter what you do, calling any kind of delete on str has no effect.
Ownership of resources, and how to release any resources owned, are part of the interface to a function, and should be documented at the same time as you document what the return value actually is.
It all depends on what getStr() does. It may even be that you have to call free on the pointer if getStr() created it with malloc. It may be that getStr() is returning a pointer to a static area (not very thread safe, but it happens) or any number of other things.
Part of the contract and documentation for getStr() should be who owns the pointer it returns.
Here are some examples of possible getStr() functions...
In this case getStr() owns the pointer and you don't have to do anything to free it. OTOH, what's being pointed at may change the next time you call getStr() so you should probably make your own copy if you need to keep it around for any length of time:
const char *getStr()
{
static char buf[30] = "Silly counter";
buf[0] = buf[0] + 1;
return buf;
}
In this case, you will eventually need to call free on the pointer returned:
const char *getStr()
{
return strdup("Silly string");
}
In this case, you will need to call plain old delete on the pointer returned:
const char *getStr()
{
return new char;
}
In this case, you will need to call delete [] on the pointer returned:
const char *getStr()
{
return new char[50];
}
There are many other possibilities. As I stated previously, part of the contract for a function (which should appear in its documentation) is who owns the pointer returned and how that data pointed to must be disposed of if doing so is the caller's responsibility.
It depends on how getStr() has been designed. It could return a pointer to a string that is still owned by someone else (and in this case the answer is no) or it may return a pointer to and the caller becomes the owner (and in this case the answer is yes).
You should check the documentation of getStr to know.
If the ownership of the returned area is of the caller then probably in C++ returning an std::string would have been a much better idea.
It's a good idea to do so if it's going out of scope. I'd recommend also setting the pointer to null to ensure it isn't dangling:
delete[] str;
str = null;
#include <iostream>
using namespace std;
class Marks
{
public:
char* name();
};
char* Marks::name()
{
char temp[30];
cout<<"Enter a name:"<<endl;
cin.getline(temp,30);
return temp;
}
int main ()
{
char *name;
Marks test1;
name=test1.name();
//cout<<"name:"; //uncomment this line to see the problem
cout<<name<<endl;
return 0;
}
You are returning address of a local variable:
char temp[30];
// ...
return temp;
This is a strict no-no in C or C++. The moment you come out of Marks::name() your temp variable goes BOOM! You can no longer access it -- doing that invokes Undefined Behavior. Try this,
#include <string> // somewhere at the top
// ...
std::string Marks::name()
{
std::string line;
cout<<"Enter a name:"<<endl;
std::getline(cout, line);
return line;
}
The problem is because the value that name is pointing to has been destroyed. You are returning the address of a local variable from Marks::name(). Most likely a side affect of the first cout is causing the contents of name to be destroyed. You're probably just getting lucky when the first cout is commented out.
The correct way to do this is to allocate some memory, return that, and then destroy it when you're done:
char* Marks::name()
{
char* temp = new char[30];
cout<<"Enter a name:"<<endl;
cin.getline(temp,30);
return temp;
}
int main ()
{
char *name;
Marks test1;
name=test1.name();
cout<<"name:";
cout<<name<<endl;
delete[] name;
return 0;
}
Don't forget to use delete[], rather than just delete, since otherwise only the first character would be deallocated.
You're returning a stack-based pointer (a pointer that resides in the stack of the called process) that will be released whenever the Marks::name() method ends.
This is basic C/C++ memory management question, so I encourage you to read some books on the topic.
There are several ways of doing this correctly. For example, reserving the memory for the string in the calling function and passing this pointer to the function:
In the main() method:
char name[30];
Marks test1;
test1.name(name);
(here name has the correct value) with the corresponding method:
char* Marks::name(char* temp)
{
cout<<"Enter a name:"<<endl;
cin.getline(temp,30);
return temp;
}
But there are other ways of managing static and dynamic memory for strings.
Well, you have a pretty nasty bug in Marks::name() where you return a pointer to a temporary variable. temp will be destroyed at the exit of the function as it's going out of scope, so you are returning a pointer to a variable that doesn't exist anymore.
Marks::name() returns a pointer to a local variable.
That memory will be freed when the function exits.
The reason you still get the right output as long as you don't call any functions in between your calls to Marks::name and cout::operator << is that no other allocation claims that memory area.
You could use std::string instead of a char* if you intend to return a non-static string by value.
Alternatively, you could pass the char buffer to the name function as a char* and also pass the buffer's size and have Marks::name fill that buffer (e.g. using strncpy or strncpy_s)
void Marks::name( char* buffer, int length )
{
cout<<"Enter a name:"<<endl;
cin.getline(buffer,length);
}
void main()
{
char buffer[30];
Marks::name( buffer, 30 );
}
All the answers so far are correct, but some of the ways of implementing this could have been better. I know its a very simple test application, but consider the following:
char* Marks::name()
{
char* temp = new char[30];
cout<<"Enter a name:"<<endl;
cin.getline(temp,30);
return temp;
}
int main ()
{
char *name;
Marks test1;
name=test1.name();
cout<<"name:";
cout<<name<<endl;
delete[] name;
return 0;
}
Here, it is the function name() which is allocating the memory, but it is not deleting it. This is an inconsistancy which can lead to problems, especially in a more complicated senario. It might be better to do this (assuming you know ahead of time how much space you are going to give people to write in...)
//this time, pass in some ALREADY allocated memory, and a length count.
void Marks::name(char *buf, int len)
{
cout<<"Enter a name (max " << len <<" letters):"<<endl;
cin.getline(buf,len); //read into the memory provided
}
int main ()
{
//preallocate your memory so that the same code that allocates...
char *name = new char[30];
Marks test1;
test1.name(name, 30);
cout<<"name:";
cout<<name<<endl;
//... also deallocates it. This is perhaps cleaner in terms of responcibility.
delete[] name;
return 0;
}
In reality there is no right or wrong way to do this kind of thing. Sometimes a function has to allocate memory to use and return this for other applications to use, this is just an example where you should think about who is newing and try to make it consistant when coming to delete.