cpointersmallocrewriting

Malloc rewriting data in another malloc


im trying to get a file named "konferencnyZoznam" sorted by lines into separete dynamic arrays, and than return them to the main function (so i could use them for anotherfunctions). I am not really sure what is causing the problem, but what i saw from debugger and from outputs, that the malloc function allocates space too close together and than every time the function is called, the data in it are rewritten.

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

void n(char ***pid,char ***ptitle,char ***pname,char ***pdate,FILE **pFile);
void s(char **id);

int main() {
    int k=0;
    char c;
    char *id=NULL,*title=NULL,*name=NULL,*date=NULL;
    char **pid=&id,**ptitle=&title,**pname=&name,**pdate=&date;
    FILE *file,**pFile=&file;
    file= fopen("KonferencnyZoznam.txt","r");
    while(k==0) {
    printf("which function you want to call ?:\n");
    scanf(" %c",&c);
        if (c == 'v') {

        }
        else if (c == 'p') {

        }
        else if (c == 'n') {
            n(&pid,&ptitle,&pname,&pdate,pFile);
            s(id);
            k=0;  //for some reason it even changes k, so i need to change it back here, so program wont end!!
        }
        else if (c == 'k') {
            k=1;
        }
        else{
            printf("function not recognized, try again\n");
        }
    }
    /*for (int i=0;i<strlen(id);i++){
        free(id[i]);
    }*/
    return 50;
}

void n(char ***pid,char ***ptitle,char ***pname,char ***pdate,FILE **pFile){
    char f[100];
    int pr=1,i=0;
    int ni=0,nn=0,nt=0,nd=0;
    while (fgets(f,100,*pFile)){
        pr++;
    }
    printf("pr: %d\n",pr);
    rewind(*pFile);
    (**pid)=(char**) malloc(pr*sizeof (char*));
    (**ptitle)=(char**) malloc(pr*sizeof (char*));
    (**pname)=(char**) malloc(pr*sizeof (char*));
    (**pdate)=(char**) malloc(pr*sizeof (char*));
    for (int m=0;m< (pr/5);m++){
        (*pid)[m]=(char*)malloc(sizeof (char*));
        (*ptitle)[m]=(char*)malloc(sizeof (char*));
        (*pname)[m]=(char*)malloc(sizeof (char*));
        (*pdate)[m]=(char*)malloc(sizeof (char*));
    }

    do {
        fgets(f,100,*pFile);
        printf("f: %s",f);
        if (i % 5 == 0) {
            //(*pid)[ni] = (char *) realloc((*pid)[ni],(strlen(f)+1) * sizeof(char));
            strcpy((*pid)[ni],f);
            printf("%s", (*pid)[ni]);
            ni++;
        } else if (i % 5 == 1) {
            //(*ptitle)[nt] = (char *) realloc((*pid),(strlen(f)+1) * sizeof(char));
            strcpy((*ptitle)[nt], f);
            printf("%s", (*ptitle)[nt]);
            nt++;
        } else if (i % 5 == 2) {
            //(*pname)[nn] = (char *) malloc((strlen(f)+1) * sizeof(char));
            strcpy((*pname)[nn], f);
            printf("%s", (*pname)[nn]);
            nn++;
        } else if (i % 5 == 3) {
            //(*pdate)[nd] = (char *) malloc((strlen(f)+1) * sizeof(char));
            strcpy((*pdate)[nd], f);
            printf("%s", (*pdate)[nd]);
            nd++;
        } else {
            printf("\n");
        }
        for (int j=0;j<100;j++) {
            f[j] = '\0';
        }
        i++;
    } while (i<pr);

    for (int p=0;p<5;p++){
        printf("%s",*pid[p]);
    }
}

// this function is here for me to see which data i can later acces in other functions down the line
void s(char **id){
    printf("%s\n",id[0]);
}

and this is how the txt file looks

UP12345678
Zaklady proceduralneho programovania 2
Jan Zelenka#A#
202004050800

UP12457896
Deep learning
Jozko Mrkvicka#A#
202004051120

UD12365478
Cloud computing
Jana Mrkvickova#A#Jozko Mrkvicka#K#
202004051030

UP98632541
Metody inspirovane prirodou
Jan Oriesok#A#Jozko Mrkvicka#A#
202004051520

PP96385214
Spracovanie obrazu
Jozko Mrkvicka#A#
202004051200

well, i tried almost all that i could. i tried cahnging the size of the malloc, adding or taking away * and pointers, even rewriting the whole n function like 5 or 6 times, and well, im running out of ideas of what to do ...

