I wrote a C program to practice DSA, specifically queues.
I wrote a function free_q() to free the dynamically allocated memories, but when I print the pointer to these structures, I get a memory address that is not equal to when I print %p NULL. I'd like to know why isn't the pointer Q set to NULL when freeing not only the dynam. all. structure but also the pointer to the array inside the structure.
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
struct queue_rec
{
unsigned int front;
unsigned int rear;
unsigned int max_size;
unsigned int size;
int *arr_struct;
};
typedef struct queue_rec *QUEUE;
int
isEmpty(QUEUE Q)
{
return(Q->size==0);
}
int isFull(QUEUE Q)
{
return(Q->size>=Q->max_size);
}
QUEUE
create_queue(unsigned int size)
{
QUEUE Q = (QUEUE) malloc(sizeof(struct queue_rec));
if(Q==NULL){printf("Out of space!");}
else
{
Q->arr_struct = (int *) malloc(size * sizeof(int));
if(Q->arr_struct == NULL){printf("Out of space!");}
else
{
Q->size = 0;
Q->front = 1;
Q->rear = 0;
Q->max_size = size;
}
}
return Q;
}
unsigned int
succ(unsigned int value, QUEUE Q)
{
if(++value==Q->max_size){value=0;}
return value;
}
void
enqueue(int data, QUEUE Q)
{
if(isFull(Q)){printf("Queue is full!");}
else
{
Q->size++;
Q->rear = succ(Q->rear, Q);
Q->arr_struct[Q->rear] = data;
}
}
void
dequeue(QUEUE Q)
{
if(isEmpty(Q)){printf("Queue is empty!");}
else
{
Q->size--;
printf("%d", Q->arr_struct[Q->front]);
Q->front = succ(Q->front,Q);
}
}
void
free_q(QUEUE Q)
{
free(Q->arr_struct);
free(Q);
Q = NULL;
}
int main()
{
QUEUE Q = create_queue(4);
free_q(Q);
printf("%p\c", Q);
printf("%p", NULL);
return 0;
}
OUTPUT:
00031480
00000000
free takes a pointer as argument, which means that it can only alter what the pointer is pointing to. It cannot change the pointer point to another object.
void foo(int *p) {
// Code
}
int main(void) {
int x = 42;
int *p = &x;
int *q = &x;
foo(p);
if(p == q)
puts("Equal address"); // Guaranteed to be printed
if(*p == *q)
puts("Equal value"); // Depends on body of foo()
}
The above code is guaranteed to print "Equal address" irregardless of the body in foo. But it's NOT guaranteed to print "Equal value". If the signature instead was void foo(int **p) and you called it with foo(&p) it would have been different.
If you really want, you could do like this:
void
free_q(QUEUE *Q)
{
free((*Q)->arr_struct);
free(*Q);
*Q = NULL;
}
But I would in general not recommend such things. The need for nulling pointers can be a symptom that you don't have as much control as you think. When would you use it? To see if you have freed it properly? Not a good idea. Look at this:
QUEUE q = create_queue(42);
QUEUE p = q;
free_q(&q);
if(p == NULL) {
// OOOPS
Instead, I'd do like this:
typedef struct queue_rec QUEUE; // No pointer
QUEUE
create_queue(unsigned int size)
{
int *arr = malloc(size * sizeof *arr);
if(!arr){
fprintf(stderr, "Out of space");
exit(1);
}
return (QUEUE) { .max_size = size, .arr_struct = arr };
}
and if you for some reason want to dynamically allocate a whole queue, do it manually:
QUEUE *q = malloc(sizeof *q);
*q = create_queue(42);
Also, I would discourage typedefing pointers.
Related
Why pointer to custom struct doesn't work in that code?
Why I'm getting warning in that line with p->x = x?
Why I'm getting second warning in line with strcpy_s?
#include <stdlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct sptr {
int x;
char* s;
struct sptr* next;
} ptr;
void add(ptr* p, int x, const char* s) {
ptr* o = p;
p = (ptr*) malloc(sizeof(ptr));
p->x = x; // warning
p->s = (char*)malloc(20 * sizeof(char));
strcpy_s(p->s, 20, (char*)s); // warning
p->next = o;
}
void show(ptr* p) {
ptr* o = p;
while (o != NULL) {
printf("%d %s\n", o -> x, o -> s);
o = o->next;
}
}
int main() {
ptr* p = NULL;
add(p, 5, "xcvxvxv");
add(p, 7, "adadad");
show(p);
return 0;
}
Pointers are values.
add is receiving a copy of the NULL pointer value. Changing the local variable p, in add, to a new pointer value returned by malloc does not change the separate, local variable p in main.
Just as if you wanted to change the value of an int in the caller's scope, you'd use an int * argument:
void change(int *val)
{
*val = 10;
}
int main(void)
{
int a = 5;
change(&a);
}
Changing the value of an int * in the caller's scope would require an int ** argument.
#include <stdlib.h>
void change(int **val)
{
*val = malloc(sizeof **val);
}
int main(void)
{
int *a;
change(&a);
}
This extends to any type.
malloc can fail, and return NULL. Performing indirection on a NULL pointer value is Undefined Behaviour.
You must guard against this happening by checking the return value of malloc.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node {
int x;
char *s;
struct node *next;
} Node;
void add(Node **p, int x, const char *s) {
Node *new_node = malloc(sizeof *new_node);
if (!new_node) {
perror("allocating node");
exit(EXIT_FAILURE);
}
new_node->s = malloc(1 + strlen(s));
if (!new_node->s) {
perror("allocating node string");
exit(EXIT_FAILURE);
}
new_node->x = x;
strcpy(new_node->s, s);
new_node->next = *p;
*p = new_node;
}
void show(Node *p) {
while (p) {
printf("%d %s\n", p->x, p->s);
p = p->next;
}
}
int main(void) {
Node *list = NULL;
add(&list, 5, "xcvxvxv");
add(&list, 7, "adadad");
show(list);
}
Why pointer to custom struct doesn't work in that code?
TBD
Why I'm getting warning in that line with p->x = x?
Why I'm getting second warning in line with strcpy_s?
2 warnings occur because code de-referenced the pointer from malloc() without first checking if the pointer might be NULL.
my code is not working but when I change struct stack *sp; to struct stack * sp = (struct stack *) malloc(sizeof(struct stack)); it start working. I am confused in when to allocate memory in heap to struct stack *ptr and when to not. It will be better if u can give me an example when struct stack *ptr can be used and when to use struct stack * sp = (struct stack *) malloc(sizeof(struct stack));
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stack
{
int size;
int top;
char *arr;
};
int stackTop(struct stack* sp){
return sp->arr[sp->top];
}
int isEmpty(struct stack *ptr)
{
if (ptr->top == -1)
{
return 1;
}
else
{
return 0;
}
}
int isFull(struct stack *ptr)
{
if (ptr->top == ptr->size - 1)
{
return 1;
}
else
{
return 0;
}
}
void push(struct stack* ptr, char val){
if(isFull(ptr)){
printf("Stack Overflow! Cannot push %d to the stack\n", val);
}
else{
ptr->top++;
ptr->arr[ptr->top] = val;
}
}
char pop(struct stack* ptr){
if(isEmpty(ptr)){
printf("Stack Underflow! Cannot pop from the stack\n");
return -1;
}
else{
char val = ptr->arr[ptr->top];
ptr->top--;
return val;
}
}
int precedence(char ch){
if(ch == '*' || ch=='/')
return 3;
else if(ch == '+' || ch=='-')
return 2;
else
return 0;
}
int isOperator(char ch){
if(ch=='+' || ch=='-' ||ch=='*' || ch=='/')
return 1;
else
return 0;
}
char* infixToPostfix(char* infix){
struct stack *sp;
sp->size = 10;
sp->top = -1;
sp->arr = (char *) malloc(sp->size * sizeof(char));
char * postfix = (char *) malloc((strlen(infix)+1) * sizeof(char));
int i=0; // Track infix traversal
int j = 0; // Track postfix addition
while (infix[i]!='\0')
{
if(!isOperator(infix[i])){
postfix[j] = infix[i];
j++;
i++;
}
else{
if(precedence(infix[i])> precedence(stackTop(sp))){
push(sp, infix[i]);
i++;
}
else{
postfix[j] = pop(sp);
j++;
}
}
}
while (!isEmpty(sp))
{
postfix[j] = pop(sp);
j++;
}
postfix[j] = '\0';
return postfix;
}
int main()
{
char * infix = "x-y/z-k*d";
printf("postfix is %s", infixToPostfix(infix));
return 0;
}
Two things to always remember when working with pointers in C:
Memory allocation is your problem. You have to think about the allocation of the memory which a pointer variable points to.
You have to be clear in your mind about the distinction between the pointer versus the data that it points to.
So when you say
struct stack *sp;
that will never work, all by itself. It won't work for a program that's implementing a stack, and it won't work for a program that's implementing any other kind of data structure.
When you write
struct stack *sp;
there is one important thing that you have done, and there is one important thing that you have not done.
The compiler allocates space to store one pointer. This pointer is known as sp. But:
The value of this pointer is indeterminate, which means that it does not point anywhere yet. You can't actually use the pointer variable sp for anything. (Yet.)
Or, in other words, going back to the distinction I mentioned earlier, you have taken care of the pointer but you don't have any data that the pointer points to.
But when you say
sp = malloc(sizeof(struct stack));
(and assuming malloc succeeds), now sp points somewhere: it points to a chunk of properly-allocated memory sufficient to hold one struct stack.
Basically I made a create_app() function to allocate 2 nodes in the stack, each having a pointer to an array[max]; undo() pops the last element, and before returning it, it adds it into the REDO node's array. redo() does the opposite, pops the last element in it's array, putting it into Undo's array before returning it. What did I do wrong ?
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#define EMPTY_TOS (-1)
typedef struct node *node_ptr;
struct node
{
int arr_size;
int tos;
int *arr_stack;
node_ptr next;
};
typedef node_ptr STACK;
STACK
create_app(int max)
{
STACK UNDO = (STACK) malloc(sizeof(struct node));
STACK REDO = (STACK) malloc(sizeof(struct node));
{
UNDO->arr_stack == (int *) malloc(max * sizeof(int));
REDO->arr_stack == (int *) malloc(max * sizeof(int));
if(UNDO->arr_stack != NULL){printf("Out of space!");}
else
{
UNDO->tos = EMPTY_TOS;
REDO->tos = EMPTY_TOS;
UNDO->arr_size = max;
REDO->arr_size = max;
UNDO->next = REDO;
REDO->next = UNDO;
return UNDO;
}
}
}
int
isEmpty(STACK S)
{
return(S->tos==-1);
}
int
isFull(STACK S)
{
return(S->tos>=S->arr_size-1);
}
void
push(int x, STACK S)
{
if(isFull(S)){printf("Stack full!");}
else
{
S->arr_stack[++S->tos] = x;
}
}
int
undo(STACK S)
{
if(isEmpty(S)){printf("Nothing to undo!");}
else
{
S->next->arr_stack[++S->next->tos] = S->arr_stack[S->tos];
printf("%d",S->arr_stack[S->tos--]);
}
}
int
redo(STACK S)
{
if(isEmpty(S->next)){printf("Nothing to redo!");}
else
{
int temp = S->next->arr_stack[S->next->tos];
push(S->next->arr_stack[S->next->tos], S);
S->next->tos--;
printf("%d",temp);
}
}
int main()
{
STACK app = create_app(5);
push(1,app);
push(2,app);
push(3,app);
undo(app);
undo(app);
redo(app);
redo(app);
/* Expected output: 3223 */
return 0;
}
Some small errors were in your code, like these ones in create_app() which seem like typos.
UNDO->arr_stack == (int *) malloc(max * sizeof(int));
REDO->arr_stack == (int *) malloc(max * sizeof(int));
^
|
if(UNDO->arr_stack != NULL){printf("Out of space!");}
^
|
...
and some int returning functions did not return anything in the else part which gave some warnings.
Here is the modified code, which worked fine for me
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#define EMPTY_TOS (-1)
typedef struct node* node_ptr;
struct node
{
int arr_size;
int tos;
int *arr_stack;
node_ptr next;
};
typedef node_ptr STACK;
STACK
create_app(int max)
{
STACK UNDO = (STACK) malloc(sizeof(struct node));
STACK REDO = (STACK) malloc(sizeof(struct node));
{
UNDO->arr_stack = (int *) malloc(max * sizeof(int));
REDO->arr_stack = (int *) malloc(max * sizeof(int));
if(UNDO->arr_stack == NULL){printf("Out of space!");
return NULL;}
else
{
UNDO->tos = EMPTY_TOS;
REDO->tos = EMPTY_TOS;
UNDO->arr_size = max;
REDO->arr_size = max;
UNDO->next = REDO;
REDO->next = UNDO;
return UNDO;
}
}
}
int
isEmpty(STACK S)
{
return (S->tos == -1);
}
int
isFull(STACK S)
{
return (S->tos >= S->arr_size-1);
}
void
push(int x, STACK S)
{
if(isFull(S)){printf("Stack full!");}
else
{
S->arr_stack[++S->tos] = x;
}
}
void
undo(STACK S)
{
if(isEmpty(S)){printf("Nothing to undo!");}
else
{
S->next->arr_stack[++S->next->tos] = S->arr_stack[S->tos];
printf("%d",S->arr_stack[S->tos--]);
}
}
void
redo(STACK S)
{
if(isEmpty(S->next)){printf("Nothing to redo!");}
else
{
int temp = S->next->arr_stack[S->next->tos];
push(S->next->arr_stack[S->next->tos], S);
S->next->tos--;
printf("%d",temp);
}
}
int main()
{
STACK app = create_app(5);
push(1,app);
push(2,app);
push(3,app);
undo(app);
undo(app);
redo(app);
redo(app);
/* Expected output: 3223 */
return 0;
}
Result:
3223
However, always take precaution in deallocating the memory malloced using free().
I'm writing a simple parser in C and I'm not sure which is the best way to pass results up my tree as it gets evaluated.
Here's my current code, the node struct and the walk function to evaluate the tree.
typedef struct node {
struct node* left;
struct node* right;
void* data;
Symbol type;
} node;
void* walk(node* n) {
if (n != NULL) {
if (n->type == plus) {
int x = 0;
int a = *(int*)walk(n->left);
int b = *(int*)walk(n->right);
x = a + b;
return &x;
} else if (n->type == number) {
return (int*)n->data;
}
}
return NULL;
}
From the code you can see when I add two numbers together I'm storing the result in a local variable and returning the address to that variable, I know this is undefined behaviour, so I thought about using malloc and changing my code to this:
int* x = malloc(1 * sizeof(int));
int a = *(int*)walk(n->left);
int b = *(int*)walk(n->right);
*x = a + b;
return x;
But the problem with this code is, I'm not sure what is the best way to free this memory I just malloc'd.
Should I walk the tree a second time and free all of the memory that way or is the a better way to free the memory when I'm done or is there a better way to propagate values through my tree?
No need to traverse the tree for second time. Notice that you do not need values of a and b after summing them into x. so you can free them after addition which is shown in #flu's answer. More over, you can do it without using extra memory for flag.
Note: this code will through runtime error for invalid input. to handle this errors check for NULL pointers before accessing a pointer.
void* walk(node* n) {
if (n != NULL) {
if (n->type == plus) {
int * x = malloc(sizeof(int));
int * a = (int*)walk(n->left);
int * b = (int*)walk(n->right);
*x = *a + *b;
free(a);
free(b);
return x;
} else if (n->type == number) {
int * val = malloc(sizeof(int)); //allocate dynamic memory for the leaf node so that all nodes can be freed without checking.
*val = n->data;
return val;
}
}
return NULL;
}
You could add an extra argument needToFree to inform the caller to free the returned pointer.
void* walk(node* n, bool* needToFree) {
if (n != NULL) {
if (n->type == plus) {
bool needToFreeA;
bool needToFreeB;
int * x = malloc(sizeof(int));
int * a = (int*)walk(n->left, &needToFreeA);
int * b = (int*)walk(n->right, &needToFreeB);
*x = *a + *b;
if( needToFreeA ) free(a);
if( needToFreeB ) free(b);
*needToFree = true;
return x;
} else if (n->type == number) {
*needToFree = false;
return (int*)n->data;
}
}
*needToFree = false;
return NULL;
}
I'm getting a segmentation fault when trying to access data stored in my TreeNode. Here is the code:
#include <stdio.h>
#include <stdlib.h>
typedef struct NodeTag{
int value;
struct NodeTag *LLink;
struct NodeTag *RLink;
} TreeNode;
void inOrder(TreeNode * n){
if(n->LLink != NULL)
inOrder(n->LLink);
printf("%d ", n->value);
if(n->RLink != NULL)
inOrder(n->RLink);
}
void newNode(TreeNode * n, int v){
n = malloc(sizeof(TreeNode));
n->value = v;
n->LLink = NULL;
n->RLink = NULL;
}
void addValue(TreeNode * r, int value){
if(value < r->value){
if(r->LLink == NULL){
newNode(r->LLink, value);
} else {
addValue(r->LLink, value);
}
} else if (value > r->value) {
if(r->RLink == NULL){
newNode(r->RLink, value);
} else {
addValue(r->RLink, value);
}
}
}
int main(){
TreeNode * root = 0;
newNode(root, 1);
printf("%d\n", root->value); //<--This is where I get the fault
//addValue(root, 3);
//addValue(root, 10);
//addValue(root, 2);
//inOrder(root);
return 0;
}
If anyone can explain to me why I'm getting this error it would be greatly appreciated. I'm a student learning C and I'm not too familiar with pointers and such.
void newNode(TreeNode * n, int v){
n = malloc(sizeof(TreeNode));
n->value = v;
n->LLink = NULL;
n->RLink = NULL;
}
In this code, n is a pointer to a TreeNode struct but if you assign something to n, this is not visible outside of the function as the pointer is passed by value.
void writeToA ( int a ) {
a = 5;
}
int main ( ) {
int x = 10;
writeToA(x)
printf("%d\n", x);
}
What will this code print? It will print 10, not 5. That's because the value of x is passed to the function, not a reference to x. Changing that value within the function will not change the value of x outside the function.
A pointer is also a value, basically it is an int and the int value is a memory address:
void writeToPtr1 ( int * a ) {
int i = 10;
a = &i; // `a` now points to the memory address of i
}
void writeToPtr2 ( int * a ) {
*a = 5; // This doesn't change where `a` points to,
// it writes 5 to the memory address to that `a` points to.
}
int main ( ) {
int x = 10;
int *ptr = &x; // ptr now points to the memory address of x!
writeToPtr1(ptr);
// ptr still points to the memory address of x!
// As not a reference to ptr was passed, the memory
// address of x was passed to the function!
writeToPtr2(ptr);
// ptr still points to the memory address of x!
// But this memory now has the value 5 and not 10 anymore.
}
You need to return the result of the allocation:
TreeNode * newNode ( int v ) {
TreeNode * n = malloc(sizeof(TreeNode));
n->value = v;
n->LLink = NULL;
n->RLink = NULL;
return n;
}
int main ( ) {
TreeNode * root = newNode(1);
printf("%d\n", root->value);
return 0;
}
Or you need to pass a reference to the pointer and then change the value the pointer points to:
void newNode ( TreeNode ** outNode, int v ) {
// TreeNode ** is a pointer to a pointer to a TreeNode!
TreeNode * n = malloc(sizeof(TreeNode));
n->value = v;
n->LLink = NULL;
n->RLink = NULL;
*outNode = n; // Make the pointer point to `n`
}
int main ( ) {
TreeNode * root = NULL;
newNode(&root, 1); // Pass a pointer to root
printf("%d\n", root->value);
return 0;
}
newNode shall either return a pointer to allocated memory or you can send double pointer to the function and allocate memory there.
TreeNode* newNode(int v){
TreeNode *new_node = malloc(sizeof(TreeNode));
n->value = v;
n->LLink = NULL;
n->RLink = NULL;
return new_node
}
or
void newNode(TreeNode ** n, int v){
*n = malloc(sizeof(TreeNode));
(*n)->value = v;
(*n)->LLink = NULL;
(*n)->RLink = NULL;
}
In C arguments are passed by value. Calling newNode(r->LLink, value) will therefore not modify r->LLink.
Consider this simple function:
void Foo(int x)
{
x = x * 2 ;
}
Will calling Foo(n) multiply n by 2 ? No.
You would either need this:
void Foo(int *x)
{
*x = *x * 2 ;
}
and call Foo(&n);
or:
void Foo(int x)
{
return x * 2 ;
}
and call n = Foo(n);