Realloc array of Strings in C? segmentation error - c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void sortString(const char* input, char* output);
int cmpstr(void const *a,void const *b);
int readAllWords(FILE* f, char*** res, int * num_read);
int main (int argc, char ** argv)
{
char **wordList;
FILE* fid;
int numWords;
fid = fopen(argv[1],"r");
readAllWords(fid, &wordList,&numWords);
}
int readAllWords(FILE* f, char*** res, int * num_read)
{
char buffer[128];
*num_read = 0;
int size;
while(fgets(buffer,128,f))
{
*num_read = *num_read +1;
size = strlen(buffer);
res = (char***)malloc(sizeof(char**));
*res = (char **)realloc(*res,sizeof(char*)*(*num_read));
(*res)[(*num_read)-1] = (char *)realloc((*res)[(*num_read)-1],sizeof(char)*size);
strcpy((*res)[(*num_read)-1],buffer);
printf("%s\n",(*res)[(*num_read)-1]);
}
printf("%s\n",(*res)[0]);
}
The values are storing and it prints out inside the while loop. But after the while loop, it cannot print out the strings.
The File is given in the main function. Do not understand why realloc is causing the loss of data?

One problem is that the code doesn't initialize res in main(), so you attempt to realloc() an indeterminate value. Either NULL or a value previously returned by malloc() or realloc() (or calloc()) would be OK, but since you pass an indeterminate value, you are invoking undefined behaviour, and a crash is a valid response to doing that.
However, there's a lot of other code in the function that should be reviewed as well.
This code works, and gets a clean bill of health from valgrind.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void readAllLines(FILE *f, char ***res, int *num_read);
int main(int argc, char **argv)
{
char **wordList = 0;
FILE *fid;
int numLines = 0;
if (argc > 1 && (fid = fopen(argv[1], "r")) != 0)
{
readAllLines(fid, &wordList, &numLines);
fclose(fid);
for (int i = 0; i < numLines; i++)
printf("%d: %s", i, wordList[i]);
for (int i = 0; i < numLines; i++)
free(wordList[i]);
free(wordList);
}
return 0;
}
void readAllLines(FILE *f, char ***res, int *num_read)
{
char buffer[128];
int size;
while (fgets(buffer, sizeof(buffer), f))
{
*num_read = *num_read + 1;
size = strlen(buffer) + 1;
char **space = (char **)realloc(*res, sizeof(char *) * (*num_read));
if (space == 0)
return;
*res = space;
(*res)[*num_read - 1] = (char *)malloc(sizeof(char) * size);
if ((*res)[*num_read - 1] == 0)
return;
strcpy((*res)[*num_read - 1], buffer);
printf("%s\n", (*res)[*num_read - 1]);
}
printf("%s\n", (*res)[0]);
}

Possible reason for a segmentation fault:
res = (char***)malloc(sizeof(char**));
*res = (char **)realloc(*res,sizeof(char*)*(*num_read));
In the second line you try to reallocate whatever *res is pointing to. However since you did not initialize *res this could be anything. This will work only if *res == NULL. I guess it should be malloc, not realloc.
Other problems:
You allocate everything new in each loop iteration. This is a huge memory leak.
You already pass a valid memory address pointing to an char** by res, you shouldn't allocate for it again. It is an out parameter. (Remove the malloc call)
You need an initial malloc for *res before the loop (Or set *res = NULL).
The second realloc for *res[...] should be a malloc, because you never actually reallocate here. Also instead of allocating size bytes, you should allocate size+1 bytes for the terminating \0.
Your function has no return statement although it is non-void.

Related

Using an array of structures with call by reference

