1

Because some of the fields are blank, I can't use sscanf nor strtok. The solution seems to be to use strsep which is working properly. My issue is that all of the previous structs in the array seem to be getting overwritten by the current iteration of the array.

This is the struct (in airPdata.h):

typedef struct airPdata{
  char *siteNumber; // FAA Site Number
  char *LocID; // Airport's "Short Name"
  char *fieldName; // Airport Name
  char *city; // Associated City
  char *state; // State
  char *latitude; // Latitude
  char *longitude; // Longitude
  char controlTower; // Control Tower
} airPdata;

Here's my code:

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


int main(int argc, char* argv [])
{
    FILE *fp;
    char fileName[100];
    char buf[250];
    int i = 0,j;
    struct airPdata airports[875];
    char *token;


    //request name of file with file type
    printf("What is the name of the data file (including file type)?  ");
    scanf("%s", fileName);

    //determine if file can be succesfully opened
    fp = fopen(fileName, "r");
    if(fp == NULL)
    {
        fprintf(stderr, "Can't open input file %s, Exiting safely...\n", fileName);
        exit(EXIT_FAILURE);
    }


    //printing the header lines to stdout
    printf("\n\n%-12s%-11s%-42s%-34s%-3s%-15s%-16s Tower\n","FAA Site", "Short Name", "Airport Name", "City", "ST","Latitude", "Longitude");
    printf("%-12s%-11s%-42s%-34s%-3s%-15s%-16s =====\n","========", "==========", "============", "====", "==","========", "=========");



    //reading in data to the structs
    for(i = 0; i < 875; i++)
    {
        //allocate memory for the data in current struct
        airports[i].siteNumber = malloc(51);
        airports[i].LocID = malloc(51);
        airports[i].fieldName = malloc(51);
        airports[i].city = malloc(51);
        airports[i].state = malloc(51);
        airports[i].latitude = malloc(51);
        airports[i].longitude = malloc(51);

        //buffer for current line
        if(fgets(buf, sizeof(buf), fp) == NULL) break;
        char *line = buf;
        /*sscanf(buf, "%[^,],%[^,],%[^,],%[^,],%[^,],%*[^,],%*[^,],%*[^,],%[^,],%[^,],%*[^,],%*[^,],%*[^,],%*[^,],%[^,],%*[^,],%*[^,],%*[^,],%*d",
            airports[i].siteNumber,
            airports[i].LocID,
            airports[i].fieldName,
            airports[i].city,
            airports[i].state,
            airports[i].latitude,
            airports[i].longitude,
            &airports[i].controlTower);*/

        //iterates through the 15 values in the line (could be blank) 
        //and assigns data to values that are necessary
        for(j = 1; j <= 15; j++)
        {
            //i use a switch case because I know which values I'm going to need
            switch(j)
            {
                case 1:
                airports[i].siteNumber = strsep(&line, ",");
                break;

                case 2:
                airports[i].LocID = strsep(&line, ",");
                break;

                case 3:
                airports[i].fieldName = strsep(&line, ",");
                break;

                case 4:
                airports[i].city = strsep(&line, ",");
                break;

                case 5:
                airports[i].state = strsep(&line, ",");
                break;

                case 9:
                airports[i].latitude = strsep(&line, ",");
                break;

                case 10:
                airports[i].longitude = strsep(&line, ",");
                break;

                case 15:
                token = strsep(&line, ",");
                airports[i].controlTower = token[0];
                break;

                default:
                token = strsep(&line, ",");

            }
        }
    }

    //test printing 
    printf("%s\n", airports[0].fieldName);
    printf("%s\n", airports[1].fieldName);
    printf("%s\n", airports[2].fieldName);
    printf("%s\n", airports[3].fieldName);
    printf("%s\n", airports[4].fieldName);


    fflush(stdout);

    fclose(fp);


   return 0;
}

5 lines of expected input:

03406.20*H,2FD7,AIR ORLANDO,ORLANDO,FL,ASO,ORL,PR,28-26-08.0210N,081-28-23.2590W,PR,,NON-NPIAS,,N,A,,0,18400
03406.36*H,2FL5,BROOKSVILLE INTL AIRWAYS- INC,ORLANDO,FL,ASO,ORL,PR,28-25-26.0000N,081-27-35.0000W,PR,,NON-NPIAS,,N,,,0,53800
03406.18*H,32FL,MEYER,ORLANDO,FL,ASO,ORL,PR,28-30-05.0120N,081-26-39.2560W,PR,,NON-NPIAS,,N,,,0,0
03406.11*H,37FA,FLORIDA HOSPITAL,ORLANDO,FL,ASO,ORL,PR,28-34-32.0020N,081-22-06.2490W,PR,,NON-NPIAS,,N,,,0,0
03406.31*H,3FD5,ARNOLD PALMER HOSPITAL,ORLANDO,FL,ASO,ORL,PR,28-31-21.0090N,081-22-49.2520W,PR,,NON-NPIAS,,N,,,0,0

Expected output from my test printfs (just getting the fieldName):

AIR ORLANDO
BROOKSVILLE INTL AIRWAYS- INC
MEYER
FLORIDA HOSPITAL
ARNOLD PALMER HOSPITAL

Output I'm getting:

ARNOLD PALMER HOSPITAL
ARNOLD PALMER HOSPITAL
ARNOLD PALMER HOSPITAL
ARNOLD PALMER HOSPITAL
ARNOLD PALMER HOSPITAL

I can't figure out why I'm getting this output. Any help would be appreciated, even if you have a better solution. Thanks in advance :)

LJ O
  • 11
  • 2
  • 4
    After `airports[i].fieldName = malloc(51)`, think about what `airports[i].fieldName = strsep(&line, ",")` is doing... Hint: It does *not* [copy](http://en.cppreference.com/w/c/string/byte/strcpy) the string. – Some programmer dude Feb 08 '18 at 17:15
  • 4
    Might as well suggest [strdup()](http://man7.org/linux/man-pages/man3/strdup.3.html) instead of a malloc/strcpy combo. – Dúthomhas Feb 08 '18 at 17:20
  • @Dúthomhas Because `strdup` isn't in standard C. :) It's in POSIX and is available in Windows as well, but it's still not a portable function. – Some programmer dude Feb 08 '18 at 17:24
  • Kind of a duplicate of https://stackoverflow.com/questions/3131319/how-to-correctly-assign-a-new-string-value as `strsep` a pointer to a string. – Support Ukraine Feb 08 '18 at 17:39
  • 1
    Try: `airports[i].fieldName = strsep(&line, ",");` --> `strcpy(airports[i].fieldName, strsep(&line, ","));` It's pretty unsafe but as long as the input is well-formed, it should work – Support Ukraine Feb 08 '18 at 17:50
  • @Someprogrammerdude OP is using non-standard, BSD strsep(), but suggesting to use strdup(), available in _every_ C library since the 90s, is not portable? Next we have dangerous alternatives being suggested? LOL. – Dúthomhas Feb 08 '18 at 18:03
  • @Dúthomhas Although I agree with `strsep/strdup`, `strdup()` is not available in a number of embedded compilers. Neither is it available in gcc when coding to spec. – chux - Reinstate Monica Feb 08 '18 at 18:35
  • Why 51 when the string may need size 250 due to `char buf[250];`? – chux - Reinstate Monica Feb 08 '18 at 18:39
  • Drop the `airports[i].fieldName = malloc(51);` and use `airports[i].fieldName = strdup(strsep(&line, ","));` – chux - Reinstate Monica Feb 08 '18 at 18:54

0 Answers0