double pointer to struct inside struct - c

How can i access to a duble pointer in a struct pointer??
with the code bellow, calling addBow() give me a Segmentation fault (core dumped) error
typedef struct
{
int size;
tCity **cities;
}tGraph;
//para iniciar el grafo
void initGraph(tGraph *graph, int size)
{
graph = (tGraph*)malloc(sizeof(tGraph));
graph->cities = (tCity**)malloc(sizeof(tCity*) * size);
graph->size = size;
}
//agrega un arco entre ciudades
void addBow(tGraph *graph, int id, tCity *city)
{
if ( graph->cities[id] == NULL )
{
graph->cities[id] = city;
}
else
{
tCity *cur = graph->cities[id];
while ( getNext(cur) != NULL )
{
cur = getNext(cur);
}
setNext(cur, city);
}
}
which is the correct syntax for graph->cities[id]??
Thanks
SOLUTION:
editing the initGraph solve the problem since the memory wasn't allocated
tGraph* initGraph(int size)
{
tGraph *graph = (tGraph*)malloc(sizeof(tGraph));
graph->cities = (tCity**)malloc(sizeof(tCity*) * size);
graph->size = size;
return graph;
}

You should either have initGraph() take (**graph) or return the graph. Since the malloc address of graph is local to initGraph.
Something like:
void initGraph(tGraph **graph, int size)
{
tgraph *temp;
temp = (tGraph*)malloc(sizeof(tGraph*));
temp->cities = (tCity**)malloc(sizeof(tCity*) * size);
temp->size = size;
*graph = temp;
}

graph = (tGraph*)malloc(sizeof(tGraph*));
There is one of your problems...
it should be
graph = malloc(sizeof(tGraph));

Make initGraph () return a pointer to tGraph.
tGraph* initGraph(int size) {
tGraph* graph;
graph = malloc(sizeof(tGraph));
graph->cities = malloc(sizeof(tCity*) * size);
graph->size = size;
return graph;
}

//consider this example
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct test{
int val;
}test;
typedef struct data{
char ch[10];
test **p;
}data;
int main(){
data *d=malloc(sizeof(data));
strcpy(d->ch,"hello");
d->p=(test**)malloc(sizeof(test*));
d->p[0]=(test*)malloc(sizeof(test));
d->p[0]->val=10;
printf("%s,%d",d->ch,d->p[0]->val);
}

Related

C - Separate Chaining Hash Table - Output and Space Issues

