2017-01-31 2 views
1

Ich habe versucht, dieses eine für eine Weile jetzt herauszufinden, und ich fühle mich wie ich nah sein muss. Grundsätzlich habe ich eine Datei mit verschiedenen Ländereinträgen, die durch neue Zeilen getrennt sind. Jeder Datensatz enthält durch Komma getrennte Felder, von denen ich versuche, bestimmte zu extrahieren.Wie lese ich eine durch Kommas getrennte Zeile in einer Textdatei und füge ihre Felder in ein Array von Strukturzeigern ein?

Zum Beispiel (in einer einzigen Zeile):

60, AFG, Afghanistan, Asien, Süd- und Zentralasien, 652090,1919,22720000,45.9,5976, Afganistan/Afqanestan, Islamisches Emirat, Mohammad Omar, 1, AF

Jede dieser Zeilen bildet eine Struktur. Im Wesentlichen möchte ich jede dieser Zeilen lesen und sie in ein Array von Strukturzeigern (so dynamisch) einfügen. Ich möchte auch nur bestimmte Felder. Wenn ich die Zeile "Tokenize" möchte ich die Felder für Code, Name, Bevölkerung und Lebenserwartung. jeweils:

AFG, Afghanistan, 22720000, 45.

Mein Gedanke war, verwenden fgets(), um jede Zeile in der Datei zu lesen, und in einer Schleife malloc() etwas Speicher für die Zeiger, tokenize auf die Felder, die ich will, dann einfügen. Allerdings muss etwas, was ich mache, falsch sein, da verschiedene Tests nichts in meiner Ausgabe zu zeigen scheinen.

Hier ist meine bisherige Arbeit. Ich würde jede und jede Hilfe schätzen.

#include "allheaders.h" // contains all common headers for personal use 

#define BUF_SIZE 512 
#define NUM_RECS 238 

typedef struct { 
    char code[4]; 
    char name[40]; 
    int population; 
    float lifeExpectancy; 
} Country; 

typedef Country *countryPtr; 

int main(int argc, const char* argv[]) { 

/* Opening the file */ 
FILE *filePtr; // pointer to file 
if ((filePtr = fopen("AllCountries.dat", "r")) == NULL) { // if couldn't open file 
    printf("Error opening file\n"); // error message 
    exit(1); 
} 

/* Reading the file */ 
char buffer[BUF_SIZE]; // buffer to read 
int index = 0; 
char *token; 
countryPtr *myCountries = malloc(sizeof(*myCountries) * NUM_RECS); 
for(int i = 0; i < NUM_RECS; ++i) { 
    myCountries[i] = malloc(sizeof(*myCountries[i])); 
} 

while (fgets(buffer, BUF_SIZE, filePtr) != NULL) { 

    token = strtok(buffer,","); 
    token = strtok(NULL, ","); 
    strcpy(myCountries[index]->code, token); 
    token = strtok(NULL, ","); 
    strcpy(myCountries[index]->name, token); 
    token = strtok(NULL, ","); 
    token = strtok(NULL, ","); 
    token = strtok(NULL, ","); 
    token = strtok(NULL, ","); 
    token = strtok(NULL, ","); 
    myCountries[index]->population = atoi(token); 
    token = strtok(NULL, ","); 
    myCountries[index]->lifeExpectancy = atof(token); 
    //printf("%s", buffer); 
    index++; 
} 

printf("%s", myCountries[1]->code); // test? 
free(myCountries); 

}

+1

Schlagen Sie ein paar grundlegende Debugging. Mit einem Debugger oder sogar grundlegenden Debug-Print-Anweisungen. Untersuchen Sie zum Beispiel "Puffer" und "Token" nach jeder Zeile in der Schleife. – kaylum

+0

Für Starter ist "Index" nicht initialisiert. Etwas, das Sie mit einem einfachen Debugging wie vorgeschlagen leicht erkennen können. – kaylum

+0

Jetzt, da Sie das 'Index' Problem behoben haben, ist das nächste Problem, dass Ihre' Code' Puffer nicht groß genug sind; 'Zeichencode [3];'. Zeichenfolgen in C sind NUL-terminiert. Um eine 3-Buchstaben-Zeichenfolge zu speichern, benötigen Sie also 4 Zeichen. Sie haben also Pufferüberläufe, die zu einem nicht definierten Verhalten führen. – kaylum

Antwort

0

ich es um die Lösung basierend auf Ihren Code und Datendatei einen anderen Ansatz markiert zu verbessern. Ich habe es getestet. Es funktioniert mit einer Datei des Datensatztyps, den Sie angezeigt haben. Hoffentlich wird es einige Dinge erklären und Ihre Arbeit erleichtern und Ihnen einen guten Arbeitsplatz geben.

Ich mag es nicht, Programme in einer Weise zu schreiben, die die Anzahl der Datensätze in einer Datei auf allgemeinen Prinzipien vorauszählen (zeitraubend) oder vorher kennen muss, außer vielleicht in seltenen Fällen. Also wenn ich Dateien lese, bevorzuge ich Speicher zuzuweisen, während ich gehe. Nun, wenn es eine große Datei und viele Daten gibt, dann müssen Sie ein besseres Speicherverwaltungsschema entwickeln, als alles im Speicher zu behalten. Irgendwann ist es besser, wenn Sie eine bestimmte db-Lösung verwenden. MySQL, eine API, Bibliothek, Parser, etc ... aber das sollte für kleine Dateien funktionieren.

