benekastah
benekastah

Reputation: 5711

Why does passing a struct in this way produce a segfault?

I'm trying to get the hang of c and I can't figure out why this code is producing a segfault.

// In src/test.c

#include <stdio.h>

typedef struct {
    int length;
    int *arr[1000];
} Stack;

void push(Stack *stack, int el) {
    (*stack->arr)[stack->length++] = el;
}

int pop(Stack *stack) {
    return (*stack->arr)[--stack->length];
}

int main(int argc, char* argv[]) {
    Stack stack;
    push(&stack, 5);
    printf("%d\n", pop(&stack));
    return 0;
}

Then I compile and run:

$ gcc src/test.c -o test && ./test
[1]    79484 segmentation fault  ./test

Upvotes: 0

Views: 69

Answers (4)

Jonathan Leffler
Jonathan Leffler

Reputation: 754010

The type of the array in the structure is wrong; it should be int arr[1000];.

As written, you're using uninitialized variables all over the place; neither the length nor any of the pointers in your arr are set to anything reliable (though the pointers should be plain int anyway). Because you have pointers instead of int in your stack, you have a very complex expression to access the stack (the (*stack->arr)[stack->length++], etc), which should be much simpler, as in this rewritten code below.

#include <stdio.h>

typedef struct
{
    int length;
    int arr[1000];
} Stack;

void push(Stack *stack, int el)
{
    stack->arr[stack->length++] = el;
}

int pop(Stack *stack)
{
    return stack->arr[--stack->length];
}

int main(void)
{
    Stack stack = { 0, { 0 } };
    push(&stack, 5);
    printf("%d\n", pop(&stack));
    return 0;
}

Upvotes: 1

ffhaddad
ffhaddad

Reputation: 1723

You have a few problems.

Like others have mentioned, your int length struct member is never set to zero and thus could contain anything.

You must set the length to 0.

Second, int *arr[1000] is an array of integer pointers. So simply assigning an int to a particular array position is wrong.

You want something more like this:

// In src/test.c

#include <stdio.h>

typedef struct {
    int length;
    int arr[1000]; // Code change (create an array of integers)
} Stack;

void push(Stack *stack, int el) {
    stack->arr[stack->length++] = el; // Code change (no need for additional
                                      // structure member dereference).
}

int pop(Stack *stack) {
    return stack->arr[--stack->length]; // Code change (no need for additional
                                        // structure member dereference).
}

int main(int argc, char* argv[]) {
    Stack stack;
    stack.length = 0; // Code change (set the starting length value to 0)
    push(&stack, 5);
    printf("%d\n", pop(&stack));
    return 0;
}

Upvotes: 4

dexterous
dexterous

Reputation: 6526

#include <stdio.h>

typedef struct {
    int length;
    int arr[1000];
} Stack;

void push(Stack *stack, int el) {
    (stack->arr)[stack->length++] = el;
}

int pop(Stack *stack) {
    return (stack->arr)[--stack->length];
}


int main(int argc, char* argv[]) {
    Stack stack;
    memset(&stack,0,sizeof(Stack));
    push(&stack, 5);
    printf("%d\n", pop(&stack));
    return 0;
}

The thumb rule is allocate memory before accessing it.

Upvotes: 0

OldProgrammer
OldProgrammer

Reputation: 12169

In your structure, "length" is never initialized, so it contains garbage. WHen you then reference:

(*stack->arr)[stack->length++]

it is indexing memory at an undefined location. So, you need some function, like "init_stack()" to initialize the structs data members to well known values (like zero).

Upvotes: 1

Related Questions