Memory Error in C struct - c

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;

Related

Malloc breaks function

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

My application crashed without any error, problem with for loop(?)

My teacher gave me a library that describes a single linked list. I am writing a main file to test it, and i ran into a very weird problem.
This is the header for the linked list library (There are more function, but i only putin the one i used):
#ifndef DSSINGLYLINKEDLIST_H
#define DSSINGLYLINKEDLIST_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct _SListEntry SListEntry;
typedef struct _SListIterator SListIterator;
typedef void *SListValue;
/**
* Definition of a #ref SListIterator.
*/
struct _SListIterator {
SListEntry **prevNext;
SListEntry *current;
};
#define SLIST_NULL ((void *) 0)
typedef int (*SListCompareFunc)(SListValue value1, SListValue value2);
typedef int (*SListEqualFunc)(SListValue value1, SListValue value2);
SListEntry *slist_append(SListEntry **list, SListValue data);
SListValue slist_nthData(SListEntry *list, unsigned int n);
unsigned int slist_length(SListEntry *list);
#ifdef __cplusplus
}
#endif
#endif /* #ifndef DSSINGLYLINKEDLIST_H */
This is my .c file:
#include <stdlib.h>
#include <stdio.h>
#include "dssinglylinkedlist.h"
struct _SListEntry {
SListValue data;
SListEntry *next;
};
SListEntry *slist_append(SListEntry **list, SListValue data)
{
/* Create new list entry */
SListEntry *newEntry = malloc(sizeof(SListEntry));
if (newEntry == NULL) {
return NULL;
}
newEntry->data = data;
newEntry->next = NULL;
/* Hooking into the list is different if the list is empty */
SListEntry *rover;
if (*list == NULL) {
/* Create the start of the list */
*list = newEntry;
} else {
/* Find the end of list */
rover=*list;
while (rover->next != NULL) {
rover = rover->next;
}
/* Add to the end of list */
rover->next = newEntry;
}
return newEntry;
}
SListValue slist_nthData(SListEntry *list, unsigned int n)
{
/* Find the specified entry */
SListEntry *entry = slist_nthEntry(list, n);
/* If out of range, return NULL, otherwise return the data */
if (entry == NULL) {
return SLIST_NULL;
} else {
return entry->data;
}
}
unsigned int slist_length(SListEntry *list)
{
SListEntry *entry = list;
unsigned int length = 0;
while (entry != NULL) {
/* Count the number of entries */
++length;
entry = entry->next;
}
return length;
}
I think there's nothing wrong with these code.
I am writing a main using this library to store information of two polynomial:
#include <stdio.h>
#include <stdlib.h>
#include "dssinglylinkedlist.h"
void printPolynomial(SListEntry*);
int main()
{
SListEntry *poly1;
int n;
printf("Input n for poly1: ");
scanf("%d", &n);
printf("Input poly1: ");
for (int i=0; i<=n; i++) {
int *temp = (int *) malloc(sizeof (int));
scanf("%d", temp);
slist_append(&poly1, temp);
}
printPolynomial(poly1);
SListEntry *poly2;
printf("Input n for poly2: ");
scanf("%d", &n);
printf("Input poly2: ");
// for (int i=0; i<=n; i++) {
// int *temp = (int *) malloc(sizeof (int));
// scanf("%d", temp);
// slist_append(&poly2, temp);
// }
// printPolynomial(poly2);
return 0;
}
void printPolynomial(SListEntry *list)
{
int length = (int)slist_length(list);
for (int i = 0; i < length; i++) {
int temp = *((int *)slist_nthData(list,(unsigned int)i));
if (i >0 && temp >= 0) {
printf("+");
}
printf("%d*x^%d", temp, length-i-1);
}
printf("\n");
}
So if i comments the second loop (after i print 'Input poly2', like i wrote above), i can still input my poly1 and print it. But if i un-comments it, my program crashes immediately when i append the first element of poly1.
What is the problem of my code?

How to deal with old references to a resized hash table?

I'm currently working on a hash table implementation in C. I'm trying to implement dynamic resizing, but came across a problem.
If resizing a hash table means creating a new one with double (or half) the size, rehashing, and deleting the old one, how can I deal with old references the user may have made to the old table? Example code (I've omitted error checking just for this example):
int main(int argc, char *argv[])
{
ht = ht_create(5) /* make hashtable with size 5 */
ht_insert("john", "employee"); /* key-val pair "john -> employee" */
ht_insert("alice", "employee");
char *position = ht_get(ht, "alice"); /* get alice's position from hashtable ht */
ht_insert("bob", "boss"); /* this insert exceeds the load factor, resizes the hash table */
printf("%s", position); /* returns NULL because the previous hashtable that was resized was freed */
return 0;
}
In this case position pointed to alice's value which was found in the hashtable. When it was resized, we freed the hash table and lost it. How can I fix this problem, so the user won't have to worry that a previously defined pointer was freed?
EDIT: my current hash table implementation
hash.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hash.h"
#define LOADFACTOR 0.75
typedef struct tableentry /* hashtab entry */
{
struct tableentry *next;
char *key;
void *val;
} tableentry_t;
typedef struct hashtable
{
datatype_t type;
size_t size;
size_t load; /* number of keys filled */
struct tableentry **tab;
} hashtable_t;
/* creates hashtable */
/* NOTE: dynamically allocated, remember to ht_free() */
hashtable_t *ht_create(size_t size, datatype_t type)
{
hashtable_t *ht = NULL;
if ((ht = malloc(sizeof(hashtable_t))) == NULL)
return NULL;
/* allocate ht's table */
if ((ht->tab = malloc(sizeof(tableentry_t) * size)) == NULL)
return NULL;
/* null-initialize table */
size_t i;
for (i = 0; i < size; i++)
ht->tab[i] = NULL;
ht->size = size;
ht->type = type;
return ht;
}
/* creates hash for a hashtab */
static unsigned hash(char *s)
{
unsigned hashval;
for (hashval = 0; *s != '\0'; s++)
hashval = *s + 31 * hashval;
return hashval;
}
static int *intdup(int *i)
{
int *new;
if ((new = malloc(sizeof(int))) == NULL)
return NULL;
*new = *i;
return new;
}
static void free_te(tableentry_t *te)
{
free(te->key);
free(te->val);
free(te);
}
/* loops through linked list freeing */
static void free_te_list(tableentry_t *te)
{
tableentry_t *next;
while (te != NULL)
{
next = te->next;
free_te(te);
te = next;
}
}
/* creates a key-val pair */
static tableentry_t *alloc_te(char *k, void *v, datatype_t type)
{
tableentry_t *te = NULL;
int status = 0;
/* alloc struct */
if ((te = calloc(1, sizeof(*te))) == NULL)
status = -1;
/* alloc key */
if ((te->key = strdup(k)) == NULL)
status = -1;
/* alloc value */
int *d;
char *s;
switch (type)
{
case STRING:
s = (char *) v;
if ((te->val = strdup(s)) == NULL)
status = -1;
break;
case INTEGER:
d = (int *) v;
if ((te->val = intdup(d)) == NULL)
status = -1;
break;
default:
status = -1;
}
if (status < 0)
{
free_te_list(te);
return NULL;
}
te->next = NULL;
return te;
}
static tableentry_t *lookup(hashtable_t *ht, char *k)
{
tableentry_t *te;
/* step through linked list */
for (te = ht->tab[hash(k) % ht->size]; te != NULL; te = te->next)
if (strcmp(te->key, k) == 0)
return te; /* found */
return NULL; /* not found */
}
/* inserts the key-val pair */
hashtable_t *ht_insert(hashtable_t *ht, char *k, void *v)
{
tableentry_t *te;
/* unique entry */
if ((te = lookup(ht, k)) == NULL)
{
te = alloc_te(k, v, ht->type);
unsigned hashval = hash(k) % ht->size;
/* insert at beginning of linked list */
te->next = ht->tab[hashval];
ht->tab[hashval] = te;
ht->load++;
}
/* replace val of previous entry */
else
{
free(te->val);
switch (ht->type)
{
case STRING:
if ((te->val = strdup(v)) == NULL)
return NULL;
break;
case INTEGER:
if ((te->val = intdup(v)) == NULL)
return NULL;
break;
default:
return NULL;
}
}
return ht;
}
static void delete_te(hashtable_t *ht, char *k)
{
tableentry_t *te, *prev;
unsigned hashval = hash(k) % ht->size;
te = ht->tab[hashval];
/* point head to next element if deleting head */
if (strcmp(te->key, k) == 0)
{
ht->tab[hashval] = te->next;
free_te(te);
ht->load--;
return;
}
/* otherwise look through, keeping track of prev to reassign its ->next */
for (; te != NULL; te = te->next)
{
if (strcmp(te->key, k) == 0)
{
prev->next = te->next;
free_te(te);
ht->load--;
return;
}
prev = te;
}
}
hashtable_t *ht_delete(hashtable_t *ht, char *k)
{
size_t i;
if (lookup(ht, k) == NULL)
return NULL;
else
delete_te(ht, k);
}
/* retrieve value from key */
void *ht_get(hashtable_t *ht, char *k)
{
tableentry_t *te;
if ((te = lookup(ht, k)) == NULL)
return NULL;
return te->val;
}
/* frees hashtable created from ht_create() */
void ht_free(hashtable_t *ht)
{
size_t i;
if (ht)
{
for (i = 0; i < ht->size; i++)
if (ht->tab[i] != NULL)
free_te_list(ht->tab[i]);
free(ht);
}
}
/* resizes hashtable, returns new hashtable and frees old */
static hashtable_t *resize(hashtable_t *oht, size_t size)
{
hashtable_t *nht; /* new hashtable */
nht = ht_create(size, oht->type);
/* rehash */
size_t i;
tableentry_t *te;
/* loop through hashtable */
for (i = 0; i < oht->size; i++)
/* loop through linked list */
for (te = oht->tab[i]; te != NULL; te = te->next)
/* insert & rehash old vals into new ht */
if (ht_insert(nht, te->key, te->val) == NULL)
return NULL;
ht_free(oht);
return nht;
}
hash.h
/* a hash-table implementation in c */
/*
hashing algorithm: hashval = *s + 31 * hashval
resolves collisions using linked lists
*/
#ifndef HASH
#define HASH
typedef struct hashtable hashtable_t;
typedef enum datatype {STRING, INTEGER} datatype_t;
/* inserts the key-val pair */
hashtable_t *ht_insert(hashtable_t *ht, char *k, void *v);
/* creates hashtable */
/* NOTE: dynamically allocated, remember to ht_free() */
hashtable_t *ht_create(size_t size, datatype_t type);
/* frees hashtable created from ht_create() */
void ht_free(hashtable_t *ht);
/* retrive value from key */
void *ht_get(hashtable_t *ht, char *k);
hashtable_t *ht_delete(hashtable_t *ht, char *k);
#endif
Do not use the hash table as the container for the data; only use it to refer to the data, and you won't have that problem.
For example, let's say you have key-value pairs, using a structure with the actual data in the C99 flexible array member:
struct pair {
struct pair *next; /* For hash chaining */
size_t hash; /* For the raw key hash */
/* Payload: */
size_t offset; /* value starts at (data + offset) */
char data[]; /* key starts at (data) */
};
static inline const char *pair_key(struct pair *ref)
{
return (const char *)(ref->data);
}
static inline const char *pair_value(struct pair *ref)
{
return (const char *)(ref->data + ref->offset);
}
Your hash table can then be simply
struct pair_hash_table {
size_t size;
struct pair **entry;
};
If you have struct pair_hash_table *ht, and struct pair *foo with foo->hash containing the hash of the key, then foo should be in the singly-linked list hanging off ht->entry[foo->hash % ht->size];.
Let's say you wish to resize the hash table ht. You choose a new size, and allocate enough memory for that many struct pair *. Then, you go through each singly-linked list in each old hash entry, detaching them from the old list, and prepending them to the lists in correct hash table entries in the new hash table. Then you just free the old hash table entry array, replacing it with the new one:
int resize_pair_hash_table(struct pair_hash_table *ht, const size_t new_size)
{
struct pair **entry, *curr, *next;
size_t i, k;
if (!ht || new_size < 1)
return -1; /* Invalid parameters */
entry = malloc(new_size * sizeof entry[0]);
if (!entry)
return -1; /* Out of memory */
/* Initialize new entry array to empty. */
for (i = 0; i < new_size; i++)
entry[i] = NULL;
for (i = 0; i < ht->size; i++) {
/* Detach the singly-linked list. */
next = ht->entry[i];
ht->entry[i] = NULL;
while (next) {
/* Detach the next element, as 'curr' */
curr = next;
next = next->next;
/* k is the index to this hash in the new array */
k = curr->hash % new_size;
/* Prepend to the list in the new array */
curr->next = entry[k];
entry[k] = curr;
}
}
/* Old array is no longer needed, */
free(ht->entry);
/* so replace it with the new one. */
ht->entry = entry;
ht->size = size;
return 0; /* Success */
}
Note that the hash field in struct pair is not modified, nor recalculated.
Having the raw hash (as opposed to modulo table-size), means you can speed up the key search even when different keys use the same slot:
struct pair *find_key(struct pair_hash_table *ht,
const char *key, const size_t key_hash)
{
struct pair *curr = ht->entry[key_hash % ht->size];
while (curr)
if (curr->hash == key_hash && !strcmp(key, pair_key(next)))
return curr;
else
curr = curr->next;
return NULL; /* Not found. */
}
In C, the logical and operator, &&, is short-circuiting. If the left side is not true, the right side is not evaluated at all, because the entire expression can never be true in that case.
Above, this means that the raw hash value of the key is compared, and only when they do match, the actual strings are compared. If your hash algorithm is even halfway good, this means that if the key already exists, typically only one string comparison is done; and if the key does not exist in the table, typically no string comparisons are done.
You can deal with them the same way the standard library (C++) deals with this exact problem:
Some operations on containers (e.g. insertion, erasing, resizing) invalidate iterators.
For instance std::unordered_map which is basically a hash table implemented with buckets has these rules:
insertion
unordered_[multi]{set,map}: all iterators invalidated when rehashing
occurs, but references unaffected [23.2.5/8]. Rehashing does not occur
if the insertion does not cause the container's size to exceed z * B
where z is the maximum load factor and B the current number of
buckets. [23.2.5/14]
erasure
unordered_[multi]{set,map}: only iterators and references to the
erased elements are invalidated [23.2.5/13]
Iterator invalidation rules
The C++ concept of iterators is a generalization of pointers. So this concept can be applied to C.
Your only other alternative is that instead of holding the objects directly into the container you add another level of indirection and hold some sort of proxy. And so the elements always stay at the same position in memory. It's the proxies that move around on resizing/inserting etc. But you need to analize this scenario: are the added double indirection (which will surely affect performance in a negative way) and increase implementation complexity worth it? Is is that important to have persistent pointers?

Writing dynamic double linked list with a sentinel and struct type in C

I was trying to create that list by using example from "Introduction to Algorithms (3rd Edition)". But I experienced some difficulties which I cannot understand. Firstly, the work of the program is changing due to existence of printf function in precise place. There is one place which needs printf and a lot of other places which can't have printf. Secondly, value of L.nil.next changes after every line of code which does something referred to struct. Unfortunately, because of that changing value I cannot fix the program. I would be very pleased if someone fixed and forced it to work like dynamic double linked list with a sentinel.
There is a code
#include <stdio.h>
#include <stdlib.h>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
struct sentinel{
struct listel* nil;
};
struct listel{
struct listel* prev;
int key;
struct listel* next;
};
int list_search(struct sentinel *L, int k);
void list_insert(struct sentinel *L, struct listel *x);
void list_delete(struct sentinel *L, struct listel *x);
int main(int argc, char *argv[]) {
int s;
struct sentinel *L=(struct sentinel*)malloc(sizeof(struct sentinel));
printf("---sentinel created\n"); //FORCED TO WRITE
// printf("L.nil = %p\nL.nil.prev = %p\nL.nil.next = %p\n", L->nil, L->nil->prev, L->nil->next);
L->nil->next=L->nil;
L->nil->prev=L->nil;
// printf("sentinel parameters set\n"); //NOT ALLOWED TO WRITE
// printf("L.nil = %p\nL.nil.prev = %p\nL.nil.next = %p\n", L->nil, L->nil->prev, L->nil->next); //NOW ALLOWED TO WRITE
struct listel *x=(struct listel*)malloc(sizeof(struct listel));
printf("created x\n");
// printf("L.nil.next=%p\n", L->nil->next); //NOT ALLOWED TO WRITE
// printf("prev = %p\nkey = %d\nnext = %p\n", x->prev, x->key, x->next); //NOW ALLOWED TO WRITE
struct listel *y=(struct listel*)malloc(sizeof(struct listel));
printf("created y\n");
// printf("L.nil.next=%p\n", L->nil->next); //NOT ALLOWED TO WRITE
struct listel *z=(struct listel*)malloc(sizeof(struct listel));
printf("created z\n");
// printf("L.nil.next=%p\n", L->nil->next); //NOT ALLOWED TO WRITE
x->key=8;
// printf("x.key = %d is set\n", x->key); //NOT ALLOWED TO WRITE
// printf("L.nil.next=%p\n", L->nil->next); //NOT ALLOWED TO WRITE
// x->next=L->nil->next; //Trying to check line from list_insert without using that function
// printf("x.next=L.nil.next=%p\n", x->next); //NOT ALLOWED TO WRITE
list_insert(L, x); //I have checked no further
x->key=3;
list_insert(L, y);
x->key=4;
list_insert(L, z);
printf("%d\n", list_search(L, 8));
printf("%d\n", list_search(L, 6));
printf("%d\n", list_search(L, 3));
return 0;
}
int list_search(struct sentinel *L, int k){
struct listel *x=(struct listel*)malloc(sizeof(struct listel));
x = L->nil->next;
while (x!=L->nil && x->key!=k) x=x->next;
if (x==L->nil) return 0;
return (x->key);
}
void list_insert(struct sentinel *L, struct listel *x){
printf(" LIST INSERT\n");
// printf(" L.nil.next=%p\n", L->nil->next);
x->next=L->nil->next;
// printf(" x.next=L.nil.next=%p\n", x->next); //NOT ALLOWED TO WRITE - I have checked no further
L->nil->next->prev=x;
L->nil->next=x;
x->prev=L->nil;
}
void list_delete(struct sentinel *L, struct listel *x){
x->prev->next=x->next;
x->next->prev=x->prev;
}
malloc does not initialise the allocated memory to anything sensible, so
struct sentinel *L=(struct sentinel*)malloc(sizeof(struct sentinel));
printf( ... L->nil, L->nil->prev ... UNDEFINED!! CRASH!! );
L->nil->next=L->nil; // UNDEFINED!! CRASH!!
L->nil->prev=L->nil; // UNDEFINED!! CRASH!!
Delete all this and start with:
struct sentinel *L=(struct sentinel*)malloc(sizeof(struct sentinel));
L->nil = NULL;
You should be able to see that L->nil->prev and L->nil->next are meaningless unless L actually contains a valid list element, e.g. if you did this:
struct listel *x=(struct listel*)malloc(sizeof(struct listel));
x->prev = NULL;
x->next = NULL;
L->nil = x;
then L->nil->prev == x->prev == NULL and L->nil->next == x->next == NULL
Looking at the code, it's working with a circular double linked list with a sentinel node. This is how C++ std::list is usually implemented.
Use a typedef to simplify the code. This syntax is "legacy" compatible:
typedef struct listel_{
struct listel_* next;
struct listel_* prev;
int key;
}listel;
A sentinel node is the same as a regular node, and should use the same struct, in this case listel. Example code to initialize a sentinel node to represent an empty list by setting the sentinel node's next (first node) pointer and previous (last node) pointer to point to the sentinel node.
listel *L
/* ... */
/* allocate and initialize a sentinel node */
L = (listel *)malloc(sizeof(listel));
L->next = L; /* pointer to first node of list */
L->prev = L; /* pointer to last node of list */
list_insert should take a key as input and allocate a node internally (no need for x, y, z):
void list_insert(listel *L, int k);
list_delete should take a key as input and delete a node internally.
void list_insert(listel *L, int k);
list_search should not allocate a node, it works with an existing list. Normally list_search would return a pointer to node if found or NULL if not found.
listel * list_search(listel *L, int k);
Working example with added display function:
#include <stdio.h>
#include <stdlib.h>
typedef struct listel_{
struct listel_* next;
struct listel_* prev;
int key;
}listel;
void list_display(listel *L);
listel * list_search(listel *L, int k);
void list_insert(listel *L, int k);
void list_delete(listel *L, int k);
int main(int argc, char *argv[]) {
listel *L;
/* allocate sentinel node */
L =(listel *)malloc(sizeof(listel));
L->next = L;
L->prev = L;
/* display list while inserting 3 nodes */
list_display(L);
list_insert(L, 8);
list_display(L);
list_insert(L, 3);
list_display(L);
list_insert(L, 4);
list_display(L);
/* display search list results */
printf("%d %d\n", (list_search(L, 8) != NULL) ? 8 : 0, 8);
printf("%d %d\n", (list_search(L, 6) != NULL) ? 6 : 0, 6);
printf("%d %d\n", (list_search(L, 3) != NULL) ? 3 : 0, 3);
printf("\n");
/* display list while deleting 3 nodes */
list_display(L);
list_delete(L, 3);
list_display(L);
list_delete(L, 8);
list_display(L);
list_delete(L, 4);
list_display(L);
/* free sentinel node */
free(L);
return 0;
}
void list_display(listel *L)
{
listel *e;
if(L == NULL || L->next == L) /* if list empty */
return; /* return */
e = L->next; /* display list forward */
do{
printf("%d ", e->key);
e = e->next;
}while(e != L);
printf("\n");
e = L->prev; /* display list backward */
do{
printf("%d ", e->key);
e = e->prev;
}while(e != L);
printf("\n\n");
}
listel* list_search(listel *L, int k){
listel *e;
if(L == NULL || L->next == L) /* if list empty */
return NULL; /* return null */
e = L->next;
while (e != L && e->key != k) e=e->next;
if (e == L) /* if not found */
return NULL; /* return null */
return e;
}
void list_insert(listel *L, int k){
listel *e;
if(L == NULL) /* if no sentinel node */
return; /* return */
e = (listel *)malloc(sizeof(listel));
if(e == NULL) /* if can't allocate node */
return; /* return */
e->next = L->next; /* e->next = first node */
e->prev = L; /* e->prev = sentinel */
e->key = k;
L->next->prev = e;
L->next = e;
}
void list_delete(listel *L, int k){
listel *e;
if(L == NULL || L->next == L) /* if list empty */
return; /* return */
e = L->next;
while (e != L && e->key != k) e=e->next;
if (e == L) /* if not found */
return; /* return null */
e->prev->next = e->next; /* remove node from list */
e->next->prev = e->prev;
free(e); /* free node */
}

How preprocessor (i.e.#define) works? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I have the basic knowledge of preprocessor.But i have never understood how it works.Can some body explain me how it works?I would prefer practical explanation.Thank you.
#define A 1234
Literally as far as the compiler is concerned, every instance of A is now 1234.
Its useful for code readability and modifieability. If you have a constant number for instance thats used in 7-8 different functions, you can #define it and use a token instead, and then change it in 1 place rather then 7-8.
Alternatives to using #define are using constant variables or enums.
#define myVar 755
const int myVar = 755;
enum{ myVar = 755 };
Are all functionally equivalent in most cases.
#define MY_MACRO my_var
Everytime your compilator finds "MY_MACRO" in your code while creating the binary code, it considers you wrote "my_var".
In one of my assignment i have implemented simple pre-processor using c.I have used the simple hash table to store the name and its definition.
for example,
#define a 4
so here a is name and 4 is its definition.
So both a and 4 will be stored in the hash table.
now whenever in program name 'a' is encountered then it will be simply replaced by 4.
i am posting my code in c for pre-processor.Which is very simple.But it would be very helpful for you to understand how pre-processor works.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define HASHSIZE 101
#define BUFSIZE 100
#define MAXWORD 100
struct tnode {
int loc[10]; // to store the locations at which words occur
int i; // to store the index of array loc
char *word;
int count;
struct tnode *left;
struct tnode *right;
};
static struct nlist *hashtab[HASHSIZE];
int getword(char *word, int lim);
struct tnode *addtree(struct tnode *, char *);
void treeprint(struct tnode *);
struct tnode *talloc(void);
struct nlist {
/* table entry: */
struct nlist *next;
/* next entry in chain */
char *name;
/* defined name */
char *defn;
/* replacement text */
};
char buf[BUFSIZE];
int bufp = 0;
unsigned hash(char *s);
struct nlist *lookup(char *s);
char *strdup1(char *);
struct nlist *install(char *name, char *defn);
int undef(char *s); // this function will remove entry
struct tnode *z[10]; // to store address of each node(word)
int total = 0; // index for array z
char s1[1000]; // to store entire input
static int q = 0; // index to s1
int main() {
struct nlist *pt;
char word[100];
char name1[10];
char defn1[10];
int i = 0;
int k = 0;
/*
#define pi 5 is entered then...*/
while (getword(word, MAXWORD) != EOF) {
if (isalnum(word[0]) && (i == 0)) {
if ((pt = lookup(&word[0])) !=
NULL) // if name1(pi) is already present then replace it with its definition name(5)
{
strcpy(word, (pt->defn)); // if pi is alerady there then replace name by its definition
// strcpy((pt->defn),word);
for (k = 0; word[k] != '\0'; k++, q++) {
s1[q] = word[k];
}
} else // otherwise print the word
{
for (k = 0; word[k] != '\0'; k++, q++) {
s1[q] = word[k];
}
}
}
if (isalnum(word[0])) {
if (i == 2) // copy word to defn1(i.e. defn1=5)
{
strcpy(defn1, word);
install(name1, defn1);
i = 0;
}
}
if (isalnum(word[0])) {
if (i == 1) // copy the word to name1(i.e. name1=pi)
{
strcpy(name1, word);
i++;
}
}
if (word[0] == '#') {
if ((strcmp(word, "#define")) == 0) // if #define found then increase i to get next word(i.e. pi)
{
i++;
} else {
for (k = 0; word[k] != '\0'; k++, q++) {
s1[q] = word[k];
}
}
}
}
// printf("%d",i);
// printf("%s %s",name,defn);
// printf("%s",pt->defn);
printf("%s", s1);
}
unsigned hash(char *s) {
unsigned hashval;
for (hashval = 0; *s != '\0'; s++)
hashval = *s + 31 * hashval;
return hashval % HASHSIZE;
}
/* lookup: look for s in hashtab */
struct nlist *lookup(char *s) {
struct nlist *np;
for (np = hashtab[hash(s)]; np != NULL; np = np->next)
if (strcmp(s, np->name) == 0)
return np;
/* found */
return NULL;
/* not found */
}
/* install: put (name, defn) in hashtab */
struct nlist *install(char *name, char *defn) {
struct nlist *np;
unsigned hashval;
if ((np = lookup(name)) == NULL) { /* not found */
np = (struct nlist *)malloc(sizeof(*np));
if (np == NULL || (np->name = strdup1(name)) == NULL)
return NULL;
hashval = hash(name);
np->next = hashtab[hashval];
hashtab[hashval] = np;
} else
/* already there */
free((void *)np->defn);
/*free previous defn */
if ((np->defn = strdup1(defn)) == NULL)
return NULL;
return np;
}
char *strdup1(char *s) {
char *p;
/* make a duplicate of s */
p = (char *)malloc(strlen(s) + 1); /* +1 for '\0' */
if (p != NULL)
strcpy(p, s);
return p;
}
int undef(char *s) {
struct nlist *np1;
if ((np1 = lookup(s)) != NULL) {
hashtab[hash(s)] = NULL; // delete the entry in array hashtab associated to s
free(np1); // free memory allocated to s
return 1; // if sucessful then return 1 else 0
}
return 0;
}
int getword(char *word, int lim) {
int c, getch(void);
void ungetch(int);
char *w = word;
while (isspace(c = getch())) {
s1[q] = ' ';
q++;
} // takes the space in string s1
if (c != EOF)
*w++ = c;
if (!isalnum(c) && (c != '#')) /*takes all character except #,digit and number in s*/
{
if (c != EOF) {
s1[q] = c;
q++;
}
*w = '\0';
return c;
}
for (; --lim > 0; w++)
if (!isalnum(*w = getch())) {
ungetch(*w);
break;
}
*w = '\0';
return word[0];
}
int getch(void) /* get a (possibly pushed-back) character */
{
return (bufp > 0) ? buf[--bufp] : getchar();
}
void ungetch(int c)
/* push character back on input */
{
if (bufp >= BUFSIZE)
printf("ungetch: too many characters\n");
else
buf[bufp++] = c;
}
/* addtree: add a node with w, at or below p */
struct tnode *addtree(struct tnode *p, char *w) {
int cond;
if (p == NULL) {
/* a new word has arrived */
p = talloc();
/* make a new node */
p->word = strdup(w);
p->count = 1;
p->left = p->right = NULL;
} else if ((cond = strcmp(w, p->word)) == 0)
p->count++;
/* repeated word */
else if (cond < 0)
/* less than into left subtree */
p->left = addtree(p->left, w);
else
/* greater than into right subtree */
p->right = addtree(p->right, w);
return p;
}
/* talloc: make a tnode */
struct tnode *talloc(void) {
return (struct tnode *)malloc(sizeof(struct tnode));
}
void treeprint(struct tnode *p) {
int i = 0;
for (i = 0; i < total; i++)
printf("%s", z[i]->word);
}
The code is self explanatory.Mind you it is very simple pre-processor.
The purpose of a #define is to give a value or macro a simple name that you can use in your program. This is called a symbolic constant. In stead of having to remember the value or retype the macro everywhere you need it, you define it once and use the name wherever you need. Also, to define for example the size of something (array, buffer), you define it once. Should you later need to change the size, you only need to edit the definition. These are only some examples of #defines.
The preprocessor reads the program text and replaces the macros and constants with their actual values. If a part of the program text is enclosed in #ifdef...#endif (conditional compilation) and the #ifdef evalates to FALSE, then that part is left out. In the next step the actual compiler compiles the resulting program text into actual code.

Resources