Passing struct to function and adding elements - c

I'm new to C. I'm trying to pass a struct list to a function and within that function fill the list. Code is as follows:
#include <stdio.h>
#include <stdlib.h>
struct Abc {
int test;
struct Abc *next;
};
void demo_fill(struct Abc *data);
int main(int argc, char **argv) {
struct Abc *db = NULL;
demo_fill(db);
printf("%d\n",db->test);
return 0;
}
void demo_fill(struct Abc *data) {
int i;
for( i = 0; i < 5; i++ ) {
struct Abc *new;
new = malloc(sizeof(struct Abc));
new->test = i;
new->next = data;
data = new;
}
}
When running this a 'Segmentation fault (core dumped)' error occurs because the struct is still NULL when I try to print the first element. What am I doing wrong?

You're passing the pointer by value. You need to pass a pointer to a pointer if you want the change the value of the caller's pointer:
int main(int argc, char **argv) {
struct Abc *db = NULL;
demo_fill(&db);
printf("%d\n",db->test);
return 0;
}
void demo_fill(struct Abc **data) {
int i;
for( i = 0; i < 5; i++ ) {
struct Abc *new;
new = malloc(sizeof(struct Abc));
new->test = i;
new->next = *data;
*data = new;
}
}

Assigning data to new will have no effect. data is a local copy of the pointer. Pass a double pointer to fix that. Something like this:
void demo_fill(struct Abc** data) {
int i;
for( i = 0; i < 5; i++ ) {
struct Abc *new;
new = malloc(sizeof(struct Abc));
new->test = i;
new->next = *data;
*data = new;
}
}
And of course you will have to pas the pointer to db in main:
demo_fill(&db)

You can pass a pointer to the pointer as the other two answers say, so i just point out an alternative you might also consider: Instead of using a single struct you could use one struct for the list and another for entry-links:
struct link {
int test;
struct link* next;
};
struct list {
struct link* first;
};
void demo_fill(struct list* data);
You can then modify the first entry of the list without thinking about ** syntax.

Related

struct that holds struct, how to dereference

i have couple of linked lists in my larger program which i now want to keep in a struct (t_holder).
typedef struct s_list
{
int val;
struct t_list *next;
} t_list;
typedef struct s_holder
{
t_list *a_starts;
// more lists...
} t_holder;
now i try to figure out how i dereference this in my program.
void try_out(t_holder *list_holder, int num)
{
//assigning something to a_starts
list_holder->a_starts->val = num;
}
int main(int argc, char *argv[])
{
t_holder *list_holder;
int num;
num = 42;
list_holder = NULL;
try_out(list_holder, num);
return (0);
}
in the function "try_out" i simlpy try to assign a value to a_starts->val but my debugger shows me ACCESS_ERROR if i declare it like this
list_holder->a_starts->val = num;
For starters this typedef declarations
typedef struct s_list
{
int val;
struct t_list *next; // <===
} t_list;
is incorrect. It seems you mean
typedef struct s_list
{
int val;
struct s_list *next; // <===
} t_list;
As for your other code then you declared a null pointer
t_holder *list_holder;
//...
list_holder = NULL;
So dereferencing the null pointer results in undefined behavior.
You need to write something like the following
t_holder list_holder = { .a_starts = NULL };
//...
try_out( &list_holder, num);
and then within the function something like
void try_out(t_holder *list_holder, int num)
{
t_list *node = malloc( sizeof( *node ) );
node->val = num;
node->next = list_holder->a_starts;
list_holder->a_starts = node;
}

How to implement this create function correctly?

