Thread: Help with my project (I'm a newbie...)

  1. #1
    Registered User
    Join Date
    Feb 2018
    Posts
    9

    Help with my project (I'm a newbie...)

    Hello! I'm doing a project in C for college, where I have to use .csv files. It's almost finished, but I need some help. I created a account on Stack Overflow, but some of the other users treated me in a bad way, maybe because I'm somewhat a newbie at programming. So, I decided to join this forum, for me to get some help. Sorry if you don't understand something, because english isn't my first language.

    One of the things I have to do is search for meteorological information from a .csv file, named "meteo.csv". In the function
    Code:
    search_date_by_city
    , which code is down below, I ask the user to search for a city, then I confirm if that city exists in other file ("cities.csv"), and then I ask for a date, in the format YYYY-MM-DD. That function calls another one,
    Code:
    search_meteo_by_city_by_date
    , that confirms if the date really exists on the file "meteo.csv", as well if the city's id exists in that file. (Every city has an specific id). However, the 'if' inside the cycle 'for' has an error. I know I can't compare a string with an integer, I know that is possible to convert in one another,but I don't know if I can use that in this case. 'id' is an integer, and 'meteo_city_id' is a string. Sincerely, I don't know what to do.
    At the same time, in that same 'for', there is 'i < 152', that is the number of rows each file has. However, it's possible for the user to add rows in the file. If it adds some rows, that code doesn't work anymore. How can I replace this number with a variable that defines the end of the file, regardless of the number of lines added later?

    Sorry if the task is a bit confuse. All help is welcome. Thanks.

    Here is the code:

    Code:
    typedef struct city_t{    char city_id[TAM_STR];
        char city_name[TAM_STR];
        char county_name[TAM_STR];
        char district_name[TAM_STR];
    } city_t;
    
    
    typedef struct meteo_t{
        char meteo_id[TAM_STR];
        char meteo_city_id[TAM_STR];
        char tempt_max[TAM_STR];
        char tempt_min[TAM_STR];
        char humidity[TAM_STR];
        char preassure[TAM_STR];
        char date[11];
    } meteo_t;
    
    void search_meteo_by_city_by_date(meteo_t *meteo, size_t len, const char *city, const int id, const char *date)
    {       
        bool find = false;
       
        if(meteo == NULL || city == NULL || id == NULL || date == NULL) {
            printf("ERROR");
        }
    
    
        for(size_t i = 0; i < 152; ++i) {
            if (strcasecmp(date, meteo[i].date) == 0 && id == meteo[i].meteo_city_id) {
                find = true;
                printf("Informations for: %s in %s \nMaximum temperature: %s ºC\nMinimum temperature: %s ºC\nHumidity: %s \nPressure: %s hPa\n\n\n", city, date, meteo[i].tempt_max, meteo[i].tempt_min, meteo[i].humidity, meteo[i].preassure);
            }
        }
        if(find == false) {
            printf("No data for: %s\n", city);
        }
    }
    
    void search_date_by_city() {
    
    
        size_t cities_len;
        city_t *cities = read_cities("cidades.csv", &cities_len);
        char local[100];
        char date[100];
        
        // error
        if(cities == NULL) {
            printf("ERROR");
        }
        
        printf("City: ");    
        scanf("%[^\n]%*c", local);  
        
        int id = search_for_city_by_name(cities, &cities_len, cidade);
    
    
        if(id == -1) {
            printf("That city doesn't exist\n");    
            return;
        }
    
    
        printf("Date: ");    
        scanf("%[^\n]%*c", date);  
    
    
        size_t meteo_len;
        meteo_t *meteo = read_meteo("meteo.csv", &meteo_len);
        
        if(meteo == NULL) {
            printf("ERROR");
        }
    
    
        search_meteo_by_city_by_date(meteo, &meteo_len, cidade, id, date);
    }

  2. #2
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    I'm assuming that the read_cities and read_meteo functions were given to you? If not, then you should probably read in integers and floats as integers and floats instead of strings in the first place.

    If you can't change that, then you need to convert the string into an integer before comparing to an actual integer. The atoi function (prototyped in stdlib.h) is probably simplest (there is also strtol and sscanf).
    Code:
    int meteo_city_id = atoi(meteo[i].meteo_city_id);
    if (strcasecmp(date, meteo[i].date) == 0 && id == meteo_city_id)
    As for a variable number of rows in the file, you are passing "len" into search_meteo_by_city_by_date, so presumably that is the number of rows.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  3. #3
    Registered User
    Join Date
    Feb 2018
    Posts
    9
    Thanks for the help!!
    I have those two fuctions, in fact. If it's necessary, I edit my first post and add them.
    I will try to do the way you advised me.

    EDIT:
    It worked! Thanks!

    (Do you have any idea about how can I do to replace the 152?)
    Last edited by Jessijow; 02-17-2018 at 01:21 PM.

  4. #4
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    I know I can't compare a string with an integer, I know that is possible to convert in one another,but I don't know if I can use that in this case. 'id' is an integer, and 'meteo_city_id' is a string. Sincerely, I don't know what to do.
    Well, there is no real way around just doing one of the options really. You could make your own comparison function which hides the need to convert one thing into the other if you wanted.

    Code:
    int equalsid(int id, const char *sid) 
    {
       char *tail = NULL;
       int rhs = strtol(sid, &tail, 0);
       if (tail != sid && (*tail == ',' || *tail == '\0' || *tail == '\n'))
          return id == rhs;
       else
          return 0;
    }
    At the same time, in that same 'for', there is 'i < 152', that is the number of rows each file has. However, it's possible for the user to add rows in the file. If it adds some rows, that code doesn't work anymore. How can I replace this number with a variable that defines the end of the file, regardless of the number of lines added later?
    There is a parameter called len in that function, maybe use that.

  5. #5
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    Quote Originally Posted by Jessijow View Post
    Do you have any idea about how can I do to replace the 152?
    I said in my last post that the variable "len" probably contains the number of rows. So just replace 152 with len.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  6. #6
    Registered User
    Join Date
    Feb 2018
    Posts
    9
    Thanks for everyone's help!
    Sorry, I didn't see that part! But it doesn't work, the program compiles but after displaying the information, the run fails.

  7. #7
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    Code:
        size_t meteo_len;
        meteo_t *meteo = read_meteo("meteo.csv", &meteo_len);
    can you post this function then? It probably has a bug, and meteo_len is what you pass into the search by city by date function.

  8. #8
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    Like whiteflags said, it could be that read_meteo has a bug. I was assuming that read_meteo was given to you. Did you write it yourself? Post it in either case.

    I also noticed that in search_date_by_city (at least the version you posted), you read the city name into "local" but then pass a non-existent variable called "cidade" to the search function.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  9. #9
    Registered User
    Join Date
    Feb 2018
    Posts
    9
    Code:
    city_t *read_meteo(const char *filename, size_t *len) //le a informacao meteorologica do ficheiro{
        if(filename == NULL || len == NULL)
            return NULL;
    
    
        FILE *fp = fopen(filename, "r");
        if(fp == NULL)
        {
            fprintf(stderr, "Could not open %s: %s\n", "meteorologia.csv", strerror(errno));
            return NULL;
        }
        meteo_t *arr = NULL, *tmp;
        *len = 0;
        // assuming that no line will be longer than 1023 chars long
        char line[1024];
    
    
        while(fgets(line, sizeof line, fp))
        {
            tmp = realloc(arr, (*len + 1) * sizeof *arr);
            if(tmp == NULL)
            {
                fprintf(stderr, "could not parse the whole file %s\n", "meteorologia.csv");
                // returning all parsed cities so far
                if(*len == 0)
                {
                    free(arr);
                    arr = NULL;
                }
                return arr;
            }
            arr = tmp;
            sscanf(line, "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%s", (arr[*len].meteo_id), (arr[*len].meteo_city_id), (arr[*len].tempt_max), (arr[*len].tempt_min), (arr[*len].humidity), (arr[*len].preassure), (arr[*len].date));
            (*len)++;
        }
        fclose(fp);
        // file is empty or all lines have wrong format
        if(*len == 0)
        {
            free(arr);
            arr = NULL;
        }
        return arr;
    }
    Sorry... When I was translating the code into English, I forgot that part... Consider "cidades" as local, please...

  10. #10
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    The return type is wrong (should be meteo_t). Probably another translation error!

    Does the input file have a header line? If so, you need to skip it with an initial fgets call before the loop.

    If the cities file also has a header line, then you need to do the same thing in that function.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  11. #11
    Registered User
    Join Date
    Feb 2018
    Posts
    9
    Yeah... "meteorologia.csv" should be "meteo.csv". I think everything other than this is translated, except the first comment, but that's not important...
    Sorry, I'm not understanding what you're trying to say...

    By the way, someone knows how to remove rows in a .csv file? I was searching in the internet, but the only thing that appeared was code in C#... Thanks for the help, everyone!
    Last edited by Jessijow; 02-17-2018 at 04:09 PM.

  12. #12
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    Quote Originally Posted by Jessijow View Post
    Yeah... "meteorologia.csv" should be "meteo.csv".
    I was talking about the return type of the function. The function you posted has a return type of city_t, but it should be meteo_t.

    Quote Originally Posted by Jessijow View Post
    Sorry, I'm not understanding what you're trying to say...
    Run this program and post what it prints.
    (You may need to change the file name.)
    Code:
    #include <stdio.h>
    #include <string.h>
    
    int main() {
        int size = 0;
        char line[1024];
    
        FILE *f = fopen("meteo.csv", "r");
        if (!f) {perror("fopen"); return 1;}
    
        // print first line
        fgets(line, sizeof line, f);
        printf("%s", line);
        if (!strchr(line, '\n')) printf("long line: %d\n", size);
        size++;
    
        // count remaining lines
        while (fgets(line, sizeof line, f) != NULL) {
            if (!strchr(line, '\n')) printf("long line: %d\n", size);
            size++;
        }
    
        fclose(f);
        printf("size: %d\n", size);
    
        return 0;
    }
    Quote Originally Posted by Jessijow View Post
    By the way, someone knows how to remove rows in a .csv file?
    Just read from one file and write the lines you want to keep to a new file.
    Why do you want to do that?
    Last edited by john.c; 02-17-2018 at 04:31 PM.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  13. #13
    Registered User
    Join Date
    Feb 2018
    Posts
    9
    That is what appeared in the output:

    Código Meteorológico,Código da Cidade,Temperatura máxima,Temperatura mínima,Humidade,Pressão,Data
    size: 1


    RUN SUCCESSFUL (total time: 252ms)

    Translated: Weater code,City code,Maximum temperature,Minimum temperature,Humidity,Pressure,Date
    size: 1


    That part of cities_t as an error. I changed it to meteo_c, and replaced 152 by len, but happens the same thing from before.


    This is a project from my college. One of the functions I have to put in is the removal of information or rows from the file.

  14. #14
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    The program I posted had an error. I fixed it above. Could you copy it again and run it again? It should tell you how many lines there are and whether there are any extra-long lines.

    Anyway, with what you've posted we can see that the first line is a "header" line, which lists the column names.
    You need to skip that line when you're reading the data.
    Code:
        char line[1024];
        fgets(line, sizeof line, fp);    // skip header line
        while(fgets(line, sizeof line, fp)) {
    You should probably do the same when reading the city file.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  15. #15
    Registered User
    Join Date
    Feb 2018
    Posts
    9
    Thanks for all the help!! I already solved the problem in the 'for'. It was a & that shouldn't be there...
    If I have more difficulties in this work, I'll ask again in this thread, and I'll edit this reply.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 4
    Last Post: 08-02-2013, 06:45 PM
  2. Replies: 4
    Last Post: 03-10-2013, 05:40 PM
  3. Need help with a newbie project!
    By Eep in forum C++ Programming
    Replies: 18
    Last Post: 06-30-2012, 12:12 PM
  4. Project Euler Solved but want help improving the code Newbie
    By whiterebbit in forum C++ Programming
    Replies: 4
    Last Post: 12-09-2008, 07:00 AM
  5. newbie q: include files outside the project dir?
    By BrianK in forum Windows Programming
    Replies: 3
    Last Post: 06-29-2004, 03:45 PM

Tags for this Thread