1

I want to read some numbers from a file with the goal of getting them into a "multidimensional" int array called point. I want to put each line of the file in a first dimensional element and every substring I get delivered by strtok in a "sub-element" of the dimension where the matching line is put.

I do so by running two encapsulated for loops, the first one to get every line from the file chronologically and the second to split the lines with the help of strtok and store it in a char* array to later convert it to int with strtol.

Works fine with every delimited string but the very first one. The first substring in the first line of the file always gets saved as a 0, no matter what number there actually is at that position in the file. Any ideas what could cause this problem? I have been looking for hours but can't fix it.

Through fault exclusion I've come to the conclusion that there's most likely something wrong with the first call of strtok(). But it seems fine to me.

void pointvalue() {
    char **substr = malloc(3 * sizeof(char*));
    int point[5][3];
    char buffer[20];
    char*endpos;

    FILE *pf = fopen("PATH", "r");

    if (pf != NULL) {
        for(int i = 0; fgets(buffer, 20, pf); i++) {

            for(int k = 0; k < 3; k++) {
                if (k == 0) substr[k] = strtok(buffer, ";");
                else {
                    substr[k] = strtok(NULL, ";");

                }
                point[i][k] = strtol(substr[k], &endpos, 0);

                printf("%d ",point[i][k]);
            }
        }
    } else {
        perror("Couldn`t load file");
    }
}     

In the file two lines of numbers with a delimiter ";" are written. Example:

3;4;5;
6;9;2;

The function I've written prints:

0 4 5 6 9 2

EDIT: Here is what is printed out when i use:

printf("[%s] %d\n",substr[k],point[i][k]);

    [´╗┐3] 0[4] 4[5] 5[6] 6[9] 9[2] 2
Sören
  • 45
  • 4
  • `char **substr=malloc(3*sizeof(int))` is wrong, if you want to allocate an array of 3 pointers to `int`. It's even more wrong if you want to create an array of pointers to `char`. And if neither of those are what you want, then you're seem to be way off. – Some programmer dude Jul 18 '19 at 16:26
  • Oh yes, you are completely right, sorry actually did fail to spot this. I have edided it in my code now to what I actually wanted to do here. However it does not solve the problem. – Sören Jul 18 '19 at 16:31
  • `strtok` is allowed to modify its argument. – S.S. Anne Jul 18 '19 at 17:07
  • Possible duplicate of [Why is strtok changing its input like this?](https://stackoverflow.com/questions/9406475/why-is-strtok-changing-its-input-like-this) – S.S. Anne Jul 18 '19 at 17:08
  • 1
    Is there something wrong with your input file? I copy/pasted your function and it prints ```3 4 5 6 9 2``` – Dale Jul 18 '19 at 17:24
  • 2
    I think it's time for you to [learn how to debug your programs](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/). More specifically how to use a debugger to step through your code line by line while monitoring variables and their values. – Some programmer dude Jul 18 '19 at 18:52
  • 2
    If you're using Windows to create your test file, make sure that your text editor is not creating a file starting with a [UTF-8 BOM](https://en.m.wikipedia.org/wiki/Byte_order_mark) (Hex EF BB BF). A hex dump of the file will tell you. – rici Jul 18 '19 at 20:43

2 Answers2

1
int point[5][3];
...
for(int i = 0; fgets(buffer, 20, pf); i++) {
    ...
    point[i][k] = strtol(substr[k], &endpos, 0);
    ...
}

While this might not be the source of your issue, please note that it is very easy for your program to write to random locations in memory, leading to undefined behavior.

That will happen if the for will be executed for more than 5 times: i will point outside point.

virolino
  • 2,073
  • 5
  • 21
1

The very likely cause of your problem is the input file contains an initial byte sequence known as BOM (for byte order mark) supposed to indicate that the file contents is a UTF-8 encoded stream of bytes.

You should configure your text editor to avoid producing such an indicator or modify your program to ignore it.

Note that you should prevent buffer overflows by limiting the number of lines read from the file and you should close the file too.

Here is a simplified version of your function:

void pointvalue() {
    int point[5][3] = {{ 0 }};
    char buffer[128];
    FILE *pf = fopen("PATH", "r");

    if (pf != NULL) {
        /* skip an initial BOM in the text file */
        scanf(pf, "%*1[\xEF]%*1[\xBB]%*1[\xBF]");

        for (int i = 0; i < 5 && fgets(buffer, sizeof buf, pf); i++) {
            k = sscanf(pf, "%d;%d;%d", &point[i][0], &point[i][1], &point[i][2]);
            for (int j = 0; j < k; j++) {
                printf("%d ", point[i][k]);
            }
            printf("\n");
        }
        fclose(pf);
    } else {
        perror("Couldn't load the PATH file");
    }
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • Thanks for the answer, you were indeed right, the standard Windows text-editor did put such a BOM in my file, deleted the BOM with the help of Notepad++ and it works just fine now, thanks for the code snippet also. – Sören Jul 19 '19 at 07:49