char pointer initialization in C - c

I am not so clear on character pointer and how they work.
The program builds, but crashes when I run it.
char *ab = NULL;
//ab = "abc123"; // works fine
sprintf(ab, "abc%d", 123); // this line seems to crash the program
I don't get how this can be wrong, when sprintf takes in a (char * str) as a first argument.
Can anyone please explain this to me?

You have allocated no memory to use with ab.
The first assignment works because you are assigning to ab a string constant: "abc123". Memory for constant strings are provided by the compiler on your behalf: you don't need to allocate this memory.
Before you can use ab with e.g. sprintf, you'll need to allocate some memory using malloc, and assign that space to ab:
ab = malloc(sizeof(char) * (NUM_CHARS + 1));
Then your sprintf will work so long as you've made enough space using malloc. Note: the + 1 is for the null terminator.
Alternately you can make some memory for ab by declaring it as an array:
char ab[NUM_CHARS + 1];
Without allocating memory somehow for ab, the sprintf call will try to write to NULL, which is undefined behavior; this is the cause of your crash.

You can do this
char ab[10]; //allocate memory
sprintf(ab, "abc%d", 123);

You need to allocate memory for your data. Indeed sprintf takes char*, but it doesn't allocate memory for you.
The first line works fine because compiler automatically allocates data for constant tables of chars defined at compile time.

Unlike in Java or other higher level languages, many of the C library's string functions don't simply set a string reference, instead they operate on a block of pre-allocated memory called a character array.
Your first line is saying that ab points to a non-existent memory location.
You'd have more luck if, instead of char *ab = NULL; you did either:
char ab[12];
or:
char *ab = (char*)malloc(12);

"ab" is null and sprintf is trying to write to it, you have to allocate it first.
char ab[20];
sprintf(ab, "abc%d", 123); //
or
char * ab = malloc(20); // new, whatever
sprintf(ab, "abc%d", 123); //

There are several things to think about here. Your original example is below:
char *ab = NULL;
//ab = "abc123"; // works fine
sprintf(ab, "abc%d", 123); // this line seems to crash the program
char *ab = NULL; is a pointer to a character and is initialized to NULL;
I don't think ab = "abc123"; worked fine unless it looked like char *ab = "abc123";. That is because you initialized char *ab to a read-only string. The initialization probably took place at compile time.
Your sprintf(ab, "abc%d", 123); line failed, because you did not initialize any memory for the char *ab pointer ahead of time. In other words, you did not do something like:
ab = malloc((sizeof(char) * 3) + 1); /* + 1 allows for null string terminator. */
You can fix your problem one of two ways. Either allocate dynamic memory as shown above, or you can make the string an array of a fixed length, like char ab[25] = {0};. Usually, I create an array of a length like 1024, 256, or some number that will usually cover most of my string length cases. Then I use char pointers for functions that operate on the array.

Related

Memory, pointers, and pointers to pointers

