typedef struct{
char** strings_cmd;
int size_cmd;
}parseInfo;
....
parseInfo* parse(char* cmd){
char* temp = strdup(cmd);
char* temp_split = strtok(temp," ");
int i = 0;
char** strings = (char**)malloc(sizeof(char*));
if(strings == NULL){
printf("no memory allocated strings parse()\n");
exit(1);
}
while(temp_split != NULL){
strings[i++] = strdup(temp_split);
strings = realloc(strings,i * sizeof(char*));
if(strings == NULL){
printf("no memory allocated strings (while) parse()\n");
exit(1);
}
temp_split = strtok(NULL," ");
}
strings[i] = NULL;
parseInfo* info = (parseInfo*)malloc(sizeof(parseInfo));
if(info == NULL){
printf("no memory allocated info parse()\n");
exit(1);
}
info->strings_cmd = strings;
info->size_cmd = i;
return info;
}
hello guys i get the error:
realloc(): invalid next size.
and what i try to do is to input a string and split it down into words
for example i input = "Hello World".
and to split it = "Hello" , "World"
but when i pass 4 words i got this error...
For starters the function has a memory leak because in the beginning of the function there is allocated memory
parseInfo* parse(char* cmd){
char* temp = strdup(cmd);
//...
that was not freed.
In this while loop
while(temp_split != NULL){
strings[i++] = strdup(temp_split);
strings = realloc(strings,i * sizeof(char*));
if(strings == NULL){
printf("no memory allocated strings (while) parse()\n");
exit(1);
}
temp_split = strtok(NULL," ");
You need to wirte
strings = realloc(strings, ( i + 1 ) * sizeof(char*));
to reserve one element for the terminating null pointer used in this statement
strings[i] = NULL;
And you will need to free the allocated dynamically memory in the beginning of the function like
free( temp );
}
you are allocating an array of pointers with one less element that it is required.
This line is bad:
strings = realloc(strings,i * sizeof(char*));
This line is resizing the array to i elements.
Then, in the next iteration, some value is stored to the i-th element of the array (pointed at by) strings. The array has only i elements (0 to i-1), so this is out-of-range access.
Allocate enough elements to fix:
strings = realloc(strings,(i + 1) * sizeof(char*));
Also note that casting results of malloc() family is considered as a bad practice.
Related
I have a 2d dynamically allocated char array that is supposed to hold strings from a file (stdin) up to a space character. Since I don't know how many strings are in the file, I'm constantly reallocating bigger chunks of memory for the 2d array so I have enough space to store each individual string. For instance, if I type in "hello world" as input to the program, I expect 'h' to be printed out since hello would be the first string and h would be the first character of that string.
size_t size_buffer = 1;
char* buffer = (char*) malloc(size_buffer * sizeof(char)); //initial allocation that can hold 1 single char
size_t cur_nchars = 0; //number of characters read in current string
size_t size_words = 1; //initially only hold 1 string
char** words = (char**) malloc(size_words * sizeof(char*));
size_t cur_nwords = 0; //number of strings read
char read;
while ((read = getchar()) != EOF && !ferror(stdin)) {
if (read == ' ') { //space character
//printf("reached a space character\n");
words[cur_nwords] = buffer; //store string into words string array
cur_nwords++; //increase number of words stored
if (cur_nwords == size_words) { //maximum size hit
size_words *= 2; //multiply old size by 2
char** temp_words = (char**) realloc(words, size_words); //realloc new array twice as big
if (!temp_words) {
printf("can't allocate more memory");
for (size_t i = 0; i < cur_nwords; ++i) {
free(words[i]);
}
free(words);
exit(1);
}
else
words = temp_words; //have old point to new
}
buffer = NULL;
buffer = (char*)malloc(sizeof(char));
cur_nchars = 0;
continue;
}
if (cur_nchars == size_buffer) { //maximum length of string reached
size_buffer *= 2; //new max length is doubled
char* temp = realloc(buffer, size_buffer); //reallocate memory
if (!temp) {
printf("can't allocate more memory");
free(buffer);
exit(1);
}
else {
buffer = temp; //set buffer to point to same location as temp
}
}
buffer[cur_nchars] = read; //store character in char array
cur_nchars++; //increase # chars in string
}
printf("%c", words[0][0]); //throws error!
However after the code exits this loop, the contents of the 2d array words seems to be getting wiped for some reason (can't read memory error)...I have a feeling that I'm not reallocating the memory to the 2d array correctly. Do I need to reallocate the char array strings themselves as well when I'm reallocating the 2d array if the length of the strings themselves aren't changing?
I'm trying to have this function read a sentence and store each word into an array of strings. I store the sentence in line:
char** storewords(char* line){
char** newArr = (char**) malloc(sizeof(char*));
free(word);
return newArr;
}
I later call this function and try to print each word in the array:
main {
// ........ //
//function to get a line into line//
}
void printArr(char** newArr) {
int i = 0;
}
}
I use while (newArr[i] != NULL) in order to tell the program to iterate through the array until encountering a NULL item.
The memory seems to be allocated weirdly, because when I print it out, some words don't seem to print sometimes but other times works perfectly.
For example, if I input "hello hi", I get:
newArr 0:
newArr 1: hi
and "hello my name is" will get:
newArr 0: hello
newArr 1: my
newArr 2: name
newArr 3:
but if I input something longer like "hello my name is stackoverflow", I get the correct results.
If I understand the idea behind your storewords correct, you want to:
a) Start with a single char pointer
b) Add an extra char pointer each time you call realloc
so that you can set the last char pointer to NULL so that it serves as an "end-of-array" marker.
If that is your intention, the problem is the realloc.
char** newArr = (char**) malloc(sizeof(char*)); // Now you have 1 char pointer
char* word;
int count = 0; // Notice that you (correctly) initialize count to zero
word = strtok(line, " ");
while (word != NULL) {
newArr = (char**) realloc(newArr, sizeof(char*) * (count + 1));
// The first time you execute the realloc, you want to
// increase the number of char pointers from 1 to 2.
// But count is zero so count + 1 is only 1.
// In other words, you only got 1 element but
// you wanted 2 elements.
So instead do:
newArr = (char**) realloc(newArr, sizeof(char*) * (count + 2));
as count is "2 behind" the number of elements you want.
BTW: Doing realloc directly into destination variable is bad. Always do it in two a temp variable. Check for NULL. If not NULL, assign the temp variable to the destination.
BTW: No need to cast the value returned by realloc and malloc
BTW: Remove free(word); It does nothing and you don't want to free anything here.
So with the above in mind, your function could be:
char** storewords(char* line){
char** tmp;
char** newArr = malloc(sizeof(char*));
char* word;
int count = 0;
word = strtok(line, " ");
while (word != NULL) {
tmp = realloc(newArr, sizeof(char*) * (count + 2));
if (tmp == NULL)
{
// realloc failed - add error handling - for now just exit
exit(1);
}
newArr = tmp;
newArr[count] = malloc(strlen(word) * sizeof(char) + 1);
// put the word in array
sscanf(word, "%s", newArr[count]);
count++;
word = strtok(NULL, " ");
}
newArr[count] = NULL; //set the last item in the array as null
return newArr;
}
while you play with string you should be always very careful. Here you are using pointer of pointer so use them like pointer rather use as array and mix and match. While you write a program, arrange the algorithm first how you are going to implement it step by step and write it down in a paper, which is call as procedural design as well. I have modified your program below see your mistakes here. Also see how I just use the pointer of pointers as pointer only but not like array. So I leave the code for printArr to you to change it from array to pointer so that you can enjoy it. GOOD LUCK!!
char** storewords(char* line){
char** newArr = (char**) malloc(sizeof(char*));
char* word;
int count = 1;
word = strtok(line, " ");
*newArr = word; //store the pointer of word at the first location
while (word != NULL) {
newArr = (char**) realloc(newArr, sizeof(char*) * (count + 1));
//newArr[count] = (char*)malloc(strlen(word) * sizeof(char) + 1);//you dont need this line at all
// put the word in array
//sscanf(word, "%s", newArr[count]);
word = strtok(NULL, " ");//get the next word
*(newArr+count)=word;//store the next word here
count++;
}
*(newArr+count) = NULL; //set the last item in the array as null
free(word);
return newArr;
}
void printArr(char** newArr) {
int i = 0;
while (newArr[i] != NULL) {
printf("newArr %d: %s\n", i, newArr[i]);
i++;
}
}
int main() {
// ........ //
//function to get a line into line//
char *line = malloc(100);
strcpy(line, "Hello world how are you!");
char** newArr = storewords(line);
printArr(newArr);
return 0;
}
I have a function that takes a string and split it into tokens, because I want to return these tokens I allocate a variable using malloc.
char** analyze(char* buffer)
{
int i= 0;
char* token[512];
char** final = (char**)malloc(strlen(buffer)+1);
if ( final == NULL ) { perror("Failed to malloc"); exit(10); }
token[i] = strtok(buffer, " ");
while( token[i] != NULL )
{
final[i] = malloc(strlen(token[i])+1);
if( final[i] == NULL ) { perror("Failed to malloc"); exit(11); }
final[i] = token[i];
i++;
token[i] = strtok(NULL, " ");
}
final[i] = malloc(sizeof(char));
if( final[i] == NULL ) { perror("Failed to malloc"); exit(12); }
final[i] = NULL;
return final;
}
And I try to free this table with another function:
void free_table(char** job)
{
int i = 0;
while( job[i] != NULL )
{
free(job[i]);
i++;
}
free(job[i]); //free the last
free(job);
}
In main I use:
char** job = analyze(buffer); // buffer contains the string
and
free_table(job);
when I try to free the table I get this error:
*** Error in `./a.out': free(): invalid pointer: 0x00007ffd003f62b0 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7fdb2e5497e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x7fe0a)[0x7fdb2e551e0a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7fdb2e55598c]
./a.out[0x4012d6]
and the error goes on...
What am I doing wrong?
To begin with:
char** final = (char**)malloc(strlen(buffer)+1);
This allocates strlen(buffer) + 1 bytes, not that amount of "elements". And since sizeof(char*) is most likely very much larger than a single byte, you might be allocating to little memory here.
Since you don't know how many tokens there might be you should not allocate a fixed amount, but instead use realloc to reallocate as needed.
Then the second problem:
final[i] = malloc(strlen(token[i])+1);
...
final[i] = token[i];
In the first statement you allocate memory enough for the string pointed to by token[i], and assign the pointer to that memory to final[i]. But then you immediately reassign final[i] to point somewhere else, some memory that you haven't gotten from malloc. You should copy the string instead of reassigning the pointer:
strcpy(final[i], token[i]);
On an unrelated note, there's no need for token to be an array of pointer. It can be just a pointer:
char *token = strtok(...);
Example of a possible implementation:
char **analyze(char *buffer)
{
size_t current_token_index = 0;
char **tokens = NULL;
// Get the first "token"
char *current_token = strtok(buffer, " ");
while (current_token != NULL)
{
// (Re)allocate memory for the tokens array
char **temp = realloc(tokens, sizeof *temp * (current_token_index + 1));
if (temp == NULL)
{
// TODO: Better error handling
// (like freeing the tokens already allocated)
return NULL;
}
tokens = temp;
// Allocate memory for the "token" and copy it
tokens[current_token_index++] = strdup(current_token);
// Get the next "token"
current_token = strtok(NULL, " ");
}
// Final reallocation to make sure there is a terminating null pointer
char **temp = realloc(tokens, sizeof *temp * (current_token_index + 1));
if (temp == NULL)
{
// TODO: Better error handling
// (like freeing the tokens already allocated)
return NULL;
}
tokens = temp;
// Terminate the array
tokens[current_token_index] = NULL;
return tokens;
}
Note that strdup isn't a standard C function, but it is prevalent enough to assume it will exist. In the unlikely case where it doesn't exist, it's easy to implement yourself.
I am just starting to learn about malloc'd and realloc'd arrays. Can anyone help explain to me how to properly free my following array? I have tried looking at other posts, but I have a hard time understanding memory allocation in C.
char ** result = NULL;
int numSpaces = 0;
char * p = strtok(command, " ");
/* split string and append tokens to 'result' */
while (p)
{
result = realloc (result, sizeof (char*) * ++numSpaces);
if (result == NULL)
exit (-1); /* memory allocation failed */
result[numSpaces-1] = p;
p = strtok(NULL, " ");
}
Freeing realloc-ed memory is not different from freeing malloc-ed memory, in that all you need is to call free on the result at the end, when you no longer need the memory.
Your code, however, has a pattern that may lead to a memory leak: you are assigning realloc-ed block back to result without checking it for NULL. If realloc fails, the previous value of the result becomes unrecoverable, because it has been overwritten by NULL.
Here is how you could fix this issue:
char **temp = realloc(result, sizeof (char*) * ++numSpaces);
if (temp == NULL) {
free(result); // Free the old memory block
exit (-1); /* memory allocation failed */
}
result = temp;
At some point after you are done using result, you need to call free(result);.
This might look like:
char ** result = NULL;
int numSpaces = 0;
char * p = strtok(command, " ");
while (p) {
result = realloc (result, sizeof (char*) * ++numSpaces);
result[numSpaces-1] = p;
p = strtok(NULL, " ");
}
for (i=0; i<numSpaces; ++i)
printf("word %d: %s\n", i, result[i]);
free(result);
This question already has answers here:
Using realloc inside a function [duplicate]
(2 answers)
Closed 8 years ago.
I have a problem I can't solve. I split a string in substrings and put these substrings in an array. Everything goes fine until the search function ends. the strtok function makes perfect substrings and then everything is nicely putten in the array but when the function ends the array loses all his content. I've tried a lot of different things but nothing seems to work. I want the words array to keep his content when the search function ends and returns to main.
int main(void)
{
char** words=NULL;
char argument[26] = "just+an+example";
search(argument, words);
}
search(char* argument, char** words)
{
char* p = strtok (argument, "+");
int n_spaces = 0;
while (p)
{
words = realloc(words, sizeof(char*)* ++n_spaces);
if (words == NULL)
exit(-1); // memory allocation failed
words[n_spaces-1] = p;
p = strtok(NULL, "+");
}
// realloc one extra element for the last NULL
words = realloc(words, sizeof(char*)* (n_spaces+1));
words[n_spaces] = 0;
}
I'm guessing that you want words in main to point to an array of pointers to the places where the delimiter is. You need to pass in the address of the variable words to search, and inside search, modify the memory pointed at by the variable words.
Try this:
int main(void)
{
char** words = NULL;
char argument[26] = "just+an+example";
search(argument, &words);
}
search(char* argument, char*** words)
{
char* p = strtok (argument, "+");
int n_spaces = 0;
while (p)
{
*words = realloc(*words, sizeof(char*) ++n_spaces);
if (*words == NULL)
exit(-1); // memory allocation failed
(*words)[n_spaces-1] = p;
p = strtok(NULL, "+");
}
// realloc one extra element for the last NULL
*words = realloc(words, sizeof(char*)* (n_spaces+1));
(*words)[n_spaces] = 0;
}
I didn't review your logic in search at all, so you may not be done debugging yet.
I was doing af few things wrong. First of all in the main function when I called the search function I had to pass the adress of my array (&words). My second mistake was instead of copying the substrings itself I copied the pointers to the substrings. At the end of the function these pointers are freed so my array lost his content at the end of the function. To fix this I had to malloc every time I wanted to copy a new string to my array and use strcpy to copy the string where the pointer points to to my array.
int main(void)
{
char** words = NULL;
char argument[26] = "just+an+example";
search(argument, &words);
}
search(char* argument, char*** words)
{
char* p = strtok (argument, "+");
int n_spaces = 0;
while (p)
{
*words = realloc(*words, sizeof(char*) ++n_spaces);
if (*words == NULL)
exit(-1); // memory allocation failed
(*words)[n_spaces - 1] = malloc(sizeof(char)* (strlen(p) + 1));
strcpy((*words)[n_spaces - 1], p);
p = strtok(NULL, "+");
}
}