C++ : Why I can't print a const char* with sprintf? - c++

What am I missing here ? It's driving me nuts !
I have a function that returns a const char*
const char* Notation() const
{
char s[10];
int x=5;
sprintf(s, "%d", x);
return s;
}
Now in another part of the code I am doing this :
.....
.....
char str[50];
sprintf(str, "%s", Notation());
.....
.....
but str remains unchanged.
If instead I do this :
.....
.....
char str[50];
str[0]=0;
strcat(str, Notation());
.....
.....
str is correctly set.
I am wondering why sprintf doesn't work as expected...

You're trying to return an array allocated on stack and its behaviour is undefined.
const char* Notation() const
{
char s[10];
int x=5;
sprintf(s, "%d", x);
return s;
}
here s isn't going to be around after you've returned from the function Notation(). If you aren't concerned with thread safety you could make s static.
const char* Notation() const
{
static char s[10];
....

In both cases, it invokes undefined behavior, as Notation() returns a local array which gets destroyed on returning. You're unlucky that it works in one case, making you feel that it is correct.
The solution is to use std::string as:
std::string Notation() const
{
char s[10];
int x=5;
sprintf(s, "%d", x);
return s; //it is okay now, s gets converted into std::string
}
Or using C++ stream as:
std::string Notation() const
{
int x=5;
std::ostringstream oss;
oss << x;
return oss.str();
}
and then:
char str[50];
sprintf(str, "%s", Notation().c_str());
The benefit (and beauty) of std::ostringstream (and std::string) is that you don't have to know the size of output in advance, which means you don't have to use magic number such as 10 in array declaration char s[10]. These classes are safe in that sense.

char s[10] in Notation is placed on stack so it gets destroyed after exit from Notation function. Such variables are called automatic. You need to save your string in heap using new:
char *s = new char[10];
But you have to free this memory manually:
char str[50];
const char *nt = Notation();
sprintf(str, "%s", nt);
printf("%s", str);
delete[] nt;
If you really use C++ then use built-in string class like Nawaz suggested. If you somehow restricted to raw pointers then allocate buffer outside Notation and pass it as destanation parameter like in sprintf or strcat.

Related

How do you unindex a struct?

How do I unindex a struct? Example:
typedef struct String_s {
int current_location;
int size;
char data[0];
} String;
char* String_getCString(String *str){
return &str->data[0];
}
//this is supposed to take the result of 'String_getCString' and reverse the process to get the String*
//i.e. String_getCString(CString_getString(str)) == str
String* CString_getString(char *str){
//???
}
int foo(char *cstr){
printf("%s\n", cstr);
fflush(0);
free(CString_getString(cstr));
}
int main(int argc, char *argv[]){
const char *hello_world = "hello world";
String *str = (String*)malloc(sizeof(String)+1000*sizeof(char));
str->size = 1000;
str->count = strlen(hello_world);
char *cstr = String_getCString(str);
strcpy(cstr, hello_world);
foo(cstr);
return 0;
}
I'm not 100% sure I understand what you want CString_getString to do, but if you want it to return the address of the overall String object when passed the address of the embedded data field, then that's straightforward, but dangerous:
#include <stddef.h>
String *CString_getString(char *str)
{
return (String *)(str - offsetof(String, data));
}
If the type of the field you wished to "unindex" were anything other than [signed/unsigned/] char, you would need to cast the input pointer to char * before the subtraction, as well as casting to the desired return type afterward.
This is dangerous because CString_getString has no way of knowing whether you've passed in a str that really is the embedded data field of a String object. If you get it wrong, the C compiler sits back and watches it blow up on you at runtime. But, arguably, this is no worse than anything else one does in C all the time, and this can be a useful technique. It is, for instance, heavily used in the guts of Linux: http://lxr.free-electrons.com/ident?i=container_of

How to return a char* from a function in C++ [duplicate]

This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 9 years ago.
I have the following function in c++
char* Test::convertToSHA(const char* cc) {
const char* salt ="sh$^$##!&7hbfvatfacv####bagg=shjgvshvcbschj";
time_t currentTime;
time(&currentTime);
CCString startTimeString;
startTimeString.createWithFormat("%d", currentTime);
std::string s = cc;
s += startTimeString.getCString();
s += salt;
char *str = new char[strlen(s.c_str()) + 1];
int length=strlen(str);
unsigned char hash[length*2];
char hexstring[41];
sha1::calc(str,length,hash);
sha1::toHexString(hash, hexstring);
return hexstring;
}
And in the call i use
char* output=NULL;
output= Test::convertToSHA("hello");
This is causing my code to crash. Is there a problem with me returning a string ? How can i return from this function ?
You can never return a local pointer in C or C++. Instead, either pass the pointer as a parameter:
void Test::convertToSHA(const char* cc, const char* hexstring) {
//no change to body
//no return statement needed
}
//then when calling the function:
char hexstring[41];
convertToSHA(cc, hexstring);
//hexstring has been modified
Or just use std::string instead. Use the c_str() if you need to convert to a c-style string (you still can't return the pointer, though).
I'm assuming you're using this library. I find it odd that it claims to be written in C++ but doesn't take advantage of C++ idioms. The function modifies the pointer, and doesn't return anything, so you do need a local variable. Lucky for you, std::strings will happily accept a char [] argument.
std::string Test::convertToSHA(const char* cc) {
// ...
char hexstring[41];
sha1::calc(str,length,hash);
sha1::toHexString(hash, hexstring);
std::string ret(hexstring);
return ret;
}

Converting a string to char*

I am trying to write a function to convert a std::string to char* .
The first one I have written was this:
char* $ (string str)
{
char* cstr;
const unsigned int length=str.size();
cstr=new char[1000];
for(int i=0;i<length;i++)
cstr[i]=str[i];
cstr[length]=0;
return cstr;
}
But the problem was the memory leak: let's suppose that I do this:
char* cstr;
string str1("hello"),str2("hello2");
cstr=$(str1);
cstr=$(str2);
There is a memory leak in this case.The first allocated string is not reachable but it's reference is lost.
So I made the same using static:
char* $ (string str)
{
static char cstr[1000];
const unsigned int length=str.size();
for(int i=0;i<length;i++)
cstr[i]=str[i];
cstr[length]=0;
return cstr;
}
But the problem now is that the static char fields are accessible:
char* cstr;
string str("hello");
cstr=$(str);
$(str)[5]='!';
This is possibile, the 6th character is modified and so also the C-style string pointed by cstr is modified.
Using const:
const char* $ (string str)
{
static char cstr[1000];
const unsigned int length=str.size();
for(int i=0;i<length;i++)
cstr[i]=str[i];
cstr[length]=0;
return cstr;
}
The problem is that a char pointer is not compatible with a const char pointer, so I can't do this:
string str("hello");
char* cstr;
cstr=$(str);
But I can only use a const char pointer.
What I would do is to have a function which the return value could be placed only as right operand, but not as left operand of an assignment.How could this be done?
I tried to do this:
char* toCharArray(string& str)
{
std::unique_ptr<char>p(new char[1000]);
char* temp=p.get();
for(unsigned int i=0;i<str.size();i++)
{
*temp=str[i];
temp++;
}
return p.get();
}
But the problem is still there, I don't see the difference between this and the other solution I posted using static.Since a code like this:
char* cstr;
string str("hello");
cstr=toCharArray(str);
toCharArray(str)[0]='o';
cout << cstr;
Modifies the string (prints "oello").
Problem still not solved.
You can prevent memory leaks by returning the allocated array as either std::unique_ptr<char[]> or std::vector<char>; both will release the memory if they are reassigned or go out of scope.
You can get a char* pointer to the contents as ptr.get() or &vec[0] respectively.
By the way, since the length is known, the array length really should be length+1, not 1000. Fixed-sized buffers are an overrun waiting to happen. Also, $ is not a portable name for a function.
http://www.cplusplus.com/reference/string/string/c_str/
Look at the example, specifically:
char * cstr, *p;
string str ("Please split this phrase into tokens");
cstr = new char [str.size()+1];
strcpy (cstr, str.c_str());
You need to create a new char * and copy the contents of the std::string over it.
You can use strcpy.
I don't see why you're surprised by the memory leak. If you're making a copy of something, you've got to put it somewhere.
You can either put all the copies in the same place (running a risk of overflow, and putting the onus of taking a proper copy on the client, or they run the risk of unexpected corruption), or you do the allocation (they still have to do the freeing, but at least they don't have to copy), or you get them to pass a buffer and a size into your function.
And seriously, $ as a function name?
What about str.c_str()? Or strdup(str.c_str()) if you want a copy.

c++: write a char at a given char* causes segfault

I want to copy a char to an address where a given char* points to.
it's in a function which is called by main:
char data = " ";
myfunction(data, somethingelse);
...
inside the function i have something like
void myfunction(char* data, short somethingelse) {
...
char byte = 0;
inputfilestream.read(&byte, 1);
*data = byte; // here i get the segfault
data++;
...
}
the segfault also comes when i to the copy using strncpy:
strncpy(data, byte, 1);
why is there a segfault? data isn't const and the address where i actually write to is exactly the same as the one where i allocated the data-array. i've tested that multiple times.
thanks in advance.
String literals are readonly. If you want a modifyable string, you must use an array, e.g.:
char data[10];
Or:
char *data = new char[10];
To elaborate a bit more: the type of a string literal is actually const char*. Assigning a string literal to a non-const char* is therefore technically invalid, but most compilers allow it anyway for legacy reasons. Many modern compilers will at least issue a warning when you try to do that.
data is assigned a string literal. String literals are ready only, and writing to them will cause segfaults.
Try this:
char data[10]; // or whatever size you want.
instead.
why is there a segfault? data isn't const and the address where i actually write to is exactly the same as the one where i allocated the data-array.
You didn't allocate anything. char *data = " "; shouldn't even compile in C++. You are assigning a constant string to a non-constant.
char byte = 0;
inputfilestream.read(&byte, 1);
*data = byte; // here i get the segfault
data++; // << How many times?
No problem
#include <stdio.h>
int main(int argc, char **argv)
{
char *data = "Yello"; // or char data[] = "Yello";
*data = 'H';
puts(data); // Hello
}

how to copy char * into a string and vice-versa

If i pass a char * into a function. I want to then take that char * convert it to a std::string and once I get my result convert it back to char * from a std::string to show the result.
I don't know how to do this for conversion ( I am not talking const char * but just char *)
I am not sure how to manipulate the value of the pointer I send in.
so steps i need to do
take in a char *
convert it into a string.
take the result of that string and put it back in the form of a char *
return the result such that the value should be available outside the function and not get destroyed.
If possible can i see how it could be done via reference vs a pointer (whose address I pass in by value however I can still modify the value that pointer is pointing to. so even though the copy of the pointer address in the function gets destroyed i still see the changed value outside.
thanks!
Converting a char* to a std::string:
char* c = "Hello, world";
std::string s(c);
Converting a std::string to a char*:
std::string s = "Hello, world";
char* c = new char[s.length() + 1];
strcpy(c, s.c_str());
// and then later on, when you are done with the `char*`:
delete[] c;
I prefer to use a std::vector<char> instead of an actual char*; then you don't have to manage your own memory:
std::string s = "Hello, world";
std::vector<char> v(s.begin(), s.end());
v.push_back('\0'); // Make sure we are null-terminated
char* c = &v[0];
You need to watch how you handle the memory from the pointer you return, for example the code below will not work because the memory allocated in the std::string will be released when fn() exits.
const char* fn(const char*psz) {
std::string s(psz);
// do something with s
return s.c_str(); //BAD
}
One solution is to allocate the memory in the function and make sure the caller of the function releases it:
const char* fn(const char*psz) {
std::string s(psz);
// do something with s
char *ret = new char[s.size()]; //memory allocated
strcpy(ret, s.c_str());
return ret;
}
....
const char* p = fn("some text");
//do something with p
delete[] p;// release the array of chars
Alternatively, if you know an upper bound on the size of the string you can create it on the stack yourself and pass in a pointer, e.g.
void fn(const char*in size_t bufsize, char* out) {
std::string s(psz);
// do something with s
strcpy_s(out, bufsize, s.c_str()); //strcpy_s is a microsoft specific safe str copy
}
....
const int BUFSIZE = 100;
char str[BUFSIZE];
fn("some text", BUFSIZE, str);
//ok to use str (memory gets deleted when it goes out of scope)
You can maintain a garbage collector for your library implemented as
std::vector<char*> g_gc; which is accessible in your library 'lib'. Later, you can release all pointers in g_gc at your convenience by calling lib::release_garbage();
char* lib::func(char*pStr)
{
std::string str(pStr);
char *outStr = new char[str.size()+1];
strcpy(outStr, str.c_str());
g_gc.push_back(outStr); // collect garbage
return outStr;
}
release_garbage function will look like:
void lib::release_garbage()
{
for(int i=0;i<g_gc.size();i++)
{
delete g_gc[i];
}
g_gc.clear();
}
In a single threaded model, you can keep this g_gc static. Multi-threaded model would involve locking/unlocking it.