Kudayar Pirimbaev
Kudayar Pirimbaev

Reputation: 1320

C: Adjacency lists from graph - segmentation fault

NOTE: I can't use '.' and '->' operators on a graph. That's why I use these macros.

For the following declaration of graph (that I cannot change - assignment, so please don't ask me anything about it),

#include <stdio.h>
#include <stdlib.h>
#define TAG(vp)   ((vp)->tag)
#define LABEL(vp) ((vp)->label)  
#define EDGE(vp)  ((vp)->edge)

typedef struct vertex 
{
    char tag; /* can be used for any puproses; haven't used though */
    char *label;
    struct vertex *edge[1];
}
vertex, *vp;

I wrote the following structure and function that creates adjacency lists for graph.

typedef struct adjList
{
    vp node;
    struct adjList *next;
}
adjList;


void createList (adjList *list, vp graph, int *place) /* place stores an index in an array of adjacency lists */
{
    int i, temp = *place;
    adjList *ptr;
    if (graph)
    {
        list[temp].node = graph;
        list[temp].next = NULL;
        if (EDGE (graph))
        {
            ptr = list[temp].next;
            for (i = 0; EDGE (graph)[i]; ++i)
            {
                ptr = malloc (sizeof (adjList));
                ptr->node = EDGE (graph)[i];
                ptr = ptr->next;
            }
        }
        ++(*place);
        list = realloc (list, sizeof (adjList) * (*place + 1));
        for (i = 0; EDGE (graph)[i]; ++i)
        {
            createList (list, EDGE (graph)[i], place);
        }
    }
}

Using this main, I get a segmentation fault.

int main()
{
    int i;
    int *temp = malloc (sizeof (int));
    adjList *list, *ptr;
    vp test;
    *temp = 0; /* temp is an index starting from 0 */
    test = malloc (sizeof (*test) + 4 * sizeof (vp));
    list = malloc (sizeof (adjList));
    LABEL (test) = malloc (sizeof (char));
    LABEL (test)[0] = 'a';
    for (i = 0; i < 3; ++i)
    {
        EDGE (test)[i] = malloc (sizeof (vertex));
    }
    LABEL (EDGE (test)[0]) = malloc (sizeof (char));
    LABEL (EDGE (test)[0])[0] = 'b';
    LABEL (EDGE (test)[1]) = malloc (sizeof (char));
    LABEL (EDGE (test)[1])[0] = 'c';
    LABEL (EDGE (test)[2]) = malloc (sizeof (char));
    LABEL (EDGE (test)[2])[0] = 'd';
    EDGE (EDGE (test)[0])[0] = NULL;
    EDGE (EDGE (test)[1])[0] = NULL;
    EDGE (EDGE (test)[2])[0] = NULL;
    EDGE (test)[3] = NULL;
    printf ("%d\n", sizeof (EDGE (test)) / sizeof (vp));
    createList (list, test, temp);
    list = realloc (list, sizeof (adjList) * (*temp));
    printf ("%c\n", LABEL (test)[0]);
    printf ("%d\n", (test == list[0].node));
    for (ptr = list; ptr; ptr = ptr->next)
    {
        printf ("%c ", LABEL (ptr->node)[0]);
    }
    printf ("\n");
    return 0;
}

While debugging it, I found that my function that creates adjacency lists does not even store pointers in "adjList" structures. Maybe I'm not allocating memory properly. Any bit of help will be appreciated.

Thanks in advance.

Upvotes: 0

Views: 206

Answers (1)

Jonathan Leffler
Jonathan Leffler

Reputation: 753475

Run on Mac OS X, I get the message:

graph(70806) malloc: *** error for object 0x7fb211c03b20: pointer being realloc'd was not allocated

With this annotated version of the createList() function:

static
void createList (adjList *list, vp graph, int *place) /* place stores an index in an array of adjacency lists */
{
    int i, temp = *place;
    adjList *ptr;
    if (graph)
    {
        printf("-->> %s()\n", __func__);
        list[temp].node = graph;
        list[temp].next = NULL;
        if (EDGE (graph))
        {
            ptr = list[temp].next;
            for (i = 0; EDGE (graph)[i]; ++i)
            {
                ptr = malloc (sizeof (adjList));
                ptr->node = EDGE (graph)[i];
                ptr = ptr->next;
            }
        }
        ++(*place);
        printf("About to realloc() in createList()\n");
        list = realloc (list, sizeof (adjList) * (*place + 1));
        printf("Back from realloc() in createList()\n");
        for (i = 0; EDGE (graph)[i]; ++i)
        {
            printf("Recursing in createList\n");
            createList (list, EDGE (graph)[i], place);
            printf("Back from recursive createList\n");
        }
        printf("<<-- %s()\n", __func__);
    }
}

the output from the run is:

1
-->> createList()
About to realloc() in createList()
Back from realloc() in createList()
Recursing in createList
-->> createList()
About to realloc() in createList()
Back from realloc() in createList()
<<-- createList()
Back from recursive createList
Recursing in createList
-->> createList()
About to realloc() in createList()
graph(70904) malloc: *** error for object 0x7fefca403b20: pointer being realloc'd was not allocated
*** set a breakpoint in malloc_error_break to debug

The trouble is that createList() reallocates the list passed in, but cannot tell the calling code the address of the new list. You'll either need to revise createList() to return the new list, or arrange to pass an adjList **list into the function — in either case, with consequential changes.

Upvotes: 1

Related Questions