Here is my problem: I have to make this program for school and I spent the last hour debugging and googling and haven't found an answer.
I have an array of structures in my main and I want to give that array to my function seteverythingup (by call by reference) because in this function a string I read from a file is split up, and I want to write it into the structure but I always get a SIGSEV error when strcpy with the struct array.
This is my main:
int main(int argc, char *argv[])
{
FILE* datei;
int size = 10;
int used = 0;
char line[1000];
struct raeume *arr = (raeume *) malloc(size * sizeof(raeume*));
if(arr == NULL){
return 0;
}
if(argc < 2){
return 0;
}
datei = fopen(argv[1], "rt");
if(datei == NULL){
return 0;
}
fgets(line,sizeof(line),datei);
while(fgets(line,sizeof(line),datei)){
int l = strlen(line);
if(line[l-1] == '\n'){
line[l-1] = '\0';
}
seteverythingup(&line,arr,size,&used);
}
ausgabeunsortiert(arr,size);
fclose(datei);
return 0;
}
and this is my function:
void seteverythingup(char line[],struct raeume *arr[], int size,int used)
{
char *token,raumnummer[5],klasse[6];
int tische = 0;
const char c[2] = ";";
int i=0;
token = strtok(line, c);
strcpy(raumnummer,token);
while(token != NULL )
{
token = strtok(NULL, c);
if(i==0){
strcpy(klasse,token);
}else if(i==1){
sscanf(token,"%d",&tische);
}
i++;
}
managesize(&arr[size],&size,used);
strcpy(arr[used]->number,raumnummer);
strcpy(arr[used]->klasse,klasse);
arr[used]->tische = tische;
used++;
}
Edit: Since there is more confusion I wrote a short program that works out the part you are having trouble with.
#include <cstdlib>
struct raeume {
int foo;
int bar;
};
void seteverythingup(struct raeume *arr, size_t len) {
for (size_t i = 0; i < len; ++i) {
arr[i].foo = 42;
arr[i].bar = 53;
}
}
int main() {
const size_t size = 10;
struct raeume *arr = (struct raeume*) malloc(size * sizeof(struct raeume));
seteverythingup(arr, size);
return 0;
}
So basically the signature of your functions is somewhat odd. Malloc returns you a pointer to a memory location. So you really dont need a pointer to an array. Just pass the function the pointer you got from malloc and the function will be able to manipulate that region.
Original Answer:
malloc(size * sizeof(raeume*));
This is probably the part of the code that gives you a hard time. sizeof returns the size of a type. You ask sizeof how many bytes a pointer to you raeume struct requires. what you probably wanted to do is ask for the size of the struct itself and allocate size times space for that. So the correct call to malloc would be:
malloc(size * sizeof(struct raeume));

Error at execution because of realloc

i wrote a little console program which stores words in an array, represented by char** test_tab, and then print them.
The program works fine as long as it does not go through the conditionalrealloc() (e.g if i increase sizeto 1000).
But if realloc() get called the program crashes during the array printing, probably because the memory is messed up in there.
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
char* get_word();
int main(int argc, char* argv[])
{
size_t size = 100;
size_t nb_pointer = 0;
char** test_tab = malloc(size * sizeof *test_tab);
char** temp_tab;
while((*(test_tab + nb_pointer) = get_word()) != NULL)
{
nb_pointer++;
if(nb_pointer >= size)
{
size += 100;
temp_tab = realloc(test_tab, size);
if(temp_tab != NULL)
test_tab = temp_tab;
else
{
free(test_tab);
exit(1);
}
}
}
for(nb_pointer = 0; *(test_tab + nb_pointer) != NULL; nb_pointer++)
printf("%s\n", *(test_tab + nb_pointer));
free(test_tab);
return 0;
}
Can someone explains me what i am doing wrong right here? Thanks.
The amount of memory in the realloc is not calculated correctly.
temp_tab = realloc(test_tab, size);
should be
temp_tab = realloc(test_tab, size * sizeof *test_tab);
Every time you are trying to push one string and at the same time take all the previously pushed string with you. Now string means char * & hence you need to use sizeof(char*) * size & then you need to allocate the memory to the string again to store the actual character..However you can also approach in this way
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static int size = 0; // static global means no risk while including this file
char** push(char** memptr, char* data) {
size++;
if (size == 1)
memptr = (char**)malloc(size * sizeof(char*));
else
memptr = (char**)realloc(memptr, size* sizeof(char*));
memptr[size - 1] = (char*)malloc(sizeof(char) * strlen(data) + 1);
strncpy(memptr[size - 1], data, strlen(data));
memptr[size - 1][strlen(data) -1] = '\0'; // over writing the `\n` from `fgets`
return memptr;
}
int main() {
char buf[1024];
int i;
static char** memptr = NULL;
for (i = 0; i < 5; i++){
fgets(buf, 1024, stdin);
memptr = push(memptr, buf);
}
for (i = 0; i < size; i++)
printf("%s\n", memptr[i]);
return 0;
}

memory leakage on asprintf using inside a loop in C