so basically I wrote a program to initialize, insert, and output the whole hash table. I thought I did pretty good, but there's many issues.
First issue being, some names are displayed with an additional weird character, why??
Second issue being, I can only input a size parameter (for initialize(size) function) of <8. Anything above 7 will output "Out of Space!" but why?? I thought I managed the space pretty well from what I was taught at uni:((
Please help!
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct list_node *node_ptr;
struct list_node
{
node_ptr next;
char *key;
char *value;
};
typedef node_ptr LIST;
typedef node_ptr position;
struct hash_table
{
LIST *list_ptr_arr;
unsigned int table_size;
};
typedef struct hash_table *HASHTABLE;
unsigned long long int
hash(const char *key, unsigned int hash_size)
{
unsigned long long int hash;
for(int i = 0; key[i]; i++)
{
hash = (hash<<32)+key[i];
}
return (hash%hash_size);
}
unsigned int
next_prime(int number)
{
int j;
for(int i = number; ; i++)
{
for(j = 2; j<i; j++)
{
if(i%j == 0){break;}
}
if(i==j){return j;}
}
}
HASHTABLE
initialize(unsigned int table_size)
{
HASHTABLE H;
H = (HASHTABLE) malloc(sizeof(struct hash_table));
if(H==NULL){printf("Out of Space!"); return 0;}
H->table_size = next_prime(table_size);
H->list_ptr_arr = (position*) malloc(sizeof(LIST)*H->table_size);
if(H->list_ptr_arr==NULL){printf("Out of Space!"); return 0;}
H->list_ptr_arr = (LIST*) malloc(sizeof(struct list_node)*H->table_size);
for(unsigned int i = 0; i<H->table_size; i++)
{
if(H->list_ptr_arr[i]==NULL){printf("Out of Space!"); return 0;}
H->list_ptr_arr[i]=NULL;
}
return H;
}
position
set(const char *key, const char *value)
{
position entry = (position) malloc(sizeof(struct list_node));
entry->value = (char*) malloc(strlen(value)+1);
entry->key = (char*) malloc(strlen(key)+1);
strncpy(entry->key,key,strlen(key));
strncpy(entry->value,value,strlen(value));
entry->next = NULL;
return entry;
}
void
insert(const char *key, const char *value, HASHTABLE H)
{
unsigned int slot = hash(key, H->table_size);
node_ptr entry = H->list_ptr_arr[slot];
node_ptr prev;
if(entry==NULL)
{
H->list_ptr_arr[slot] = set(key, value);
return;
}
while(entry!=NULL)
{
if(strcmp(entry->key, key)==0)
{
free(entry->value);
entry->value = malloc(strlen(value)+1);
strncpy(entry->value,value,strlen(value));
return;
}
prev = entry;
entry = prev->next;
}
prev->next = set(key, value);
}
void
dump(HASHTABLE H)
{
for(unsigned int i = 0; i<H->table_size; i++)
{
position entry = H->list_ptr_arr[i];
if(H->list_ptr_arr[i]==NULL){continue;}
printf("slot[%d]: ", i);
for(;;)
{
printf("%s|%s -> ", entry->key, entry->value);
if(entry->next == NULL)
{
printf("NULL");
break;
}
entry = entry->next;
}
printf("\n");
}
}
int main()
{
HASHTABLE H = initialize(7);
insert("name1", "David", H);
insert("name2", "Lara", H);
insert("name3", "Slavka", H);
insert("name4", "Ivo", H);
insert("name5", "Radka", H);
insert("name6", "Kvetka", H);
dump(H);
return 0;
}
Then I tried to change it up a bit:
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct list_node *node_ptr;
struct list_node
{
node_ptr next;
char *key;
char *value;
};
typedef node_ptr LIST;
typedef node_ptr position;
struct hash_table
{
LIST *list_ptr_arr;
unsigned int table_size;
};
typedef struct hash_table *HASHTABLE;
unsigned long long int
hash(const char *key, unsigned int hash_size)
{
unsigned long long int hash;
for(int i = 0; key[i]; i++)
{
hash = (hash<<32)+key[i];
}
return (hash%hash_size);
}
unsigned int
next_prime(int number)
{
int j;
for(int i = number; ; i++)
{
for(j = 2; j<i; j++)
{
if(i%j == 0){break;}
}
if(i==j){return j;}
}
}
HASHTABLE
initialize(unsigned int table_size)
{
HASHTABLE H;
H = (HASHTABLE) malloc(sizeof(struct hash_table));
if(H==NULL){printf("Out of Space!1"); return 0;}
H->table_size = next_prime(table_size);
H->list_ptr_arr = (position*) malloc(sizeof(LIST)*H->table_size);
if(H->list_ptr_arr==NULL){printf("Out of Space!2"); return 0;}
H->list_ptr_arr = (LIST*) malloc(sizeof(struct list_node)*H->table_size);
for(unsigned int i = 0; i<H->table_size; ++i)
{
if(H->list_ptr_arr[i]==NULL){printf("Out of Space!3"); return 0;}
H->list_ptr_arr[i]->value="HEAD";
H->list_ptr_arr[i]->next=NULL;
}
return H;
}
void
insert(const char *key, const char *value, HASHTABLE H)
{
unsigned int slot = hash(key, H->table_size);
LIST entry = H->list_ptr_arr[slot], newNode;
newNode = (position) malloc(sizeof(struct list_node));
if(newNode==NULL){printf("Out of Space4!"); return;}
newNode->next = entry->next;
strncpy(newNode->key,key,strlen(key));
strncpy(newNode->value,value,strlen(value));
entry->next = newNode;
}
void
dump(HASHTABLE H)
{
for(unsigned int i = 0; i<H->table_size; i++)
{
position entry = H->list_ptr_arr[i];
position p = entry->next;
if(p==NULL){continue;}
printf("slot[%d]: ", i);
for(;;)
{
printf("%s|%s -> ", p->key, p->value);
if(p->next == NULL)
{
printf("NULL");
break;
}
p = p->next;
}
printf("\n");
}
}
int main()
{
HASHTABLE H = initialize(4);
insert("name1", "David", H);
insert("name2", "Lara", H);
insert("name3", "Slavka", H);
insert("name4", "Ivo", H);
insert("name5", "Radka", H);
insert("name6", "Kvetka", H);
dump(H);
return 0;
}
Thank you!
I modified the second piece of code, it runs correctly on my computer.
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 256
// typedefing struct list_node multiple times is confusing, so I remove these typedefs
struct list_node {
struct list_node *next;
// strings need storage space in the memory,
// declaring key and value as array here can save some calls to malloc()
char key[MAX_SIZE];
char value[MAX_SIZE];
};
struct hash_table {
struct list_node **list_ptr_arr;
unsigned int table_size;
};
// it's better not to hide pointer type using typedef
typedef struct hash_table HASHTABLE;
unsigned long long int hash(const char *key, unsigned int hash_size) {
// hash is not initialized originally (the value is choosed randomly)
unsigned long long int hash = 5;
for (int i = 0; key[i]; i++) {
hash = (hash << 32) + key[i];
}
return (hash%hash_size);
}
unsigned int next_prime(int number) {
int j;
for (int i = number; ; i++) {
for (j = 2; j < i; j++) {
if (i%j == 0) { break; }
}
if (i == j) { return j; }
}
}
HASHTABLE *initialize(unsigned int table_size) {
HASHTABLE *H;
// you don't need to type cast malloc() result in C
H = malloc(sizeof(*H));
H->table_size = next_prime(table_size);
// I suppose list_ptr_arr is a pointer to an array of struct list_node * object
H->list_ptr_arr = malloc(sizeof(*(H->list_ptr_arr)) * H->table_size);
for (unsigned int i = 0; i < H->table_size; ++i) {
// malloc() for H->list_ptr_arr only allocated area for struct list_node * array, the struct list_node pointed to is not allocated yet, so malloc() here
H->list_ptr_arr[i] = malloc(sizeof(*(H->list_ptr_arr[i])));
strcpy(H->list_ptr_arr[i]->value, "HEAD");
H->list_ptr_arr[i]->next = NULL;
}
return H;
}
void insert(const char *key, const char *value, HASHTABLE *H) {
unsigned int slot = hash(key, H->table_size);
struct list_node *entry = H->list_ptr_arr[slot], *newNode;
newNode = malloc(sizeof(*newNode));
newNode->next = entry->next;
// strlen() doesn't count the '\0', just use strcpy here
strcpy(newNode->key, key);
strcpy(newNode->value, value);
entry->next = newNode;
}
void dump(HASHTABLE *H) {
for (unsigned int i = 0; i < H->table_size; i++) {
struct list_node *entry = H->list_ptr_arr[i];
struct list_node *p = entry->next;
if (p == NULL) { continue; }
printf("slot[%d]: ", i);
for (;;) {
printf("%s|%s -> ", p->key, p->value);
if (p->next == NULL) {
printf("NULL");
break;
}
p = p->next;
}
printf("\n");
}
}
int main() {
HASHTABLE *H = initialize(4);
insert("name1", "David", H);
insert("name2", "Lara", H);
insert("name3", "Slavka", H);
insert("name4", "Ivo", H);
insert("name5", "Radka", H);
insert("name6", "Kvetka", H);
dump(H);
return 0;
}
P.S. Don't forget to free the hashtable.

Building BFS with an implemented queue in C

I'm implementing a graph traversal breadth-first search that I found here. However, their implementation involves integers and without any linked list. I was playing around with it a little bit I have no luck in getting any results because it doesn't seem to work as intended.
This is the code that I currently have:
(main.c)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
typedef struct s_list
{
struct s_list *next;
void *content;
} t_list;
typedef struct s_queue
{
t_list *first;
t_list *last;
} t_queue;
typedef struct s_node
{
struct s_node *next;
int vertex;
} t_node;
typedef struct s_graph
{
t_node **adj_lists;
int *visited;
int total_vertices;
} t_graph;
/*Graph functions*/
t_node *create_node(int vertex);
t_graph *create_graph(int vertices);
void add_edge(t_graph *graph, int src, int dst);
void bfs(t_graph *graph, int start_vertex);
/*Misc functions*/
void my_putstr(char *str);
void *my_memalloc(size_t size);
void *my_memset(void *ptr, int value, size_t num);
void my_bzero(void *s, size_t n);
/*Queue functions*/
t_queue *init_queue(void);
void enqueue(t_queue *queue, void *content);
void *dequeue(t_queue *queue);
void *peek_queue(t_queue *queue);
int is_empty(t_queue *queue);
void my_print_queue(t_queue *queue);
t_node *create_node(int val)
{
t_node *new_node;
new_node = (t_node*)my_memalloc(sizeof(t_node));
new_node->vertex = val;
new_node->next = NULL;
return (new_node);
}
t_graph *create_graph(int vertices)
{
int i;
t_graph *graph;
i = 0;
graph = my_memalloc(sizeof(t_graph));
graph->total_vertices = vertices;
printf("graph->total_vertices: %d\n", vertices);
graph->adj_lists = (t_node**)my_memalloc(sizeof(t_node));
graph->visited = my_memalloc(sizeof(int) * vertices);
while (i < vertices)
{
graph->adj_lists[i] = NULL;
graph->visited[i] = 0;
i++;
}
return (graph);
}
void add_edge(t_graph *graph, int src, int dst)
{
t_node *new_node;
new_node = create_node(dst);
new_node->next = graph->adj_lists[src];
graph->adj_lists[src] = new_node;
new_node = create_node(src);
new_node->next = graph->adj_lists[dst];
graph->adj_lists[dst] = new_node;
}
void bfs(t_graph *graph, int start_vertex)
{
t_queue *queue;
queue = init_queue();
graph->visited[start_vertex] = 1;
printf("start_vertex before enqueue %d\n", start_vertex);
my_print_queue(queue);
enqueue(queue, &start_vertex);
printf("start_vertex after enqueue %d\n", start_vertex);
while (!is_empty(queue))
{
my_print_queue(queue);
int current_vertex;
t_node *tmp;
current_vertex = (int)dequeue(queue);
printf("Visited %d nodes\n", current_vertex);
tmp = graph->adj_lists[current_vertex];
while (tmp)
{
int adj_vertex;
adj_vertex = tmp->vertex;
if (graph->visited[adj_vertex] == 0)
{
graph->visited[adj_vertex] = 1;
printf("%d\n", graph->visited[adj_vertex]);
enqueue(queue, &adj_vertex);
my_print_queue(queue);
}
tmp = tmp->next;
}
}
}
t_queue *init_queue(void)
{
t_queue *node;
node = (t_queue *)my_memalloc(sizeof(t_queue));
node->first = NULL;
node->last = NULL;
return (node);
}
void enqueue(t_queue *queue, void *content)
{
t_list *node;
node = (t_list *)my_memalloc(sizeof(t_list));
node->content = content;
node->next = NULL;
if (!queue->last)
{
queue->last = node;
queue->first = node;
}
else
{
queue->last->next = node;
queue->last = queue->last->next;
}
return ;
}
void *dequeue(t_queue *queue)
{
t_list *tmp;
tmp = queue->first;
if (!tmp)
return (NULL);
else
{
queue->first = tmp->next;
return (tmp->content);
}
}
void *peek_queue(t_queue *queue)
{
if (queue->first == NULL)
return (NULL);
return (queue->first->content);
}
int is_empty(t_queue *queue)
{
return (queue->first == NULL);
}
void my_print_queue(t_queue *queue)
{
if (is_empty(queue))
my_putstr("Empty queue\n");
else
{
while (!is_empty(queue))
{
int val = *(int *)queue->first->content;
printf("%d \n", val);
dequeue(queue);
}
}
}
void my_putstr(char *str)
{
int i;
i = 0;
while (str[i])
write(1, &str[i++], 1);
}
void *my_memalloc(size_t size)
{
char *str;
str = ((void*)malloc(size));
if (!str)
return (NULL);
my_bzero(str, size);
return (str);
}
void *my_memset(void *ptr, int value, size_t num)
{
unsigned char *uptr;
uptr = (unsigned char*)ptr;
while (num--)
*uptr++ = (unsigned char)value;
return (ptr);
}
void my_bzero(void *s, size_t n)
{
my_memset(s, 0, n);
}
int main(void)
{
t_graph *graph;
graph = create_graph(3);
add_edge(graph, 0, 1);
add_edge(graph, 0, 2);
add_edge(graph, 2, 4);
bfs(graph, 2);
return (0);
}
I did some research like type-casting a void pointer to make it into a char or int, or any other data type. What happens is that the create graph does it's creation after calling it; but, when it comes to the bfs, it doesn't show the correct output after. It never prints the visited vertices. I'm getting a result of
graph->total_vertices: 3
start_vertex before enqueue 2
Empty queue
start_vertex after enqueue 2
2
Visited 0 nodes
The expected output should be something like this:
Queue contains
0 Resetting queueVisited 0
Queue contains
2 1 Visited 2
Queue contains
1 4 Visited 1
Queue contains
4 Resetting queueVisited 4
I've been trying to figure out by myself to the point that I'm burning out. What am I doing wrong in here?
While posting this, I will keep debugging on my side and see what it does with a couple print statements.
I can point out the following mistakes:
my_print_queue destroys your queue. So anything after it's call works with empty queue.
You don't fill visited with to zeroes. By default their values is pretty much arbitrary. Since you compare their values with 0, it makes sense that comparison fails.

ds_list can't handle more than 3 elements

i don't know why i can't even add 4th element...
(im working on windows with mingw)
this is my code:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 100
typedef struct ds_list_element {
char value[MAX];
struct ds_list_element *next;
}* ds_list;
int ds_list_empty(ds_list id) { // id listy
if (id == NULL) return 1;
else return 0;
}
ds_list ds_list_add(ds_list id, char add[MAX]) {
ds_list temp;
temp = (ds_list)(malloc(sizeof(ds_list)));
strcpy(temp->value,add);
temp->next = id;
return temp;
}
void ds_list_print(ds_list id) {
if (ds_list_empty(id) == 0) {
printf("%s\n",id->value);
ds_list_print(id->next);
}
}
int main () {
ds_list my_list = NULL;
my_list = ds_list_add(my_list,"one");
my_list = ds_list_add(my_list,"two");
my_list = ds_list_add(my_list,"three");
my_list = ds_list_add(my_list,"four");
ds_list_print(my_list);
return 0;
}
and the result is:
four
three
two
y
Press any key to continue . . .
i don't know why it is happening. everything should work fine.
my friend told me it is working on ubuntu...
temp = (ds_list)(malloc(sizeof(ds_list)));
will be
temp = malloc(sizeof(*temp)));
You want to allocate memory for struct ds_list_element not struct ds_list_element*. Don't hide pointers behind typedef name. It rarely helps.
Also you should check the return value of malloc and the casting is not needed.
Use ds_list as structure not a pointer
typedef struct ds_list_element {
char value[MAX];
struct ds_list_element *next;
}ds_list;
and allocate memory for the structure not a pointer.
Working program:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 100
typedef struct ds_list_element {
char value[MAX];
struct ds_list_element *next;
}ds_list;
int ds_list_empty(ds_list *id) { // id listy
if (id == NULL) return 1;
else return 0;
}
ds_list * ds_list_add(ds_list *id, char add[MAX]) {
ds_list *temp;
temp = (malloc(sizeof(ds_list)));
strcpy(temp->value,add);
temp->next = id;
return temp;
}
void ds_list_print(ds_list *id) {
if (ds_list_empty(id) == 0) {
printf("%s\n",id->value);
ds_list_print(id->next);
}
}
int main () {
ds_list *my_list = NULL;
my_list = ds_list_add(my_list,"one");
my_list = ds_list_add(my_list,"two");
my_list = ds_list_add(my_list,"three");
my_list = ds_list_add(my_list,"four");
ds_list_print(my_list);
return 0;
}
Output:
four
three
two
one

C - accessing dynamic array within a struct

I'm trying to create cluster with dynamic array objects.
Struct definitions are following:
struct obj_t {
int id;
float x;
float y;
};
struct cluster_t {
int size;
int capacity;
struct obj_t *obj;
};
Function for adding object to cluster is:
void append_cluster(struct cluster_t *c, struct obj_t obj)
{
if(c->capacity < (c->size + 1))
{
c = resize_cluster(c, c->size + 1);
}
if(c == NULL)
return;
c->obj[c->size] = obj; //at this point program crashes.
c->size++;
}
EDIT: Here is resize_cluster() function:
struct cluster_t *resize_cluster(struct cluster_t *c, int new_cap)
{
if (c->capacity >= new_cap)
return c;
size_t size = sizeof(struct obj_t) * new_cap;
void *arr = realloc(c->obj, size);
if (arr == NULL)
return NULL;
c->obj = (struct obj_t*)arr;
c->capacity = new_cap;
return c;
}
EDIT 2: Here is cluster initialization:
void init_cluster(struct cluster_t *c, int cap)
{
c = malloc(sizeof(struct cluster_t));
c->size = 0;
c->capacity = cap;
c->obj = (struct obj_t*)malloc(cap * sizeof(struct obj_t));
}
I can't figure out why program crashes when I try to add the object to the array in cluster. Is accessing array this way wrong? If so, how should I access it?
The issue is the call to init_cluster(). The c parameter is passed-by-value, so whatever you are sending remains unmodified:
struct cluster_t * c;
init_cluster(c, 1);
// c is uninitialized!
One fix would be to pass a pointer to an object:
struct cluster_t c;
init_cluster(&c, 1);
Then remove c = malloc(sizeof(struct cluster_t)); from init_cluster();
Or, you could create an alloc_cluster function:
struct cluster_t * alloc_cluster(int cap)
{
c = malloc(sizeof(struct cluster_t));
c->size = 0;
c->capacity = cap;
c->obj = malloc(cap * sizeof(struct obj_t));
return c;
}
And call it like:
struct cluster_t *c = init_cluster(1);

Stack that contains Pointers to other Structs

I tried making a Stack that contains Pointers(meaning adresses) that point to some other kind of structs(Prof or Stud). But I can't seem to manage it. The errors were infinite. Here's the code:
struct MyStack
{
int head;
void **stack;
int size;
};
struct stud
{
char flag;
char fname[50];
int semester;
};
struct prof
{
char flag;
char fname[50];
char course[30];
};
int InitStack(int size,struct MyStack *stack);
int InitStack(int size,struct MyStack *stack)
{
stack->size = size;
*stack->stack=(int *) malloc(size*sizeof(int) ); //Is this RIGHT?
stack->head=-1;
return 0;
}
int main()
{
int size,sel;
size = GiveSize();
struct MyStack NewStack;
InitStack(size,&NewStack);
do{
sel=Menu();
Select(sel,NewStack.head,&NewStack);
}while (sel!=0);
return 0;
}
How I can push pointers(that point to studs and profs) to the stack?
Heres the code:
int CreateStud(struct MyStack *stack,char *name,int sem,int *head,int n)
{
struct stud newStud;
int thead=*head;
newStud.flag='s';
strcpy(newStud.fname,name);
newStud.semester=sem;
Push(stack,&thead,&newStud,n);
*head=thead;
return 0;
}
int Push(struct MyStack *stack,int *head, void *elem,int n)
{
if(*head>=n-1)
return 0;
stack->stack[++*head]=elem;
return 1;
}
Your InitStack function should be
int InitStack(int size,struct MyStack *stack)
{
stack->size = size;
stack->stack= malloc(size * sizeof(void*));
stack->head=-1;
return 0;
}
The push function should be something like
int Push(struct MyStack *stack, void *str)
{
/* Check if stack is full */
stack->head++;
stack->stack[stack->head] = str;
return 0;
}
The you can use it as
struct stud s1;
struct prof p1;
Push(&NewStack, &s1);
Push(&NewStack, &p1);

Resources