简体   繁体   中英

In C, how would you save different lines of a text file to different variables

How would I save different lines from a text File to different variables of different datatypes; all of these variables make up a struct (in my example a flight struct with the following).

struct Flight
{
     int flightNum;
     char desination[30];
     char departDay[15];
};

An Example of the information that I would like to add via text file would be.

111
NYC
Monday

I obviously want to save the words NYC and Monday to a char array, but I want to save 111 to an integer variable

So far I have

while (fscanf(flightInfo, "%s", tempName) != EOF)
{
     fscanf(flightInfo, "%d\n", &tempNum);
     flight.flightNumber = tempNum;
     fscanf(flightInfo, "%s\n", tempName);
     strcpy(flight.desination, tempName);
     fscanf(flightInfo, "%s\n", tempName)
     strcpy(flight.departDay, tempName);
}

Assume that flightInfo is a pointer to a filename, tempNum is an integer, and tempName is a char array

It sounds like you're on the right track.

What about something like this:

#define MAX_FLIGHTS 100
...
struct Flight flights[MAX_FLIGHTS ];
int n_flights = 0;
...
while (!feof(fp) && (n_flights < MAX_FLIGHTS-1))
{
     if (fscanf(fp, "%d\n", &flights[n_flights].flightNum) != 1)
        error_handler();
     if (fscanf(fp, "%29s\n", flights[n_flights].destination) != 1)
        error_handler();
     if (fscanf(fp, "%14s\n", flights[n_flights].departDay) != 1)
        error_handler();
     ++n_flights;
}
...

ADDENDUM: Per Chux's suggestion, I've modified the code to mitigate against potential buffer overruns, by setting scanf max string length to 29 (1 less than char[30] buffer size).

Here is a more detailed explanation:

SonarSource: "scanf()" and "fscanf()" format strings should specify a field width for the "%s" string placeholder

The first question you have to answer is this: how important is it for the file to be readable by people, or on other platforms?

If it isn't that important, then I recommend serializing with fwrite() and fread() . That is easier to code for each record, and - as long as your structs are all the same size - allows O(1) access to any record in the file.

If you do want to store these as individual lines, the best way to read a line in from a file is with fgets()

Pseudocode follows:

typedef struct flight {
  int flightNum;
  char desination[30];
  char departDay[15];
} flight;

typedef struct flightSet {
  flight *flights;
  size_t n; /* number of flights */
  size_t nAlloc; /* number of flights you have space for */
} flightSet;

#define FLIGHTSET_INIT_SIZE 16
#define MAX_LINE_LENGTH 128
#define FILENAME "file.txt"

// Create a new flightSet, calling it F
// Allocate FLIGHTSET_INIT_ALLOC number of flight structures for F->flights
// Set F->n to 0
// Set F->nAlloc to FLIGHTSET_INIT_ALLOC

/* Set up other variables */
size_t i = 0;                       // iterator */
char buffer[MAX_LINE_LENGTH];   // for reading with fgets() */
flights *temp;                  // for realloc()ing when we have more flights to read
                            // after reaching nAlloc flights
char *endptr;                   // for using strtol() to get a number from buffer
FILE *fp;                       // for reading from the file

// Open FILENAME with fp for reading

//MAIN LOOP
  // If i == F->nAlloc, use realloc() to double the allocation of F->flights
  // If successful, double F->nAlloc

  if (fgets(buffer, MAX_LINE_LENGTH, fp) == NULL) {
      // End of file
      // Use break to get out of the main loop
  }

  F->flights[i]->flightNum = (int)strtol(buffer, &endptr, 10);
  if (endptr == buffer) {
    // The first invalid character that can't be converted to a number is at the very beginning
    // of the buffer, so this is not a valid numerical character and your data file is corrupt
    // Print out an error message
    break; 
  }

  if (fgets(buffer, MAX_LINE_LENGTH, fp) == NULL) {
      // End of file when expecting new line; file format error
      // Use break to get out of the main loop
  } else {
     F->flights[i]->destination = strdup(buffer);  // If your system has strdup()
     // Check for memory allocation
  }

  if (fgets(buffer, MAX_LINE_LENGTH, fp) == NULL) {
      // End of file when expecting new line; file format error
      // Use break to get out of the main loop
  } else {
     F->flights[i]->departDay = strdup(buffer);  // If your system has strdup()
     // Check for memory allocation
  }

  // If you've gotten here so far without errors, great!
  //    Increment F->n to reflect the number of successful records we have in F.
  //    Increment i, the loop iterator

//Final cleanup.  Should include closing the file, and freeing any allocated
//memory that didn't end up in a valid record. 

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