Hi,

well what I'm trying to do with this, is to read a text file line by line and pass its data to the struct. the problem is that not only i can't read the strings and put it on the struct fields, I also get a segmentation fault.
Could someone give me a little "light" here?

thanks!

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

#define MAX_LENGHT 78

typedef struct
{
  char id_num[5];
  char space;
  char Name[50];
  char Departure[10];
  char Arrival[10];
  char Day[2];
} PASSENGER;

 
void open_file() {
  
  FILE *fp;
  char s[20];
  char s2[]="reservations.txt";
  
  fprintf(stdout,"Write the text file name: ");
  fgets(s,20,stdin);
  if (!(strcmp(s,s2)==0)) {
    s[strlen(s)-1]='\0';
    fp=fopen(s,"r");
    if (fp==NULL) {
      fprintf(stderr,"Impossible to open the file %s\n\n",s);
      exit(1);
    }
    else
      fprintf(stdout,"File opened\n\n");

    /* read lines from the file and save it on str */
  char str[MAX_LENGHT];
  PASSENGER p[6];
  int i;
  
  while ((fgets(str,MAX_LENGHT,fp))!=NULL) {
    fprintf(stdout,"%s",str); /* shows every line in the text file */ 
      for (i=0;i<6;++i) {
	fscanf(fp,"%s%c%s%s%s%s",p[i].id_num,&p[i]space,p[i].Name,p[i].Departure,p[i].Arrival,p[i].Day); /* Should read the fields from the file */
	printf("%s%c%s%s%s%s",p[i].id_num,p[i]space,p[i].Name,p[i].Departure,p[i].Arrival,p[i].Day); /* should show the fields from file /*
    }
  }
  }
}



/* the text file is like this:                          

34012 Philip Morris                                     Lisbon    Milan     01
21092 John Peter Smith                                  Paris     Amsterdam 03
32467 Ann Mary Baptist                                  Madrid    Frankfurt 21
45201 Marian  Silver                                    Budapest  Roma      02
42506 Michaelangelo Marks                               Berlin    New York  30
12345 Bob Wilson                                        Stuttgart Copenhagen07


*/

,

You've got a lot there that needs tweaking. I first found it confusing how you got typos in what would appear to be a copy-and-paste, but I guess what you posted was an intermediate attempt since it wouldn't even compile.

After fixing those and ditching the user input for the filename, I could finally take a bit of a look at the loops. Your nested while and for loop combo shows a bit of confusion with what you're doing. If you read a line and display it (reading with the fgets ), you're not going to have the opportunity to read it again using fscanf . So I would assume you meant to parse the string read by fgets with sscanf (which is a good approach).

The format of your input file makes even sscanf parsing a bit funky. And your structure elements seemed to need to be increased in size to accomodate the null terminator for the strings.

I might come up with the following, but it would still be rather ugly.

#include <stdio.h>

typedef struct
{
   char id_num[6];
   char Name[51];
   char Departure[11];
   char Arrival[11];
   char Day[3];
} PASSENGER;

void open_file(const char *filename)
{
   PASSENGER p[6] = {0};
   int i = 0;
   FILE *file = fopen(filename, "r");
   if ( file )
   {
      char line[80];
      /* Read the file line by line. */
      while ( fgets(line, sizeof line, file) && i < 6 )
      {
         fputs(line, stdout); /* Display the line. */
         if ( sscanf(line, "%5s %50c%10c%10c%3s",
                     p[i].id_num,
                     p[i].Name,
                     p[i].Departure,
                     p[i].Arrival,
                     p[i].Day) == 5 )
         {
            printf("id_num = \"%s\"\n", p[i].id_num);
            printf("Name = \"%s\"\n", p[i].Name);
            printf("Departure = \"%s\"\n", p[i].Departure);
            printf("Arrival = \"%s\"\n", p[i].Arrival);
            printf("Day = \"%s\"\n", p[i].Day);
            ++i;
         }
      }
      fclose(file);
   }
   else
   {
      perror(filename);
   }
}

int main(void)
{
   open_file("file.txt");
   return 0;
}

As to the seg faults you were getting, I did not look into it at all. The code needed fixing just to build. But I recommend checking return values from the standard library functions being called. Check for success before pushing forward. For example: you possibly read the first line with fgets, then read the next 6 lines with fscanf -- but your file only contained 6 lines; reading 7 lines where there are only 6 might be bad.

Or maybe your format string was rather messed up ( %s stopping at whitespace, for example), and the text you were reading was very out of sync so that you were putting, say, a 10-character string into a 3-element array. Check return values.

first of all dave thks for the reply and for the help.


now what i have its a problem when i display individually the values of the struct fields.

this is my output:

34012 Philip Morris Lisbon Milan 01
id_num = "34012"
Name = "Philip"
Departure = "Morris"
Arrival = "Lisbon"
Day = "Mi"
21092 John Peter Smith Paris Amsterdam 03
id_num = "21092"
Name = "John"
Departure = "Peter"
Arrival = "Smith"
Day = "Pa"
32467 Ann Mary Baptist Madrid Frankfurt 21
id_num = "32467"
Name = "Ann"
Departure = "Mary"
Arrival = "Baptist"
Day = "Ma"
45201 Marian Silver Budapest Roma 02
id_num = "45201"
Name = "Marian"
Departure = "Silver"
Arrival = "Budapest"
Day = "Ro"
42506 Michaelangelo Marks Berlin New York 30
id_num = "42506"
Name = "Michaelangelo"
Departure = "Marks"
Arrival = "Berlin"
Day = "Ne"
12345 Bob Wilson Stuttgart Copenhagen07
id_num = "12345"
Name = "Bob"
Departure = "Wilson"
Arrival = "Stuttgart"
Day = "Co"

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

typedef struct
{
   char id_num[6];
   char Name[51];
   char Departure[11];
   char Arrival[11];
   char Day[3];
} PASSENGER;

void open_file(const char *filename)
{
   PASSENGER p[20]={0};
   int i = 0;
   FILE *fp;
   fp = fopen (filename, "r");
   if ( fp!=NULL )
   {
      char line[80];
      /* Read the file line by line. */
      while ( fgets(line, sizeof line, fp) && i < 20 )
      {
         fputs(line, stdout); /* Display the line. */
         if ( sscanf(line, "%5s %50s%10s%10s%2s",
                     p[i].id_num,
                     p[i].Name,
                     p[i].Departure,
                     p[i].Arrival,
                     p[i].Day) == 5 )
         {
            printf("id_num = \"%s\"\n", p[i].id_num);
            printf("Name = \"%s\"\n", p[i].Name);
            printf("Departure = \"%s\"\n", p[i].Departure);
            printf("Arrival = \"%s\"\n", p[i].Arrival);
            printf("Day = \"%s\"\n", p[i].Day);
            ++i;
         }
      }
      fclose(fp);
   }
   else {
      fprintf(stderr,"Impossible to open the file\n");
      exit(1);
    }
}

main() {
  
   open_file("reservations.txt");

}

i get the same output if i use fread followed by fscanf.

while ( fread(p, sizeof (p), 1, file) && i < 20 )
      {
         if ( fscanf(file, "%5s %50s%10s%10s%3s",
                     p[i].id_num,
                     p[i].Name,
                     p[i].Departure,
                     p[i].Arrival,
                     p[i].Day) == 5 )
         {
            printf("id_num = \"%s\"\n", p[i].id_num);
            printf("Name = \"%s\"\n", p[i].Name);
            printf("Departure = \"%s\"\n", p[i].Departure);
            printf("Arrival = \"%s\"\n", p[i].Arrival);
            printf("Day = \"%s\"\n", p[i].Day);
            ++i;
         }
      }

btw isn't fread() a function that only applies to binary files? at least it's what i've read in my C book.

Well, for the line
34012 Philip Morris Lisbon Milan 01
you read:

if ( fscanf(file, "%5s %50s%10s%10s%3s",
    p[i].id_num,    // 34012 
    p[i].Name,      // Philip 
    p[i].Departure, //Morris 
    p[i].Arrival,   // Lisbon 
    p[i].Day) == 5 )

Now, what changes seem obvious?

Well, for the line
34012 Philip Morris Lisbon Milan 01
you read:

if ( fscanf(file, "%5s %50s%10s%10s%3s",
    p[i].id_num,    // 34012 
    p[i].Name,      // Philip 
    p[i].Departure, //Morris 
    p[i].Arrival,   // Lisbon 
    p[i].Day) == 5 )

Now, what changes seem obvious?

but how can I read the full name and put it in p.Name? what I mean is is that I have a text file from which I Should read 5 chars for the id_num, a space in blank, 50 characters for the Name, 10 for the Departure, 10 for the Arrival and 2 for the Day. shouldn't the fscanf(file, "%5s %50s%10s%10s%3s") get the 1st 5 chars to the id_num, a space in blank, then 50 charters to the Name and so on?

scanf() functions cannot read past whitespace. Therefore
34012 Philip Morris Lisbon Milan 01
is 6 fields, not 5.

How can scanf() tell between
"Philip Morris" Lisbon Milan
Philip "Morris Lisbon" Milan
Philip Morris "Lisbon Milan"
?

Read each field (ID, Fname, LName, Depart...) and combine the name into your NAME field.

But then you have the problem of:
3124 Johnny Van Zant New York Los Angeles 07
If you can guarantee that name is only 2-words and arrive&dest are 1 each, the above should work.

Another thought -- is the file actually formatted like

34012 Philip Morris                 Lisbon    Milan      01

with all the spacing?

Another thought -- is the file actually formatted like

34012 Philip Morris                 Lisbon    Milan      01

with all the spacing?

yes. every line of the text has 5 chars for the id_num,a space in blank,50 characters for the Name, 10 for the departure, 10 for the arrival and 2 for day. all the lines of the file have this format.
Your Example of Johnny Van Zant it's good, because some lines of the file contain Names with 3 or 4 words, but they don't exceed the 50 characters.
that's why I'm trying to get strings with a particular length for each struct fields. i thought that if i put the fscanf(file, "%5s %50s%10s%10s%3s") i would get a string with 5 chars for num_id, a space in blank,a string with 50 chars for Name and so on. is there any function that does this?

thks

You should have specified that 14 hours ago! What you posted has only one space...

Use fgets() . It can read exactly x number of characters. Or use strncpy() to move the fields after reading teh entire line. But scanf() functions aren't smart enough to read the format you want without a very confusing format specifier.

now what i have its a problem when i display individually the values of the struct fields.

this is my output:

34012 Philip Morris Lisbon Milan 01
id_num = "34012"
Name = "Philip"
Departure = "Morris"
Arrival = "Lisbon"
Day = "Mi"
21092 John Peter Smith Paris Amsterdam 03
id_num = "21092"
Name = "John"
Departure = "Peter"
Arrival = "Smith"
Day = "Pa"

Yeah, didn't I mention that?

The format of your input file makes even sscanf parsing a bit funky.

And I chose %c instead of %s ? Because of the funky formatting? Did you try running what I posted? The result leaves a little to be desired, but it doesn't have the issues you brought back in with changing %c to %s .

i get the same output if i use fread followed by fscanf.

Didn't I mention not doing that? That taking input twice was a bad thing? Combining fgets or fread with fscanf is not going to improve your situation.

Yeah, didn't I mention that?

And I chose %c instead of %s ? Because of the funky formatting? Did you try running what I posted? The result leaves a little to be desired, but it doesn't have the issues you brought back in with changing %c to %s .

Didn't I mention not doing that? That taking input twice was a bad thing? Combining fgets or fread with fscanf is not going to improve your situation.

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

typedef struct {
  
   char id_num[5];
   char space;
   char Name[50];
   char Departure[10];
   char Arrival[10];
   char Day[2];
} PASSENGER;

void open_file(const char *filename)
{
   PASSENGER p[20]={0};
   int i = 0;
   FILE *fp;
   fp = fopen (filename, "r");
   if ( fp!=NULL )
   {
      char line[80];
      /* Read the file line by line. */
      while ( fgets(line, sizeof line, fp) && i < 20 )
      {
	fputs(line, stdout); /* Display the line. */
        if (fread(p[i].id_num, sizeof p[i].id_num, 1, fp) == 1)
	  printf("id_num = \"%s\"\n", p[i].id_num);
	if (fread(&p[i].space, sizeof p[i].space, 1, fp) == 1)
	  printf("Here's the space in blank\"%c\"\n", p[i].space);
	if (fread(p[i].Name, sizeof p[i].Name, 1, fp) == 1)
	  printf("Name = \"%s\"\n", p[i].Name);
	if (fread(p[i].Departure, sizeof p[i].Departure, 1, fp) == 1)
	  printf("Departure = \"%s\"\n", p[i].Departure);
	if (fread(p[i].Arrival, sizeof p[i].Arrival, 1, fp) == 1)
	  printf("Arrival = \"%s\"\n", p[i].Arrival);
	if (fread(p[i].Day, sizeof p[i].Day, 1, fp) == 1)
	printf("Day = \"%s\"\n", p[i].Day);
            ++i;
      }
   }
   else {
     fprintf(stderr,"Impossible to open the file\n");
     exit(1);
    }
    fclose(fp);
}

main() {
 
   open_file("reservations.txt");
}

this is my output, but what I would want is to print the string read from file, and then show each of the fields separately.
what is wrong here?

34012 Philip Morris Lisbon Milan 01
id_num = "21092"
Here's the space in blank" "
Name = "John Peter Smith "
Departure = "Paris "
Arrival = "Amsterdam "
Day = "03"

id_num = "32467"
Here's the space in blank" "
Name = "Ann Mary Baptist "
Departure = "Madrid "
Arrival = "Frankfurt "
Day = "21"

id_num = "45201"
Here's the space in blank" "
Name = "Marian Silver "
Departure = "Budapest "
Arrival = "Roma "
Day = "02"

id_num = "42506"
Here's the space in blank" "
Name = "Michaelangelo Marks "
Departure = "Berlin "
Arrival = "New York "
Day = "30"

id_num = "12345"
Here's the space in blank" "
Name = "Bob Wilson "
Departure = "Stuttgart "
Arrival = "Copenhagen"
Day = "07"

Get rid of duplicate reading attempts on the file. Don't call fgets if you are simply going to ignore and discard what it reads.

[edit]Still haven't caught on that you can't null-terminate a 5-character string in a 5-character array? And repeat with the others?

Edited 6 Years Ago by Dave Sinkula: n/a

Get rid of duplicate reading attempts on the file. Don't call fgets if you are simply going to ignore and discard what it reads.

i don't get it.

i don't get it.

You use fgets to read line one. Then you don't parse the line, you just print it. That data is now gone, lost.

Then you read line 2 with fread . This incompletely parses line 2. Using fread , you will have to match the file exactly -- and that will include reading the newlines.

By using fread and not matching things exactly, you've messed things up. You've doubled your messups by doing the fgets call.

Early on I said that using fgets with sscanf is a pretty good method, but that getting the format strings is a little tricky. Well, so is using fread . Six of one, half dozen of the other, I'd choose fgets with sscanf -- and so I did.

The code I posted gets the fields correctly; I don't care for the trailing spaces. But that's me.

[edit]This is the output of the code I posted in #2:

34012 Philip Morris                                     Lisbon    Milan     01
id_num = "34012"
Name = "Philip Morris                                     "
Departure = "Lisbon    "
Arrival = "Milan     "
Day = "01"
21092 John Peter Smith                                  Paris     Amsterdam 03
id_num = "21092"
Name = "John Peter Smith                                  "
Departure = "Paris     "
Arrival = "Amsterdam "
Day = "03"
32467 Ann Mary Baptist                                  Madrid    Frankfurt 21
id_num = "32467"
Name = "Ann Mary Baptist                                  "
Departure = "Madrid    "
Arrival = "Frankfurt "
Day = "21"
45201 Marian  Silver                                    Budapest  Roma      02
id_num = "45201"
Name = "Marian  Silver                                    "
Departure = "Budapest  "
Arrival = "Roma      "
Day = "02"
42506 Michaelangelo Marks                               Berlin    New York  30
id_num = "42506"
Name = "Michaelangelo Marks                               "
Departure = "Berlin    "
Arrival = "New York  "
Day = "30"
12345 Bob Wilson                                        Stuttgart Copenhagen07
id_num = "12345"
Name = "Bob Wilson                                        "
Departure = "Stuttgart "
Arrival = "Copenhagen"
Day = "07"

If I hadn't marked the beginning and end of the string with double-quotes, would the output not look dandy?

[edit=2]I had also changed the sizes of the char arrays in the structure to accommodate the null terminator for the strings.

Edited 6 Years Ago by Dave Sinkula: n/a

Hey Dave,

yes you're right since the 2nd post( who would have thought it :P), I put in my head that i wanted to read the struct fields from the file with fread()... but then I took your advice.


well now what i'm trying to do is to write all the struct fields i got from the file to a different one.
it writes something but i don't understand what it is and why they have different encoding!

#include <stdio.h>

typedef struct
{
   char id_num[6];
   char space;
   char Name[51];
   char Departure[11];
   char Arrival[11];
   char Day[3];
} PASSENGER;

void open_file(const char *filename)
{
   PASSENGER p[10] = {0};
   int i = 0;
   FILE *file = fopen(filename, "r");
   if ( file )
   {
      char line[80];
      /* Read the file line by line. */
      while ( fgets(line, sizeof line, file) && i < 10 )
      {
         fputs(line, stdout); /* Display the line. */
         if ( sscanf(line, "%5s%c%50c%10c%10c%2s",
                     p[i].id_num,
		     &p[i].space,
                     p[i].Name,
                     p[i].Departure,
                     p[i].Arrival,
                     p[i].Day) == 6 )
         {
            printf("id_num = \"%.5s\"\n", p[i].id_num);
	    printf("Your blank space is here \"%c\"\n", p[i].space);
            printf("Name = \"%.50s\"\n", p[i].Name);
            printf("Departure = \"%.10s\"\n", p[i].Departure);
            printf("Arrival = \"%.10s\"\n", p[i].Arrival);
            printf("Day = \"%.2s\"\n", p[i].Day);
            ++i;
         }
      }
      fclose(file);
   }
   else
   {
      perror(filename);
   }
   FILE *fout;
   fout = fopen("reservations2.txt","w");
   if (fout != NULL) {
     // write each struct field in the file
     for (i=0;i<10;i++) {
       fprintf(fout,
       "%.5s%c%.50s%.10s%.10s%.2s\n",
	p[i].id_num,
        p[i].space,
        p[i].Name,
        p[i].Departure,
        p[i].Arrival,
        p[i].Day);
     }
     
   }
   else
     perror("reservations2.txt");
}

main()
{
   open_file("reservations.txt");
}

once again Dave thanks!

Attachments
34012 Philip Morris                                     Lisbon    Milan     01
21092 John Peter Smith                                  Paris     Amsterdam 03
32467 Ann Mary Baptist                                  Madrid    Frankfurt 21
45201 Marian  Silver                                    Budapest  Roma      02
42506 Michaelangelo Marks                               Berlin    New York  30
12345 Bob Wilson                                        Stuttgart Copenhagen07

never mind i dit it. now it writes like it should.
here's the code.

FILE *fout;
   fin =fopen(filename,"r");
   int n=0;
   char line1[80];
   fout = fopen("reservations2.txt","w");
   if (fout != NULL && fin != NULL) {
     while ( fgets(line1, sizeof line1, fin) && n<10) {
     // write each struct field in the file
       fprintf(fout,
       "%.5s%c%.50s%.10s%.10s%.2s\n",
	p[n].id_num,
        p[n].space,
        p[n].Name,
        p[n].Departure,
        p[n].Arrival,
        p[n].Day);
	++n;
     }
     
   }

Edited 6 Years Ago by krap_nek: n/a

Hi,
In the code provided by Dave,
I dont understand, what is it that is making the 'line[] array' read a new line in every iteration.

I mean it is possible that the code fills the same line from file in the structure every iteration.

This article has been dead for over six months. Start a new discussion instead.