Pointer-to-pointer not working during function call? - c

I am trying to write a separate file with helper functions for stack operations. I want to pass the stack top by reference as an argument to stack operations from the main file.
Since top is getting modified, I am passing the pointer top by reference. But even then, it is not working. Where am I going wrong?
P.S.: I know that this is not the best way to implement Stack, but i just wanted to understand why it is not working.
//Stack.h
void print(stacknode **P)
{
stacknode *S;
S=*P;
printf("Printing stack from top to bottom...\n");
stacknode *temp=S;
while(temp != NULL)
{
printf("%d\t", temp->data);
temp=temp->next;
}
printf("\n");
}
void push(stacknode **P, int n)
{
stacknode *S;
S=*P;
stacknode *new=(stacknode *)malloc(sizeof(stacknode));
new->data=n;
new->next=S;
S=new;
print(&S);
}
//main.c
main()
{
printf("Creating new stack...\n");
stacknode *S=NULL;
printf("Pushing first number....\n");
push(&S, 2);
print(&S);/*Prints nothing*/
}

Since top is getting modified, I am passing the pointer top by
reference.
But you don't use that fact to change the top. Here's one solution (I haven't compiled or tested this so it may contain errors):
Stack.h: (declarations only in header files, no code)
typedef struct stacknode stacknode;
struct stacknode {
stacknode* next;
int data;
};
void print(stacknode* top); // no need for ptr ref
void push(stacknode** ptop);
Stack.c:
#include "Stack.h"
#include <stdio.h>
void print(stacknode* top)
{
printf("Printing stack from top to bottom...\n");
for (stacknode* p = top; p; p = p->next)
{
printf("%d\t", p->data);
}
printf("\n");
}
void push(stacknode** ptop, int n)
{
stacknode* p = malloc(sizeof *p); // don't cast malloc in C
if (!p)
/* handle out of memory */;
p->data = n;
p->next = *ptop;
*ptop = p;
print(p);
}
main.c:
#include "Stack.h"
#include <stdio.h>
int main(void) // declare return type
{
printf("Creating new stack...\n");
stacknode* S = NULL;
printf("Pushing first number....\n");
push(&S, 2);
print(S);
return 0;
}

Related

What is wrong with my linked list, and why won't it properly set my head to NULL in C?

This is my program I have written in C, I created a structure and a head and I am trying to make a linked list, but I keep getting read access violations and it seems I am not passing in my head pointer properly and it keeps having problems when it is trying to add to my list.
#define _CRT_SECURE_NO_WARNINGS // Since I want to strictly use ANSI C and not Microsoft C without getting the warning message, I'm adding this line of code before I include header files.
#include <stdio.h> // "#include" includes the contents of another file, commonly called header file, into the source code file.
#include <string.h> // This library contains a variety of functions to manipulate strings.
#include <stdlib.h> // Header file which has the necessary information to include the input/output related functions in our program.
#define MAX 100
typedef struct node {
char model[MAX];
float price;
int miles;
struct node *next;
} *NODEPTR;
NODEPTR getNode();
void freeNode(NODEPTR p);
void printTotalMiles(NODEPTR);
void addLast(NODEPTR *list, char c[], float pri, int num);
int main(void) { //It is the first function of every C program that is responsible for starting the execution and termination of the program.
int i = 0;
NODEPTR head = NULL;
if (head == NULL) {
printf("NULL");
}
//head = (NODEPTR) malloc(sizeof(struct node));
//head->next = NULL;
//addFront(head, 2600.00, 48000);
//addFront(head, 1400.00, 22000);
//printf("first, %d", head->price);
addLast(head, "64 Impala", 1800.00, 12000);
addLast(head, "56 Ford", 500.00, 23000);
//printTotalMiles(head);
//printArray(p);
return 0; // This statement indicates "main()" is returning the value 0 upon completion.
} // Curly brace marks the end of the function.
NODEPTR getNode(void) {
NODEPTR p;
p = (NODEPTR)malloc(sizeof(struct node));
if (p == NULL) {
printf("List Overflow.");
}
return (p);
}
void freeNode(NODEPTR p) {
free(p);
}
void addFront(NODEPTR *list, float pri, int num) {
NODEPTR p, q;
p = getNode();
//strcpy(p->model, c);
// memset(p->model, '\0', sizeof(c))
//printf("%s\n", p->model);
p->price = pri;
p->miles = num;
p->next = *list;
*list = p;
q = *list;
printf("hey %.2f hey\n", q->price);
}
void printTotalMiles(NODEPTR *list) {
int total = 0;
NODEPTR p;
while (*list) {
p = *list;
printf(" Car: \tPrice: %.2f\tI drove it: %d\n", p->price, p->miles);
total += p->miles;
list = p->next;
}
printf("The Total Miles: %d", total);
}
void addLast(NODEPTR *list, char c[], float pri, int num) {
NODEPTR p, q;
p = getNode();
memset(p->model, '\0', sizeof(c));
strcpy(p->model, c);
p->price = pri;
p->miles = num;
p->next = NULL;
if (*list == NULL) {
*list = p;
} else {
q = *list;
while (q->next) {
q = q->next;
}
q->next = p;
}
}
//void printArray(struct node cars[]) { //function definition
// break;
//}
How can I get it so I can properly add nodes to this list?
I just want it to add nodes to the list with the character, float and int. I tried messing with the pointers, I tried setting head first and setting head->next to null as well but nothing seems to work. It keeps having errors every time it tries to deal with the null.
void addLast(NODEPTR* list, char c[], float pri, int num);
addLast wants a pointer to pointer (read Is it a good idea to typedef pointers?), but you pass a single pointer here:
addLast(head, "64 Impala", 1800.00, 12000);
addLast(head, "56 Ford", 500.00, 23000);
switch to
addLast(&head, "64 Impala", 1800.00, 12000);
addLast(&head, "56 Ford", 500.00, 23000);
And here:
void addLast(NODEPTR* list, char c[], float pri, int num) {
NODEPTR p, q;
p = getNode();
memset(p->model, '\0', sizeof(c));
strcpy(p->model, c);
sizeof(c) is the size of a pointer (read What is ‘array decaying’ in C?).
Use the size of the member, in this case MAX:
memset(p->model, '\0', MAX);
or better yet: delete the whole line, you don't need it if you call strcpy on the next line.
One more:
void printTotalMiles(NODEPTR* list) {
differs from the propotype:
void printTotalMiles(NODEPTR);
Compile with warnings.

Segmentation fault when reading from stack

This is my first time creating stacks. I'm quite clear at what I must do, but am quite discouraged by the code not working.
It runs fine till I try to retrieve any data from the root, which immediately results in a segfault.
Here's my program:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct stackNode
{
char letter;
struct stackNode * next;
};
int size=0;
int capacity=10;
struct stackNode * root=NULL;
void push(char data, struct stackNode * root)
{
if(size==capacity)
{
printf("Error: Stack Overflow\n");
return;
}
struct stackNode * new=(struct stackNode *)malloc(sizeof(struct stackNode *));
new->letter=data;
new->next=root;
printf("%c,%u", new->letter, new->next);
root=new;
printf("%c,%u", new->letter, new->next);
size++;
}
char pop(struct stackNode ** root)
{
if(size==0)
{
printf("Error: Stack is Empty\n");
return '\0';
}
printf("\npop*\n");
char temp;
printf("\n*\n");
struct stackNode * tempad;
printf("\n*\n");
temp=(*root)->letter;
printf("\n*\n");
tempad=*root;
printf("\n*\n");
*root=(*root)->next;
printf("\n*\n");
free(tempad);
printf("\n*\n");
size--;
return temp;
}
int main()
{
push('c', root);
push('v', root);
push('n', root);
printf("%c %c %c", pop(&root), pop(&root), pop(&root));
}
Here's the output:
pop*
*
*
Segmentation fault
Could someone point out the mistake?
The main issue is usage of unnecessary global variables which seem to be causing confusion. In push, the parameter is of type struct stackNode * yet it's being manipulated as if it referred to the global root. But root = new is purely local and has no impact on the global root. However, size++ does impact the global scope. This corrupts the stack's logical state, and your error handler at the beginning of pop thinks that size == 3 and doesn't complain. The function then dutifully dereferences root, crashing the program.
A correct stack class should not use global data. It should encapsulate all necessary state in structs. This makes it reusable, enabling creation of multiple stacks (a property I'd want in most classes I'm using).
A few other suggestions:
Avoid side effects where possible. Prints are OK for temporary debugging purposes but should be completely separated from program logic otherwise.
If you are planning on writing error handlers, print to stderr and avoid magic values like return '\0'; that might be mistaken for actual node data.
Don't cast the result of malloc. This can suppress errors and is visually noisy.
Hardcoding capacity feels pretty arbitrary. I'm not sure there's any point to having this (but if there is, add it to the struct). If there's too much metadata about the stack inside each node (ideally, there should be none), create a Stack struct to contain this metadata and point it to the actual stackNode chain.
Another stack design point: malloc/free are slow. For character data, a simple array with a top pointer will be faster and simpler to implement. You can amortize allocation calls with periodic doubling the array when top >= capacity and contracting when top < capacity / 2.
Here's a quick re-write (without the suggestion for the Stack wrapper struct or the array):
#include <stdio.h>
#include <stdlib.h>
struct stackNode {
char letter;
struct stackNode *next;
int size;
};
void push(char data, struct stackNode **root) {
struct stackNode *new = malloc(sizeof(*new));
new->size = *root ? (*root)->size + 1 : 1;
new->letter = data;
new->next = *root;
*root = new;
}
char pop(struct stackNode **root) {
if (!*root || !(*root)->size) {
fprintf(stderr, "pop from empty stack\n");
exit(1);
}
char popped = (*root)->letter;
struct stackNode *cull = *root;
*root = (*root)->next;
free(cull);
return popped;
}
int main() {
struct stackNode *root = NULL;
push('c', &root);
push('v', &root);
push('n', &root);
while (root) {
printf("%c ", pop(&root));
}
puts("");
return 0;
}
This is really confusingly written code (i.e globals with the same name as variables in the local scope). I'm just going to rewrite it, untested and on mobile but should be fine. You can diff to see the issue(s). For one thing though you're setting local variable root to the newest allocation rather than global root.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct stackNode
{
char letter;
struct stackNode* prev;
};
stackNode* kTailStack = NULL;
void push(char data)
{
stackNode* p=(stackNode *)malloc(sizeof(stackNode));
p->letter=data;
p->prev=kTailStack;
kTailStack = p;
}
char pop()
{
stackNode* prev_tail = kTailStack;
char n = 0;
if (prev_tail != NULL)
{
n = prev_tail->letter;
kTailStack = prev_tail->prev;
free(prev_tail);
}
return n;
}
int main()
{
push('c', kTailStack);
push('v', kTailStack);
push('n', kTailStack);
printf("%c %c %c", pop(kTailStack), pop(kTailStack), pop(kTailStack));
}

Segmentation Fault (singal 11 sigsegv) with linked list

Was writing a program to practice before with linked lists and pointers before pset5 and am left with two memory errors that i have not been able to remedy.
#include <stdio.h>
#include <stdlib.h>
//define struct for Nodes
typedef struct list
{
int data;
int key;
struct list* next;
}Node;
//function declarations
Node* create(int a, int *counter);
void insert(int a, int *counter);
void delete_list();
void printlist();
//global pointers
Node* Head = NULL;
Node* Current = NULL;
int main()
{
int *keycounter =(int*)malloc(sizeof(int));
int value = 20;
keycounter = 0;
Head=create(value, keycounter);
value = 30;
insert(value, keycounter);
value = 40;
insert(value, keycounter);
printlist();
delete_list();
free(keycounter);
return 0;
}
// VV functions VV
void delete_list()
{
free(Head);
free(Current);
}
Node* create(int a, int *counter)
{
Node* ptr=malloc(sizeof(Node));
if(!ptr)
{
printf("ERROR-NOT ENOUGH MEMORY\n");
free(ptr);
return 0;
}
ptr->data=a;
ptr->key=*counter;
counter++;
return ptr;
}
void insert(int a, int *counter)
{
Node* ptr=malloc(sizeof(Node));
if(!ptr) {
printf("ERROR-NOT ENOUGH MEMORY\n");
free(ptr);
}
ptr->data=a;
ptr->key=*counter;
//point next field to old head
ptr->next=Head;
//assign current node as head of singly linked list
Head=ptr;
counter++;
}
//Thank you guys over at tutorialspoint for this neat idea for testing this.
//https://www.tutorialspoint.com/data_structures_algorithms/linked_list_program_in_c.htm
void printlist()
{
Node* ptr=Head;
printf("TESTING\n");
while(ptr != NULL) {
printf("%p*NODE* KEY:%i VALUE:%i PTR NEXT:%p\n \n", ptr, ptr->key, ptr->data, ptr->next);
ptr=ptr->next;
}
}
Here is my valgrind output:
Still learning so alot of the valgrind output is pretty arcane to me and threads on stack exchange regarding the "signal 11 (SIGSEGV)" error are difficult to comprehend as well.
Also, any tips or advice on my code would be appreciated.
There is a problem in your code. See the below lines:
int main()
{
int *keycounter =(int*)malloc(sizeof(int));
int value = 20;
keycounter = 0; ===> You are setting the pointer to NULL effectively nullifying the effect of your malloc call above
So, in your create function, when you try to access counter, it is leading to NULL pointer dereference
Node* create(int a, int *counter)
{
Node* ptr=malloc(sizeof(Node));
if(!ptr)
{
printf("ERROR-NOT ENOUGH MEMORY\n");
free(ptr);
return 0;
}
ptr->data=a;
ptr->key=*counter; ==> Here it will lead to NULL pointer dereference
If your key member in the struct is just an integer, then no need to pass a pointer (counter is a pointer), you can as well pass an integer and set it.

Writing a push and pop in c

Original Q: I'm trying to create this calculator in C for a project. I got the math functions working, but not I am stuck on how to handle the push an pop. Can somebody help me get started? I know what push and pop are supposed to do from java, but I am not sure how to use them without using nodes or an array.
My includes and stack struct:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "stack.h"
#include "debug.h"
#define DEFAULT_CAPACITY 16
struct stack {
size_t capacity;
size_t size;
stack_item *data;
};
My attempted push and pop:
UPDATED
void push_stack (stack *this, stack_item item) {
if (full_stack (this)) realloc_stack (this);
this->data[this->size++]=item;
}
stack_item pop_stack (stack *this) {
assert (! empty_stack (this));
if(this->data == NULL){
fprintf(stderr, "fail");}
else{
stack_item tempPop = this->data[this->size--];
return tempPop;}
}
Updated Q: This is now what I am doing for my push/pop method. I am getting no warnings and no errors, but when I run it, it seg faults after it should pop.
My new question is, does it appear that something I am doing in this block of code is causing my seg fault?
Use linked lists.
struct stack_element {
struct stack_element* next; // reserved for stack control
int data0; // whatever
int data1;
int data2;
};
void push_stack(struct stack_element** stack, struct stack_element* element)
{
element->next = *stack;
*stack = element;
}
struct stack_element* pop_stack(struct stack_element** stack)
{
struct stack_element* element = *stack;
if (element)
*stack = element->next;
return element;
}
struct stack_element* stack = NULL; // your stack. its empty
Creating new stack element and adding to stack:
struct stack_element* element = malloc(sizeof(struct stack_element)); // created new element
element->data0 = 123;
element->data1 = 456;
element->data2 = 789;
push_stack(&stack, element); // stored in stack
Fetching an element from stack:
struct stack_element* element = pop_stack(&stack);
if (element == NULL)
printf("Stack was empty, no elements to fetch.");
PS: The same element can never be pushed to the stack more than once.
You can also have the stack control separated from the data, in which case you will be able to store the same element more than once:
struct stack_control {
struct stack_control* next;
void* data;
};
void push_stack(struct stack_control** stack, void* data)
{
struct stack_control* temp = malloc(sizeof(struct stack_control));
temp->data = data;
temp->next = *stack;
*stack = temp;
}
void* pop_stack(struct stack_control** stack)
{
void* data = NULL;
struct stack_control* temp = *stack;
if (temp)
{
data = temp->data;
*stack = temp->next;
free(temp);
}
return data;
}
struct stack_control* stack = NULL; // empty stack
This code the way it is can be used to stack pointers of any type, because void* is generic.
//Validation sample code of behavior
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if 0
#include "stack.h"
#include "debug.h"
#else
typedef char* stack_item;
#endif
#define DEFAULT_CAPACITY 16
struct stack {
size_t capacity;
size_t size;
stack_item *data;
};
typedef struct stack stack;
stack *Stack(void){
stack *s = malloc(sizeof(stack));
s->capacity = DEFAULT_CAPACITY;
s->size = 0;
s->data = malloc(s->capacity * sizeof(stack_item));
return s;
}
int full_stack(stack *this){
return this->capacity == this->size;
}
int empty_stack(stack *this){
return this->size == 0;
}
void realloc_stack(stack *this){
this->capacity += DEFAULT_CAPACITY;
this->data = realloc(this->data, this->capacity*sizeof(stack_item));
}
void push_stack (stack *this, stack_item item) {
if (full_stack (this))
realloc_stack (this);
this->data[this->size++]=item;
}
stack_item pop_stack (stack *this) {
assert (!empty_stack (this));
if(this->data == NULL){
fprintf(stderr, "fail");
exit(1);//Maybe malloc or realloc
}
return this->data[--(this->size)];
}
int main(void){
stack *s = Stack();
push_stack(s, "sin");
push_stack(s, "+");
push_stack(s, "cos");
while(!empty_stack(s)){
puts(pop_stack(s));
}
//Stack_(s);//call destructor
return 0;
}
I understand what you mean when you say "I know what push and pop are supposed to do from java", but please bear in mind that push and pop are just operations that you can do to a data structure that is known as a stack. A stack is more of an idea and that concept can be implemented in any language.
To start of, I would advice you not to use a array. A stack imposes an order in the way you access elements and its perfectly fine with a nice linked list because you only need to remove from the head and add elements to the same head. You typically use an array when you want to access elements at any position in O(1) complexity. The effect of using a linked list is that you dont really have a bound in the number of elements you can add to the stack (unless you really want to).
If you decide to go for a linked list I would advice you to use two structures:
struct stack_node {
int data;
stack_node* next;
};
struct stack {
int current_size;
int max_size;
struct stack_node head;
};
The you can always do
void push(struct stack* s, int x){
if(s->max_size > s->current_size+1){
add to the stack
} else {
stack is full!!
}
}
int pop(struct stack* s) {
if(s->current_size == 0){
Ops! No data in stack, throw error or something
} else {
return head and remove item from stack
}
}
Note that this is only a template to give you an idea... Also, I dont really understand in your code what does "realloc_stack". I think the main problem in your code is that you might still be in a bit of a java minset and programming C requires you to think a bit more low level and do more thinks yourself...

pointers and values

I have written the following code, and it prints the root value correctly, but not the ret value. Here a memory address is potentially printed (1707388). I believe that ret could now be modified and the result would be seen in main. Any help is appreciated.
#include <stdlib.h>
struct node{
int value;
int order;
struct node *left;
struct node *right;
};
typedef struct node node_t;
node_t array[10];
void createTree(node_t *p, int order){
p->value = rand()%10;
p->order = order;
printf("%i", p->value);
printf(" ");
printf("%i\n", p->order);
if (!order){
p->left = NULL;
p->right = NULL;
return;
}
order--;
createTree(&p->left, order);
createTree(&p->right, order);
}
void traverse(node_t *current, node_t *ret, int size){
printf("%i\n", current->value);
if (current->value > size){
ret = current;
traverse(&current->left, &ret, size);
traverse(&current->right, &ret, size);
}
return;
}
int main(void){
node_t *root = &array[0];
node_t *ret;
srand(time(NULL));
createTree(root, 4);
int i = 3;
printf("%s", "root-value: ");
printf("%i\n", root->value);
traverse(root, ret, i);
printf("%s", "root-value: ");
printf("%i\n", root->value);
printf("%i\n", ret->value);
return 1;
}
This:
void createTree(node_t *p, int order)
Should be
void createTree(node_t **p, int order)
Otherwise you are modifying a local node_t pointer, instead of the one outside the function. Your tree isn't being built properly either.
You are passing ret by value to
void traverse(node_t *current, node_t *ret, int size){
When the function changes ret, the changes do not propagate back to the caller.
This means that ret in main() remains uninitialized, and the behaviour of your code is undefined.
To fix this, make traverse either return ret, or take it as node_t**.
There are few issues with the code.
First, you don't correctly allocate the memory for nodes. In your code, you are passing wrong pointer type, futhermore, pointer to uninitialized area.
Here, how it can be used differently:
node_t *createTree(int order)
{
node_t *result = malloc(sizeof(*result));
result->value = rand() % 10;
result->order = order;
if (order)
{
result->left = createTree(order - 1);
result->right = createTree(order - 1);
}
else
{
result->left = result->right = 0;
}
return result;
}
Then, your traverse function need some block to restrict agains failed search:
node_t *traverse(node_t *current, int size)
{
node_t *ret = NULL;
if (current->value > size)
{
// assuming current node fit - stops the search
ret = current;
}
if (!ret && current->left)
{
// try left node
ret = traverse(current->left, size);
}
if (!ret && current->right)
{
// try right node
ret = traverse(current->right, size);
}
return ret;
}
In case you need (usually you do), here is a destroyTree:
void destroyTree(node_t *node)
{
if (!node) return; // we treat NULL as a valid pointer for simplicity
destroyTree(node->left);
destroyTree(node->right);
free(node);
}
And here is a usage example:
node_t *root, *found;
root = createTree(4);
found = traverse(root, 3);
if (found)
{
printf("Found!");
}
destroyTree(root);
In traverse(node_t *current, node_t *ret, int size), ret is a stack variable. In other words, you are passing the pointer by value, instead of passing it by reference.
What have you done at the moment is essentially the same as:
int f(int i) {
...
i = <any value>;
...
}
In this case you are modifying only a copy of the value.
In your program, you are also modifying a copy of the pointer. Outside of the function the pointer stays not modified.
If you want to modify it, you need to pass a pointer to it:
void traverse(node_t *current, node_t **ret, int size){
...
*ret = current;
...
return;
}
The same for createTree().

Resources