David
David

Reputation: 2721

What is causing the segmentation fault error in in this tiny c program?

I am writing a small c program to practicing malloc and sscanf library functions. But unfortunately I get a segmentation fault error. I have googled and struggled for hours but with no result. Anybody could lead me out of this?

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

void print_array(int a[], int num_elements);

int main(void) {
    int m;    
    printf("How many numbers do you count: \n");  
    scanf("%d", &m);
    int *a = (int*)malloc(m * sizeof(int*));
    char buf[100];
    setbuf(stdin, NULL);
    if (fgets(buf, sizeof buf, stdin) != NULL) {
        char *p = buf;
        int n, index;
        while (sscanf(p, "%d %n", &a[index], &n) == 1 && index < m) {
            // do something with array[i]
            index++;  // Increment after success @BLUEPIXY
            p += n;
        }
        if (*p != '\0')
            printf("you are giving non-numbers, will be ignored");
    }

    print_array(a, m);
    free(a);
    return 0;
}

void print_array(int a[], int num_elements) {
    int i;
    for (i = 0; i < num_elements; i++) {
        printf("%d ", a[i]);
    }
}

Upvotes: 3

Views: 226

Answers (3)

chqrlie
chqrlie

Reputation: 144959

Your program has multiple errors:

  • you do not check the return value of scanf(). Invalid input will cause m to remain uninitialized, allocating m * sizeof(int) may fail.

  • The size computed for malloc is incorrect. Casting the return value of malloc() is not necessary in C and considered bad style. Furthermore, you should check for allocation failure. Use this instead:

    int *a = malloc(m * sizeof(int));
    
  • index is uninitialized in sscanf(p, "%d %n", &a[index], &n) definitely causing undefined behavior as you are telling sscanf() to store the int value into some random address in memory.

  • you test index < m after storing to &a[index], causing a potential buffer overflow. Swap the test in front of the sscanf().

Here is a modified version:

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

void print_array(const int a[], int num_elements);

int main(void) {
    int m;    
    printf("How many numbers do you count:\n");  
    if (scanf("%d", &m) != 1 || m <= 0) {
        fprintf(stderr, "invalid input\n");
        return 1;
    }
    int *a = malloc(m * sizeof(int));
    if (a == NULL) {
        fprintf(stderr, "memory allocation failed\n");
        return 1;
    }
    char buf[100];
    setbuf(stdin, NULL);  // why do you want stdin to be unbuffered?
    if (fgets(buf, sizeof buf, stdin) != NULL) {
        char *p = buf;
        int n, index = 0;
        while (index < m && sscanf(p, "%d %n", &a[index], &n) == 1) {
            // do something with array[i]
            index++;  // Increment after success @BLUEPIXY
            p += n;
        }
        if (*p != '\0') {
            printf("you are giving non-numbers or extra input, will be ignored\n");
        }
    }

    print_array(a, m);
    free(a);
    return 0;
}

void print_array(const int a[], int num_elements) {
    for (int i = 0; i < num_elements; i++) {
        printf("%d ", a[i]);
    }
    printf("\n");
}

Upvotes: 1

Pbd
Pbd

Reputation: 1319

Your malloc is faulty. Replace int* a = (int*)malloc(m*sizeof(int*)); with int* a = (int *)malloc(m*sizeof(int));. You got lucky here, that sizeof int is smaller than int*, otherwise you can get in whole bunch of problems.

I couldn't reproduce the error, better give input text next time, but to debug segfault i depend on gdb.

$ gcc -g prog.c -o prog

$ gdb prog

gdb> run [args]

This will break the program at line which is causing segfault. Use this tutorial for more knowledge. gdb tutorial

Upvotes: 3

Paul Ogilvie
Paul Ogilvie

Reputation: 25286

Most [potential] causes of errors seem to come from not initializing your automatic variables:

scanf("%d",&m);

If this fails, then m has an undefined value as you didn't initialize it.

in sscanf you use &a[index] but index has not been initialized so it can be written anywhere.

See also the comments, that identify more erors (e.g. checking the return value of sscanf).

Upvotes: 0

Related Questions