2

I have a homework where i need to read from a file and save in arrays informations like the city name, the country code, the county name and the population

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

int main () 
{
    struct Country
    {
       char name [100];   // Le nom ASCII
       char code[100]; // Le code de deux lettres
   };

   //const struct Pays PAYS_BIDON = {"??", "??"};
   
   struct City
   {
       char name[100]; // Le nom ASCII
       long population;          // La population
       struct Country country;          // Le pays de la ville
   };
    struct City city;
    FILE* fp = fopen("fich.txt", "r");
 
    if (!fp)
    {
        printf("Can't open file\n");
    }
    else 
    {
        char buffer[1024];
        while (fgets(buffer, 1024, fp))
        {
            int i =0;
            char* value = strtok(buffer, "\t");
            while (value) 
            {
                strcpy(city.name,value);
                value = strtok(NULL, "\t");
                printf("name : %s\n", city.name);
              
            }
            
        }
        fclose(fp);
    }
    return 0;

} 

until here my code is working but when i try to read the country name it doesn't work :

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

int main () 
{
    struct Country
    {
       char name [100];   // Le nom ASCII
       char code[100]; // Le code de deux lettres
   };

   //const struct Pays PAYS_BIDON = {"??", "??"};
   
   struct City
   {
       char name[100]; // Le nom ASCII
       long population;          // La population
       struct Country country;          // Le pays de la ville
   };
    struct City city;
    FILE* fp = fopen("fich.txt", "r");
 
    if (!fp)
    {
        printf("Can't open file\n");
    }
    else 
    {
        char buffer[1024];
        while (fgets(buffer, 1024, fp))
        {
            int i =0;
            char* value = strtok(buffer, "\t");
            while (value) 
            {
                strcpy(city.name,value);
                value = strtok(NULL, "\t");
                printf("city name : %s\n", city.name);
                strcpy(city.country.name,value);
                value = strtok(NULL, "\t");
                printf("country : %s\n", city.country.name);
                
            }
            
        }
        fclose(fp);
    }
    return 0;

} 

the data in the file are like this:

3040051 les Escaldes    les Escaldes    Ehskal'des-Ehndzhordani,Escaldes,Escaldes-Engordany,Les Escaldes,esukarudesu=engorudani jiao qu,lai sai si ka er de-en ge er da,Эскальдес-Энджордани,エスカルデス=エンゴルダニ教区,萊塞斯卡爾德-恩戈爾達,萊塞斯卡爾德-恩戈爾達    42.50729    1.53414 P   PPLA    AD      08              15853       1033    Europe/Andorra  2008-10-15
3041563 Andorra la Vella    Andorra la Vella    ALV,Ando-la-Vyey,Andora,Andora la Vela,Andora la Velja,Andora lja Vehl'ja,Andoro Malnova,Andorra,Andorra Tuan,Andorra a Vella,Andorra la Biella,Andorra la Vella,Andorra la Vielha,Andorra-a-Velha,Andorra-la-Vel'ja,Andorra-la-Vielye,Andorre-la-Vieille,Andò-la-Vyèy,Andòrra la Vièlha,an dao er cheng,andolalabeya,andwra la fyla,Ανδόρρα,Андора ла Веля,Андора ла Веља,Андора ля Вэлья,Андорра-ла-Велья,אנדורה לה וולה,أندورا لا فيلا,አንዶራ ላ ቬላ,アンドラ・ラ・ヴェリャ,安道爾城,안도라라베야 42.50779    1.52109 P   PPLC    AD      07              20430       1037    Europe/Andorra  2020-03-03
290594  Umm Al Quwain City  Umm Al Quwain City  Oumm al Qaiwain,Oumm al Qaïwaïn,Um al Kawain,Um al Quweim,Umm Al Quwain City,Umm al Qaiwain,Umm al Qawain,Umm al Qaywayn,Umm al-Quwain,Umm-ehl'-Kajvajn,Yumul al Quwain,am alqywyn,mdynt am alqywyn,Умм-эль-Кайвайн,أم القيوين,مدينة ام القيوين 25.56473    55.55517    P   PPLA    AE      07              62747       2   Asia/Dubai  2019-10-24