I am working on a short program that reads a .txt file. Intially, I was playing around in main function, and I had gotten to my code to work just fine. Later, I decided to abstract it to a function. Now, I cannot seem to get my code to work, and I have been hung up on this problem for quite some time.
I think my biggest issue is that I don't really understand what is going on at a memory/hardware level. I understand that a pointer simply holds a memory address, and a pointer to a pointer simply holds a memory address to an another memory address, a short breadcrumb trail to what we really want.
Yet, now that I am introducing malloc() to expand the amount of memory allocated, I seem to lose sight of whats going on. In fact, I am not really sure how to think of memory at all anymore.
So, a char takes up a single byte, correct?
If I understand correctly, then by a char* takes up a single byte of memory?
If we were to have a:
char* str = "hello"
Would it be say safe to assume that it takes up 6 bytes of memory (including the null character)?
And, if we wanted to allocate memory for some "size" unknown at compile time, then we would need to dynamically allocate memory.
int size = determine_size();
char* str = NULL;
str = (char*)malloc(size * sizeof(char));
Is this syntactically correct so far?
Now, if you would judge my interpretation. We are telling the compiler that we need "size" number of contiguous memory reserved for chars. If size was equal to 10, then str* would point to the first address of 10 memory addresses, correct?
Now, if we could go one step further.
int size = determine_size();
char* str = NULL;
file_read("filename.txt", size, &str);
This is where my feet start to leave the ground. My interpretation is that file_read() looks something like this:
int file_read(char* filename, int size, char** buffer) {
// Set up FILE stream
// Allocate memory to buffer
buffer = malloc(size * sizeof(char));
// Add characters to buffer
int i = 0;
char c;
while((c=fgetc(file))!=EOF){
*(buffer + i) = (char)c;
i++;
}
Adding the characters to the buffer and allocating the memory is what is I cannot seem to wrap my head around.
If **buffer is pointing to *str which is equal to null, then how do I allocate memory to *str and add characters to it?
I understand that this is lengthy, but I appreciate the time you all are taking to read this! Let me know if I can clarify anything.
EDIT:
Whoa, my code is working now, thanks so much!
Although, I don't know why this works:
*((*buffer) + i) = (char)c;
So, a char takes up a single byte, correct?
Yes.
If I understand correctly, by default a char* takes up a single byte of memory.
Your wording is somewhat ambiguous. A char takes up a single byte of memory. A char * can point to one char, i.e. one byte of memory, or a char array, i.e. multiple bytes of memory.
The pointer itself takes up more than a single byte. The exact value is implementation-defined, usually 4 bytes (32bit) or 8 bytes (64bit). You can check the exact value with printf( "%zd\n", sizeof char * ).
If we were to have a char* str = "hello", would it be say safe to assume that it takes up 6 bytes of memory (including the null character)?
Yes.
And, if we wanted to allocate memory for some "size" unknown at compile time, then we would need to dynamically allocate memory.
int size = determine_size();
char* str = NULL;
str = (char*)malloc(size * sizeof(char));
Is this syntactically correct so far?
Do not cast the result of malloc. And sizeof char is by definition always 1.
If size was equal to 10, then str* would point to the first address of 10 memory addresses, correct?
Yes. Well, almost. str* makes no sense, and it's 10 chars, not 10 memory addresses. But str would point to the first of the 10 chars, yes.
Now, if we could go one step further.
int size = determine_size();
char* str = NULL;
file_read("filename.txt", size, &str);
This is where my feet start to leave the ground. My interpretation is that file_read() looks something like this:
int file_read(char* filename, int size, char** buffer) {
// Set up FILE stream
// Allocate memory to buffer
buffer = malloc(size * sizeof(char));
No. You would write *buffer = malloc( size );. The idea is that the memory you are allocating inside the function can be addressed by the caller of the function. So the pointer provided by the caller -- str, which is NULL at the point of the call -- needs to be changed. That is why the caller passes the address of str, so you can write the pointer returned by malloc() to that address. After your function returns, the caller's str will no longer be NULL, but contain the address returned by malloc().
buffer is the address of str, passed to the function by value. Allocating to buffer would only change that (local) pointer value.
Allocating to *buffer, on the other hand, is the same as allocating to str. The caller will "see" the change to str after your file_read() returns.
Although, I don't know why this works: *((*buffer) + i) = (char)c;
buffer is the address of str.
*buffer is, basically, the same as str -- a pointer to char (array).
(*buffer) + i) is pointer arithmetic -- the pointer *buffer plus i means a pointer to the ith element of the array.
*((*buffer) + i) is dereferencing that pointer to the ith element -- a single char.
to which you are then assigning (char)c.
A simpler expression doing the same thing would be:
(*buffer)[i] = (char)c;
with char **buffer, buffer stands for the pointer to the pointer to the char, *buffer accesses the pointer to a char, and **buffer accesses the char value itself.
To pass back a pointer to a new array of chars, write *buffer = malloc(size).
To write values into the char array, write *((*buffer) + i) = c, or (probably simpler) (*buffer)[i] = c
See the following snippet demonstrating what's going on:
void generate0to9(char** buffer) {
*buffer = malloc(11); // *buffer dereferences the pointer to the pointer buffer one time, i.e. it writes a (new) pointer value into the address passed in by `buffer`
for (int i=0;i<=9;i++) {
//*((*buffer)+i) = '0' + i;
(*buffer)[i] = '0' + i;
}
(*buffer)[10]='\0';
}
int main(void) {
char *b = NULL;
generate0to9(&b); // pass a pointer to the pointer b, such that the pointer`s value can be changed in the function
printf("b: %s\n", b);
free(b);
return 0;
}
Output:
0123456789

(C Programming) Making a char ** array like argv

In a program I am writing I made a Tokenize struct that says:
TokenizerT *Tokenize(TokenizerT *str) {
TokenizerT *tok;
*tok->array = malloc(sizeof(TokenizerT));
char * arr = malloc(sizeof(50));
const char *s = str->input_strng;
int i = 0;
char *ds = malloc(strlen(s) + 1);
strcpy(ds, s);
*tok->array[i] = strtok(ds, " ");
while(*tok->array[i]) {
*tok->array[++i] = strtok(NULL, " ");
}
free(ds);
return tok;
}
where TokenizeT is defined as:
struct TokenizerT_ {
char * input_strng;
int count;
char **array[];
};
So what I am trying to do is create smaller tokens out of a large token that I already created. I had issues returning an array so I made array part of the TokenizerT struct so I can access it by doing tok->array. I am getting no errors when I build the program, but when I try to print the tokens I get issues.
TokenizerT *ans;
TokenizerT *a = Tokenize(tkstr);
char ** ab = a->array;
ans = TKCreate(ab[0]);
printf("%s", ans->input_strng);
TKCreate works because I use it to print argv but when i try to print ab it does not work. I figured it would be like argv so work as well. If someone can help me it would be greatl appreciated. Thank you.
Creating the Tokenizer
I'm going to go out on a limb, and guess that the intent of:
TokenizerT *tok;
*tok->array = malloc(sizeof(TokenizerT));
char * arr = malloc(sizeof(50));
was to dynamically allocate a single TokenizerT with the capacity to contain 49 strings and a NULL endmarker. arr is not used anywhere in the code, and tok is never given a value; it seems to make more sense if the values are each shifted one statement up, and corrected:
// Note: I use 'sizeof *tok' instead of naming the type because that's
// my style; it allows me to easily change the type of the variable
// being assigned to. I leave out the parentheses because
// that makes sure that I don't provide a type.
// Not everyone likes this convention, but it has worked pretty
// well for me over the years. If you prefer, you could just as
// well use sizeof(TokenizerT).
TokenizerT *tok = malloc(sizeof *tok);
// (See the third section of the answer for why this is not *tok->array)
tok->array = malloc(50 * sizeof *tok->array);
(tok->array is not a great name. I would have used tok->argv since you are apparently trying to produce an argument vector, and that's the conventional name for one. In that case, tok->count would probably be tok->argc, but I don't know what your intention for that member is since you never use it.)
Filling in the argument vector
strtok will overwrite (some) bytes in the character string it is given, so it is entirely correct to create a copy (here ds), and your code to do so is correct. But note that all of the pointers returned by strtok are pointers to character in the copy. So when you call free(ds), you free the storage occupied by all of those tokens, which means that your new freshly-created TokenizerT, which you are just about to return to an unsuspecting caller, is full of dangling pointers. So that will never do; you need to avoid freeing those strings until the argument vector is no longer needed.
But that leads to another problem: how will the string be freed? You don't save the value of ds, and it is possible that the first token returned by strtok does not start at the beginning of ds. (That will happen if the first character in the string is a space character.) And if you don't have a pointer to the very beginning of the allocated storage, you cannot free the storage.
The TokenizerT struct
char is a character (usually a byte). char* is a pointer to a character, which is usually (but not necessarily) a pointer to the beginning of a NUL-terminated string. char** is a pointer to a character pointer, which is usually (but not necessarily) the first character pointer in an array of character pointers.
So what is char** array[]? (Note the trailing []). "Obviously", it's an array of unspecified length of char**. Because the length of the array is not specified, it is an "incomplete type". Using an incomplete array type as the last element in a struct is allowed by modern C, but it requires you to know what you're doing. If you use sizeof(TokenizerT), you'll end up with the size of the struct without the incomplete type; that is, as though the size of the array had been 0 (although that's technically illegal).
At any rate, that wasn't what you wanted. What you wanted was a simple char**, which is the type of an argument vector. (It's not the same as char*[] but both of those pointers can be indexed by an integer i to return the ith string in the vector, so it's probably good enough.)
That's not all that's wrong with this code, but it's a good start at fixing it. Good luck.

