Search code examples
cfunctionparameter-passingcalloc

I have problems making a function to handle a matrix using calloc


I want to dynamicly construct a matrix in C from a text document using a function. I ran into problems when making the matrix using calloc and probably when giving the values to the matrice elements, and I couldn't find anything. I can handle a vector.

Code here:

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

void beolvas_ellista(int *, int *, int *, int *, int ***, char *);

int main()
{
    int ir, suly, csom, el, i, **ellista;

    //The following commented code works
    /*FILE * f;
    f=fopen("be.txt","r");

    fscanf(f,"%d",&ir);
    fscanf(f,"%d",&suly);
    fscanf(f,"%d",&csom);
    fscanf(f,"%d",&el);

    ellista=(int **)calloc(2,sizeof(int *));
    for(i=0;i<el;++i)
    {
        ellista[i]=(int *)calloc(el,sizeof(int));
    }
    i=0;
    while(!feof(f))
    {
        fscanf(f,"%d",&ellista[0][i]);
        fscanf(f,"%d",&ellista[1][i]);
        ++i;
    }

    for(i=0;i<el;++i)
        printf("%d %d\n",ellista[0][i],ellista[1][i]);

    fclose(f);*/

    beolvas_ellista(&ir, &suly, &csom, &el, &ellista, "be.txt");

    for(i=0;i<el;++i)
        printf("%d %d\n",ellista[0][i],ellista[1][i]);

    return 0;
}

void beolvas_ellista(int *ir, int *suly, int *csom, int *el, int ***ellista, char *allomany)
{
    int i;
    FILE * f;
    f=fopen(allomany,"r");

    fscanf(f,"%d",ir);
    fscanf(f,"%d",suly);
    fscanf(f,"%d",csom);
    fscanf(f,"%d",el);

    *ellista=(int **)calloc(2,sizeof(int *));
    for(i=0;i<*el;++i)
    {
        *ellista[i]=(int *)calloc(*el,sizeof(int));
    }

    i=0;
    while(!feof(f))
    {
        fscanf(f,"%d",ellista[0][i]);
        fscanf(f,"%d",ellista[1][i]);
        ++i;
    }

    fclose(f);
}

Here is the text file:

be.txt

0 0
7 8
1 2
1 3
2 3
3 4
4 5
4 6
5 7
6 7

Also here is the code that I used to gather information:

void beolvas(int*pn, int**pa, char*allomany)
{
int i;FILE*f;
f=fopen(allomany,"r");
fscanf(f,"%d",pn);
*pa=(int*)malloc((*pn)*sizeof(int));
for(i=0; i<*pn; i++)
fscanf(f,"%d",(*pa)+i);
fclose(f);
}
main()
{
int n, *a;
beolvas(&n, &a, "be.txt");
...
}

Solution

  • The following bullet-list the items wrong in your function.

    • You're incorrectly using feof() as the break condition of your while loop. See this question for more information.

    • You ignore the return result of fscanf() and with that thereby have no assurance at all the parameter parsing succeeded or not. See the documentation of fscanf().

    • Your code does not fit the model of the file content. The file, according to your code, should set ir, suly, csom, and el to values 0, 0, 7, and 8 respectively. You then allocate space for exactly two pointers-to-int, saving the result in ellista, then proceed to index into *ellista up to el items, which is clearly not 2. It is neither clear nor evident that you want a 2xN matrix or an Nx2 matrix when this is finished, and the code as-written does neither correctly.

    • Stylistic, but helpful: You should be setting your out-parameters on success of your function, not on initial entrance or parse. Eg: Your ellista by-address parameter should be set as the last operation, not the first, based on the success of the function. Declare a local int** local; temp var, run your algorithm populating that, and upon success set the out-parameter.

    All of that said, I think you want a 2xN matrix, and if so, the code below will do that. Note this does not check the results of the malloc and calloc calls, which i leave to you. This function will return zero (0) on success, non-zero on failure :

    int beolvas_ellista(int *ir, int *suly, int *csom, int *el, int ***ellista, const char *allomany)
    {
        FILE * f = fopen(allomany,"r");
        int ** local =  NULL;
        int i, res = -1;
    
        if (f == NULL)
            return res;
    
        if (fscanf(f,"%d",ir) == 1 &&
            fscanf(f, "%d",suly) == 1 &&
            fscanf(f,"%d",csom) == 1 &&
            fscanf(f,"%d",el) == 1)
        {
            // allocate two pointers, then in those two pointers, allocate
            //  space for *el integers.
            local = malloc(2 * sizeof(*local));
            local[0] = calloc(*el, sizeof(*(local[0])));
            local[1] = calloc(*el, sizeof(*(local[0])));
    
            for (i=0; i<*el; ++i)
            {
                if (fscanf(f, "%d", local[0]+i) != 1 ||
                    fscanf(f, "%d", local[1]+i) != 1)
                    break;
            }
    
            // only if i == *el did we finish the above
            if (i == *el)
            {
                *ellista = local;
                res = 0;
            }
            else
            {   // failed to read file content. free up memory
                // and return error state.
                free(local[0]);
                free(local[1]);
                free(local);
            }
        }
        fclose(f);
        return res;
    }