'Getting strings from file gone wrong

The idea of this function is to get strings from file like this:

The file CLIENTS_BOOK: client1,client2,client3

and to get this in array of strings, eg:

  • CLIENTS_BOOK_ARRAY[i] to be equal to "client1"
  • CLIENTS_BOOK_ARRAY[i+1] to be equal to "client2"
  • CLIENTS_BOOK_ARRAY[i+2] to be equal to "client3"

Here is the code:

//global array
static char CLIENTS_BOOK_ARRAY[MAX_SIZE_OF_ARRAYS][MAX_SIZE_OF_ARRAYS];

void get_clients_string() {
    int i = 0;
    int n = 0;
    char *token;
    char help[256];
    FILE *InputFile;
    InputFile = fopen(CLIENTS_BOOK, "r");
    fscanf(InputFile, "%s", help);
    token = strtok(help, ",");
    while (token != NULL) {
        strncpy(CLIENTS_BOOK_ARRAY[i], token, MAX_SIZE_OF_ARRAYS);
        token = strtok(NULL, ",");
        i++;
    }
    n = i;

    fclose(InputFile);
}

When I run it, it is giving Segmentation fault(core dumped) When running it with gdb it is giving

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7f2ce38 in __strncpy_avx2_rtm () from /usr/lib/libc.so.6

The interesting part comes when it is running as intended on my pc (Arch linux, amd cpu), and it does not on my laptop (Arch linux, intel cpu).



Solution 1:[1]

There are multiple problems in your code:

  • you do not test the return value of fopen(). If the file cannot be open, InputFile will be a null pointer and fscanf() will have undefined behavior.

  • fscanf(InputFile, "%s", help); will write beyond the end of the help array if the word in the file has 256 bytes or more. Use this instead:

    fscanf(InputFile, "%255s", help);
    

    or possibly:

    fgets(help, sizeof help, InputFile);
    

    and test for failure to read the file contents.

  • strncpy is not your friend: strncpy(CLIENTS_BOOK_ARRAY[i], token, MAX_SIZE_OF_ARRAYS) will not null terminate the string if it happens to be longer than MAX_SIZE_OF_ARRAYS - 1 bytes. Do not use strncpy, use strncat, snprintf or strlcpy if available instead.

  • the loop does not stop at the end of the 2D array: you should check that i < MAX_SIZE_OF_ARRAYS in the while test.

Here is a modified version:

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

#define CLIENT_SIZE    100
#define CLIENT_NUMBER  100
#define CLIENTS_BOOK   "client_book.txt"

static char client_book[CLIENT_NUMBER][CLIENT_SIZE];

int get_clients_string(void) {
    int n = 0;
    char buf[256];
    FILE *InputFile = fopen(CLIENTS_BOOK, "r");
    if (InputFile == NULL) {
        fprintf(stderr, "error opening %s: %s\n",
                CLIENTS_BOOK, strerror(errno));
        return -1;
    }
    if (fgets(buf, sizeof buf, InputFile)) {
        char *token = strtok(help, ",\n");
        while (n < CLIENT_NUMBER && token != NULL) {
            client_book[n][0] = '\0';
            strncat(client_book[n], token, CLIENT_SIZE - 1);
            token = strtok(NULL, ",");
            n++;
        }
    } else {
        fprintf(stderr, "%s: no clients\n", CLIENTS_BOOK);
    }
    fclose(InputFile);
    return n;
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1