Alistair Alva
Alistair Alva

Reputation: 29

How should I fill an array of ints from a file using command line args? The size of the file and the no. of elements may vary

I am really new to programming in C. I have an assignment where I have to fill an array of integers from a text file using command line arguments. The array should be able to take in all the numbers from the file. This is the segment of code that is supposed to do the above, but it fails. I still have to add error checking but I just need to know where I am going wrong, and if I am on the right path.

From what I know so far, I will have to use memory allocation to make my array dynamic. I have used ftell() to find the size of the file in bytes so I can allocate memory accordingly.

#include <stdio.h>
#include <math.h>
#include <stdbool.h>
#include <fstream>
#include <stdlib.h>

int main(int argc, char *argv[]) {

    if (argc > 2) {
        printf(stderr, "Error, too many arguments supplied.");
        exit(1);
    }

    if (argc == 2) {
        int *numArray = NULL; //pointer to integer

        FILE* inputFile = fopen(argv[1], "r");

        fseek(inputFile, 0, SEEK_END);

        // calculating the size of the file 
        int fileSize = ftell(inputFile);

        numArray = malloc(fileSize * sizeof(int));

        if (numArray == NULL) {
            printf(stderr, "Error: File is empty.");
            exit(1);
        }

        int num;
        int arraySize = sizeof(numArray) / sizeof(numArray[0]);

        for (int i = 0; i < arraySize; i++) {
            fscanf(inputFile, "%d", &num);
            numArray[i] = num;
        }

        fclose(inputFile);
    }

}

If file contains: 67, 66, 353, 789, 2342, NumArray = {67, 66, 353, 789, 2342}

Upvotes: 2

Views: 65

Answers (1)

chqrlie
chqrlie

Reputation: 144780

There are multiple problems in the code:

  • <fstream> is a C++ header, do not mix C and C++.
  • printf(stderr, "Error, too many arguments supplied."); should produce a warning about the type mismatch on its first argument. use fprintf to print to stderr.
  • The file is open in text mode, not binary mode, so ftell() might not return the number of bytes in the file.
  • file open failure is not tested.
  • Allocating fileSize * sizeof(int) is overkill. The numbers are in text format, so at most fileSize / 2 numbers can by found in the file, and likely much less than that.
  • failure to allocate bytes does not mean the file is empty.
  • You should reallocate the array as you read more numbers from the file. This allows also for reading from devices that are not seekable such as terminals and named pipes.
  • arraySize = sizeof(numArray) / sizeof(numArray[0]) does not compute the number of elements in the array because numArray is a pointer to an array, not an array. Furthermore you should just keep the number of actual numbers read, which is the final value of i in the for loop.
  • you should test the return value of fscanf(): 1 means the conversion succeeded, 0 means invalid input is present, that cannot be converted to an integer, EOF means end of file, or possibly I/O error.

Here is a modified version:

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

int main(int argc, char *argv[]) {

    if (argc != 2) {
        fprintf(stderr, "The program expects a single command line argument\n");
        return 1;
    } else {
        int *numArray = NULL;
        size_t arraySize = 0;
        size_t arrayCount = 0;
        FILE *inputFile = fopen(argv[1], "r");
        int res, num;

        if (inputFile == NULL) {
            fprintf(stderr, "Cannot open file %s: %s\n", strerror(errno));
            return 1;
        }
        while ((res = fscanf(inputFile, "%d", &num)) == 1) {
            if (arrayCount >= ArraySize) {
                size_t newSize = arraySize ? arraySize * 2 : 32;
                int *newArray = realloc(numArray, newSize * sizeof(int));
                if (newArray == NULL) {
                    fprintf(stderr, "Out of memory for %zu elements\n", newSize);
                    exit(1);
                }
                numArray = newArray;
                arraySize = newSize;
            }
            numArray[arrayCount++] = num;
        }
        if (res != EOF) {
            fprintf(stderr, "Invalid input for element %zu\n", arrayCount);
        }
        if (arrayCount == 0) {
            if (res == EOF) {
                fprintf(stderr, "File %s is empty\n", argv[1]);
            }
            fclose(inputFile);
            return 1;
        }
        ...  // do something with the arrayCount elements in numArray
        free(numArray);
        fclose(inputFile);
    }
    return 0;
}

Upvotes: 2

Related Questions