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.
Related
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.
I am creating a variable tree, but I've got an error, seemingly in the insert or print_wevr function.
When I run the program I get an infinite loop.
How can I go about this?
/*5 - VarTrees*/
/*var_trees.c*/
#include <stdio.h>
#include <stdlib.h>
#include "var_trees.h"
/*Defining the struture of variable tree.
* The nodes has tree fields:
info: an generic information
first: the first child-node
next: the next sibling-node
*/
struct var_tree{
void* info;
Var_Tree* first;
Var_Tree* next;
};
/*Create the tree*/
Var_Tree* create(void* info)
{
Var_Tree* t = (Var_Tree*) malloc(sizeof(Var_Tree));
t->info = info;
t->first = NULL;
t->next = NULL;
return t;
}
/*Insert a node*/
void insert(Var_Tree* t,Var_Tree* st)
{
st->next = t->first;
t->first = st;
}
/*go_through the tree*/
void go(Var_Tree* t, void (*cb)(void*))
{
Var_Tree* p;
cb(t->info);
for(p = t->first; p != NULL; p = p->next)
go(t,cb);
printf(">");
}
/*Remove a node*/
//void remov(Var_Tree* t, void* info);
/*5 - VarTrees*/
/*main.c*/
#include <stdio.h>
#include <stdlib.h>
#include "var_trees.h"
Var_Tree* create_int(int info)
{
return create(&info);
}
void print_int(void* info)
{
int* t = (int*) info;
printf("<%d",*t);
}
int main(void)
{
Var_Tree* a = create_int(4);
Var_Tree* b = create_int(3);
Var_Tree* c = create_int(23);
Var_Tree* d = create_int(1);
Var_Tree* e = create_int(2);
insert(a,b);
go(a,print_tree);
}
The function create_int is a function for creating a node with the field info as int.
print_int is a callback function that prints an integer (the '<' creates a type of textual notation for trees).
Here in go function, you are making a recursive call without changing the parameters that eventually lead to infinite recursion.
void go(Var_Tree* t, void (*cb)(void*))
{
Var_Tree* p;
cb(t->info);
for(p = t->first; p != NULL; p = p->next)
go(t,cb); //<-----here you are calling the same
function with the same parameter that leads to an infinite loop
printf(">");
}
You should pass the value of p in place of t.
void go(Var_Tree* t, void (*cb)(void*))
{
Var_Tree* p;
cb(t->info);
for(p = t->first; p != NULL; p = p->next)
go(p,cb); //<----change t to p
printf(">");
}
I have to make a list that arrange the people in decreasing order of their number('no' for my program). I tryed to make it by modifying the addNode function but I got no result(peoples do not arrange by their number). This is my code:
Header code:
#ifndef __EX__
#define __EX__
typedef struct Person{
char name[10];
float no;
struct Person *pNext;
} NODE, *pNODE, **ppNODE;
void addNode(ppNODE, pNODE);
void travers(pNODE, unsigned int*);
#endif
Functions folder:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <string.h>
#include "EX.h"
void addNode (ppNODE ppPrim, pNODE p){
pNODE q = (pNODE)malloc(sizeof(NODE));
assert(q!=NULL);
printf("Add name: \n");
scanf("%s", &q->name);
printf("\nAdd no: ");
scanf("%f", &q->no);
if (p == NULL || q->no < p->no) {
q->pNext = *ppPrim;
*ppPrim = q;
} else {
q->pNext = p->pNext;
p->pNext = q;
}
return;
}
void travers(pNODE pPrim, unsigned int *pLen){
*pLen = 0;
pNODE tmp = pPrim;
while (tmp != NULL){
puts (tmp->name);
fprintf(stdout, " no %.2f\n", tmp->no);
tmp = tmp->pNext;
(*pLen)++;
}
return;
}
Main folder:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <string.h>
#include "EX.h"
int main(){
unsigned int len;
pNODE prim = NULL;
int i;
for (i=0; i<=1; i++){
addNode(&prim, prim);
addNode(&prim, prim->pNext);
}
travers(prim, &len);
return 0;
}
When you insert a new node to the list, you must traverse the list until you find a suitable place to insert it. Your code takes a second argument, which isn't really needed and causes confusion, and only looks at that.
The code to insert a code q at the end of a list that is defined by its head is:
Node *prev = NULL;
Node *p = *head;
while (p) {
prev = p;
p = p->pNext;
}
q->pNext = p;
if (prev == NULL) {
*head = q;
} else {
prev->pNext = q;
}
You can get rid of keeping track of the previous node and the distinction between inserting at the head and inserting after that by traversing the list with a pointer to node pointer:
Node **p = &head;
while (*p && (*p)->no < q->no) {
p = &(*p)->pNext;
}
q->pNext = *p;
*p = q;
In this concise code, p holds the address of the head at first and the address of the pNext pointer of the previous node. Both can be updated via *p.
You can now use this code to traverse only as far as the numbers associated with each node are smaller than the one of the node to insert. here's a complete program:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef struct Node Node;
void addNode(Node **p, const char *name, float no);
void travers(Node *pPrim, unsigned int *pLen);
struct Node {
char name[10];
float no;
Node *pNext;
};
void addNode(Node **p, const char *name, float no)
{
Node *q = malloc(sizeof(*q));
assert(q != NULL);
snprintf(q->name, sizeof(q->name), "%s", name);
q->no = no;
while (*p && (*p)->no < q->no) {
p = &(*p)->pNext;
}
q->pNext = *p;
*p = q;
}
void traverse(const Node *pPrim, unsigned int *pLen)
{
*pLen = 0;
while (pPrim != NULL) {
fprintf(stdout, "%-12s%.2f\n", pPrim->name, pPrim->no);
pPrim = pPrim->pNext;
(*pLen)++;
}
}
int main()
{
unsigned int len;
Node *prim = NULL;
addNode(&prim, "Alice", 0.23);
addNode(&prim, "Bob", 0.08);
addNode(&prim, "Charlie", 0.64);
addNode(&prim, "Dora", 0.82);
traverse(prim, &len);
printf("\n%u entries.\n", len);
return 0;
}
Things to node:
I've used Node * and Node ** instead of the typedeffed pNODE and ppNODE. In my opinion using the C pointer syntax is clearer.
You should separate taking user input from adding a node.
In your code you shouldn't pass the address of the char array when scanning a string, just the char array. (It happens to work, but it isn't correct. The compiler should warn you about that.)
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);
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
union value {
long long i;
unsigned long long u;
double d;
long double ld;
void *p;
void (*g) ();
};
struct foo {
struct {
union value max;
union value min;
}limits;
};
struct bucket_info {
void *p; // free position
void *limit; // end position
struct bucket_info *next; // next bucket
};
#define NODES 8192
void * my_malloc(size_t size)
{
void *p = malloc(size);
if (!p)
exit(1);
memset(p, 0, size);
return p;
}
void * alloc_bucket(size_t size)
{
struct bucket_info *pb;
pb = my_malloc(sizeof(struct bucket_info) + size);
pb->p = pb + 1;
pb->limit = (char *)pb->p + size;
return pb;
}
void * alloc_for_size(struct bucket_info *s, size_t size)
{
void *ret;
while (s->next)
s = s->next;
if ((char *)s->p + size > (char *)s->limit) {
struct bucket_info *pb = alloc_bucket(size * NODES);
s->next = pb;
s = pb;
}
ret = s->p;
s->p = (char *)s->p + size;
return ret;
}
static void * alloc_node(struct bucket_info **s, size_t size)
{
if (!*s)
*s = alloc_bucket(size * NODES);
return alloc_for_size(*s, size);
}
static struct bucket_info *foo_info;
void * alloc_foo_node()
{
void *ret = alloc_node(&foo_info, sizeof(struct foo));
return ret;
}
struct foo * new_foo()
{
return alloc_foo_node();
}
void test(int t, struct foo *foo1)
{
struct foo *foo2 = new_foo();
// Crash at this line
*foo2 = *foo1;
// comment this switch statement, it works. why?
switch (t) {
case 1:
break;
default:
break;
}
}
int main(int argc, const char * argv[]) {
struct foo *foo1 = new_foo();
test(10, foo1);
return 0;
}
Above is the complete code. And I've compiled it with clang, got a 'Segment Fault 11' at line:
*foo2 = *foo1;
Then, change this line to:
memcpy(foo2, foo1, sizeof(struct Foo));
It works.
Then I've tried compiled these two cases with gcc, there is no problem.
The value returned by alloc_foo_node may not be correctly aligned for struct foo.
On my system, printing _Alignof(struct foo) gives 16, but the pointers foo1 and foo2 are not multiples of 16.
So it causes undefined behaviour to convert the unaligned result of alloc_foo_node to have type struct foo *.
To fix this you have to muck around a lot more with your allocation code, to make sure that it only ever hands out space that is on the correct boundary for struct foo. You could use max_align_t to help with this (it is defined so that _Alignof(max_align_t) is the biggest possible alignment required).