Reputation: 1257
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
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
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
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