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);
Related
I'm working on a crosswords program in which a word dictionary is necessary. I'm trying load a jspell dictionary file into an dynamic string array but i keep getting the
error malloc(): mismatching next->prev_size (unsorted)
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "dictionary.h"
void dict_init(Dictionary * dict, char * dict_dir, size_t w_len)
{
printf("dictionary.c (dict_init): initializing dictionary.\n");
/*Adjust this value to control the initial array size*/
size_t init_size = 1000;
/*initialize dictionary file directory*/
dict->dir = malloc(strlen(dict_dir) * sizeof(char) + 1);
strcpy(dict->dir, dict_dir);
/*create memory for words array*/
dict->words = malloc(init_size * sizeof(char *));
/*initialize array size*/
dict->size = init_size;
/*initilize word length*/
dict->w_len = w_len;
/*initialize word counter*/
dict->counter = 0;
/*load words into dictionary*/
dict_load(dict);
printf("dictionary.c (dict_init): dictionary initialized.\n");
}
void dict_add(Dictionary * dict, char * word)
{
char ** dictionary = dict->words;
/*check if word array is full*/
if(dict->counter == dict->size)
{
/*increrase size of dictionary*/
dict->size *= 1.5;
dict->words = realloc(dict->words, dict->size * sizeof(char *));
}
/*add word to dictionary*/
dictionary[dict->counter] = malloc(strlen(word) * sizeof(char) + 1);
strcpy(dictionary[dict->counter], word);
dict->counter++;
free(word);
}
void dict_free(Dictionary * dict)
{
free(dict->words);
}
void dict_load(Dictionary * dict)
{
FILE * fp;
char * line = NULL;
char * word = NULL;
size_t len = 0;
ssize_t read;
fp = fopen(dict->dir, "r");
/*check if file exists*/
if (fp == NULL)
{
perror("ERROR: File not found.");
exit(EXIT_FAILURE);
}
/*discard first line*/
if(strstr(dict->dir, ".dic"))
getline(&line, &len, fp);
/*read file lines*/
while ((read = getline(&line, &len, fp)) != -1)
{
if(((strstr(line, "[CAT=punct") == NULL) && (word = parse_line(line, dict->w_len)) != NULL)) {
dict_add(dict, word);
}
}
fclose(fp);
free(line);
printf("dictionary.c (dict_load): dictionary loaded %ld words.\n", dict->counter);
}
char * parse_line(char * line, size_t w_len)
{
int i;
char s_tmp[101] = "";
char * dlm_slash, * dlm_space, * dlm_tab , *substring;
/*get delimiter pointer*/
dlm_slash = strchr(line, '/');
dlm_space = strchr(line, ' ');
dlm_tab = strchr(line, '\t');
/*check if delimiter exists in line*/
if(dlm_slash != NULL)
i = (int)(dlm_slash - line);
else if(dlm_space != NULL)
i = (int)(dlm_space - line);
else if(dlm_tab != NULL)
i = (int)(dlm_tab - line);
else
{
/*replace '\n' with '\0'*/
line[strcspn(line, "\n")] = '\0';
i = strlen(line);
}
strncpy(s_tmp, line, i);
substring = malloc(sizeof(char) * strlen(s_tmp) + 1);
strncpy(substring, s_tmp, strlen(s_tmp));
/*lowercase word*/
lower_case(substring);
if((is_valid(substring) == 0) && (strlen(substring) <= w_len))
return substring;
free(substring);
return NULL;
}
Here's the basic problem, I think:
void dict_add(Dictionary * dict, char * word) {
char ** dictionary = dict->words; /* **** 1 **** */
/*check if word array is full*/
if(dict->counter == dict->size)
{
/*increrase size of dictionary*/
dict->size *= 1.5; /* **** 2 **** */
dict->words = realloc(dict->words, dict->size * sizeof(char *));
/* **** 3 **** */
}
/*add word to dictionary*/
This one is the problem:
dictionary[dict->counter] = malloc(strlen(word) * sizeof(char) + 1);
strcpy(dictionary[dict->counter], word);
dict->counter++;
free(word); /* **** 4 **** */
}
The problem is that dictionary was saved before you called realloc. realloc might make a brand-new memory allocation, in which case it will automatically free() the old one after copying its contents into the new one. So any copy of the pointer which you made before calling realloc might end up pointing to unallocated memory. Writing to unallocated memory is a big no-no; in this particular case, you're probably overwriting malloc's bookkeeping information about the unallocated block, which is why it detects the problem and complains. Count yourself lucky: lots of memory corruption problems go undetected for quite a while until the factory explodes.
Some other issues which I noticed while writing this, with numbered comments in the source:
There's actually no need for the variable dictionary at all.
dict->size is an integer. Forcing conversion to a floating point number and then truncating back to an integer is not very useful. Prefer dict->size += dict->size/2;. Even better would be to first make sure that dict->size isn't so big that increasing it will cause integer wraparound. (This is not undefined behaviour on unsigned types like size_t, but it's not going to produce correct results.)
Here you could actually use a temporary, because realloc might return NULL indicating a memory allocation failure. If that happens, the original allocation is not automatically freed, and you don't have a way to free it. (Actually you do, since you have a variable confusingly called dictionary, but in point 1 I recommended that you get rid of it.) A more idiomatic call would be:
if(dict->counter == dict->size) {
/*increrase size of dictionary*/
dict->size += dict->size / 2; /* See point 2, above */
char** new_words = realloc(dict->words, dict->size * sizeof(*new_words));
if (new_words == NULL) {
/* Report allocation error and free all the memory you've allocated */
/* Then probably exit(1) but if this were a library function, just
* return some kind of failure indication so that the caller can do
* their own clean-up.
*/
}
dict->words = new_words;
}
dict->words[dict->counter] = word; /* See point 4, below */
You're freeing word here because it was allocated in parse_line(). But if you know you're going to free it anyway, there wasn't much point making a copy of it first. You might as well just use it. (But you need to document the fact that this function takes ownership of the word passed as an argument.)
It might be considered cleaner to do the copy as you do but then not free the argument, leaving it for the caller to do that. That would have the advantage of allowing the caller to provide a word which hadn't been dynamically allocated, or use the word for some other purpose.
(Not indicated in this snippet, but nonetheless important). Every block of allocated memory must be freed. So your program should execute free exactly as many times as it executed malloc. But you don't do that; you just free the array of word pointers, and let the words pointed to in that array leak. You should fix that. (Note that you don't need an extra call to free for a call to realloc, since realloc itself frees the old block if it allocates a new one. You only need to match the initial malloc with a free.)
i have function which is written in c ,in this function i allocate 2 string as temp and found, but i cant free temp string.
i think it may due to using of temp in result array.
can any one helps me.
here is the function.
void split(char* input, char* delim, char** result,int size) {
char* tmp = malloc((strlen(input)) * sizeof(char));
char* found = malloc((strlen(input)) * sizeof(char));
tmp=strcpy(tmp, input);
// #pragma omp parallel for
for (int i=0; i<size; i++) {
found = strstr(tmp, delim);
if (found != NULL) {
int length = found - tmp;
result[i]=malloc((length+1) * sizeof(char));
result[i] = strncpy(result[i], tmp, length);
*(result[i] + length) = '\0';
tmp = found + strlen(delim);
} else {
result[i]=malloc(strlen(tmp) * sizeof(char));
result[i] =strncpy(result[i], tmp, strlen(tmp));
}
}
// free(tmp);
free(found);
}
here size is number of sub strings after split
when i remove the comment of this line:
// free(tmp);
then this err occurs:
munmap_chunk(): invalid pointer
Aborted (core dumped)
can i ask you to help me for writing correct split function
You do assignments to tmp. That means the pointer tmp might no longer point to the same location that malloc returned.
You need to pass the exact same pointer to free that was returned by malloc.
You have the same problem with found, you assign to it and possible change where it points.
Passing an invalid pointer to free leads to undefined behavior.
You also have another problem: You go out of bounds of the original memory allocated and pointed to by tmp. That's because you seem to have forgotten that strings in C are really called null-terminated strings.
When you allocate memory for a string, you need to include space for the null-terminator at the end. And it's not counted by strlen.
Going out of bounds of allocated memory also leads to undefined behavior.
The function does not make a sense.
For starters it invokes undefined behavior
char* tmp = malloc((strlen(input)) * sizeof(char));
char* found = malloc((strlen(input)) * sizeof(char));
tmp=strcpy(tmp, input);
//...
because you allocated to enough memory to store the terminating zero character '\0' of the string input in the character array tmp.
Secondly the function has a memory leak because at first memory was allocated and its address was assigned to the pointer found and then the pointer found was reassigned in the call of strstr in the for loop.
char* found = malloc((strlen(input)) * sizeof(char));
//...
// #pragma omp parallel for
for (int i=0; i<size; i++) {
found = strstr(tmp, delim);
//...
So the address of the early allocated memory is lost and the memory can not be freed.
And this for loop
for (int i=0; i<size; i++) {
is just senseless.
You may not call free neither for tmp nor for found. The pointer found does not point to a dynamically allocated memory and the pointer tmp is being changed within the for loop.
here is my new function. i wrote it in recursive mode.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int get_number_of_occurence(char* string, char* delim) {
char* found = strstr(string, delim);
if(found == NULL || strcmp(found,delim) ==0 ||found =="" ){
return 0;
}else{
return 1+get_number_of_occurence(found+strlen(delim), delim);
}
}
int split(char* input, char* delim, char** result,int array_idx) {
char* found= strstr(input, delim);
if (found==""||strlen(input)==0){
return 0;
}else if(found == NULL){
result[array_idx]=malloc(strlen(input)+1 * sizeof(char));
strncpy(result[array_idx], input, strlen(input));
*(result[array_idx] + strlen(input)) = '\0';
return 0;
}else{
int length = found - input;
result[array_idx]=malloc((length+1) * sizeof(char));
strncpy(result[array_idx], input, length);
*(result[array_idx] + length) = '\0';
return split(found+strlen(delim),delim,result,array_idx+1);
}
}
int main () {
char * delim = "ooo";
char * input="ssooonn";
int size = get_number_of_occurence(input, delim);
printf("size is : %d \n",size);
char *splitted_values[size+1];
split(input, delim,splitted_values,0);
for (int i=0; i<(size+1); i++) {
printf("%s\n",splitted_values[i]);
free(splitted_values[i]);
}
}
in this code, first i count the number of occurrence of delimiter.
then i create array in that size and fill it with the help of split function.
thanks for helping.
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.
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 read the previous questions on dynamic arrays in C however I was not able to relate the answers to my question.
I am taking commands from stdin using fgets, removing the newline character and then want to store each command delimited by a space in a dynamically allocated array of strings. I however am having a lot of trouble with the correct way to allocated and reallocate memory. I am compiling with clang and keep getting segmentation fault 11. I then used -fsanitize=address and keep getting:
==2286==ERROR: AddressSanitizer: heap-buffer-overflow on address
0x60200000eeb8 at pc 0x000108fb6f85 bp 0x7fff56c49560 sp 0x7fff56c49558
WRITE of size 8 at 0x60200000eeb8 thread T0
Here is my code:
// Sets a delimiter to split the input
const char *seperator = " ";
char *token = strtok(line, seperator);
char **cmds = (char **) malloc(sizeof(char) * sizeof(*cmds));
// Adds first token to array of delimited commands
cmds[0] = token;
int count = 1;
while (token != NULL) {
token = strtok(NULL, sep);
if (token != NULL) {
cmds = (char **) realloc(cmds, sizeof(char) * (count + 1));
// Adds next token array of delimited commands
cmds[count] = token;
count++;
}
}
You're not allocating enough memory. cmds is an array of pointers, so each element is sizeof(char *) bytes, not sizeof(char) bytes.
On the initial allocation you want 1 char *, then on subsequent allocations you want count + 1.
Also, don't cast the return value of malloc, as that can hide other problems, and don't forget to check for failures.
char **cmds = malloc(sizeof(char *) * 1);
if (cmds == NULL) {
perror("malloc failed");
exit(1);
}
...
cmds = realloc(cmds, sizeof(char *) * (count + 1));
if (cmds == NULL) {
perror("reallocfailed");
exit(1);
}
The first malloc is wrong.. What'll you get when you derefer cmd by *cmd, before it's even allocated?
It also uses sizeof(char), which is wrong..
the right way would be..
// strtok modifies the string. So use writable string
char line[80] = "Hello my name is anand";
char *token = strtok(line, sep);
int count = 0;
// Alloc array of char* for total number of tokens we have right now
char **cmds = (char **) malloc(sizeof(char*) * (count + 1));
while (token != NULL)
{
/**
* Alloc memory for the actual token to be stored..
* token returned by strtok is just reference to the existing string
* in 'line'
*/
cmds[count] = malloc(sizeof(char) * ((strlen(token) + 1)));
// Adds tokens to array of delimited commands
strcpy(cmds[count], token);
count++;
token = strtok(NULL, sep);
if (token != NULL)
{
// resize array of tokens to store an extra token
char ** newCmds = (char **) realloc(cmds, sizeof(char*) * (count + 1));
// only if realloc was successful then use it.
if (newCmds != NULL)
{
cmds = newCmds;
}
}
}
First, sizeof(char) is always 1 by definition. And coding that does not make your code more readable.
But a pointer to char needs sizeof(char*) bytes (depending on the machine & ABI, that is often 8 or 4 bytes). I would at least suggest to compile your code with gcc -Wall -Wextra -g if using GCC.
At last, I find your code a bit inefficient. You are calling realloc at every loop. I would maintain a variable containing the allocated size
int allocsize = 4; // allocated size in number of elements
char **cmds = malloc(allocsize*sizeof(char*));
if (!cmds) { perror("malloc"); exit(EXIT_FAILURE); };
(BTW, always check the result of malloc; it can fail).
And to avoid realloc-ing every time, I would grow the allocated size in a geometric fashion, so inside the loop:
if (count>=allocsize) {
int newallocsize = (4*allocsize)/3+10;
cmds = realloc (cmds, newallocsize*sizeof(char*));
if (!cmds) { perror("realloc"); exit(EXIT_FAILURE); };
allocsize = newallocsize;
}
Alternatively, instead of keeping three variables: cmds, count, allocsize you could use a single struct ending with a flexible array member (and keeping its allocated and used sizes).