I'm trying to make a function to make a priority queue. My structs are this:
struct node {
char *item;
struct node *next;
};
struct queue {
struct node *start;
struct node *end;
};
struct priority_queue {
struct queue **aoq;
int x;
};
My function that I want to implement is:
struct priority_queue *priority_queue_create(int x);
Here, as seen in the structure priority_queue, struct queue **aoq is essentially an array of queues, which is want I want. int x, as in the function header, is the number of queues in the array.
My take on it is this:
struct priority_queue *priority_queue_create(int x) {
struct priority_queue *pq = malloc(sizeof(struct priority_queue));
pq->x = x;
pq->aoq = malloc(x* sizeof(struct queue));
return pq;
}
Where I put the 3 comment lines in the code above is where I suspect my error to be. I want to be able to do something like: if x = 3, there should be an array with 3 queues in it, and I suppose I'll be able to access it by doing something like
pq->aoq[0] /// to access the first queue in the array, or
pq->aoq[2] /// to access the third queue in the array
Can anyone help my fix my implementation? Thanks in advance.
Edit:
Other implementation I've tried:
struct priority_queue *priority_queue_create(int x) {
struct priority_queue *pq = malloc(sizeof(struct priority_queue *));
pq->x = x;
pq->aoq = malloc(x * sizeof(struct queue *));
for (int i = 0; i < x; ++i) {
pq->aoq[i] = malloc(sizeof(struct queue));
}
return pq;
}
From the code that you posted, I think this is the functionality that you want. You were missing the allocation of memory for the queues inside struct priority_queue, that is:
pq-> aoq = malloc( x * sizeof(struct queue *));
Adding this and keeping what you already had (with a sample main function to test the function priority_queue_create()), we have the following code:
#include <stdio.h>
#include <stdlib.h>
struct node {
char *item;
struct node *next;
};
struct queue {
struct node *start;
struct node *end;
};
struct priority_queue {
struct queue **aoq;
int x;
};
struct priority_queue *priority_queue_create(int x) {
struct priority_queue *pq = malloc(sizeof(struct priority_queue *));
pq->x = x;
pq-> aoq = malloc( x * sizeof(struct queue *));
for (int i = 0; i < x; ++i) {
pq->aoq[i] = malloc(sizeof(struct queue)); ///
}
return pq;
}
int main(){
struct priority_queue * pq = priority_queue_create(3);
char * str1 = "abcd";
char * str2 = "abcde";
pq->aoq[0]->start = malloc(sizeof(struct node));
pq->aoq[2]->start = malloc(sizeof(struct node));
pq->aoq[0]->start->item = str1;
pq->aoq[2]->start->item = str2;
printf("%s - %s\n", pq->aoq[0]->start->item, pq->aoq[2]->start->item);
free(pq->aoq[0]->start);
free(pq->aoq[2]->start);
free(pq->aoq[0]);
free(pq->aoq[1]);
free(pq->aoq[2]);
free(pq->aoq);
free(pq);
}

Pointer passed in to function not reassigning

So I'm trying to implement a linked list stack that takes in char arguments and adds them to the link list with it's ascii code as the value of the nodes.
I pass in my nstack pointer into my push function and re-assign it to new_node in order to create a new top, but my push function doesn't seem to be reassigning my nstack node - it just prints the originally initialized nstack value. Why isn't nstack being reassigned?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct list_node {
int element;
struct list_node * pnext;
};
void push(struct list_node *operators, int e);
int pop(struct list_node *operators);
int main(int argc, char *argv[]) {
int newvalue = (int)argv[1][0];
struct list_node * nstack = (struct list_node*)malloc(sizeof(struct list_node));
nstack->element = newvalue;
nstack->pnext = NULL;
int i;
for (i = 2; i < argc; i++) {
push(nstack, (int)argv[i][0]);
}
printf("top: %d\n", nstack->element);
}
void push(struct list_node *nstack, int e) {
struct list_node * new_node = (struct list_node*)malloc(sizeof(struct list_node));
new_node->pnext = nstack;
new_node->element = e;
nstack = new_node;
}
Because you are passing a copy of pointer (by value). You need something like this (pointer to pointer):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct list_node {
int element;
struct list_node * pnext;
};
void push(struct list_node **operators, int e);
int pop(struct list_node *operators);
int main(int argc, char *argv[]) {
//int newvalue = (int)argv[1][0];
int newvalue = 1;
struct list_node * nstack = (struct list_node*)malloc(sizeof(struct list_node));
nstack->element = newvalue;
nstack->pnext = NULL;
int i;
for (i = 2; i < 7; i++) {
//push(nstack, (int)argv[i][0]);
push(&nstack, i);
}
printf("top: %d\n", nstack->element);
}
void push(struct list_node **nstack, int e) {
struct list_node * new_node = (struct list_node*)malloc(sizeof(struct list_node));
new_node->pnext = *nstack;
new_node->element = e;
*nstack = new_node;
}
To expand on Tarod's correct point. What the caller function is doing is taking a copy of your pointer value and putting it onto the stack or in a register (compiler dependent) that will then be used in your push function. However, within your push function you're actually changing the value in this register or stack location before returning. But when you return the caller function basically discards this information (its popped of the stack - or, again depending on the compiler, uses the register for something else). The only way around this is to pass the address of the pointer and deference this when you need to write to it as Tarod has shown.

C: incompatible types in assignment

