简体   繁体   中英

fscanf parse data (format specifier) C++

I have a struct like so:

struct Office {
char city[50];
int employees;
char desc[200];
}

struct Office office[100];

Then I want to fill the office array within a loop until reach end of file.

here is my data:

Toronto
    151: This is HQ

Vancouver
    23: This is branch office

London
    12: This is euro branch

Take this as an example:

Toronto
    151: This is HQ

So here I want to parse it to struct:

city = "Toronto"
employees = 151
desc = "This is HQ"

Notice: After city name in the new line before the number of employess, there is TAB (4 spaces)

I have had an implementation like so, but seems it does not work properly:

int function LoadOffices(const char *f) {
  int res = 1;
  char buf[500];
  char city[50];
  int emp;
  char desc[200];
  struct Office offices[100];
  FILE *fp = fopen(f, "r");

  if (fp) {
    while (fgets(buf, sizeof(line), fp) != nullptr) {
      if (i == 0) {
        rewind(fp);
      }
      i++;
      if (fscanf(fp, "%[^\n]", city) == 1) {
        strncpy(offices[i].city, city, 50);
      } else if (fscanf(fp, "%d[^:]:%[^\n]", &emp, desc) == 2) {
        offices[i].employees = emp;
        strncpy(offices[i].desc, desc, 200);
      }
    }
    res = 0;
  } else {
    res = 1;
  }

  fclose(fp);
  return res;
}

I just want to know how to deal with TAB and empty lines

The structure of your program makes a huge difference in how easy it is to approach a problem.

For loading an array of any kind of struct there is an idiom that you should use:

  • Make a function that reads a single struct
  • Have a way to determine the success or failure of that function on the stream
  • Make another function that uses the first to read an array/list/whatever of that struct

Here is what I suggest you work on:

bool LoadAnOffice( FILE * fp, struct Office * office );
// Attempt to read a single office from the open stream 'fp'
// Returns success or failure

bool LoadOffices( FILE * fp, struct Office offices[], size_t * num_offices, size_t max_num_offices );
// Fill an array of offices by loading them from the open stream 'fp'
// Returns the number of offices loaded in '*num_offices'
// Reads at most 'max_num_offices'
// Returns 'true' if EOF encountered, 'false' otherwise

You can even add a function to do it by opening a file as you wish:

bool LoadOfficesFromFile( const char * filename, struct Office offices[], size_t * num_offices, size_t max_num_offices )
{
  FILE * f = fopen( filename, "r" );
  if (!f) return false;
  bool result = LoadOffices( f, offices, num_offices, max_num_offices );
  fclose( f );
  return result;
}

Thereafter your program can easily handle loading your offices from file:

int main(void)
{
  #define MAX_OFFICES 100
  struct Office offices[MAX_OFFICES];
  size_t n_offices = 0;

  if (!LoadOfficesFromFile( "offices.txt", offices, &n_offices, MAX_OFFICES ))
  {
    fprintf( stderr, "%s\n", "complain!" );
    ...
  }

It isn't short , but it is a good way to modularize handling file I/O for structured types. You'll find yourself using some variation of this idiom over and over and over.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM