Intelwalk
Intelwalk

Reputation: 671

Reading in from a file in C

I need to read from a file from using C.

 #include <stdio.h>

struct record{
    char name[2];
    int arrival_time;
    int job_length;
    int job_priority;
};

const int MAX = 40;

main(){

struct record jobs[MAX];
FILE *f;
fopen("data.dat","rb");
int count =0;
while(fscanf(f, "%c%c %d %d %d", &jobs[count].name, &jobs[count].arrival_time, &jobs[count].job_length, &jobs[count].job_priority) != EOF){
count++;
}
int i;
for(i =0;i<count;i++){
printf("%c%c %d %d %d", &jobs[count].name, &jobs[count].arrival_time, &jobs[count].job_length, &jobs[count].job_priority);
}


}

The data file's format is the following:

     A1 3 3 3
     B1 4 4 4
     C1 5 5 5

...

First one is char[2] and the other three int. I can't get the code right to read in until the end of file.

Anyone come across this before?

Updated Code.

Upvotes: 1

Views: 314

Answers (4)

Jonathan Leffler
Jonathan Leffler

Reputation: 754920

There are a couple of modifications needed - most notably, you need to reference the jobs array of structures:

#include <stdio.h>

struct record{
    char name[2];
    int arrival_time;
    int job_length;
    int job_priority;
};

const int MAX = 40;

int main(void)
{
    struct record jobs[MAX];
    int i = 0;
    int j;
    FILE *f = fopen("data.dat","rb");

    while (fscanf(f, "%c %d %d %d", &jobs[i].name[0], &jobs[i].arrival_time,
                  &jobs[i].job_length, &jobs[i].job_priority) == 4 && i < MAX)
        i++:

    for (j = 0; j < i; j++)
        printf("%c %d %d %d\n", jobs[j].name[0], jobs[j].arrival_time,
               jobs[j].job_length, jobs[j].job_priority);

    return(0);
}

I make sure the loop doesn't overflow the array. I print the data out (it is the most basic form of checking that you've read what you expected). The most subtle issue is the use of jobs[i].name[0]; this is necessary to read and print a single character. There's no guarantee that there is any particular value in jobs[i].name[1]; in particular, it is quite probably not an NUL '\0', and so the name is not null terminated. It seems a bit odd using a single character name; you might want to have a longer string in the structure:

char name[MAX];  // Lazy reuse of MAX for two different purposes!

fscanf(f, "%.39s ...", jobs[i].name, ...

printf("%s ...", jobs[i].name, ...

The & is now not needed. The %.39s notation is is used to read a length-limited string up to the first space. Note that the size in the string is one less than the size of the array. It can often be simplest simply to create the format string with sprintf() to get the size right.

The code does not error check the fopen() statement.


Your code prints out A 1 3 3 instead of A1 3 3 3. I tried to add a second %c to it and it did not resolve it.

I discussed names longer than one character...

If you need to read "A1", you need the name member to be bigger so that you can null terminate the string, and you need to use %s rather than %c to read the value, and you need to lose the & and subscript, and you need to protect your code from buffer overflow (because where you expect 'A1', someone will inevitably enter 'A1B2C3D4D5F6G7H8I9J10K11L12M13' and wreak havoc on your code if you do not protect against the buffer overflow. Incidentally, the change in the test of the result of fscanf() (from == EOF to != 4 was also a protection against malformed input; you can get zero successful conversions without reading any characters, in general - though your %c would eat one character per iteration).

#include <stdio.h>

struct record{
    char name[4];
    int arrival_time;
    int job_length;
    int job_priority;
};

const int MAX = 40;

int main(void)
{
    struct record jobs[MAX];
    int i = 0;
    int j;
    FILE *f = fopen("data.dat","rb");

    while (fscanf(f, "%.3s %d %d %d", jobs[i].name, &jobs[i].arrival_time,
                  &jobs[i].job_length, &jobs[i].job_priority) == 4 && i < MAX)
        i++:

    for (j = 0; j < i; j++)
        printf("%s %d %d %d\n", jobs[j].name, jobs[j].arrival_time,
               jobs[j].job_length, jobs[j].job_priority);

    return(0);
}

Upvotes: 1

Michael Dillon
Michael Dillon

Reputation: 32392

No, the lines do not contain ints. Each line is a string which can be easily parsed into four shorter strings. Then each of the strings can either be extracted and stored in your struct, or converted to ints which you can store in your struct.

The scanf function is the usual way that people do this kind of input string parsing when the data format is simple and straightforward.

Upvotes: 0

user1004499
user1004499

Reputation:

Note: this is not the best way, someone else has answered with a much easier solution using format strings and fgets which will basically do what i wanted to do in one easy line.

I am assuming you want something like this. Note that I have not tested this at all as I just wrote it out pretty quickly.

#include <stdio.h>
FILE *fileInput;

main()
{
    char* path="whatever.txt";
    fileInput = fopen(path, "r");
    int i=0;

    while (fgets(line,100,fi)!=NULL)
    {
         token[0] = strtok(line, " ");
         //now you can do whatever you wanna do with token[0]
         //in your example, token[0] is A1 on the first iteration, then B1, then C1
         while(token[i]!= NULL)
         {
             //now token[i] can be converted into an int, probably using atoi
             //in your example, token[i] will reference 3 (3 times) then 4, etc
         }
    }

}

Hope it helps!

Upvotes: 0

TridenT
TridenT

Reputation: 4909

You need to get the line and parse it according to the type you want to read.

   while(fgets(line, 80, fr) != NULL)
   {
     /* get a line, up to 80 chars from fr.  done if NULL */
     sscanf (line, "%s %d %d %d", &myText, &int1, &int2, &int3);
   }

See example here:
http://www.phanderson.com/files/file_read.html

Upvotes: 1

Related Questions