i need from the first line

     city.name = les Escaldes ;
     city.country.code = AD;
     city.population = 15853;

i need from the second line

     city.name = Andorra la Vella;
     city.country.code = AE;
     city.population = 20430;

i need from the third line

     city.name = Umm Al Quwain City;
     city.country.code = AD;
     city.population = 62747;

so i don't know what the wrong thing i'm doing or the right thing to do

Craig Estey
  • 30,627
  • 4
  • 24
  • 48
mr ma
  • 21
  • 2

1 Answers1

1

A few issues ...

  1. You are using a single instance of your struct (e.g.) struct City city;. So, when you read the second line, your overwriting/trashing the data for the first.

  2. You need an array of structs.

  3. And, although it is legal, defining the structs at function scope isn't terribly useful. If you decided to split the function into multiple ones, the others wouldn't have the struct definition. Better to define them at file scope so all functions can use them.

  4. You're using both city.name and city->name. Only one is correct.

  5. The while (value) loop doesn't work as you would intend.

  6. Also, you're not filling in all fields of the structs.

Here's a refactored version:

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

struct Country {
    char name[100];                 // Le nom ASCII
    char code[100];                 // Le code de deux lettres
};

struct City {
    char name[100];                 // Le nom ASCII
    long population;                // La population
    struct Country country;         // Le pays de la ville
};

// NOTE: need array of structs
struct City citylist[100];

int
main(void)
{
    struct City *city;

    FILE *fp = fopen("fich.txt", "r");
    if (! fp) {
        printf("Can't open file -- %s\n",strerror(errno));
        exit(1);
    }

    char buffer[1024];

    int count = 0;
    char *value;

    // load up file contents
    while (fgets(buffer, sizeof(buffer), fp)) {
        city = &citylist[count++];

        value = strtok(buffer, "\t\n");
        strcpy(city->name,value);

        value = strtok(NULL, "\t\n");
        city->population = atol(value);

        value = strtok(NULL, "\t\n");
        strcpy(city->country.name,value);

        value = strtok(NULL, "\t\n");
        strcpy(city->country.code,value);
    }

    fclose(fp);

    // print data
    for (int i = 0;  i < count;  ++i) {
        city = &citylist[i];
        printf("City: %s, population %ld, Country: %s (Code %s)\n",
            city->name,city->population,
            city->country.name,city->country.code);
    }

    return 0;
}

Note that I've defined an arbitrary fixed size array citylist. But, having a dynamic array is much more flexible. For an implementation of that, see my answer: Creation of Dynamic Array of Strings in C


UPDATE:

@CraigEstey yes i posted that's what i need from the file – mr ma

Okay, based on your updated question ...

Now that we have some sample data and what fields to extract (based on value), here is the revised code:

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

struct Country {
    char name[100];                 // Le nom ASCII
    char code[100];                 // Le code de deux lettres
};

struct City {
    char name[100];                 // Le nom ASCII
    long population;                // La population
    struct Country country;         // Le pays de la ville
};

// NOTE: need array of structs
struct City citylist[100];