I have a piece of code that looks like this
#include <stdio.h>
int main()
{
int i;
int number_of_chunks = 12;
char *final_string = NULL;
for(i = 0; i < number_of_chunks; i++)
{
char *chunk = some_hash_table.pop(i);
asprintf(&final_string, "%s%s", (final_string==NULL?"":final_string), chunk);
}
free(final_string);
return 0;
}
Here I am concatinating string chunks dynamically, meaning I don't know the size of each chunk in advance. For this I am using asprintf. The code works fine, however rise some serious memory issue. My doubt is asprintf allocates memory in each iteration and the code loses pointer in each iteration. If there is any other way I can concate string inside loop please guide me
To put your question in the simplest possible way, what you are essentially trying to do with the above code is
1. Allocate memory to a pointer continuously(in your case 12 times in the for loop) and
2. free it at the end only once, which is causing memory leak.
Like in the below code
#include <stdio.h>
int main()
{
int i;
int number_of_chunks = 12;
char *final_string = NULL;
for(i = 0; i < number_of_chunks; i++)
{
/*For example: similar to what asprintf does, allocate memory to the pointer*/
final_string = malloc(1);
}
free(final_string);
return 0;
}
From the above example it is easily visible that you have allocated the memory 12 times but freed only once.
code snippet:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int i;
int number_of_chunks = 12;
char *final_string = NULL;
char *tmp = NULL;
for(i = 0; i < number_of_chunks; i++)
{
char *chunk = some_hash_table.pop(i);
asprintf(&final_string, "%s%s", (tmp==NULL?"":tmp), chunk);
if (tmp)
free(tmp);
tmp = final_string;
}
printf("%s\n", final_string);
free(final_string);
return 0;
}
Others have already pointed out that you lose the reference to all but the last allocation and that having the same string that is written to as printf argument is probably undefined behaviour, even more so as re-allocations might occur and invalidate the format argument.
You don't use asprintf's formatting capabilities, you use it only to concatenate strings, so you might want to take another approach. You could either collect the strings in an array, determine the needed length, allocate as appropriate and fill the allocated buffer with memcpy.
Or you could write a self-allocating string buffer similar to C++'s std::stringstream, for example:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct append_t {
char *str; /* string */
size_t len; /* length of string */
size_t size; /* allocated size */
};
void append(struct append_t *app, const char *str)
{
size_t len = strlen(str);
while (app->len + len + 1 >= app->size) {
app->size = app->size ? app->size * 2 : 0x100;
app->str = realloc(app->str, app->size);
/* error handling on NULL re-allocation */
}
strcpy(app->str + app->len, str);
app->len += len;
}
int main(int argc, char **argv)
{
struct append_t app = {NULL};
for (int i = 1; i < argc; i++) {
append(&app, argv[i]);
}
if (app.str) puts(app.str);
free(app.str);
return 0;
}

Segmentation fault after while loop that follows malloc

I am trying to create a 2d array dynamically, then open a txt file and copy each lenient my 2d array. Then save this array back to my main. I keep running into a segmentation error. Any suggestions how to do fix this code?
BTW i think the problem stars after the 2nd time while loop occurs...
#include<stdio.h>
char **randomArrayofStrings(){
char **twoArray=null;
int rows=50;
int col=20;
i=0;
FILE *file=null;
int messageSize=50;//this is number is trivial
file = fopen("somefile.txt","r");
twoArray= malloc(rows*sizeof(char*));
for(i=0;i<col;i++)
{
twoArray[i]=malloc(rows*sizeof(char));
strcpy(twoArray[i], "some random word");
}
while(!feof(file))
{
fgets(dArray[i],messageSize, file);
strtok(dArray[i], "\n");
i++;
}
return twoArray;
}
int main(int argc, char **argv)
{
char **localArray=null;
localArray=randomArrayofStrings();
for(i=0;i<20;i++)//20 is just a random number
printf("Strings: %s", localArray[i]);
}
As I see, in your function randomArrayofStrings loop for goes through columns "i cols in your code. So, you allocate array of pointers first and consider it as cols and then in a loop you allocate rows.
And after malloc check the value that was returned and do not use the pointer if it is NULL after memory allocation.
To free allocated memory, use the inverted sequence - free all rows in a loop and than free cols once. E.g.:
for(i=0;i<col;i++){
free(twoArray[i]);
}
free(twoArray);
twoArray = NULL;
EDIT:
And also, to use malloc and free you need #include <stdlib.h>, and #include <string.h> for strcopy, int i=0; should be instead of i=0;, and correct null value for pointers is NULL.
And what is dArray? I do not see the declaration or definition? Dou you mean twoArray?
EDIT2:
The following is my version of your program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **randomArrayofStrings(){
char **twoArray=NULL;
char * ptr = NULL;
int rows=50; // this will be also message size
int cols=20;
int i=0;
FILE *file=NULL;
file = fopen("somefile.txt","r");
if( file == NULL )
return NULL;
twoArray = (char**) malloc(cols * sizeof(char*));
if(twoArray == NULL)
{
return NULL;
}
for(i=0;i<cols;i++)
{
twoArray[i] = (char*)malloc(rows*sizeof(char));
if(twoArray[i] == NULL)
return NULL;
strcpy(twoArray[i], "some random word");
}
i = 0; // reset counter
while(!feof(file))
{
fgets(twoArray[i], rows, file);
ptr = strchr(twoArray[i],'\n');
if( ptr )
*ptr = '\0';
else
twoArray[i][rows-1] = '\0';
i++;
if( i >= cols)
break;
}
fclose(file);
return twoArray;
}
void freeMy2dArray(char **twoArray, int n)
{
int i;
for(i=0; i < n; i++){
free(twoArray[i]);
}
free(twoArray);
twoArray = NULL;
}
int main(int argc, char **argv)
{
int i;
char **localArray=NULL;
localArray = randomArrayofStrings();
if( localArray == NULL )
return 1;
for(i=0;i<20;i++)//20 is just a random number
printf("Strings: %s\n", localArray[i]);
freeMy2dArray(localArray, 20);
}
You are not suppossed to free() twoArray inside randomArrayofStrings(). You have to free them inside main(), once you're done with using the allocated memeory.
That said, the way you're using sizeof(localArray) in main() is wrong. You have to use the exact value you did use to poupulate twoArray.

