Jack022
Jack022

Reputation: 1257

Saving data from text file to data structures in C

I have this text file with various records, each record has 4 fields, 3 strings of words and one number, for example

field one; field two; field three; 1
field one; field two; field three; 2

I need to sort those records according to the last number through an insertion sort algorithm, so the second record should be the first one in the list, since 2>1. To do that, i first need to store each record before comparing them, i'm having some problems with that.

I got this until now:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLEN 100

struct Element
   {
    char one[100];
    char two[100];
    char three[100];
    int st;
   };



int main() {

    int i;
    struct Element elements[MAXLEN];


    FILE * fpointer = fopen("clients.txt", "r");

    for (i = 0; i < MAXLEN; i++) {
       struct Element *e = elements+i;  // pointer on ith element
       fscanf(fpointer, "%99s%99s%99s%d", e->one, e->two, e->three, &e->st);
    }

    printf("%s%s%s%d", elements->one, elements->two, elements->three, elements->&st);

    fclose(fpointer);
    return 0;

}

My current problems:

1) this current program is not good for saving string of words. It's good when the record is like: string; string; string; 1 but it won't work with phrases (like in the first example).

2) I don't really understand the structure of this: i know that i'm saving each record in my array of data structures but i'm having some problems printing each record. Let's say i want to print the second record, how can i do that? In my current work i printed one, two, three and st but this way, it will only print the first record.

Upvotes: 3

Views: 1020

Answers (3)

Tim Randall
Tim Randall

Reputation: 4145

I think you have pretty much reached the answer to your second question.

for (i = 0; i < MAXLEN; i++) {
    struct Element *e = elements+i;  // pointer on ith element
    printf("%s%s%s%d", e->one, e->two, e->three, e->&st);    
}

Alternatively, you can use the form elements[i].one to access element one in the i'th element.

Upvotes: 1

kiran Biradar
kiran Biradar

Reputation: 12732

You can use %[^;] in fscanf. fscanf will read the string until reaches ;. And use ; as delimiter for fscanf. Your code will look like below.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLEN 3

struct Element
   {
    char one[100];
    char two[100];
    char three[100];
    int st;
   };



int main() {

    int i;
    struct Element elements[MAXLEN];


    FILE * fpointer = fopen("clients.txt", "r");

    for (i = 0; i < MAXLEN; i++) {
       struct Element *e = elements+i;  // pointer on ith element
       if (fscanf(fpointer, "%[^;];%[^;];%[^;];%d", e->one, e->two, e->three, &e->st) !=3)
            break;
    }

    for (i = 0; i < MAXLEN; i++) {
       struct Element *e = elements+i;  // pointer on ith element
    printf("%s%s%s%d\n", elements->one, elements->two, elements->three, elements->st);
}
    fclose(fpointer);
    return 0;

}

Upvotes: 2

Chris Turner
Chris Turner

Reputation: 8142

Using %s when calling any of the scanf functions just reads in text up to the next bit of whitespace, so will work fine if you have single words in your fields, but as you've discovered falls over if there phrases. It also will read in the delimiters into your strings too, which I doubt you want.

Instead, a better solution would be to read in the entire line into a string and parse your way through it. The following bit of code reads in a line of text with fgets and then uses strtok to split it up into chunks separated by semicolons. It keeps track of how which field it is populating using field_number so if you add more fields, it's easy to expand. And if there are less fields than expected it will stop and move onto the next line.

char buffer[1024]; // Define a really big string to hold the line of text in
char *field;
int field_number;

while(fgets(buffer,1024,fpointer))
    {
    field_number=0;
    field=strtok(buffer,";");
    while(field)
        {
        switch(field_number)
            {
        case 0:
            strcpy(elements[i].one,field);
        break;
        case 1:
            strcpy(elements[i].two,field);
        break;
        case 2:
            strcpy(elements[i].three,field);
        break;
        case 3:
            elements[i].st=atoi(field);
        break;
            }
        field=strtok(NULL,";"); // Get next field
        field_number++;
        }
    i++; // Move the index for elements to the next one
    }

In answer to your second question, elements is an array. If you do elements->one that is the same as doing elements[0].one. If you want to access the second element in your array, you'd do elements[1].one or (elements+1)->one which is what you're doing with this odd line in your original code:

   struct Element *e = elements+i;  // pointer on ith element

when really you should have been using elements[i] as that is a lot easier to read.

Upvotes: 2

Related Questions