int
main(void)
{
    struct City *city;

    FILE *fp = fopen("fich.txt", "r");
    if (! fp) {
        printf("Can't open file -- %s\n",strerror(errno));
        exit(1);
    }

    char buffer[1024];
    char *tokens[1024];

    int count = 0;
    char *value;

    // load up file contents
    while (fgets(buffer, sizeof(buffer), fp)) {

        // split line into tokens
        int tokcnt = 0;
        value = strtok(buffer,"\t\n");
        while (1) {
            if (value == NULL)
                break;
            tokens[tokcnt++] = value;
            value = strtok(NULL,"\t\n");
        }

#if DEBUG
        printf("\n");
        for (int tokidx = 0;  tokidx < tokcnt;  ++tokidx)
            printf("main: TOKEN/%d '%s'\n",tokidx,tokens[tokidx]);
#endif

        // point to new city
        city = &citylist[count++];

        strcpy(city->name,tokens[1]);
        strcpy(city->country.code,tokens[8]);
        city->population = atol(tokens[10]);
    }

    fclose(fp);

    // print data
    for (int i = 0;  i < count;  ++i) {
        city = &citylist[i];
        printf("City: %s, population %ld, Country Code %s\n",
            city->name,city->population,city->country.code);
    }

    return 0;
}

Note that to determine what were the correct line indexes, I used the debug printf calls to match your desired results:


main: TOKEN/0 '3040051'
main: TOKEN/1 'les Escaldes'
main: TOKEN/2 'les Escaldes'
main: TOKEN/3 'Ehskal'des-Ehndzhordani,Escaldes,Escaldes-Engordany,Les Escaldes,esukarudesu=engorudani jiao qu,lai sai si ka er de-en ge er da,Эскальдес-Энджордани,エスカルデス=エンゴルダニ教区,萊塞斯卡爾德-恩戈爾達,萊塞斯卡爾德-恩戈爾達'
main: TOKEN/4 '42.50729'
main: TOKEN/5 '1.53414'
main: TOKEN/6 'P'
main: TOKEN/7 'PPLA'
main: TOKEN/8 'AD'
main: TOKEN/9 '08'
main: TOKEN/10 '15853'
main: TOKEN/11 '1033'
main: TOKEN/12 'Europe/Andorra'
main: TOKEN/13 '2008-10-15'

main: TOKEN/0 '3041563'
main: TOKEN/1 'Andorra la Vella'
main: TOKEN/2 'Andorra la Vella'
main: TOKEN/3 'ALV,Ando-la-Vyey,Andora,Andora la Vela,Andora la Velja,Andora lja Vehl'ja,Andoro Malnova,Andorra,Andorra Tuan,Andorra a Vella,Andorra la Biella,Andorra la Vella,Andorra la Vielha,Andorra-a-Velha,Andorra-la-Vel'ja,Andorra-la-Vielye,Andorre-la-Vieille,Andò-la-Vyèy,Andòrra la Vièlha,an dao er cheng,andolalabeya,andwra la fyla,Ανδόρρα,Андора ла Веля,Андора ла Веља,Андора ля Вэлья,Андорра-ла-Велья,אנדורה לה וולה,أندورا لا فيلا,አንዶራ ላ ቬላ,アンドラ・ラ・ヴェリャ,安道爾城,안도라라베야'
main: TOKEN/4 '42.50779'
main: TOKEN/5 '1.52109'
main: TOKEN/6 'P'
main: TOKEN/7 'PPLC'
main: TOKEN/8 'AD'
main: TOKEN/9 '07'
main: TOKEN/10 '20430'
main: TOKEN/11 '1037'
main: TOKEN/12 'Europe/Andorra'
main: TOKEN/13 '2020-03-03'

main: TOKEN/0 '290594'
main: TOKEN/1 'Umm Al Quwain City'
main: TOKEN/2 'Umm Al Quwain City'
main: TOKEN/3 'Oumm al Qaiwain,Oumm al Qaïwaïn,Um al Kawain,Um al Quweim,Umm Al Quwain City,Umm al Qaiwain,Umm al Qawain,Umm al Qaywayn,Umm al-Quwain,Umm-ehl'-Kajvajn,Yumul al Quwain,am alqywyn,mdynt am alqywyn,Умм-эль-Кайвайн,أم القيوين,مدينة ام القيوين'
main: TOKEN/4 '25.56473'
main: TOKEN/5 '55.55517'
main: TOKEN/6 'P'
main: TOKEN/7 'PPLA'
main: TOKEN/8 'AE'
main: TOKEN/9 '07'
main: TOKEN/10 '62747'
main: TOKEN/11 '2'
main: TOKEN/12 'Asia/Dubai'
main: TOKEN/13 '2019-10-24'
City: les Escaldes, population 15853, Country Code AD
City: Andorra la Vella, population 20430, Country Code AD
City: Umm Al Quwain City, population 62747, Country Code AE

