C Dynamic Memory Allocation - Read Data from File

Go To StackoverFlow.com

2

I am working on replicating the load() function from MATLAB for use in a C application. I am having trouble dynamically loading the data and initializing the arrays that I need. More specifically, I am trying to use fgets with arrays that have been initialized with calloc, and I cannot get it to work. The function is below, and help is appreciated.

EDIT: Updated code is below the following flawed example.

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

void *load(const char *Filename);

void *load(const char *Filename)
{
    FILE* FID;
    if ((FID = fopen(Filename, "r")) == NULL)
    {
        printf("File Unavailable.\n");
    }
    else
    {
        int widthCount = 0, heightCount = 0;

        char ReadVal;
        while ((ReadVal = fgetc(FID)) != '\n')
        {
            if (ReadVal == ' ' || ReadVal == ',' || ReadVal == '\t')
            {
                widthCount++;
            }
        }

        rewind(FID);
        char* String = calloc(widthCount * 100, sizeof(char));
        while (fgets(*String, widthCount+1, FID) != EOF)
        {
            heightCount++;
        }
        double* Array = calloc(widthCount * heightCount, sizeof(double));
        rewind(FID);
        int i = 0, j = 0;
        char * pch;
        while (fgets(*String, widthCount+1, FID) != EOF)
        {
            pch = strtok(String, " ,\t");
            while (pch != NULL)
            {
                Array[i][j] = strtod(pch, NULL);
                pch = strtok (NULL, " ,\t");
                j++;
            }
            i++;
            j = 0;
        }

        fclose(FID);
        return Array;

    }

}

The revised code: This solution works, for anyone looking at a similar problem.

void *load(const char *Filename)
{
    FILE* FID;
    if ((FID = fopen(Filename, "r")) == NULL)
    {
        printf("File Unavailable.\n");
        return NULL;
    }
    else
    {   
        int widthCount = 0, heightCount = 0;
        double *Array;
        char Temp[100];
        while ((Temp[0] = fgetc(FID)) != '\n')
        {
            if (Temp[0] == '\t' || Temp[0] == ' ' || Temp[0] == ',')
            {
                widthCount++;
            }
        }
        widthCount++;
        //printf("There are %i columns\n", widthCount);
        rewind(FID);
        while (fgets(Temp, 99, FID) != NULL)
        {
            heightCount++;
        }
        //printf("There are %i rows\n", heightCount);
        Array = (double *)calloc((widthCount * heightCount), sizeof(double));
        rewind(FID);
        int i = 0;
        while (!feof(FID))
        {

            fscanf(FID, "%lf", &*(Array + i));
            fgetc(FID);
            i++;
        }

        return Array;   
    }
}
2012-04-04 16:40
by Nathan Tornquist


2

Array isn't a 2d array instead of Array[i][j] = strtod(pch, NULL); just increment the pointer *(Array++) = strtod(pch, NULL);

2012-04-04 16:42
by Martin Beckett
Thanks, I hadn't caught that. My main problem is getting past the fgets command. I need to be able to grab a each row based on the row size that I determined at runtime - Nathan Tornquist 2012-04-04 16:44
@NathanTornquist it might help to give a sample of the file format, how the line width is set etv - Martin Beckett 2012-04-04 16:46
I don't have the line width. For class, the goal was to have the user provide the dimensions of the data to load. I decided to try to load all of the data without any of those values. That's the purpose of the width and height counts at the beginning of the function - Nathan Tornquist 2012-04-04 16:48
"My main problem is getting past the fgets command." And you've noticed that fgets is totally unsuited to the job in the general case. Good. If you don't know the length of any particular line before reading it you want getline or something equivalent. As of 2008 getline is part of POSIX so it should be available on any unixish system - dmckee 2012-04-04 16:48
getline still requires a byte count though. Is there any way to completely avoid hard coding anything - Nathan Tornquist 2012-04-04 16:53
@NathanTornquist the byte count is only a hint, or the size already allocated, getline will automatically realocate the array to fit the data. If you have getlien you save a lot of work growing the array and moving data as you read the values. The alternative is to read each new value a char at a time into some small fixed buffer (eg to fit 8 or 10 decimal places) and then convert each to Arra - Martin Beckett 2012-04-04 16:56
Ads