ThatPixelCherry
ThatPixelCherry

Reputation: 323

Getting a seg-fault when setting value of pointer

There really isnt much I can say here. Here is my lexer file:

#include <ctype.h>
#include <stdio.h>
#include "vector.h"

enum TokenType
{
    tok_let = -1,
    tok_iden = -2,
    tok_int = -3,
    tok_end = -4
};

typedef struct
{
    int type;
    char* str_d;
    int int_d;
} Token;

char* seed;

int i=0;

char next_char()
{
    i++;
    return seed[i-1];
}

vector* get_tokens(char* in)
{
    vector *toks;
    vector_new(toks);

    seed = in;
    char tap;
    if(isalpha(tap = next_char()))
    {
        char* iden_str="";
        iden_str += tap;
        char nc;
        while(isalnum((nc = next_char())))
            iden_str += nc; 
        if(iden_str == "let")
        {
            Token* tp;
            tp->type = tok_let;
            vector_push(toks, (void*)tp);   
            goto out;   
        }
        Token* tp;
        tp->type = tok_iden;
        tp->str_d = iden_str;
        vector_push(toks, (void*)tp);
    }
    out:
    return toks;
}

int main()
{
    vector* toks;
    toks = get_tokens("let");
    Token* ftok = (Token*)vector_get(toks, 0);
    switch(ftok->type)
    {
        case tok_let:
            printf("Its a let\n");
            break;
        default:
            printf("Ummm lol nup\n");
            break;
    }
}

And here is my vector file:

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

typedef struct d_vector
{
    void **items;
    int capacity;
    int total;
} vector;

void vector_new(vector *v)
{
    v->capacity = 4;
    v->total = 0;
    v->items = malloc(sizeof(void*)*v->capacity);
}

int vector_total(vector *v)
{
    return v->total;
}

static void vector_resize(vector *v, int capacity)
{
    void** items = realloc(v->items, sizeof(void*) * capacity);
    if(items)
    {
        v->items = items;
        v->capacity = capacity;
    }
}

void vector_push(vector *v, void* item)
{
    if(v->capacity == v->total)
    vector_resize(v, v->capacity * 2);
    v->items[v->total++] = item;
}

void vector_set(vector *v, int index, void* item)
{
    if(index >= 0 && index < v->total)
        v->items[index] = item;
}

void* vector_get(vector *v, int index)
{
    if(index >= 0 && index < v->total)
        return v->items[index];
   return NULL;
}

void vector_remove(vector *v, int index)
{
    if(index < 0 || index >= v->total)
        return;

    v->items[index] = NULL;


        for (int i = 0; i < v->total - 1; i++) {
            v->items[i] = v->items[i + 1];
            v->items[i + 1] = NULL;
        }

        v->total--;

        if (v->total > 0 && v->total == v->capacity / 4)
            vector_resize(v, v->capacity / 2);
}

void vector_free(vector *v)
{
    free(v->items);
}

When I run the code above, I get a Seg-Fault. How can this be happening? Here is the output of gdb:

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400656 in vector_new (v=0x1) at vector.h:14
14      v->capacity = 4;

As you can see, its segfaulting when i set the vector capacity! But why?

Upvotes: 0

Views: 516

Answers (2)

zydcom
zydcom

Reputation: 518

invalid pointer dereference happened

vector *toks;
vector_new(toks);

Should be

vector *toks = (vector*)malloc(sizeof(vector));
vector_new(toks);

Upvotes: 1

e0k
e0k

Reputation: 7161

It segfaults because you dereference a garbage pointer:

vector* get_tokens(char* in)
{
  vector *toks;
  vector_new(toks);

The variable toks is not assigned to anything meaningful, just whatever garbage value happens to be floating about. This gets passed into vector_new() which immediately dereferences it:

void vector_new(vector *v)
{
  v->capacity = 4;

Then BAM! it blows up because v points nowhere appropriate.

Try mallocing a vector before making your call to vector_new() or put the malloc in vector_new() and have it return the pointer to the new vector instead. It's also a good idea to check the return value from malloc().

You might try something like:

vector *vector_new(void)
{
  vector *v;
  if ( (v = malloc(sizeof(*v))) == NULL ) {
    /* Replace with something appropriate */
    exit(EXIT_FAILURE);
  }
  v->capacity = 4;
  v->total = 0;
  if ( (v->items = malloc(sizeof(*v->items)*v->capacity)) == NULL ) {
    /* Replace with something appropriate */
    exit(EXIT_FAILURE);
  }
  return v;
}

Then change how you call it:

vector* get_tokens(char* in)
{
  vector *toks;
  toks = vector_new();

And for every malloc(), let there be a free(). Don't forget to clean up this allocation too or you'll leak memory:

void vector_free(vector *v)
{
  free(v->items);
  free(v);
}

(You defined a vector_free(), but never called it. You might want to consider doing that too.)

Upvotes: 1

Related Questions