typedef char Last_t[MAXL];
typedef char Rest_t[MAXR];
typedef struct NodeTag {
Last_t Last;
Rest_t Rest;
struct NodeTag *Link;
} Node;
typedef struct {
Node *Index[26];
Node *L;
} ContactList;
// parameter to take in a char argument to set it to contact.Last
void INS( Node *cn )
Node contactName;
contactName.Last= cn;
// temp->data=num;
//contactName.Rest=restName;
}
//cant figure out how to pass a char argument
int main(void)
{
INS("David");
}
void INS should be passing an argument of type char *, not Node, if you want the code in your main to work.
To assign it to the member Last, you would have to use strcpy or something similar. This is because you can't assign a pointer to an array. More specifically, you can't assign a char * to char[MAXL].
You could try this:
void INS( char * cn ) {
Node contactName;
strncpy (contactName.Last, cn, MAXL);
}
int main(void){
INS("David");
return 0;
}
But, this doesn't handle errors very well. Here's a way of doing it that's more error-safe:
void INS (char * cn){
Node contactName = {
.Last[0] = 0,
.Rest[0] = 0,
.Link = 0
};
if (cn){
strncpy (contactName.Last, cn, MAXL - 1);
contactName.Last[MAXL - 1] = 0;
}
}
int main (void){
INS ("David");
return 0;
}

malloc and pointer in a struct

I have the following C code:
typedef struct DListNode_ {
void *data;
struct DListNode_ *prev;
struct DListNode_ *next;
} DListNode;
typedef struct DList_ {
int size;
DListNode *tail;
DListNode *head;
} DList;
void insert(DList * list, DListNode * element, int data) {
DListNode * new_element = (DListNode *)malloc(sizeof(DListNode));
new_element->data = &data;
if (list->head==NULL) {
list->head=list->tail=new_element;
list->size++;
return;
}
if(element == NULL) {
// handle size==0?
new_element->next=list->head;
list->head->prev=new_element;
list->head=new_element;
list->size++;
} else {
printf("Not yet implemented!\n");
}
}
void printNodes(DList *list) {
DListNode * pointer = list->head;
if (pointer!=NULL) {
int v= *((int*)pointer->data);
printf("Node has value: %d\n", v);
while (pointer->next != NULL) {
v = *((int*)pointer->data);
printf("Node has value: %d\n", v);
pointer=pointer->next;
}
}
}
int main(int argc, const char * argv[])
{
int e0 = 23;
int e1 = 7;
int e2 = 11;
DList *list = (DList *)malloc(sizeof(DList));
initList(list);
assert(count(list)==0);
insert(list, NULL, e0);
assert(count(list)==1);
insert(list,NULL, e1);
assert(count(list)==2);
insert(list,NULL, e2);
assert(count(list)==3);
printNodes(list);
return 0;
}
I have a few problems:
does DListNode * new_element = (DListNode *)malloc(sizeof(DListNode)); also allocate space for the, data, prev, next pointer or do I manually need to call malloc on each of those pointers?
When I print the content of the data pointer in each node they all have the value 3 even though I insert 23, 7 and 11 and set the data pointer to the address of the int: ** new_element->data = &data;**.
(Introductionary textbooks on C have been ordered)
EDIT:
insert now takes a void pointer to the data:
// Insert data as the new head
void insert(DList *list, DListNode *element, void *data) {
DListNode *new_element = malloc(sizeof(DListNode));
new_element->data = data;
if (list->head==NULL) {
list->head=list->tail=new_element;
list->size++;
return;
}
if(element == NULL) {
new_element->next=list->head;
list->head->prev=new_element;
list->head=new_element;
list->size++;
} else {
printf("Not yet implemented!\n");
}
}
In main I do:
int main(int argc, const char * argv[])
{
int i0=7;
int *ip0 = malloc(sizeof(int));
ip0 = &i0;
int i1=8;
int *ip1 = malloc(sizeof(int));
ip1 = &i1;
int *ip2 = malloc(sizeof(int));
int i2=44;
ip2 = &i2;
DList *list = malloc(sizeof(DList));
initList(list);
// create some nodes
assert(count(list)==0);
insert(list, NULL, ip0);
assert(count(list)==1);
insert(list,NULL, ip1);
assert(count(list)==2);
insert(list,NULL, ip2);
assert(count(list)==3);
printNodes(list);
return 0;
}
which outputs:
Node has value: 44
Node has value: 44
Node has value: 8
but it should be:
Node has value: 44
Node has value: 8
Node has value: 7
malloc(sizeof(DListNode)) allocates space for exactly one DListNode, which by definition consists of a void* and two DListNode pointers. It does not initialize those pointers, though.
You're assigning the address of the data argument to insert. That's a pointer to a temporary which is invalidated once insert returns. The behavior of the program is undefined. The easy solution is to just replace void *data by int data.
You need to manually set those pointers to where they point with malloc. Without it, they will point to a space that isn't of size DListNode.
Don't make the data a pointer. Just make the data an int (it gets auto allocated) and then just set data = data (the data that is passed into insert).

Resources