cfiletextmallocargv

Count number of integers in text file in C


I made text file called qsort.txt and wrote arbitrary many integers in file (In my case 35 integers to be precise). My goal is to count how many integers are in that file, put them into an array defined by malloc() and sort them using qsort(). After that I want sorted numbers writen into a text file called sorted.txt.

This is my code, but obviously doesn't work as expected. Also I want to be more flexible with code so in FILE *fa = fopen(argv[1], "r+") is argv[1] so I can put any other text file to be sorted. Anyway my problem is that I don't know how to count how many integers are in file.

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

int compare(const void *a, const void *b) {
    if (*(int*)a < *(int*)b)
        return -1;
    else if (*(int*)a > *(int*)b)
        return 1;
    else
        return 0;
}

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

    FILE *fa = fopen(argv[1], "r+");
    if (!fa)
        exit(1);
    FILE *fb = fopen("sortirano.txt", "w+");

    long duljina, i;
    long *ptr, *zapis;
    long count = 0;

     while (!feof(fa))
         count++;

     printf("%lu\n", count);

     fseek(fa, 0, SEEK_END);
     duljina = ftell(fa);
     fseek(fa, 0, SEEK_SET);

     ptr = (long *)malloc(sizeof(long));

     while (!feof(fa)) {
         fscanf(fa, "%lu", ptr);
         count++;
     }
     printf("count: %lu\n", count);
     for (i = 0; i < count; i++)
         printf("%lu ", ptr[i]);

    printf("\n");

    free(ptr);

    fclose(fa);
    fclose(fb);

    return 0;
}

EDIT:

This is my new code, which is simpler:

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

int compare(const void *a, const void *b) {
    if (*(long*)a > *(long*)b)
        return 1;
    if (*(long*)a < *(long*)b)
        return -1;
    else
        return 0;
}

int main() {
    FILE *fa = fopen("qsort.txt", "r"); assert(fa != NULL);
    FILE *fb = fopen("sorted.txt", "w+"); assert(fa != NULL);

    long *ptr;
    long save;
    long count = 0;
    long i;
    long k;

    while ((fscanf(fa, "%ld", &save)) == 1) //number of elements
        prebroji++;

    printf("count: %ld\n", count); //checking how many elements i have, just to make sure it works ok

    ptr = (long *)malloc(count * sizeof(long)); //mallociranje

    for (i = 0; i < count; i++)
        fscanf(fa, "%ld", &ptr[i]);

    for (i = 0; i < count; i++) //checking if numbers were saved at malloc array
        printf("%ld ", ptr[i]);

    qsort(ptr, count, sizeof(long), compare);

    for (i = 0; i < count; i++) //checking if sorted correctly
        printf("%ld ", ptr[i]);

    for (i = 0; i < count; i++)
        fprintf(fb, "%ld", ptr[i]);

    printf("\n");

    free(ptr);
    fclose(fa);
    fclose(fb);

    return 0;
}

But it doesn't work: all I got are zeros printed.


Solution

  • Since the file only contains integers and whitespace, you can parse it with fscanf("%ld", ...) and store the numbers into an array you reallocate on purpose as you read more numbers.

    Note these remarks:

    Here is a modified version:

    #include <errno.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int compare(const void *aa, const void *bb) {
        const long int *a = aa;
        const long int *b = bb;
        return (*a > *b) - (*a < *b);
    }
    
    int main(int argc, char **argv) {
        if (argc < 2) {
            fprintf(stderr, "missing argument\n");
            return 1;
        }
        FILE *fa = fopen(argv[1], "r");
        if (!fa) {
            fprintf(stderr, "cannot open %s: %s\n", argv[1], strerror(errno));
            return 1;
        }
    
        long *ptr = NULL;
        size_t alloc = 0, count = 0;
        long value;
    
        while (fscanf(fa, "%ld", &value) == 1) {
            if (count == alloc) {
                size_t new_alloc = alloc + alloc / 2 + 32;
                long *new_ptr = realloc(ptr, sizeof(*ptr) * new_alloc);
                if (!new_ptr) {
                    fprintf(stderr, "out of memory for %zu entries\n", new_alloc);
                    free(ptr);
                    fclose(fa);
                    return 1;
                }
                ptr = new_ptr;
                alloc = new_alloc;
            }
            ptr[count++] = value;
        }
        fclose(fa);
    
        printf("count: %zu\n", count);
    
        qsort(ptr, count, sizeof(*ptr), compare);
    
        const char *outfile = "sorted.txt";
        FILE *fb = fopen(outfile, "w");
        if (!fb) {
            fprintf(stderr, "cannot open %s: %s\n", outfile, strerror(errno));
            free(ptr);
            return 1;
        }
    
        for (size_t i = 0; i < count; i++) {
            fprintf(fb, "%ld\n", ptr[i]);
        }
    
        fclose(fb);
        free(ptr);
    
        return 0;
    }
    

    EDIT:

    You new code has multiple problems: