I have a problem where my malloc breaks my program. Removing it will make it work but I need it furter on. Can someone please explain what i'm doing wrong. Thanks in advance!!
I have this function in my graph.c
bool graph_initialise(graph_t *graph, unsigned vertex_count)
{
assert(graph != NULL);
graph = (struct graph_s*) malloc(sizeof(struct graph_s));
if (graph == NULL){return true;}
graph->vertex_count = vertex_count;
graph->adjacency_lists = (struct adjacency_list_s*) malloc(vertex_count * sizeof(struct adjacency_list_s));
if (graph->adjacency_lists == NULL){
return true;
}
int i;
for (i = 1; i < vertex_count; ++i){
graph->adjacency_lists[i].first = NULL;
}
return false;
and this in my graph.h
typedef struct edge_s
{
/* Points to the next edge when this edge is part of a linked list. */
struct edge_s *next;
unsigned tail; /* The tail of this edge. */
unsigned head; /* The head of this edge. */
unsigned weight; /* The weight of this edge. */
} edge_t;
typedef struct adjacency_list_s
{
edge_t *first; /* Pointer to the first element of the adjacency list */
} adjacency_list_t;
/* Type representing a graph */
typedef struct graph_s
{
unsigned vertex_count; /* Number of vertices in this graph. */
unsigned edge_count; /* Number of edges in this graph. */
/* Pointer to the first element of an array of adjacency lists. The array
* is indexed by vertex number
*/
adjacency_list_t *adjacency_lists;
} graph_t;
I suspect this issue is that you are expecting this function to allocate grph for you then operating on the allocated graph from the calling code (you dont show the calling code)
ie you are doing something like
graph *gptr;
graph_initialise(gptr,42);
printf("vc = %d", gptr->vertex_count);
trouble is that grpah_initialize doesnt set gptr. You need instead
bool graph_initialise(graph_t **gptr, unsigned vertex_count)
{
*gptr = (struct graph_s*) malloc(sizeof(struct graph_s));
graph_t *graph = *gptr;
if (graph == NULL){return true;}
graph->vertex_count = vertex_count;
graph->adjacency_lists = (struct adjacency_list_s*) malloc(vertex_count * sizeof(struct adjacency_list_s));
if (graph->adjacency_lists == NULL){
return true;
}
int i;
for (i = 1; i < vertex_count; ++i){
graph->adjacency_lists[i].first = NULL;
}
return false;
and call it like this
graph *gptr;
graph_initialise(&gptr,42);
printf("vc = %d", gptr->vertex_count);
also that for loop should probably start at 0 not 1
Related
I have a list defined as
typedef struct node {
Voo *voo;
ListaReservas nodeReservas; /* Ignore this */
struct node *next;
} *Node;
I created some functions to help me add or remove nodes from the list like:
/* creates a node */
Node criaNode(Voo v) {
Node new = (Node)malloc(sizeof(struct node));
new->voo = &v;
/* I had new->voo = v; but vscode told me it was wrong so i changed it to &v */
new->next = NULL;
return new;
}
Voo is defined as:
typedef struct {
int dia;
int mes;
int ano;
} Data;
typedef struct {
int horas;
int minutos;
} Tempo;
typedef struct {
char codigo[LEN_CODIGO + 1];
char partidaID[LEN_ID + 1];
char chegadaID[LEN_ID + 1];
Data datapartida;
Tempo horapartida;
Tempo duracao;
Data datachegada;
Tempo horachegada;
int capacidade;
} Voo;
Now I wanted to iterate through the list and print its values as such
Voo *v;
for (n = headVoos; n != NULL; n = n->next) {
v = n->voo;
printf("%s %s %s %.2d-%.2d-%d %.2d:%.2d\n",
v->codigo, v->partidaID, v->chegadaID,
v->datapartida.dia, v->datapartida.mes, v->datapartida.ano,
v->horapartida.horas, v->horapartida.minutos);
}
The program is not printing correctly. For example where it should appear
AA1 AAA AAD 16-03-2022 14:50
its appearing instead
� 146187376-32765--1940381952 40355300:50
What's causing this and how can I avoid it in the future?
EDIT
After replacing in the struct node the Voo *voo definition by Voo voo, I am now getting an error in one of the auxiliary functions:
/* deletes node */
Node eliminaNode(Node head, Voo v)
{
Node n, prev;
for (n = head, prev = NULL; n != NULL; prev = n, n = n->next)
{
if (n->voo == v) /* expression must have arithmetic or pointer error */
{
if (n == head)
head = n->next;
else
prev->next = n->next;
free(n->next);
free(n);
break;
}
}
return head;
}
In criaNode you're taking the address of the parameter v and returning it from the function via a pointer to dynamic memory. That address is no longer valid after the function returns. Subsequently dereferencing that invalid address then triggers undefined behavior.
It probably makes more sense for struct node to contain a Voo directly instead of a pointer to one. So change the member to a non-pointer:
Voo voo;
And assign the parameter directly:
new->voo = v;
There are multiple problems here:
there seems to be a confusion between structures and pointers to structures. In C, you must understand the difference between manipulating objects (allocating as local objects or from the head, passing as arguments or returning as values) and pointers to objects, which are a more idiomatic as arguments to functions and allow functions to modify the object they point to.
the confusion is amplified by a very error prone construction: hiding pointers behind typedefs. Do not do that, define object types for the actual structure, using the same or a different name as the struct tag, and make all pointers explicit with the * syntax.
you pass an actual Voo object as an argument and allocate a list node using the address of this argument. This is incorrect because the argument will be discarded as soon as the function returns, makeing the list point to invalid memory and explaining the weird output you observe.
Node eliminaNode(Node head, Voo v) should take a pointer to the head node and return a success indicator. It should take a Voo * argument and it should not free(n->next) because the next node is still in use after the removal.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#define LEN_CODIGO 30
#define LEN_ID 30
typedef struct Data {
int dia;
int mes;
int ano;
} Data;
typedef struct Tempo {
int horas;
int minutos;
} Tempo;
typedef struct Voo {
char codigo[LEN_CODIGO+ 1];
char partidaID[LEN_ID + 1];
char chegadaID[LEN_ID + 1];
Data datapartida;
Tempo horapartida;
Tempo duracao;
Data datachegada;
Tempo horachegada;
int capacidade;
} Voo;
typedef struct Node {
struct Voo *voo;
//ListaReservas nodeReservas; /* Ignore this */
struct Node *next;
} Node;
/* creates a node */
Node *criaNode(Voo *v) {
/* allocation with calloc is safer as the object will be initialized to 0 */
Node *nodep = calloc(1, sizeof(*new));
if (nodep) {
nodep->voo = v;
nodep->next = NULL;
}
return nodep;
}
/* deletes node */
int eliminaNode(Node **head, Voo *v) {
for (Node *n = *head, *prev = NULL; n != NULL; prev = n, n = n->next) {
if (n->voo == v) {
if (n == *head)
*head = n->next;
else
prev->next = n->next;
free(n);
return 1; /* article was found and freed */
}
}
return 0; /* article was not found */
}
void printList(const Node *head) {
for (const Node *n = head; n != NULL; n = n->next) {
const Voo *v = n->voo;
printf("%s %s %s %.2d-%.2d-%.2d %.2d:%.2d\n",
v->codigo, v->partidaID, v->chegadaID,
v->datapartida.dia, v->datapartida.mes, v->datapartida.ano,
v->horapartida.horas, v->horapartida.minutos);
}
}
I use this data structure to store a graph:
struct Vertex
{
struct Line *a;
struct Line *b;
int X;
int Y;
struct Vertex *next;
struct Edge *edges;
int edgeCount;
};
struct Edge
{
struct Vertex *dst;
struct Vertex *src;
struct Edge *next;
float weight;
bool included;
bool visited;
};
I generate a linked list of vertices(the list is my graph) in a loop:
struct Edge *edge= malloc(sizeof(struct Edge));
////here I add edge's data
if(graph->edges == NULL)
{
graph->edges = edge;
}
else
{
edge->next = graph->edges;
}
And now I need to permute resulting array. It is simple with common array of integers:
void swap(int a, int b)
{
int temp = a;
a = b;
b = temp;
}
void permutation(int* randomArray, int numIndex)
{
for (i = 0; i < numIndex; i++)
{
int randomOffset = rand() % (numIndex - i);
swap(randomArray[i], randomArray[i+randomOffset]);
}
}
But how to do the same with linked list?
Create an array of struct Edge * that contains all edges, built when the linked list is created, permute that array, rebuild the linked list.
The variables
struct Edge *pedges[MAXEDGES]; // or allocate dynamically (see below)
int nedges = 0;
then when list is created
struct Edge *edge= malloc(sizeof(struct Edge)); // your code
pedges[nedges++] = edge;
permutations are done the same way
void permuteEdges(struct Edge *pe, int ne) {
int i;
for (i = 0 ; i < ne ; i++) {
int randomOffset = rand() % (ne - i);
swap(pe[i], pe[i+randomOffset]);
}
}
finally, rebuild the linked list
for (i = 0 ; i < ne ; i++) {
if ( ! i) {
graph->edges = pe[i];
}
else {
pe[i-1]->next = pe[i];
}
}
ensure the last item next property points to NULL
pe[ne-1]->next = NULL;
Note that you could allocate pedges dynamically (to be freed after use). For instance if you use the array for a single shuffle, there is no need to keep that amount of memory in the heap.
Dynamic allocation
struct Edge *pedges = malloc(MAXEDGES * sizeof(*pedges));
...use it...
free(pedges);
I'm trying to implement a graph to store a list of data from a text file such as the following:
0,1 (node 0 links to 1)
0,2 (node 0 links to 2)
1,2 (node 1 links to 2)
2,1 (node 2 links to 1)
Anyways I come across trouble when it comes down to defining the structures. I'm torn between using a matrix or adjacent lists, but I think I will go with lists, I am just not sure how to define the structures. Should I use variable sized arrays, linked lists or something else? Which way would be the easiest?
struct grph{
};
struct node{
//ID of the node
int id;
};
Second, how do I store the data into this graph, this is where I come across the most trouble. Essentially, I thought it would be easy like linked lists where you just keep adding a node to the end. The difference here is that each node can point to many different nodes or to none at all. How do I link the graph structure with all the linked node structures?
When using linked lists for example, how would I store what node 0 connects to in the example above? I understand you use a matrix or list/array, but I'm seriously getting confused because of the lack of examples of such implementations in C. Any examples I found just made it much worse then I was before.
This is just an example:
struct node{
int id;
struct node **out;
int num_out;
/* optional: if you want doubly links */
struct node **in;
int num_in;
};
/* quick access to a node given an id */
struct node *node_list;
/* connect 'from' to 'to' */
void link(struct node *graph, int from, int to) {
struct node *nfrom = &node_list[from],
*nto = &node_list[to];
nfrom->num_out++;
nfrom->out = realloc(nfrom->out,
sizeof(struct node*) * nfrom->num_out);
nfrom->out[num_out-1] = nto;
/* also do similar to nto->in if you want doubly links */
}
In answer to your first question: adjacency matrix vs adjacency lists? If you expect your graph to be dense, i.e. most nodes are adjacent with most other nodes, then go for the matrix as most operations are much easier on matrices. If you really need a transitive closure, then matrices are probably better also, as these tend to be dense. Otherwise adjacency lists are faster and smaller.
A graph would look as follows:
typedef struct node * node_p;
typedef struct edge * edge_p;
typedef struct edge
{ node_p source, target;
/* Add any data in the edges */
} edge;
typedef struct node
{ edge_p * pred, * succ;
node_p next;
/* Add any data in the nodes */
} node;
typedef struct graph
{ node_p N;
} graph;
The N field of graph would start a linked list of the nodes of the graph using the next field of node to link the list. The pred and succ can be arrays allocated using malloc and realloc for the successor and predecessor edges in the graph (arrays of pointers to edges and NULL terminated). Even though keeping both successor and predecessors may seem redundant, you will find that most graph algorithms like to be able to walk both ways. The source and target field of an edge point back to the nodes. If you don't expect to store data in the edges, then you could let the pred and succ arrays point back directly to the nodes and forget about the edge type.
Don't try to use realloc on N in the graph because all the addresses of the nodes may change and these are heavily used in the remainder of the graph.
P.S: Personally I prefer circular linked lists over NULL ended linked lists, because the code for most, if not all, operations are much simpler. In that case graph would contain a (dummy) node instead of a pointer.
You could do something like this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct
{
void* pElements;
size_t ElementSize;
size_t Count; // how many elements exist
size_t TotalCount; // for how many elements space allocated
} tArray;
void ArrayInit(tArray* pArray, size_t ElementSize)
{
pArray->pElements = NULL;
pArray->ElementSize = ElementSize;
pArray->TotalCount = pArray->Count = 0;
}
void ArrayDestroy(tArray* pArray)
{
free(pArray->pElements);
ArrayInit(pArray, 0);
}
int ArrayGrowByOne(tArray* pArray)
{
if (pArray->Count == pArray->TotalCount) // used up all allocated space
{
size_t newTotalCount, newTotalSize;
void* p;
if (pArray->TotalCount == 0)
{
newTotalCount = 1;
}
else
{
newTotalCount = 2 * pArray->TotalCount; // double the allocated count
if (newTotalCount / 2 != pArray->TotalCount) // count overflow
return 0;
}
newTotalSize = newTotalCount * pArray->ElementSize;
if (newTotalSize / pArray->ElementSize != newTotalCount) // size overflow
return 0;
p = realloc(pArray->pElements, newTotalSize);
if (p == NULL) // out of memory
return 0;
pArray->pElements = p;
pArray->TotalCount = newTotalCount;
}
pArray->Count++;
return 1;
}
int ArrayInsertElement(tArray* pArray, size_t pos, void* pElement)
{
if (pos > pArray->Count) // bad position
return 0;
if (!ArrayGrowByOne(pArray)) // couldn't grow
return 0;
if (pos < pArray->Count - 1)
memmove((char*)pArray->pElements + (pos + 1) * pArray->ElementSize,
(char*)pArray->pElements + pos * pArray->ElementSize,
(pArray->Count - 1 - pos) * pArray->ElementSize);
memcpy((char*)pArray->pElements + pos * pArray->ElementSize,
pElement,
pArray->ElementSize);
return 1;
}
typedef struct
{
int Id;
int Data;
tArray LinksTo; // links from this node to other nodes (array of Id's)
tArray LinksFrom; // back links from other nodes to this node (array of Id's)
} tNode;
typedef struct
{
tArray Nodes;
} tGraph;
void GraphInit(tGraph* pGraph)
{
ArrayInit(&pGraph->Nodes, sizeof(tNode));
}
void GraphPrintNodes(tGraph* pGraph)
{
size_t i, j;
if (pGraph->Nodes.Count == 0)
{
printf("Empty graph.\n");
}
for (i = 0; i < pGraph->Nodes.Count; i++)
{
tNode* pNode = (tNode*)pGraph->Nodes.pElements + i;
printf("Node %d:\n Data: %d\n", pNode->Id, pNode->Data);
if (pNode->LinksTo.Count)
{
printf(" Links to:\n");
for (j = 0; j < pNode->LinksTo.Count; j++)
{
int* p = (int*)pNode->LinksTo.pElements + j;
printf(" Node %d\n", *p);
}
}
}
}
void GraphDestroy(tGraph* pGraph)
{
size_t i;
for (i = 0; i < pGraph->Nodes.Count; i++)
{
tNode* pNode = (tNode*)pGraph->Nodes.pElements + i;
ArrayDestroy(&pNode->LinksTo);
ArrayDestroy(&pNode->LinksFrom);
}
ArrayDestroy(&pGraph->Nodes);
}
int NodeIdComparator(const void* p1, const void* p2)
{
const tNode* pa = p1;
const tNode* pb = p2;
if (pa->Id < pb->Id)
return -1;
if (pa->Id > pb->Id)
return 1;
return 0;
}
int IntComparator(const void* p1, const void* p2)
{
const int* pa = p1;
const int* pb = p2;
if (*pa < *pb)
return -1;
if (*pa > *pb)
return 1;
return 0;
}
size_t GraphFindNodeIndexById(tGraph* pGraph, int Id)
{
tNode* pNode = bsearch(&Id,
pGraph->Nodes.pElements,
pGraph->Nodes.Count,
pGraph->Nodes.ElementSize,
&NodeIdComparator);
if (pNode == NULL)
return (size_t)-1;
return pNode - (tNode*)pGraph->Nodes.pElements;
}
int GraphInsertNode(tGraph* pGraph, int Id, int Data)
{
size_t idx = GraphFindNodeIndexById(pGraph, Id);
tNode node;
if (idx != (size_t)-1) // node with this Id already exist
return 0;
node.Id = Id;
node.Data = Data;
ArrayInit(&node.LinksTo, sizeof(int));
ArrayInit(&node.LinksFrom, sizeof(int));
if (!ArrayInsertElement(&pGraph->Nodes, pGraph->Nodes.Count, &node))
return 0;
qsort(pGraph->Nodes.pElements,
pGraph->Nodes.Count,
pGraph->Nodes.ElementSize,
&NodeIdComparator); // maintain order for binary search
return 1;
}
int GraphLinkNodes(tGraph* pGraph, int IdFrom, int IdTo)
{
size_t idxFrom = GraphFindNodeIndexById(pGraph, IdFrom);
size_t idxTo = GraphFindNodeIndexById(pGraph, IdTo);
tNode *pFrom, *pTo;
if (idxFrom == (size_t)-1 || idxTo == (size_t)-1) // one or both nodes don't exist
return 0;
pFrom = (tNode*)pGraph->Nodes.pElements + idxFrom;
pTo = (tNode*)pGraph->Nodes.pElements + idxTo;
// link IdFrom -> IdTo
if (bsearch(&IdTo,
pFrom->LinksTo.pElements,
pFrom->LinksTo.Count,
pFrom->LinksTo.ElementSize,
&IntComparator) == NULL) // IdFrom doesn't link to IdTo yet
{
if (!ArrayInsertElement(&pFrom->LinksTo, pFrom->LinksTo.Count, &IdTo))
return 0;
qsort(pFrom->LinksTo.pElements,
pFrom->LinksTo.Count,
pFrom->LinksTo.ElementSize,
&IntComparator); // maintain order for binary search
}
// back link IdFrom <- IdTo
if (bsearch(&IdFrom,
pTo->LinksFrom.pElements,
pTo->LinksFrom.Count,
pTo->LinksFrom.ElementSize,
&IntComparator) == NULL) // IdFrom doesn't link to IdTo yet
{
if (!ArrayInsertElement(&pTo->LinksFrom, pTo->LinksFrom.Count, &IdFrom))
return 0;
qsort(pTo->LinksFrom.pElements,
pTo->LinksFrom.Count,
pTo->LinksFrom.ElementSize,
&IntComparator); // maintain order for binary search
}
return 1;
}
int main(void)
{
tGraph g;
printf("\nCreating empty graph...\n");
GraphInit(&g);
GraphPrintNodes(&g);
printf("\nInserting nodes...\n");
GraphInsertNode(&g, 0, 0);
GraphInsertNode(&g, 1, 101);
GraphInsertNode(&g, 2, 202);
GraphPrintNodes(&g);
printf("\nLinking nodes...\n");
GraphLinkNodes(&g, 0, 1);
GraphLinkNodes(&g, 0, 2);
GraphLinkNodes(&g, 1, 2);
GraphLinkNodes(&g, 2, 1);
GraphPrintNodes(&g);
printf("\nDestroying graph...\n");
GraphDestroy(&g);
GraphPrintNodes(&g);
// repeat
printf("\nLet's repeat...\n");
printf("\nCreating empty graph...\n");
GraphInit(&g);
GraphPrintNodes(&g);
printf("\nInserting nodes...\n");
GraphInsertNode(&g, 1, 111);
GraphInsertNode(&g, 2, 222);
GraphInsertNode(&g, 3, 333);
GraphPrintNodes(&g);
printf("\nLinking nodes...\n");
GraphLinkNodes(&g, 1, 2);
GraphLinkNodes(&g, 2, 3);
GraphLinkNodes(&g, 3, 1);
GraphPrintNodes(&g);
printf("\nDestroying graph...\n");
GraphDestroy(&g);
GraphPrintNodes(&g);
return 0;
}
Output (ideone):
Creating empty graph...
Empty graph.
Inserting nodes...
Node 0:
Data: 0
Node 1:
Data: 101
Node 2:
Data: 202
Linking nodes...
Node 0:
Data: 0
Links to:
Node 1
Node 2
Node 1:
Data: 101
Links to:
Node 2
Node 2:
Data: 202
Links to:
Node 1
Destroying graph...
Empty graph.
Let's repeat...
Creating empty graph...
Empty graph.
Inserting nodes...
Node 1:
Data: 111
Node 2:
Data: 222
Node 3:
Data: 333
Linking nodes...
Node 1:
Data: 111
Links to:
Node 2
Node 2:
Data: 222
Links to:
Node 3
Node 3:
Data: 333
Links to:
Node 1
Destroying graph...
Empty graph.
It seems quite like my working, social networking...
You could define the node and links seperately. In c language, you could define as:
struct graph_node{
int id;
struct node_following *following;
struct graph_node *next_node;
}
struct node_following{
int id;
struct node_following *next_node;
}
For your example, the result is:
root -> node0 -> node1 -> node2
The content of root might be: id = -1; following=NULL; next_node= node0
The content of node0 might be: id = 0; next_node = node1; following point to a list of node_following as:
following -> {1, address of next node} -> {2, NULL}
The content of node1 might be: id = 1; next_node = node2; following point to a list of node_following as:
following -> {2, NULL}
The content of node2 might be: id = 2; next_node = NULL; following point to a list of node_following as:
following -> {1, NULL}
Essentially, it is a quesition on how to store a two-dimensional matrix. If the matrix is sparse, use the linked list. Otherwise, bitmap is a better solution.
I'm trying to implement sequence_insert_at using the add_to_front function here
Everything before
typedef struct sequence *Sequence;
is pasted from another c file.
void sequence_insert_at(Sequence s, int pos, int item)
{
struct node* temp = s->lst;
for(; pos > 0; --pos)
{
temp = temp->rest;
}
add_to_front(&temp, item);
++s->length;
if(!temp->rest)
{
s->end = temp;
}
//s->lst = temp;
}
I don't know why I keep getting a runtime error. if I clone s->lst and traverse the clone, I'm not modifying the pointer to the node in s, but if I change temp, s->lst should have the reflected changes since the nodes are all linked still. Any ideas as to how to fix this? I tried creating another node that is one before the temp after traversal, and then setting it->rest = temp, but that failed as well.
following mistakes a could spot but only so far to get the main function run
new_sequence does not initialize anything in Sequence it creates. lst is not initialized when you access it in sequence_insert_at
struct node* temp = s->lst;
here how it should look like
Sequence new_sequence()
{
Sequence s = malloc(sizeof(struct sequence));
if(!s)
{
printf("Out of memory. Can't allocate s\n");
exit(EXIT_FAILURE);
}
s->lst = malloc(sizeof(struct node));
if(! s->lst) {
printf("Out of memory. Can't allocate lst\n");
}
s->lst->rest = NULL;
s->length = 0;
return s;
}
also s->lst->rest has to be set to NULL, this is what tells that the list has no more elements an not end witch turns obsolete.
struct sequence
{
struct node* lst;
int length;
};
You should be passing the sequence itself to your functions not a pointer to some internal data in the sequence.
add_to_front(&temp, item);
Your sequence_insert_at function should be the one that can handle any position not add_to_front() so it is easier to call with the position 0 from add_to_front() and your having the the hole work done in one function, not a half here and a half there.
void sequence_insert_at(Sequence s, int pos, int item)
{
if(s && pos <= s->length) {
print_sequence(s);
struct node *newnode = malloc(sizeof(struct node));
if (newnode == NULL) {
printf("ERROR! add_to_front ran out of memory!\n");
exit(EXIT_FAILURE);
}
newnode->first = item;
struct node* temp = s->lst;
struct node* prv = NULL;
for(int i = 0; i < pos; i++) {
printf("skip %d\n", temp->first);
prv = temp;
temp = temp->rest;
}
newnode->rest = temp;
if(pos == 0) {
printf("insert as first\n");
s->lst = newnode;
} else {
printf("insert before %d\n", temp->first);
prv->rest = newnode;
}
++s->length;
}
}
and in add_to_front only one statement is needed
void add_to_front(Sequence s, int item) {
sequence_insert_at(s, 0, item);
}
as for inserting at the back of the list
void add_to_back(Sequence s, int item) {
sequence_insert_at(s, s->length, item);
}
A small test with the main function
void print_sequence(Sequence s)
{
struct node* temp = s->lst;
for(int i = 0; i < s->length; temp = temp->rest) {
printf("%d ", temp->first);
i++;
}
printf("\n");
}
int main()
{
Sequence derp = new_sequence();
sequence_insert_at(derp, 0, 14);
add_to_front(derp, 16);
sequence_insert_at(derp, 0, 17);
sequence_insert_at(derp, 2, 15);
add_to_back(derp, 13);
print_sequence(derp);
delete_sequence(derp);
return 0;
}
output is:
17 16 15 14 13
You'll have to go trough the other functions and fix them.
Finally i should note that variable names you have choosen are little bit confusing if not misleading, i would name them this way
typedef struct node {
int data; /* the data that a node holds */
struct node* next; /* the pointer to the next node */
} Node_t;
typedef struct sequence {
struct node* head; /* head or first element of the sequence/list */
int length; /* length is ok but size is better */
} Sequence_t;
The following code causes a memory error in the insert_edge function (in the line p->next = g->edges[x] I guess) for large MAXV values. For smaller ones it works great. Where is the problem? How can I define the struct that it works?
#include <stdlib.h>
#include <stdio.h>
#define MAX_LINE_SIZE (1024*128)
#define MAXV 23947347 /* maximum number of vertices */
#define NULLO 0 /* null pointer */
#define TRUE 1
#define FALSE 0
typedef int bool;
typedef struct edgenode {
int y; /* adjancency info */
int weight; /* edge weight, if any */
struct edgenode *next; /* next edge in list */
} edgenode;
typedef struct {
edgenode *edges[MAXV+1]; /* adjacency info */
int degree[MAXV+1]; /* outdegree of each vertex */
int nvertices; /* number of vertices in the graph */
int nedges; /* number of edges in the graph */
int directed; /* is the graph directed? */
} graph;
initialize_graph(graph *g, bool directed)
{
int i; /* counter */
g -> nvertices = 0;
g -> nedges = 0;
g -> directed = directed;
for (i=1; i<=MAXV; i++)
g->degree[i] = 0;
for (i=1; i<=MAXV; i++)
g->edges[i] = NULL;
}
read_graph(graph *g, bool directed, const char *filename)
{
FILE *f;
char line[MAX_LINE_SIZE], buf[10];
int format, rc;
int edge;
int vertex_n;
int vertex_m;
char *token,*token2, *s;
int v;
int i; /* counter */
/* open file */
f = fopen (filename, "r");
if (f == NULL)
return NULL;
rc = sscanf (line, "%d %d %d", &(vertex_n), &(vertex_m), &(edge));
initialize_graph(g, directed);
for (i=1; i<=edge; i++) {
s = fgets (line, MAX_LINE_SIZE, f);
token = strtok (line, " ");
token2 = strtok (NULL, " ");
int s = atoi(token);
int t = atoi(token2);
printf("%d, %d\n", start, ziel);
insert_edge(g,s,t,directed);
}
}
insert_edge(graph *g, int x, int y, bool directed)
{
edgenode *p; /* temporary pointer */
p = malloc(sizeof(edgenode)); /* allocate storage for edgenode */
p->weight = NULL;
p->y = y;
p->next = g->edges[x];
g->edges[x];
g->edges[x] = p; /* insert at head of list */
g->degree[x] ++;
if (directed == FALSE)
insert_edge(g,y,x,TRUE);
else
g->nedges ++;
}
main()
{
graph g;
read_graph(&g,FALSE, "/path/graph_with_23947347_nodes.mtx");//
}
graph g;
graph is definitively too big to fit on the stack. Put it in the heap instead:
graph* g=malloc(sizeof(graph));
And follow Graham's advice too. It may be too big even for the heap.
It looks like it may be a stack overflow. graph is a large data structure and you are allocating it locally (i.e. on the stack) in main. Try changing main to:
int main(void)
{
graph *g = malloc(sizeof(graph));
if (g != NULL)
{
read_graph(g, FALSE, "/path/graph_with_23947347_nodes.mtx");
free(g);
}
return 0;
}
Are you checking the return value from this malloc?
p = malloc(sizeof(edgenode)); /* allocate storage for edgenode */
It could be that you are simply running out of memory. Check that p is not NULL before proceeding.
p->next = g->edges[x];
g->edges[x];
g->edges[x] = p; /* insert at head of list */
This code doesn't make any sense.
In a single-linked list, you cannot insert a new node before an existing node, without having a pointer to the previous node before it. Otherwise, how can the previous node have its next pointer updated?
This inserts your node after an existing node:
p->next = g->edges[x]->next;
g->edges[x]->next = p;