Search code examples
cprintffopenfgets

CSV(ish) text handling - incorrect output on Windows, works on Linux


I am learning C and I don't understand why this code doesn't work.

It's supposed to skip the first character, separate it in 8,4,4,4,4. But it adds one extra "0" to beginning of the second column and shifts the rest.

Also when I try to run it on Windows I can't see any results. Sometimes it can't open the file, sometimes the output is wrong.

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

const int MAX_LINES = 10000000;

char s[1000];
int lines;
FILE *fptrIn, *fptrOut;

void convertData(char *s) {
    s[28] = 0;

    char gp1[8 + 1] = {0};
    char gp2[4 + 1] = {0};
    char gp3[4 + 1] = {0};
    char gp4[4 + 1] = {0};
    char gp5[4 + 1] = {0};
    char gp6[4 + 1] = {0};

    strncpy(gp1, s + 1, 8);
    strncpy(gp2, s + 8, 4);
    strncpy(gp3, s + 12, 4);
    strncpy(gp4, s + 16, 4);
    strncpy(gp5, s + 20, 4);
    strncpy(gp6, s + 24, 4);

    fprintf(fptrOut, "%s;%s;%s;%s;%s;%s\n", gp1, gp2, gp3, gp4, gp5, gp6);
}

int main() {

    if ((fptrIn = fopen("test.txt", "r")) == NULL) {
        printf("Error opening file!");
        return 1;
    }

    fptrOut = fopen("testout1.txt", "w");

    fprintf(fptrOut, "Position;Sens1;Sens2;Sens3;Check;Time\n");

    while(fgets(s, sizeof s, fptrIn) != NULL) {
        lines++;
        if (strlen(s) < 28)
            continue;
        printf("Line %d#:\n", lines);
        printf("%s\n", s);
        convertData(s);
        if (lines == MAX_LINES) {
            break;
        }
    }

    fclose(fptrIn);
    fclose(fptrOut);

    return 0;
}

Input data:

U66ACA1000D8007670000035CBE5Cd;
U66C668000D0A07DA0000037CBF60;
U66DF84000C9908480000038CC05A(;
U66F8A0000C2A08B6000003A9C154Ä;
U67114A800BBB0923000003C9C24E„;
U6729F5000B490991000003D9C348];

The output using Linux:

Position; Sens1; Sens2; Sens3; Check; Time;
66ACA100; 00D8; 0076; 7000; 0035; CBE5;
66C66800;00D0;A07D;A000;0037;CBF6;
66DF8400;00C9;9084;8000;0038;CC05;
66F8A000;00C2;A08B;6000;003A;9C15;
67114A80;00BB;B092;3000;003C;9C24;
6729F500;00B4;9099;1000;003D;9C34;

And here is the whole output on Windows (although WSL is running):

Position;Sens1;Sens2;Sens3;Check;Time;

66ACA100;0D80;0767;0000;035C;BE5
00F3B054;8000;0039;9DDE;2‘
U;69F
27000003;A6FD;687
;U6D1;D3B8;000
3731CEEÕ;
U70;4A17;0002;3901;7A0

U73764;8000;3F20;F570;0000;340

Solution

  • There isn't any need to transfer the different fields out of s[ ]...

    printf() will do what you want...

    printf( "%8.8s,%4.4s,%4.4s,%4.4s,%4.4s,%4.4s\n",
        s + 1,
        s + 1+8,
        s + 1+8+4,
        s + 1+8+4+4,
        s + 1+8+4+4+4,
        s + 1+8+4+4+4+4
        );
    

    The compiler will 'do the math', collapsing those sums into single values in the object file. Having all the numbers laid out this way in the source code makes clear the different offsets.

    One other thing... If the first character of each line is 'skipped' then you want characters in positions 1 to 28... s[28] = 0 is both wrong and unnecessary.