0

I need to read in a file that contains text, and then a double for that text. It is simply to get the mean and standard deviation for the set of numbers, so the text that comes before is irrelevant. For example, my input file looks a little like:

preface 7.0000
chapter_1 9.0000
chapter_2 12.0000
chapter_3 10.0000

etc..

In this case, it is finding the mean and std dev for the chapters of a book. I have the section of code below, but I'm not quite sure how to "ignore" the text, and only grab the doubles. At the moment this code prints out zeros and only exits the loop when it exceeds the array limit, which I set as a constant to 20 at the beginning of the program.

FILE *ifp;
char *mode = "r";
ifp = fopen("table.txt", mode); 

double values[array_limit];
int i;
double sample;

if (ifp==NULL)
{
  printf("cannot read file \n");
}

else
{
i = 0;

do
{
   fscanf(ifp, "%lf", &sample);  

   if (!feof(ifp))
   {
      values[i] = sample;
      printf("%.4lf \n", values[i]);
      i++;
      if (i>=array_limit)   //prevents program from trying read past array size limit//
        {
           printf("No more space\n");
           break;
        }
   }

   else
   {
              printf("read complete\n");
              printf("lines = %d\n", i);
   }

  }while (!feof(ifp));
  fclose(ifp);
}
tshepang
  • 12,111
  • 21
  • 91
  • 136
jesspick
  • 1
  • 1

3 Answers3

3

I think you could use fscanf(ifp, "%*[^ ] %lf", &sample) for reading from your file. The * says to ignore that particular match, the [] specifices a list of characters to match and the ^ indicates to match all characters except those in [].

Or possibly (a bit simpler) fscanf(ifp, "%*s %lf", &sample).

ilent2
  • 5,171
  • 3
  • 21
  • 30
  • Thanks so much, I knew there was a way to ignore all characters, but I didn't realise that you could just use [^] – jesspick May 21 '14 at 15:27
1

You have two major problems -- you're using feof which is pretty much always wrong, and you're not checking the return value of fscanf, which it what tells you whether you got a value or not (or whether you got to the eof).

So what you want is something like

while ((found = fscanf(ifp, "%lf", &values[i])) != EOF) {  /* loop until eof */
    if (found) {
        /* got a value, so count it */
        if (++i >= ARRAY_LIMIT) {
            printf("no more space\n");
            break;
        }
    } else {
        /* something other than a value on input, so skip over it */
        fscanf(ifp, "%*c%*[^-+.0-9]");
    }
}
Community
  • 1
  • 1
Chris Dodd
  • 119,907
  • 13
  • 134
  • 226
0

When reading in from a file, it's often best to use fgets to read one line at a time, then extract the parts you are interested in using sscanf:

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

#define ARRAY_LIMIT 10
#define LINE_LENGTH 128

int main()
{
    double values[ARRAY_LIMIT];
    int i, count = 0;
    double sample;

    FILE *ifp = fopen("table.txt", "r");
    if (ifp==NULL)
    {
        printf("cannot read file \n");
        return 1;
    }

    char buff[LINE_LENGTH];
    while (fgets(buff, LINE_LENGTH, ifp) != NULL) 
    {
        if (sscanf(buff, "%*s %lf", &sample) != 1) break;
        values[count++] = sample;
        if (count == ARRAY_LIMIT) {
            printf("No more space\n");
            break;
        }
    }    
    fclose(ifp);

    for (i = 0; i < count; ++i) {
        printf("%d: %f\n", i, values[i]);
    }

    return 0;
}

fgets returns NULL if it encounters the end of the file, or if a read error has occurred. Otherwise, it reads one line of the file into the character buffer buff.

The asterisk %*s in the sscanf means that the first part of the line is discarded. The second part is written to the variable sample. I am checking the return value of sscanf, which indicates how many values have been read successfully.

The loop breaks when the end of the file is reached or the count reaches the size of the array.

Tom Fenech
  • 72,334
  • 12
  • 107
  • 141