Search code examples
cgnu

Realloc existing data is getting lost


I am learning c programming language. The program below takes the output of a command to variable and prints it. But when reallocate the memory to extend the memory I am losing the old data.

Can you please telling what I am missing here?

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(){

FILE *fp;

char r[1024];
fp=popen("/bin/ls /etc/","r");

if(fp==NULL){
    perror("Failed to run the command");
    exit(-1);
}

int totallengthread=0,alloc_size=1024;
char *buffer = (char*) malloc(alloc_size*sizeof(char));
memset(buffer,0,sizeof(buffer));
int lenofbuff=0;
while(fgets(r,1023,fp)!=NULL){
 concat(buffer,r);
 lenofbuff=strlen(buffer);
 totallengthread+=lenofbuff;
 if(totallengthread>=alloc_size){
     alloc_size+=1024;
     realloc(buffer,alloc_size);
 }

}
pclose(fp);
printf("this is the out put =>%s",buffer);
free(buffer);
 return 0;
}
void concat(char *dest, const char *source){
    char *d=dest;
    char *s=source;
    while (*d != '\0') {
              d++;
           }
     while(*s!='\0')
        {
            *d++=*s++;
        }
    *d='\0';
}

Solution

  • I think this is a bit closer to what you want. Please see the comments in the code.

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    
    void concat(char *dest, const char *source){
        char *d=dest;
        char *s=source;
        while (*d != '\0'){
            d++;
        }
        while(*s!='\0'){
            *d++=*s++;
        }
        *d='\0';
    }
    
    int main(){
        FILE *fp;
        char r[1024];
        fp=popen("/bin/ls /etc/","r");
        if(fp==NULL){
            perror("Failed to run the command");
            exit(-1);
        }
        int totallengthread=0,alloc_size=1024;
        char *buffer = malloc(alloc_size*sizeof*buffer); //This is nicer because is type independent
        memset(buffer,'\0',sizeof*buffer); //I believe this is what you wanted.
        int lenofbuff=0;
        while(fgets(r,sizeof r,fp)){ // as @chux said this avoids hardcoding 1024-1. You also don't need to compare to NULL. 
            concat(buffer,r);
            lenofbuff=strlen(buffer);
            totallengthread+=lenofbuff;
            if(totallengthread>=alloc_size){
                alloc_size+=1024;
                buffer = realloc(buffer,alloc_size); //you need to use the return of realloc
            }
        }
        pclose(fp);
        printf("this is the out put =>%s",buffer);
        free(buffer);
        return 0;
    }
    

    As @chux mentioned, as in any memory allocation you should check whether the returned pointers are NULL, that would mean the allocation failed.

    Also, please note that

    memset(buffer,'\0',sizeof*buffer);
    

    is equivalent to

    memset(buffer,0,sizeof*buffer);
    

    and as @thebusybee mentioned this is only setting the first element of the array to the NULL character, if you were intended to fill the whole array you should do memset(buffer,0,alloc_sizesizeofbuffer);

    or just replacing

    char *buffer = malloc(alloc_size*sizeof*buffer);
    memset(buffer,0,alloc_size*sizeof*buffer);
    

    for

    char *buffer = calloc(alloc_size,sizeof*buffer);