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;   
    }
}
Nathan Tornquist
  • 6,468
  • 10
  • 47
  • 72

1 Answers1

2

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

Martin Beckett
  • 94,801
  • 28
  • 188
  • 263
  • 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 Apr 04 '12 at 16:44
  • @NathanTornquist it might help to give a sample of the file format, how the line width is set etvc – Martin Beckett Apr 04 '12 at 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 Apr 04 '12 at 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 --- ex-moderator kitten Apr 04 '12 at 16:48
  • getline still requires a byte count though. Is there any way to completely avoid hard coding anything? – Nathan Tornquist Apr 04 '12 at 16:53
  • 1
    @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 Array – Martin Beckett Apr 04 '12 at 16:56