I have a program that utilizes linked lists (as structs) to store integer elements (essentially on a stack). The problem is, when I insert integers into an array accessed via a pointer and try to print it, the numbers are not the integers that were entered (looks like a pointer, although not sure, when I try to dereference it, I get errors in compiling). New to C and this is for a class assignment, so looking more for explanations specifically on pointers and guidance as to what I may be doing wrong. I am attaching the code I've done.
For reference, the default size per node is 5 integers.
What running my code looks like:
What it should look like:
My guess is that the problem relies within the push/pop/top methods, although I did have some luck with using pointers in the make_node method, although then I got segmentation errors in the rest of the methods.
Thanks!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "int_stack.h"
/* Structure definitions from header file - all methods defined there as well.
struct is_node {
int *contents; Pointer to memory for storing up to node_capacity ints
(this has a fixed size and is determined at stack creation)
int next_index; Index of the next open position in the array of contents; starts at 0
struct is_node *next; Pointer to subsequent node in list (or NULL)
};
struct int_stack {
int size; Number of elements currently in stack
int node_capacity; Max elements per node
struct is_node *head; First node with stack contents; the contents
may be empty , but head should never be NULL
};
*/
struct is_node *make_node(int node_capacity);
/*
* Creates a stack, assigning appropriate variables.
*/
struct int_stack *make_stack(int node_capacity) {
struct int_stack *stack = NULL;
stack = malloc(sizeof(struct int_stack));
if (stack == NULL) {
fprintf(stderr, "Memory error!\n");
exit(-1);
}
stack->size = 0;
stack->node_capacity = node_capacity;
stack->head = make_node(node_capacity);
return stack;
}
/*
* Cleans up all memory used by the given stack.
*/
void free_stack(struct int_stack *stk) {
struct is_node *curnode = stk->head;
while (curnode != NULL) {
struct is_node *nextnode = curnode->next;
free(curnode);
curnode = nextnode;
}
free(stk);
}
/*
* Resets the stack, but allows it to still be used.
*/
void reset_stack(struct int_stack *stk) {
if (stk != NULL) {
struct is_node *curnode = stk->head;
while (curnode != NULL) {
struct is_node *nextnode = curnode->next;
free(curnode);
curnode = nextnode;
}
stk->size = 0;
stk->head = make_node(stk->node_capacity);
} else {
printf("Error: Stack is NULL. Cannot reset it.");
}
}
/*
* Prints the stack. Contents delimited with [] if node is at capacity
* or (] if not. The values of each node are seperated by commas.
*/
void print_stack(struct int_stack *stk) {
int i;
struct is_node *curnode = stk->head;
/* Count number of nodes */
int node_count = 1;
while (curnode->next != NULL) {
++node_count;
curnode = curnode->next;
}
/* Walk to end of stack and insert */
while (node_count > 0) {
curnode = stk->head;
for (i = 1; i < node_count; ++i) {
curnode = curnode->next;
}
if (curnode->next_index >= stk->node_capacity) {
printf("[");
} else {
printf("(");
}
for (i = curnode->next_index - 1; i >= 0; --i) {
if (i == 0) {
printf("%d]", curnode->contents[i]);
} else {
printf("%d,", curnode->contents[i]);
}
}
--node_count;
}
printf("\n");
}
/*
* Lets the user know if the stack is empty
*/
int is_empty(struct int_stack *stk) {
if(stk->size == 0) {
return 1;
}
return 0;
}
/*
* Pushes an int onto the stack
*/
void push(struct int_stack *stk, int v) {
/* Walk to end of stack and insert */
struct is_node *curnode = stk->head;
while (curnode->next != NULL) {
curnode = curnode->next;
}
if(curnode->next_index >= stk->node_capacity) {
struct is_node *new_node = make_node(stk->node_capacity);
new_node->contents[new_node->next_index] = v;
new_node->next_index += 1;
curnode->next = new_node;
} else {
curnode->contents[curnode->next_index] = v;
curnode->next_index = curnode->next_index + 1;
}
stk->size += 1;
}
/*
* Pulls the first int on the stack off the stack
*/
int pop(struct int_stack *stk) {
if (!is_empty(stk)) {
int top;
struct is_node *prevnode = stk->head;
struct is_node *curnode = stk->head;
struct is_node *nextnode = stk->head->next;
while (nextnode != NULL) {
if (nextnode->next != NULL) {
prevnode = curnode;
}
curnode = nextnode;
nextnode = curnode->next;
}
top = curnode->contents[curnode->next_index - 1];
curnode->next_index = curnode->next_index - 1;
if (curnode->next_index == 0) {
free(curnode);
curnode = NULL;
prevnode->next = NULL;
}
stk->size -= 1;
return top;
}
return -1;
}
/*
* Returns the top value from the stack.
*/
int top(struct int_stack *stk) {
struct is_node *curnode = stk->head;
while (curnode->next != NULL) {
curnode = curnode->next;
}
return curnode->contents[curnode->next_index - 1];
}
/*
* Helper method for creating nodes in the stack.
*/
struct is_node *make_node(int node_capacity) {
struct is_node *node = malloc(sizeof(struct is_node));
if (node == NULL) {
fprintf(stderr, "Memory error!\n");
exit(-1);
}
node->next = NULL;
node->next_index = 0;
int node_contents[node_capacity];
node->contents = node_contents;
return node;
}
make_node() sets node->contents to a local variable that will go out of scope as soon as the function ends. If you use contents outside the function you'll have undefined behavior.
Related
I use the following code snippet to add an element to the back of my doubly circular linked list.
typedef struct node
{
int nb;
struct node *prev;
struct node *next;
} st_node;
void add_back(st_node *origin, st_node *node)
{
st_node *tmp;
if (!origin || !node)
exit(1);
tmp = origin;
while (tmp->next != origin)
tmp = tmp->next;
tmp->next = node;
node->prev = tmp;
node->next = origin;
origin->prev = node;
}
Then I print my list with the folling function :
void printer(st_node *origin)
{
st_node *node;
node = origin;
while (node->next != origin)
{
printf("%d\n", node->nb);
node = node->next;
}
printf("%d\n", node->nb);
}
I got the origin value with printf and then random values in a loop. I don't know what to do and I realized origin->prev = node; was causing the problem inside the add_back function but I don't know why.
Here's the main:
int main(int ac, char **av)
{
st_node *stack;
int i;
if (ac <= 2)
return (1);
stack = create_element(atoi(av[1]));
i = 2;
while (i < ac)
add_back(stack, create_element(atoi(av[i++])));
printf("Stack:\n");
printer(stack);
}
st_node *create_element(int nb)
{
st_node *element;
element = malloc(sizeof(st_node *));
element->nb = nb;
element->next = element;
element->prev = element;
return (element);
}
Your create_element() function is wrong. It does not allocate enough memory for each node. This ...
st_node *element;
element = malloc(sizeof(st_node *));
... should be ...
st_node *element;
element = malloc(sizeof(st_node));
... or, better ...
st_node *element;
element = malloc(sizeof(*element));
With that correction, and adding a closing brace to main(), your program works for me.
Several bugs:
malloc in create_element is wrong
In add_back, the order of the link setting is wrong
In add_back, no need to loop to find the tail node. It is origin->prev
The printer function will segfault on an empty list because it is dereferencing node before checking whether it is non-null
The first if in main is too strict: It does not allow: ./myprogram 1 (i.e. a list with one element)
Here is the refactored/working code. It is annotated with the bugs/fixes:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int nb;
struct node *prev;
struct node *next;
} st_node;
st_node *
create_element(int nb)
{
st_node *element;
// NOTE/BUG: does _not_ allocate enough space (causing UB/undefined behavior)
#if 0
element = malloc(sizeof(st_node *));
#else
element = malloc(sizeof(*element));
#endif
element->nb = nb;
element->next = element;
element->prev = element;
return (element);
}
void
add_back(st_node *origin, st_node *node)
{
st_node *tmp;
if (!origin || !node)
exit(1);
// NOTE/BUG: no need to traverse -- origin->prev is the back
#if 0
tmp = origin;
while (tmp->next != origin)
tmp = tmp->next;
#else
tmp = origin->prev;
#endif
// NOTE/BUG: order and set is incorrect -- causes self loop
#if 0
tmp->next = node;
node->prev = tmp;
node->next = origin;
#else
node->prev = tmp;
node->next = tmp->next;
tmp->next = node;
#endif
origin->prev = node;
}
void
printer(st_node *origin)
{
st_node *node;
// NOTE/BUG: this will segfault on an empty list
#if 1
node = origin;
while (node->next != origin) {
printf("%d\n", node->nb);
node = node->next;
}
printf("%d\n", node->nb);
#else
node = origin;
if (node != NULL) {
while (1) {
printf("%d\n", node->nb);
node = node->next;
if (node == origin)
break;
}
}
#endif
}
int
main(int ac, char **av)
{
st_node *stack;
int i;
// NOTE/BUG: does _not_ allow for list of only one element
#if 0
if (ac <= 2) {
#else
if (ac < 2) {
#endif
printf("main: too short\n");
return (1);
}
stack = create_element(atoi(av[1]));
// NOTE/BUG: for loop is cleaner
#if 0
i = 2;
while (i < ac)
add_back(stack, create_element(atoi(av[i++])));
#else
for (i = 2; i < ac; ++i)
add_back(stack, create_element(atoi(av[i])));
#endif
printf("Stack:\n");
printer(stack);
}
In the above, I used cpp conditionals to denote old/broken vs. new/fixed code:
#if 0
// old code
#else
// new code
#endif
The above code fixed most of the bugs, but the program could not create an empty list.
Here's some more cleanup/refactoring to make the program more general. In particular, I generalized add_back to allow adding a node to an empty list. In the original code, it treated this as a fatal exit condition.
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int nb;
struct node *prev;
struct node *next;
} st_node;
st_node *
create_element(int nb)
{
st_node *element;
element = malloc(sizeof(*element));
element->nb = nb;
element->next = element;
element->prev = element;
return (element);
}
st_node *
add_back(st_node *origin, st_node *node)
{
st_node *tmp;
if (node == NULL)
exit(1);
do {
// add to empty list
if (origin == NULL) {
origin = node;
break;
}
tmp = origin->prev;
node->prev = tmp;
node->next = tmp->next;
tmp->next = node;
origin->prev = node;
} while (0);
return origin;
}
void
printer(st_node *origin)
{
st_node *node;
node = origin;
if (node != NULL) {
while (1) {
printf("%d\n", node->nb);
node = node->next;
if (node == origin)
break;
}
}
}
int
main(int ac, char **av)
{
st_node *stack = NULL;
int i;
for (i = 1; i < ac; ++i)
stack = add_back(stack, create_element(atoi(av[i])));
printf("Stack:\n");
printer(stack);
}
I'm coding a hash table that maps strings to integers which has and array with pointers to nodes of a linked list. It appears that I'm getting a segmentation fault in the set value method where I'm comparing the strings to see if a specific key is already in the hash table.
typedef struct _node
{
char *key;
int value;
struct _node *next; /* pointer to the next node in the list */
} node;
/*
* Declaration of the hash table struct.
* 'slot' is an array of node pointers, so it's a pointer to a pointer.
*/
typedef struct
{
node **slot;
} hash_table;
int hash(char *s)
{
int sum, size, i;
sum = 0;
size = strlen(s);
for (i = 0; i < size; i++)
{
sum += (int) s[i];
}
return (sum % SIZE_ARRAY);
}
node *create_node(char *key, int value)
{
node *result = (node *)malloc(sizeof(node));
if (result == NULL)
{
fprintf(stderr, "Fatal error: out of memory. "
"Terminating program.\n");
exit(1);
}
result->key = key;
result->value = value;
result->next = NULL;
return result;
}
/* Create a new hash table. */
hash_table *create_hash_table()
{
hash_table *table = (hash_table *)malloc(sizeof(hash_table));
if (table == NULL)
{
fprintf(stderr, "Fatal error: out of memory. "
"Terminating program.\n");
exit(1);
}
table->slot = (node **)calloc(SIZE_ARRAY, sizeof(node *));
if (table->slot == NULL)
{
fprintf(stderr, "Fatal error: out of memory. "
"Terminating program.\n");
exit(1);
}
return table;
}
void set_value(hash_table *ht, char *key, int value)
{
int indx = hash(key);
int found = 0;
node *new_node;
node *list = ht->slot[indx];
while (list != NULL)
{
if (strcmp(list->key, key) == 0)
{
found = 1;
list->value = value;
}
list++;
}
if (found == 0)
{
new_node = create_node(key, value);
new_node->next = ht->slot[indx];
ht->slot[indx] = new_node;
}
}
I used gdp to try and debug, and it seems like the error comes from the line "if (strcmp(list->key, key) == 0)", I think it might have something to do with the pointers but I'm not sure how to fix it.
The list++ in your while loop is wrong. You want: list = list->next And, in that loop, under the if you want a break; after list->value = value;
You don't really need found as you can hook off list.
Here's some refactored code:
void
set_value(hash_table * ht, char *key, int value)
{
int indx = hash(key);
node *new_node;
node *list = ht->slot[indx];
while (list != NULL) {
if (strcmp(list->key, key) == 0) {
list->value = value;
break;
}
list = list->next;
}
if (list == NULL) {
new_node = create_node(key, value);
new_node->next = ht->slot[indx];
ht->slot[indx] = new_node;
}
}
I'm writing a code that splits a doubly linked list list into two lists listA and listB and prints them out. Code seems to get job done but in the end program crashes. Debugger throws
Run-Time Check Failure #2 - Stack around the variable 'listA' was corrupted. and Run-Time Check Failure #2 - Stack around the variable 'list' was corrupted. I've read this might be caused by not enough memory allocated for my structure, but how much should I allocate?
Whole code:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int val;
struct node* prev;
struct node* next;
}Node;
typedef struct list {
Node* head;
Node* tail;
}List;
void init(List* l) {
l->head = NULL;
l->tail = NULL;
}
Node* create(int val) {
Node* ptr = (Node*)malloc(sizeof(Node));
ptr->val = val;
ptr->next = NULL;
ptr->prev = NULL;
return ptr;
}
void printList(const List* list) {
Node *ptr = list->head;
while (ptr != NULL) {
printf("%i ", ptr->val);
ptr = ptr->next;
}
puts("");
free(ptr);
}
void pushLast(List* l, Node* node) {
if (l->head == NULL) {
l->head = node;
l->tail = node;
}
else {
node->prev = l->tail;
l->tail->next = node;
l->tail = node;
}
}
void splitList(const List* list) {
List* listA;
List* listB;
init(&listA);
init(&listB);
Node* ptr = list->head;
int i = 0;
while (ptr != NULL) {
Node* node = create(ptr->val);
if (i % 2 == 0)
pushLast(&listA, node);
else
pushLast(&listB, node);
i++;
ptr = ptr->next;
}
puts("Input list");
printList(list);
puts("Odd nodes list:");
printList(&listA);
puts("Even nodes list:");
printList(&listB);
}
int main(void) {
List* list;
init(&list);
int i;
for (i = 1; i <= 10; i++) {
Node* node = create(i);
pushLast(&list, node);
}
splitList(&list);
return 0;
}
Output received:
Input list:
1 2 3 4 5 6 7 8 9 10
Odd nodes list:
1 3 5 7 9
Even nodes list:
2 4 6 8 10
Any help will be welcomed.
First, you are not allocating memory for pointers list, listA, and listB to point to.
Second, you are defining list, listA, and listB as List *. Then passing &list, &listA, &listB - which are of type List ** - to your functions, whereas your functions are expecting List *.
You need to make below changes in splitList(). (Shown only relevant part of code which has errors - or need addition of malloc):
void splitList(const List* list)
{
List *listA;
List *listB;
/* Allocate memory to which these pointers will point */
if ((listA = malloc(sizeof(List))) == NULL) {
/* Error handling code */
exit(1);
}
if ((listB = malloc(sizeof(List))) == NULL) {
/* Error handling code */
exit(1);
}
/* ... */
while (ptr != NULL)
{
Node* node = create(ptr->val);
if (i % 2 == 0)
/* pushLast(&listA, node); */ /* ISSUE here */
pushLast(listA, node);
else
/* pushLast(&listB, node); */ /* ISSUE here */
pushLast(listB, node);
i++;
ptr = ptr->next;
}
/* ... */
puts("Odd nodes list:");
/* printList(&listA); */ /* ISSUE here */
printList(listA);
free(ListA); /* Free 1 */
puts("Even nodes list:");
/* printList(&listB); */ /* ISSUE here */
printList(listB);
free(ListB); /* Free 2 */
}
Also, you need to make similar changes in main:
int main(void)
{
List* list;
/* Allocate memory */
if((list = malloc(sizeof(List))) == NULL) {
/* Error handling code */
exit(1);
}
/* init(&list); */ /* ISSUE here */
init(list);
int i;
for (i = 1; i <= 10; i++)
{
Node* node = create(i);
/* pushLast(&list, node); */ /* ISSUE here */
pushLast(list, node);
}
/* splitList(&list); */ /* ISSUE here*/
splitList(list);
free(list); /* free 3 */
return 0;
}
Also note that you need to properly free all the memory allocated using malloc to avoid memory leak. It can be seen that you are NOT freeing all the nodes in. All the you have freed is just one node in printList() function.
I am implementing a simple version of malloc, realloc, and free for an assignment and having trouble debugging. My code seems to be working for malloc, but the realloc tests are resulting in a seg fault. Specifically, the pointer passed to free() seems to be the problem.
There is a "free list" to manage the list of previously allocated blocks of memory. Each node in this list maintains the next and previous blocks, and an int free which is set to 1 when the memory is available, 0 otherwise.
void *mm_malloc(size_t size) {
if (size <= 0) return NULL;
struct list_node *node;
if (!list_head) {
node = request_block(size);
list_head = node;
list_tail = node;
} else {
node = get_free_block(size);
if (!node) { //no available existing block
node = request_block(size);
if (!node) { //request failed
return NULL;
}
} else { //available existing block
//TODO: split block
node->free = 0;
}
}
return memset(node+1, 0, node->size);
}
void *mm_realloc(void *ptr, size_t size) {
if (size <= 0) return NULL;
if (!ptr) return mm_malloc(size);
struct list_node *node = (struct list_node*)ptr - 1;
if (node->size >= size) {
// TODO: free extra space
return ptr;
}
void *new_block = mm_malloc(size);
if (!new_block) return NULL;
memcpy(new_block, ptr, node->size);
free(ptr); //Error happens with this call.
return new_block;
}
void mm_free(void *ptr) {
if (!ptr) return;
struct list_node *node = (struct list_node*)ptr - 1;
node->free = 1;
}
EDIT: left out some important helper functions
struct list_node *get_free_block(size_t size) {
struct list_node *curr = list_head;
while (curr && !(curr->free && curr->size >= size)) {
curr = curr->next;
} return curr;
}
struct list_node *request_block(size_t size) {
struct list_node *node = sbrk(0);
void *request = sbrk(size + NODE_SIZE);
if (request == (void*) -1) { // attempted sbrk failed
return NULL;
}
if (list_tail) {
node->prev = list_tail;
list_tail->next = node;
list_tail = node;
}
node->next = NULL;
node->free = 0;
node->size = size;
return node;
}
I have a program where three values are inserted into linked lists. When I try to iterate through the list I only get the first value printed. Sorry if the function names are confusing I'm still new to c and I'm trying to use the function and variable names gave me just to make my life easier when taking a test. I'm also pretty unfamiliar with debugger and how I would use it to find out what is going on here. Thanks in advance.
void program_header(char i[]);
Node *allocateNode(int iNewInfo);
Node *searchLL(Node *pHead, int iMatch, Node **ppPrecedes);
Node *insertLL(Node **ppHead, int iNewInfo);
void printLL(Node *pHead);
int main(int argc, char *argv[])
{
program_header(argv[0]);
insertLL(&pHead, 84);
insertLL(&pHead, 45);
insertLL(&pHead, 81);
printLL(pHead);
return 0;
}
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
typedef struct Node
{
int iInfo;
struct Node *pNext;
}Node;
Node *pHead = NULL;
Node *pNew = NULL;
Node *pPrecedes = NULL;
Node *allocateNode(int iNewInfo)
{
// to allocate a new node
pNew = malloc(sizeof(Node));
if (pNew == NULL)
printf("Memory allocation error");
pNew->iInfo = iNewInfo;
pNew->pNext = NULL;
return pNew;
}
Node *searchLL(Node *pHead, int iMatch, Node **ppPrecedes)
{
Node *p;
for (p = pHead; p != NULL; p = p->pNext)
{
if (iMatch == p->iInfo)
printf("Found! %d\n", iMatch);
return p;
if (iMatch < p->iInfo)
return NULL;
*ppPrecedes = p;
}
return NULL;
}
Node *insertLL(Node **ppHead, int iNewInfo)
{
Node *pFind;
// see if it already exists
pFind = searchLL(*ppHead, iNewInfo, &pPrecedes);
if(pFind != NULL)
return pFind;
// Doesn't already exist. Allocate a node and insert it
pNew = allocateNode(iNewInfo);
if(pPrecedes == NULL)
{ //insert at head
pNew->pNext = *ppHead;
*ppHead = pNew;
}
else
{ //insert after a node
pNew->pNext = pPrecedes->pNext;
pPrecedes->pNext = pNew;
}
return pNew;
}
void printLL(Node *pHead)
{
Node *p;
printf("iInfo Values\n");
for (p = pHead; p != NULL; p = p->pNext)
{
printf("%d\n", p->iInfo);
}
p = pHead;
}
void program_header(char i[])
{
int j, n = strlen(&i[2]);
char *name = &i[2], border[n], dash = '-';
// loads dashes into array
for(j = 0; j < n; j++)
border[j] = dash;
border[j] = '\0';
// print header
printf("\n~%s~\n~%s~\n~%s~\n\n"
, border, name, border);
}
I believe your problem is in your search method. I have reformatted it to show the way that it is currently behaving. To help in making your code more readable and to avoid these type of errors you should get in the habit of using braces in your if statements even if they are only one line.
This is your current code
Node *searchLL(Node *pHead, int iMatch, Node **ppPrecedes)
{
Node *p;
for (p = pHead; p != NULL; p = p->pNext)
{
if (iMatch == p->iInfo)
{
printf("Found! %d\n", iMatch);
}
return p;
if (iMatch < p->iInfo)
{
return NULL;
}
*ppPrecedes = p;
}
return NULL;
}
Notice in the for loop that no matter if a match is found or not you are always returning p which is really pHead. Then in your insert code you are checking to see if the item is found in the list. Since you always return head it thinks that the item is in the list and never adds a new item.
I haven't tested this, but I believe this is the change you would need to make. You are expecting the search to return a node if the value is already in the list. So you want to return p if there is a match, otherwise you want to return NULL:
Node *searchLL(Node *pHead, int iMatch, Node **ppPrecedes)
{
Node *p;
for (p = pHead; p != NULL; p = p->pNext)
{
if (iMatch == p->iInfo)
{
printf("Found! %d\n", iMatch);
return p;
}
if (iMatch < p->iInfo)
{
return NULL;
}
*ppPrecedes = p;
}
return NULL;
}
correct this
Node *allocateNode(int iNewInfo)
{
// to allocate a new node
pNew = malloc(sizeof(Node));
if (pNew == NULL)
printf("Memory allocation error");
pNew->iInfo = iNewInfo;
pNew->pNext = NULL;
return pNew;
}
to this
Node *allocateNode(int iNewInfo)
{
// to allocate a new node
pNew = malloc(sizeof(Node));
if (pNew){
pNew->iInfo = iNewInfo;
pNew->pNext = NULL;
}else{
printf("Memory allocation error");
}
return pNew;
}