Normalerweise in C unter UNIX bedeutet exit(0) Erfolg, exit(-1) bedeutet Fehler. Da Ihre Ländercodes 3 Zeichen lang waren, muss das Feld, das es enthält, mindestens 4 Zeichen für das nachfolgende '\ 0' haben.

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <strings.h> 

#define MAXRECL 512 
#define MAXFIELDS 100 
#define MAXFIELDL 80 

// Field indicies 

#define COUNTRY_CODE 1 
#define COUNTRY_NAME 2 
#define POPULATION  7 
#define LIFE_EXPECTANCY 8 

#define CCMAX   3 
#define CNMAX   40 

typedef struct Country { 
    struct Country *next; 
    char code[CCMAX + 1]; // (Need room for trailing '\0') 
    char name[CNMAX + 1]; // (Need room for trailing '\0') 
    int population; 
    float lifeExpectancy; 
} country_t; 

country_t *countryRecords; 

int main(int argc, const char* argv[]) { 

    FILE *fp; 
    if ((fp = fopen("AllCountries.dat", "r")) == NULL) { 
     printf("Error opening file\n"); 
     exit(-1); 
    } 
    int totalCountries = 0; 
    char buf[MAXRECL]; 
    char fields[MAXFIELDS][MAXFIELDL]; 
    country_t *prev_country = NULL; 
    while (fgets(buf, MAXRECL, fp) != NULL) { 
     ++totalCountries;  
     country_t *country = calloc(sizeof(struct Country), 1); 
     if (country == NULL) { 
      fprintf(stderr, "Out of memory\n"); 
      exit(-1); 
     } 
     char *field = strtok(buf, ","); 
     int i = 0; 
     while(field != NULL) { 
      strncpy(fields[i++], field, MAXFIELDL); 
      field = strtok(NULL, ","); 
     }   
     strcpy(country->code, fields[COUNTRY_CODE]); 
     strcpy(country->name, fields[COUNTRY_NAME]); 
     country->population = atoi(fields[POPULATION]); 
     country->lifeExpectancy = atof(fields[LIFE_EXPECTANCY]); 

     if (countryRecords == NULL) 
      countryRecords = country; 
     else 
      prev_country->next = country; 
     prev_country = country; 
    } 
    printf("Total countries: %d\n", totalCountries); 

    country_t *country = countryRecords; 
    while(country != NULL) { 
     printf("%3s %30s Population: %7d Life Expectancy: %5.2f\n", 
      country->code, country->name, country->population, country->lifeExpectancy); 
     country_t *prev_country = country; 
     country = country->next; 
     free(prev_country); 
    } 
    printf("Done\n"); 
    exit(0); 
} 
+0

Auch ich sollte erwähnen, dass ich 'calloc()' anstelle von 'malloc()' verwendet habe, weil 'calloc()' den Speicher vor der Rückgabe an nullen lässt, 'malloc()' nicht. – clearlight

1

Werfen Sie einen Blick auf die folgende. Im ersten Fall müssen Sie einige Arbeit tun, um die Bereiche NYI

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

#define BUF_SIZE 512 
#define NUM_RECS 238 

typedef struct { 
    char code[4]; // NYI - magic numbers 
    char name[41]; // NYI - magic numbers 
    int population; // NYI - what if atoi fails? 
    float lifeExpectancy; // NYI - what if atof fails? 
} Country; 

typedef Country* countryPtr; 

int main(int argc, const char* argv[]) { 
    /* Opening the file */ 
    FILE *filePtr; // pointer to file 
    if ((filePtr = fopen("a.txt", "r")) == NULL) { // if couldn't open file 
    printf("Error opening file\n"); // error message 
    exit(1); 
    } 

    /* Reading the file */ 
    char buffer[BUF_SIZE]; // buffer to read 
    int index=0; 
    char *token; // NYI - initial value 
    countryPtr* myCountries = calloc(NUM_RECS, sizeof(countryPtr)); 
    for(int i = 0; i < NUM_RECS; ++i) { 
    myCountries[i] = calloc(1, sizeof(Country)); 
    } 

    while (fgets(buffer, BUF_SIZE, filePtr) != NULL) { 
    // NYI - magic lengths/overflow strcpy targets 

    token = strtok(buffer,","); // NYI - This is probably not the best way to do this. At least fold into a loop. 
    token = strtok(NULL, ","); 
    strcpy(myCountries[index]->code, token); 
    token = strtok(NULL, ","); 
    strcpy(myCountries[index]->name, token); 
    token = strtok(NULL, ","); 
    token = strtok(NULL, ","); 
    token = strtok(NULL, ","); 
    token = strtok(NULL, ","); 
    token = strtok(NULL, ","); 

    myCountries[index]->population = atoi(token); // NYI - atoi failure 
    token = strtok(NULL, ","); 
    myCountries[index]->lifeExpectancy = atof(token); // NYI - atof failure 
    printf("%s", buffer); 
    index++; 
    } 

    printf("%s\n", myCountries[0]->code); // test? NYI - need more proof 
    free(myCountries); // NYI - this is a sequence - need to free each of the new elements 
} 
+0

Sie haben Recht mit "magischen Zahlen". Sollte Konstanten sein. Du hast Recht, dass 'atoi() und atof()' fehlgeschlagen sind.Ich konnte nicht alles in meiner Antwort ansprechen, aber [this] (http://stackoverflow.com/q/22865622/2079103) deckt das Problem der numerischen Konvertierung ab. Gut, das auch richtig zu handhaben. – clearlight

Verwandte Themen