what im expecting at the end are 4 different arrays (id, title, name and date), where these values should be there: id [[UP12345678][UP12457896][UP12457896][UP98632541][PP96385214]] title[[Zaklady proceduralneho programovania 2][Deep learning][Cloud computing][Metody inspirovane prirodou][Spracovanie obrazu]] you get the point ... oh, and i cannot use the global variables :D

thanks for any help you can give me, im really loosing my mind over this thing ...


Solution

  • Much too complicated! When you are trying to code some functionality, it is easier to code simple things and test that they do what you want, then (incrementally) add a bit more complexity until you achieve your goal.

    Below is a "stripped down" prototype for you to consider. It demonstrates what you might be able to do if you merely load the entire file into a block of dynamic memory. Here the block is "hard coded" as a compile time array of bytes.

    It seems the objective is to chop up those bytes into sections of 5 strings each. Notice that there is no need to strcpy() strings that are already present in this array (or the dynamically allocated buffer loaded from a file.)

    The number of lines in the whole block is counted, then "rounded up" to a multiple of 5 because each section of the source data is stored in 5 lines. (OP assumes responsibility for data validation.) A single array of pointers in allocated, each being set to point to the appropriate string (including 'padding' the last block.)

    Here, the rows are displayed, grouped together, like with like. Here the OP could write code to allocate separate arrays for each 'type' of string, filling those as desired.

    This is not a full solution to the OP problem, but is meant to point to a solution that does not involve exponentially more heap allocations than one might swallow.

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    int countLines( char *s ) {
        int cnt = 0;
        while( (s = strchr( s, '\n' ) ) != NULL)
            cnt++, s++;
        return cnt;
    }
    
    void show( int n, char *arr[], int max ) {
        for( int out = n; out < max; out += 5 )
            puts( arr[ out ] );
        puts( "" );
    }
    
    int main( void ) {
        char buffer[] = // Simulate buffer bulk-loaded from file with `fread()`
            "UP12345678\n"
            "Zaklady proceduralneho programovania 2\n"
            "Jan Zelenka#A#\n"
            "202004050800\n"
            "\n"
            "UP12457896\n"
            "Deep learning\n"
            "Jozko Mrkvicka#A#\n"
            "202004051120\n"
            "\n"
            "UD12365478\n"
            "Cloud computing\n"
            "Jana Mrkvickova#A#Jozko Mrkvicka#K#\n"
            "202004051030\n"
            "\n"
            "UP98632541\n"
            "Metody inspirovane prirodou\n"
            "Jan Oriesok#A#Jozko Mrkvicka#A#\n"
            "202004051520\n"
            "\n"
            "PP96385214\n"
            "Spracovanie obrazu\n"
            "Jozko Mrkvicka#A#\n"
            "202004051200\n";
    
        int i = countLines( buffer );
        printf( "%d lines\n", i );
    
        if( i%5 ) i = (i/5 + 1) * 5; // round up to nearest multiple. could be simpler.
        printf( "%d lines\n", i );
    
        char **arr = calloc( i, sizeof *arr ); // one array of pointers
    
        int use = 0;
        // assign pointers and chop into string(s)
        for( char *cp = buffer; *cp; *cp++ = '\0' ) {
            arr[ use++ ] = cp;
            cp = strchr( cp, '\n' );
            if( !cp) break;
        }
        while( use < i ) arr[ use++ ] = "empty";
        printf( "%d pointers\n\n", use );
    
        show( 0, arr, i );
        show( 1, arr, i );
        show( 2, arr, i );
        show( 3, arr, i );
    
        free( arr );
    
        return 0;
    }
    

    Results:

    24 lines
    25 lines
    25 pointers
    
    UP12345678
    UP12457896
    UD12365478
    UP98632541
    PP96385214
    
    Zaklady proceduralneho programovania 2
    Deep learning
    Cloud computing
    Metody inspirovane prirodou
    Spracovanie obrazu
    
    Jan Zelenka#A#
    Jozko Mrkvicka#A#
    Jana Mrkvickova#A#Jozko Mrkvicka#K#
    Jan Oriesok#A#Jozko Mrkvicka#A#
    Jozko Mrkvicka#A#
    
    202004050800
    202004051120
    202004051030
    202004051520
    202004051200
    

    One could use only 4 pointers for one "region" by detecting and skipping the empty 5th line of each region. This is left as an exercise for the reader.