gokhan_ozeloglu
gokhan_ozeloglu

Reputation: 133

Getting inputs from txt file and add in an array

I am newer in C language. I want to create an array for my code to make some operation. As I said above, I am trying to learn how to use C language efficiently. My problem is this: I have a input file, let's say input.txt. I know that every line have 4 different things, 2 of them are string and 2 of them number. Also, I want to create a 2D array. But I do not know how many lines will be in input file. It depends on the user. So, I have to use malloc to make my array dynamically. So, can you help me about this problem? Maybe this is so easy, but I think reading file and create some array in C more difficult than other languages. It was so easy in Python :( I am leaving my code below. If you tell me my mistakes, I will be happy :)

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

int main(int argc, char const *argv[]) {
    char *arrChar;
    int i;
    char *str;
    char *token;
    arrChar = (char *) malloc( sizeof( char ) );
    str = (char *) malloc( sizeof( char ) );
    FILE *FileChars;
    FileChars = fopen( argv[1], "r");
    i = 0;
    while ( fgets(str, sizeof str, FileChars) != NULL) {
        int j;
        for ( j = 0; j < 4; j++ ) {
                token = strtok(str, ",");
                arrChar[i][j] = token;
            }
        i++;
         }
}

Upvotes: 0

Views: 61

Answers (1)

Iharob Al Asimi
Iharob Al Asimi

Reputation: 53006

  1. You need to understand precisely what the sizeof operator does, it doesn't return the size of a dynamically allocated memory block, it returns the size of a type, in case of arrays — roughly speaking — the size is part of the type specification and so it returns the number of bytes the array occupies.

    In your case sizeof(char) is the size of the type char which is required to be exactl 1 by the ( C Standard).

    And sizeof(str) is the size of the type of str which is char *, that is, the size of a pointer. It's probably 4 or 8 depending on your current platform.

    To solve this, you have to define a length to be used throughout your program as the length of the allocated chunk of memory, that after you make sure that the allocation was successful (see below).

  2. A pointer to char can point to a sequence of elements that can be interpreted as a string if it is the correct sequence. A sequence of "printable" characters followed by a '\0' or null character is considered a string.

  3. You have to pass NULL to strtok() after the first time, if you are going to be processing the same string.

  4. You should CHECK that fopen() did return a valid stream, by comparing the return value to NULL.

  5. The same as (5), for malloc() when allocation is not possible NULL is returned and using it as a valid pointer is undefined behavior.

All that said, here is what you probably wanted to write

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

#define NUM_WORDS 100

int main(int argc, char const *argv[])
{
    char *token;
    char **words;
    char line[100];
    char *ptr;
    size_t count;
    FILE *file;

    file = fopen( argv[1], "r");
    // Check that we DID open the file
    if (file == NULL) {
        perror(argv[1]);
        return EXIT_FAILURE;
    }

    // Allocate space for `NUM_WORDS' pointers
    words = malloc(NUM_WORDS * sizeof(*words));
    // Check that we did allocate enough memory
    if (words == NULL) {
        fclose(file);
        return EXIT_FAILURE;
    }

    // We use `sizeof' here because `line' is an array
    count = 0;
    while ((count < NUM_WORDS) && (fgets(line, sizeof(line), file) != NULL)) {
        ptr = line;
        do {
            token = strtok(ptr, ",");
            // We need to copy the `token' because
            // it lies within `line' and the '\0' will
            // be replaced by the original character
            // in subsequent callse to `strtok()'
            //
            // The `strdup()' will allocate enough space with
            // `malloc()' then copy the contents of `token' to the
            // allocated buffer, and return it, so we will
            // have to call `free()' on every `words' element.
            words[count++] = strdup(token);
            // Subsequent calls to `strtok()' with the same
            // string require that the first parameter is
            // NULL
            ptr = NULL;
         } while ((count < NUM_WORDS) && (token != NULL));
    }
    // Now we may print the words and free the memory
    for (size_t index = 0; index < count; ++index) {
        puts(words[index]);
        free(words[index]);
    }
    free(words);
    return 0;
}

Note that the code above, makes sure that we don't exceed the capacity of the array of pointers words1. If you need to resize it, you will need to learn how to use realloc() and do it in a specialized routine so that your code doesn't become too complex.


1Note that the allocated space has no predefined interpretation, we do interpret it as an array but it's not an array in the sense of an array definition, which line IS, having elements of type char, line can also be interpreted as a string given it has contents compatible with the defintion given in the (2) second point above.

Upvotes: 1

Related Questions