-3
\$\begingroup\$

I am getting a segmentation fault on the below snippet, only when I go above a text file in the range of 80-100kb. It will read smaller files of text but otherwise segmentation 11.

int main(int argc, char* argv[])
{
    FILE* file;
    if (argc != 2 || (file = fopen(argv[1], "r")) == NULL) {
        printf("Invalid command\n");
        exit(EXIT_FAILURE);
    }

    int capacity = 5;
    char* buffer = malloc(capacity);
    int length = 0;

    char ch;
    while ((ch = getc(file)) != EOF) {
        if (length >= capacity)
            capacity *= 2;
        buffer = realloc(buffer, capacity);
        buffer[length++] = ch;
    }
    buffer[capacity] = '\0';

    printf("%d\n", length);
    printf("%s", buffer);
    free(buffer);
    fclose(file);
    return EXIT_SUCCESS;
}

What type of problems could I be overlooking and how can I improve this code to more efficiently achieve what I am trying to get out of it (which is to read an unknown size of text from a file and output it as a string, also dynamically allocating memory by doubling array size)?

\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

Besides not checking the return code as @CiaPan described, there's another problem, char ch; is incorrect as EOF is not representable by char, it's being converted from 0xffffffff to 0xff and might cause an early exit if the file happens to contain the byte 0xff.

Here's the fixed code:

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

int main(int argc, char* argv[])
{
    FILE* file;
    if (argc != 2 || (file = fopen(argv[1], "r")) == NULL) {
        printf("Invalid command\n");
        exit(EXIT_FAILURE);
    }

    int capacity = 5;
    char* buffer = malloc(capacity);
    if (!buffer) {
        perror("malloc()");
        exit(EXIT_FAILURE);
    }

    int length = 0;
    int ch;
    while ((ch = getc(file)) != EOF) {
        if (length >= capacity)
            capacity *= 2;

        buffer = realloc(buffer, capacity);
        if (!buffer) {
          perror("realloc()");
          exit(EXIT_FAILURE);
        }        

        buffer[length++] = ch;
    }
    buffer[capacity] = '\0';

    printf("%d\n", length);
    printf("%s", buffer);
    free(buffer);
    fclose(file);
    return EXIT_SUCCESS;
}
\$\endgroup\$
1
\$\begingroup\$

As fas as I can see you never test whether malloc and realloc return valid pointers.

IMHO, most probably you just get NULL from allocation routines; then using it causes UB, in this case resulting in memory access fault.

\$\endgroup\$
3
  • \$\begingroup\$ Okay, now this I am unfamiliar with, what do you mean by "test"? \$\endgroup\$
    – Computer
    Oct 15, 2017 at 11:38
  • 2
    \$\begingroup\$ @Computer: buffer = realloc(/* stuff */); if(buffer == NULL) /* error */. Also, your buffer string might be too large for printf("%s", buffer). \$\endgroup\$
    – hoffmale
    Oct 15, 2017 at 11:41
  • \$\begingroup\$ @Computer As @hoffmale wrote above: use a conditional instruction if (...) ... to avoid using an invalid pointer, or even better, if (...) ... else ... to avoid using an invalid pointer and to return some informative message or status in case of error. \$\endgroup\$
    – CiaPan
    Oct 16, 2017 at 5:57

Not the answer you're looking for? Browse other questions tagged or ask your own question.