Freeing a non-allocated pointer

The following code throws the error:
mem(44582) malloc: * error for object 0x7f9f8a4000e0: pointer being freed was not allocated
* set a breakpoint in malloc_error_break to debug
Abort trap: 6
I'm not sure what's going on. I'm freeing an area of memory that I explicitly malloc'd, does it have something to do with passing in a pointer to another method?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFERSIZE 10
void readstringbuffered(char *buffer);
int main(int argc, char const *argv[])
{
char *buffer = (char *)malloc(BUFFERSIZE);
readstringbuffered(buffer);
printf("%s",buffer);
free(buffer);
return EXIT_SUCCESS;
}
void readstringbuffered(char *buffer)
{
FILE *source;
source = fopen("hello.txt","r");
int current_size = BUFFERSIZE;
int len = 0;
int c;
while((c = fgetc(source)) != EOF)
{
if(len == current_size-1)
{
current_size *= 2;
char *temp = (char *)realloc(buffer,current_size);
if(!temp)
{
fprintf(stderr,"out of memory");
exit(1);
}
buffer = temp;
}
buffer[len] = c;
len++;
}
buffer[len] = 0;
}
C is a pass by value language. The modifications you make to buffer inside your readstringbuffered() function have no effect on the value of buffer in main(). If the realloc() there is ever executed, you've already freed the buffer that main knows about, and when you return - BAM - double free.
A possible solution is to pass a pointer to buffer, rather than buffer itself. Change the signature of readstringbuffered() to be:
void readstringbuffered(char **buffer)
And then use *buffer inside it. At the call site, you'd use readstringbuffered(&buffer) to pass the necessary pointer.
realloc() can release the previously allocated memory and allocate it again somewhere else, which makes your buffer pointer in main totally invalid. You can pass buffer by reference and have readstringbuffered() modify it accordingly, or return a pointer to buffer instead of void.
The buffer pointer in main() will not be modified according to the reallocations you do in readstringbuffered(), you may write back the buffer pointer using a pointer to the buffer pointer (pBuffer), like this:
void readstringbuffered(char** pBuffer,size_t* pSize)
{
char* buffer = *pBuffer;
size_t size = MIN_SIZE;
char* newBufferPtr = (char*) realloc(buffer,size);
if(newBufferPtr)
{
buffer = newBufferPtr;
}
else
{
//out of memory
free(buffer);
buffer = NULL;
size = 0;
}
if(buffer)
{
//fill the buffer
}
//must always execute
*pBuffer = buffer;
*pSize = size;
}
int main(int argc, char const *argv[])
{
char* buffer = NULL;
size_t size = 0;
readstringbuffered(&buffer,&size);
if(buffer)
{
printf("%s",buffer);
free(buffer);
}
else
{
//error
}
return EXIT_SUCCESS;
}

Resources