2

I fail parsing a CSV file in C. I need to file a struct with data from that file. This is the relevant part of my structure:

typedef struct Info {
    /* Some strings, integers, etc. */
    char correct; /* This is the value I can't set */
    short int status;
} t_info;

One line from my file looks like this xxxxxx;xxxxxxx;xxxxxxx;D;254 (the D is my problem, see below).

    char line[1024]; /* Buffer */
    t_info info;

    fgets(line, sizeof(line), fp);

    strcpy(info.xxxxxx, getLine(line, 1)); /* Works */
    strcpy(info.xxxxxx, getLine(line, 2)); /* Works */
    strcpy(info.xxxxxx, getLine(line, 3)); /* Works */
    strcpy(info.correct, getLine(line, 4)); /* Crashs! */

The getLine() function is taken from this post:

const char *getLine(char *line, int num)
{
    const char *tok, *tmp = strdup(line);

    for (tok = strtok(tmp, ";"); tok && *tok; tok = strtok(NULL, ";\n"))
    {
        if (!--num)
            return tok;
    }

    return NULL;
}

What is my problem?

Community
  • 1
  • 1
LuMa
  • 1,673
  • 3
  • 19
  • 41
  • Haven't studied this in-depthly - what if you replaced D with DD. Does it work? Maybe it fails for one char; some edge case. – pushkin Dec 20 '15 at 22:35
  • No, doesn't change anything. – LuMa Dec 20 '15 at 23:15
  • 1
    Your solution is very sloppy: the memory allocated by `strdup()` cannot be freed because there is no way to figure the address of the start of the allocated block from the pointer returned by `getLine()`. Furthermore, you do not test for `getLine()` failure, or even `fgets()` failure at end of file: a line with missing fields will cause undefined behavior. As a matter of fact, a line with long fields will also cause undefined behavior. More work needed! – chqrlie Dec 20 '15 at 23:53
  • Thanks for the input :) Will look into that. – LuMa Dec 21 '15 at 00:45

2 Answers2

5

Can not save into a char using strcpy().

typedef struct Info {
    char correct; /* This is the value I can't set */
} t_info;

strcpy(info.correct, getLine(line, 4)); /* Crashs! */

Use

info.correct = *getLine(line, 4);

Your compiler should have warned about this. Review compiler settings.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Interesting, no warnings and neither does your solution work. When debugging, the return value is in fact 'D', but somehow the strcpy-operation fails. – LuMa Dec 20 '15 at 23:21
  • @LuMa The return value from `const char *getLine(char *line, int num)` cannot be `'D'`. `'D'` is integer/char. `getLine()` returns a pointer. Anyways it is not about what `getLine()` returns. It is about the destination for `strcpy()`. `info.correct` has room for only a `char`. `strcpy()` expects a pointer to an array in which to store many `char`. – chux - Reinstate Monica Dec 20 '15 at 23:26
  • 2
    @LuMa Unclear is "neither does your solution work." and "somehow the strcpy-operation fails" as the answer should use `info.correct = *getLine(line, 4);` **instead** of `strcpy(info.correct, getLine(line, 4));` – chux - Reinstate Monica Dec 20 '15 at 23:29
  • Yes, sorry. You are right. What I wanted to say is, the function doesn't return NULL, it is in fact returning a "valid" value/pointer. – LuMa Dec 20 '15 at 23:29
  • THANKS! You saved my day. I was just to tired to read your answer correctly :) Thanks again! – LuMa Dec 20 '15 at 23:32
  • I just added a * to my existing code which wasn't your suggestion. My bad. – LuMa Dec 20 '15 at 23:32
2

The simplest way to fix this would be to get the first character of the line, and use that for the char.

info.correct = getLine(line, 4)[0];

Perhaps sscanf might be more suitable for your application (guide here) or (similar answer).

Community
  • 1
  • 1
Joseph Young
  • 2,758
  • 12
  • 23
  • Hi, it doesn't work :/ But I will take a look into sscanf. I tried fscanf but failed because I read a string which contained spaces, which made my fscanf attempt fail. – LuMa Dec 20 '15 at 23:18
  • No. The return value from the function is in fact 'D', but somehow the strcpy-function fails. – LuMa Dec 20 '15 at 23:23