Here is the final program output (without the -DDEBUG):

City: les Escaldes, population 15853, Country Code AD
City: Andorra la Vella, population 20430, Country Code AD
City: Umm Al Quwain City, population 62747, Country Code AE
Craig Estey
  • 30,627
  • 4
  • 24
  • 48
  • The program that "worked" doesn't use an array of `City` either, so you and the OP must mean different things when using the word "work". If you want to parse a line, fill a struct, then forget about it, then not using an array is perfectly fine. Of course this is useless, but then filling an array and then doing nothing with it is equally useless. – n. m. could be an AI Sep 25 '22 at 18:14
  • @n.1.8e9-where's-my-sharem. I think you're being a little nitpicky. IMO, OP's [obvious] intent was to store the data in an array. Otherwise, why use a struct at all? I had fixed the store of the data. But, because OP didn't add a separate print loop, I left that off. But, to keep the peace, I've added one. – Craig Estey Sep 25 '22 at 18:26
  • i tried the code of craig estey but after execution it gives segmentation fault – mr ma Sep 25 '22 at 18:37
  • "store the data in an array. Otherwise, why use a struct at all?" Why use an array if you just store data there and never retrieve? Same deal. "OP didn't add a separate print loop" Well if OP added one, *then* it would be a different deal, and a different question. – n. m. could be an AI Sep 25 '22 at 18:39
  • @mrma You didn't provide any sample data (in a separate code block), so the actual parsing I used with `strtok` and `atol` was just representative – Craig Estey Sep 25 '22 at 18:39
  • @mrma You didn't show you input. We can only guess what's in there. The program should work with the input guessed by Craig, but what is in *your* input? Please read about making a [mcve]. – n. m. could be an AI Sep 25 '22 at 18:41
  • @CraigEstey i should read data from a file in http://download.geonames.org/export/dump/ the name is cities15000.zip – mr ma Sep 25 '22 at 18:42
  • @mrma You should post the sample file direcctly in the question as a text and not as a link (not your entire file, and not zipped, just a few lines will do). – n. m. could be an AI Sep 25 '22 at 18:50
  • 3040051 les Escaldes les Escaldes Ehskal'des-Ehndzhordani,Escaldes,Escaldes-Engordany,Les Escaldes,esukarudesu=engorudani jiao qu,lai sai si ka er de-en ge er da,Эскальдес-Энджордани,エスカルデス=エンゴルダニ教区,萊塞斯卡爾德-恩戈爾達,萊塞斯卡爾德-恩戈爾達 42.50729 1.53414 P PPLA AD 08 15853 1033 Europe/Andorra 2008-10-15 this is aline i need les Escaldes in city.name and AD in city.country.code and 15853 in city.population and city.country.name is from another file – mr ma Sep 25 '22 at 18:53
  • @mrma There are many more fields in files in that URL. Please _edit_ your question and post a small _sample_ set (e.g. five lines or so). But, AFAICT, there are many more data fields in the file for each record than you have struct fields. And, there appear to be more/different field separators than just `\t` (e.g. `,`). – Craig Estey Sep 25 '22 at 18:54
  • 1
    @mrma What part of "_**edit**_ your _question_" is unclear? Don't put data in comments here. – Craig Estey Sep 25 '22 at 18:56
  • @CraigEstey yes i posted that's what i need from the file – mr ma Sep 25 '22 at 18:56
  • @mrma I've updated my answer based on your _real_ data from your updated question. – Craig Estey Sep 25 '22 at 22:32