Reputation: 33823
I want to assign data to a block of memory but I don't know what's the size which I need.
For example, the following is just a simple example which illustrates the purpose:
char *str = (char*)malloc(2);
for (int i = 1; i < 10; i++) {
str[i] = i;
realloc(str, strlen(str) + 1);
}
printf("%s\n", str);
The previous code prints unknown symbols like the following:
What is the problem, then?
Upvotes: 0
Views: 235
Reputation: 16540
What is the problem, then?
very simple, the values in i
are
0x00000000
0x00000001
...
0x00000009
(which do not fit into a char)
and those values are not part of the 'printable' ascii character set.
Suggest adding 0
(0x30) to each of the values as they are assigned to the array.
Also, suggest casting the int
i
to (char)
at each assignment
the values in the array do not make a 'string' as there is no terminating NUL (0x00) byte.
Following edited for the comment from lion king
Suggest writing the code similar to the following:
#include <stdio.h>
#include <stdlib.h>
int main( void )
{
char *str = malloc(2); // do not 'cast' the returned value
if( !str )
{
perror( "malloc failed" ); // output enclosed text and reason
// system thinks the 'malloc` failed
// to `stderr`
exit( EXIT_FAILURE );
}
// implied else, malloc successful
int i;
for ( i = 0; i < MAX_CHARS; i++)
{
str[i] = (char)('0' + i);
char *temp = realloc(str, i+3); // assign to temp variable
// and check if successful
// to avoid causing a memory
// leak when it fails
if( !temp )
{
perror( "realloc failed" );
free( str ); // cleanup
exit( EXIT_FAILURE );
}
// implied else, realloc successful
str = temp; // update the target variable
}
// terminate the string
str[ i ] = '\0';
printf("%s\n", str);
free( str ); // cleanup
return 0;
}
Upvotes: 0
Reputation: 13590
You are allocating memory, that's OK. You are writing a character inside the
limits, that's OK too. But then you use strlen
, that's not OK, because
strlen
expects a valid string, you are not passing string.
In C a string is just a sequence of characters that ends with the
'\0'
-terminating byte. You are not doing that, so strlen
will go beyond the
limit until it finds the '\0'
-terminating byte and this is undefined
behaviour.
Also realloc
might change the memory location when expanding the memory. You
are not accounting for that. If realloc
returns a different pointer, the old
location is invalid and the next realloc
call will yield undefined behaviour.
The way you are filling the data, you don't even need the strlen
call, i
gives you that information already.
To fix your code:
char *str = calloc(2, 1);
if(str == NULL)
{
// error handling
// do not continue
return;
}
for (int i = 0; i < 9; i++) {
str[i] = i + 1 + '0';
str[i+1] = 0; // making sure you have a valid c-string
char *tmp = realloc(str, strlen(str) + 2);
if(tmp == NULL)
{
// error handling,
// do not continue
free(str);
return;
}
// making sure that str points to the new location
// if realloc returned a different pointer
str = tmp;
}
printf("%s\n", str);
free(str);
You should always check for the return value of malloc
, calloc
, realloc
.
Also the realloc
should be strlen(str) + 2
. The +2
because you want to add
a new character and you have to have space for the '\0'
-terminating byte.
Note that for the first allocation I used calloc
, because calloc
also sets
the allocated memory to 0, great for initialization. But regardless of that, you
should set the '\0'
-terminating byte every time you add a new character
(str[i+1] = 0;
line). I also store the value i + '0'
, which is most probably
what you want. 1 != '1'
, because the character '1'
has the value 49, not 1.
See: ASCII table.
I've changed the str[i] = i + '0';
to str[i] = i + 1 + '0';
, because it
seems that you want the string to start with a '1'
, not a '0'
.
Also never forget to free the memory you've allocated. You can free the memory at the end of the program or better still, when you don't need it anymore.
Upvotes: 1