How do I make a function return a pointer to a new string in C?

I'm reading K&R and I'm almost through the chapter on pointers. I'm not entirely sure if I'm going about using them the right way. I decided to try implementing itoa(n) using pointers. Is there something glaringly wrong about the way I went about doing it? I don't particularly like that I needed to set aside a large array to work as a string buffer in order to do anything, but then again, I'm not sure if that's actually the correct way to go about it in C.
Are there any general guidelines you like to follow when deciding to use pointers in your code? Is there anything I can improve on in the code below? Is there a way I can work with strings without a static string buffer?
/*Source file: String Functions*/
#include <stdio.h>
static char stringBuffer[500];
static char *strPtr = stringBuffer;
/* Algorithm: n % 10^(n+1) / 10^(n) */
char *intToString(int n){
int p = 1;
int i = 0;
while(n/p != 0)
p*=10, i++;
for(;p != 1; p/=10)
*(strPtr++) = ((n % p)/(p/10)) + '0';
*strPtr++ = '\0';
return strPtr - i - 1;
}
int main(){
char *s[3] = {intToString(123), intToString(456), intToString(78910)};
printf("%s\n",s[2]);
int x = stringToInteger(s[2]);
printf("%d\n", x);
return 0;
}
Lastly, can someone clarify for me what the difference between an array and a pointer is? There's a section in K&R that has me very confused about it; "5.5 - Character Pointers and Functions." I'll quote it here:
"There is an important difference between the definitions:
char amessage[] = "now is the time"; /*an array*/
char *pmessage = "now is the time"; /*a pointer*/
amessage is an array, just big enough to hold the sequence of characters and '\0' that
initializes it. Individual characters within the array may be changed but amessage will
always refer to the same storage. On the other hand, pmessage is a pointer, initialized
to point to a string constant; the pointer may subsequently be modified to point
elsewhere, but the result is undefined if you try to modify the string contents."
What does that even mean?
For itoa the length of a resulting string can't be greater than the length of INT_MAX + minus sign - so you'd be safe with a buffer of that length. The length of number string is easy to determine by using log10(number) + 1, so you'd need buffer sized log10(INT_MAX) + 3, with space for minus and terminating \0.
Also, generally it's not a good practice to return pointers to 'black box' buffers from functions. Your best bet here would be to provide a buffer as a pointer argument in intToString, so then you can easily use any type of memory you like (dynamic, allocated on stack, etc.). Here's an example:
char *intToString(int n, char *buffer) {
// ...
char *bufferStart = buffer;
for(;p != 1; p/=10)
*(buffer++) = ((n % p)/(p/10)) + '0';
*buffer++ = '\0';
return bufferStart;
}
Then you can use it as follows:
char *buffer1 = malloc(30);
char buffer2[15];
intToString(10, buffer1); // providing pointer to heap allocated memory as a buffer
intToString(20, &buffer2[0]); // providing pointer to statically allocated memory
what the difference between an array and a pointer is?
The answer is in your quote - a pointer can be modified to be pointing to another memory address. Compare:
int a[] = {1, 2, 3};
int b[] = {4, 5, 6};
int *ptrA = &a[0]; // the ptrA now contains pointer to a's first element
ptrA = &b[0]; // now it's b's first element
a = b; // it won't compile
Also, arrays are generally statically allocated, while pointers are suitable for any allocation mechanism.
Regarding your code:
You are using a single static buffer for every call to intToString: this is bad because the string produced by the first call to it will be overwritten by the next.
Generally, functions that handle strings in C should either return a new buffer from malloc, or they should write into a buffer provided by the caller. Allocating a new buffer is less prone to problems due to running out of buffer space.
You are also using a static pointer for the location to write into the buffer, and it never rewinds, so that's definitely a problem: enough calls to this function, and you will run off the end of the buffer and crash.
You already have an initial loop that calculates the number of digits in the function. So you should then just make a new buffer that big using malloc, making sure to leave space for the \0, write in to that, and return it.
Also, since i is not just a loop index, change it to something more obvious like length:
That is to say: get rid of the global variables, and instead after computing length:
char *s, *result;
// compute length
s = result = malloc(length+1);
if (!s) return NULL; // out of memory
for(;p != 1; p/=10)
*(s++) = ((n % p)/(p/10)) + '0';
*s++ = '\0';
return result;
The caller is responsible for releasing the buffer when they're done with it.
Two other things I'd really recommend while learning about pointers:
Compile with all warnings turned on (-Wall etc) and if you get an error try to understand what caused it; they will have things to teach you about how you're using the language
Run your program under Valgrind or some similar checker, which will make pointer bugs more obvious, rather than causing silent corruption
Regarding your last question:
char amessage[] = "now is the time"; - is an array. Arrays cannot be reassigned to point to something else (unlike pointers), it points to a fixed address in memory. If the array was allocated in a block, it will be cleaned up at the end of the block (meaning you cannot return such an array from a function). You can however fiddle with the data inside the array as much as you like so long as you don't exceed the size of the array.
E.g. this is legal amessage[0] = 'N';
char *pmessage = "now is the time"; - is a pointer. A pointer points to a block in memory, nothing more. "now is the time" is a string literal, meaning it is stored inside the executable in a read only location. You cannot under any circumstances modify the data it is pointing to. You can however reassign the pointer to point to something else.
This is NOT legal -*pmessage = 'N'; - will segfault most likely (note that you can use the array syntax with pointers, *pmessage is equivalent to pmessage[0]).
If you compile it with gcc using the -S flag you can actually see "now is the time" stored in the read only part of the assembly executable.
One other thing to point out is that arrays decay to pointers when passed as arguments to a function. The following two declarations are equivalent:
void foo(char arr[]);
and
void foo(char* arr);
About how to use pointers and the difference between array and pointer, I recommend you read the "expert c programming" (http://www.amazon.com/Expert-Programming-Peter-van-Linden/dp/0131774298/ref=sr_1_1?ie=UTF8&qid=1371439251&sr=8-1&keywords=expert+c+programming).
Better way to return strings from functions is to allocate dynamic memory (using malloc) and fill it with the required string...return this pointer to the calling function and then free it.
Sample code :
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#define MAX_NAME_SIZE 20
char * func1()
{
char * c1= NULL;
c1 = (char*)malloc(sizeof(MAX_NAME_SIZE));
strcpy(c1,"John");
return c1;
}
main()
{
char * c2 = NULL;
c2 = func1();
printf("%s \n",c2);
free(c2);
}
And this works without the static strings.

error in using realloc in C/C++

char *t = malloc(2);
t = "as";
t = realloc(t,sizeof(char)*6);
I am getting error "invalid pointer: 0x080488d4 *"..
I am getting strange errors in using memory allocation functions. Is there any good tuts/guides which could explain me memory allocation functions.
I am using linux..
Please help..
This is your problem:
char *t = malloc(2);
t = "as";
You probably thought this would copy the two-character string "as" into the buffer you just allocated. What it actually does is throw away (leak) the buffer, and change the pointer to instead point to the string constant "as", which is stored in read-only memory next to the machine code, not on the malloc heap. Because it's not on the heap, realloc looks at the pointer and says "no can do, that's not one of mine". (The computer is being nice to you by giving you this error; when you give realloc a pointer that wasn't returned by malloc or realloc, the computer is allowed to make demons fly out of your nose if it wants.)
This is how to do what you meant to do:
char *t = malloc(3);
strcpy(t, "as");
Note that you need space for three characters, not two, because of the implicit NUL terminator.
By the way, you never need to multiply anything by sizeof(char); it is 1 by definition.
That is not how you assign strings in C.
The correct syntax is:
char* t = malloc(3); // Reserve enough space for the null-terminator \0
strncpy(t, "as", 3);
// Copy up to 3 bytes from static string "as" to char* t.
// By specifying a maximum of 3 bytes, prevent buffer-overruns
Allocating 2-bytes is NOT enough for "as".
C-strings have a 1-byte null-terminator, so you need at least 3 bytes to hold "as\0".
(\0 represents the null-terminator)
The code you wrote: t = "as"; makes the pointer t "abandon" the formerly allocated memory, and instead point to the static string "as". The memory allocated with malloc is "leaked" and cannot be recovered (until the program terminates and the OS reclaims it).
After this, you can call realloc as you originally did.
However, you should not do t = realloc(t,6);. If realloc fails for any reason, you've lost your memory.
The preferred method is:
new_t = realloc(t, 6);
if (new_t != NULL) // realloc succeeded
{ t = new_t;
}
else
{ // Error in reallocating, but at least t still points to good memory!
}
Your code reassigns t, making it point elsewhere
char *t = malloc(2); //t=0xf00ba12
t = "as"; //t=0xbeefbeef
t = realloc(t,sizeof(char)*6); //confused because t is 0xbeefbeef, not 0xf00b412.
Instead use strcpy
char *t = malloc(3); //don't forget about the '\0'
strcpy(t, "as");
t = realloc(t, 6); //now the string has room to breathe
First off, don't do that:
char *t = malloc(2);
Do this instead:
char *t = malloc(2 * sizeof(char));
/* or this: */
char *t = calloc(2, sizeof(char));
It may not seem worth the effort, but otherwise you may run into problems later when you deal with types larger than 1 byte.
In this line:
t = "as";
You're assigning the address of the string literal "as", so your pointer no longer points to the memory you allocated. You need to copy the contents of the literal to your allocated memory:
char *t = calloc(3, sizeof(char));
/* "ar" is 3 char's: 'a', 'r' and the terminating 0 byte. */
strncpy(t, "ar", 3);
/* then later: */
t = realloc(t,sizeof(char)*6);
You can also just use strdup, which is safer:
#include <string.h>
char *t = strdup("ar");
t = realloc(t,sizeof(char)*6);
And don't forget to free the memory
free(t);
char *t = malloc(2);
this means you have created a pointer to a memory location that can hold 2 bytes
+-+-+
t -> | | |
+-+-+
when you do
t = "as";
now you made t point to somewhere else than what it originally was pointing to. now it no longer points to the heap
t = realloc(t,sizeof(char)*6);
now you are taking the pointer pointing to read only memory and try to realloc it.
when you use malloc you allocate space on the heap. t in this case is a pointer to that location, an address of where the block is.
in order to put something in that spot you need to copy the data there by dereferencing t, this is done by writing * in front of t:
*t = 'a'; // now 'a' is where t points
*(t+1)='s'; // now 's' is behind a, t still pointing to 'a'
however in C, a string is always terminated with a 0 (ASCII value) written as '\0' so in order to make it a string you need to append a \0
+-+-+--+
t -> |a|s|\0|
+-+-+--+
in order to do this you need to malloc 3 bytes instead, than you can add the \0 by writing *(t+2)='\0';
now t can be treated as pointing to a string and used in functions that takes strings as arguments e.g. strlen( t ) returns 2

Sprintf Segmentation Fault

numCheck is number between 1-1000. This code gives me a segfault only when I collect the results of sprintf in charcheck. If I simply use sprintf without using the results, I don't get a seg fault. What's happening here?
char * numString;
int charcheck = sprintf(numString, "%d", numCheck);
You need to provide your own memory for sprintf. Also, don't use sprintf, but rather snprintf:
char buf[1000] = {0};
snprintf(buf, 999, ....);
Alternatively you can allocate memory dynamically:
char * buf = new char[BUFSIZE];
snprintf(buf, BUFSIZE-1, ...);
/* ... */
delete[] buf;
The pointer given as the first parameter to sprintf is expected to point to a memory location where sprintf should write the formatted string.
In this case you didn't initialize numString to point to some memory you allocated for the formatted string. Since numString isn't initialized it might point anywhere, and in your case trying to write the formatted output to that location results in a segmentation fault.
The first argument to sprintf must point to a valid buffer. You have a char* but it points to garbage.
Change your code to:
char numString[80] = { };
int charcheck = sprintf(numString, "%d", numCheck);
So that numString actually points to a valid buffer (of 80 characters in this example, all elements of which are initialised to 0).
It would also be good to use snprintf so you can pass the size of your buffer to it, which will help prevent buffer overflows:
const int bufsize = 80;
char numString[bufsize] = { };
int charcheck = snprintf(numString, bufsize - 1, "%d", numCheck);
Notice that you subtract one from the buffer size that you pass to snprintf because you don't want it to use the very last slot, which you want to make sure is NULL to denote the end of the string.
You need to allocate space for the result such as
char numString[50];
int charcheck = sprintf(numString, "%d", numCheck);
In your case the interal workings of sprintf are trying to reference NULL which is the default value for a pointer in your case.
The most straightforward thing to do is to use an array as above, e.g.,
char numString[80] = { };
suggested by Seth, Jesus and Kerrek.
I think the last answer from sth is a good explanation: "the first parameter to sprintf is expected to point to a memory location where sprintf should write the formatted string." So apart from using an array of characters, which would force the allocation of memory for the string, you can also use this:
char *numstring = (char*) malloc(80);
This should let you explicitly free the allocated memory when it is no longer needed.

Resources