How to insert nodes into list by looping? - c

How to Implement in right way to store values into linked list? In this example the last element will be "0" . Is there a possible to write the content of while loop that allows me don't create the last node which will be "0" after allocating in while loop?
void store(Stack *a, t_important *data)
{
int i;
Stack *tmp;
tmp = a;
i = 0;
while(i < data->length)
{
tmp->n = data->collection_of_ints[i];
tmp->next = malloc(sizeof(Stack));
tmp = tmp->next;
i++;
}
}
Input:
2->6->0->1->3->5->4
Output:
2->6->0->1->3->5->4->0
It is my main function in where i call the store function.
int main(int ac, char **av)
{
Actions action;
Stack *a;
Stack *b;
t_important *data;
if(ac < 2)
return (-1);
data = malloc(sizeof(*data));
stack_nums_counter(av, data);
collect(av, data);
__check__collection(data);
__collecting_ints(data);
action = init();
a = NULL;
b = NULL;
store(&a, data);
__sort_a__(&a, &b, data, action);
return (0);
}

I would make store take a Stack** instead:
void store(Stack **a, t_important *data) {
// find last `next`
while(*a) a = &(*a)->next;
// insert values
for(int i = 0; i < data->length; ++i)
{
*a = malloc(sizeof **a);
(*a)->n = data->collection_of_ints[i];
a = &(*a)->next;
}
*a = NULL; // terminate the linked list
}
and then call it like so
Stack *my_stack = NULL;
store(&my_stack, &some_t_important_instance);
If you instead want to insert the important data first in the linked list, you skip the first while loop to find the last next member:
void store(Stack **a, t_important *data) {
Stack *old_first = *a;
// insert values
for(int i = 0; i < data->length; ++i)
{
*a = malloc(sizeof **a);
(*a)->n = data->collection_of_ints[i];
a = &(*a)->next;
}
// link the last inserted node to the old first node
*a = old_first;
}

You always have uninitialized last node of the stack
tmp->next = malloc(sizeof(Stack));
tmp = tmp->next;
So when the stack is outputted then the program invokes undefined behavior.
Also it seems within the caller instead of declaring a pointer of the type Stack * you declared an object of the type Stack and are passing a pointer to it. It is a bad approach.
Nevertheless using your approach the function can be defined the following way
void store(Stack *a, t_important *data)
{
int i;
Stack *tmp;
tmp = a;
i = 0;
while(i < data->length)
{
if ( i != 0 )
{
tmp->next = malloc(sizeof(Stack));
tmp = tmp->next;
}
tmp->n = data->collection_of_ints[i];
tmp->next = NULL;
i++;
}
}

Related

Proper way of deallocation of double pointer to struct

I am trying to add memory deallocations to old C code.
I have a hash table of custom objects (HASHREC). After analysis of current code and reading other SO questions, I know that I need to provide three levels of deallocations. Fist - word member, next HASHREC*, and then HASHREC**.
My version of free_table() function frees mentioned objects. Unfortunately, Valgrind still complains that some bytes are lost.
I am not able to provide full code, it will be too long, but I am presenting how HASHREC **vocab_hash is filled inside inithashtable() and hashinsert().
Could you give me a suggestion how should I fix free_table()?
typedef struct hashrec {
char *word;
long long count;
struct hashrec *next;
} HASHREC;
HASHREC ** inithashtable() {
int i;
HASHREC **ht;
ht = (HASHREC **) malloc( sizeof(HASHREC *) * TSIZE );
for (i = 0; i < TSIZE; i++) ht[i] = (HASHREC *) NULL;
return ht;
}
void hashinsert(HASHREC **ht, char *w) {
HASHREC *htmp, *hprv;
unsigned int hval = HASHFN(w, TSIZE, SEED);
for (hprv = NULL, htmp = ht[hval]; htmp != NULL && scmp(htmp->word, w) != 0; hprv = htmp, htmp = htmp->next);
if (htmp == NULL) {
htmp = (HASHREC *) malloc( sizeof(HASHREC) ); //<-------- problematic allocation (Valgrind note)
htmp->word = (char *) malloc( strlen(w) + 1 );
strcpy(htmp->word, w);
htmp->next = NULL;
if ( hprv==NULL ) ht[hval] = htmp;
else hprv->next = htmp;
}
else {/* new records are not moved to front */
htmp->count++;
if (hprv != NULL) { /* move to front on access */
hprv->next = htmp->next;
htmp->next = ht[hval];
ht[hval] = htmp;
}
}
return;
}
void free_table(HASHREC **ht) {
int i;
HASHREC* current;
HASHREC* tmp;
for (i = 0; i < TSIZE; i++){
current = ht[i];
while(current != NULL) {
tmp = current;
current = current->next;
free(tmp->word);
}
free(ht[i]);
}
free(ht);
}
int main(int argc, char **argv) {
HASHREC **vocab_hash = inithashtable();
// ...
hashinsert(vocab_hash, w);
//....
free_table(vocab_hash);
return 0;
}
I assume the problem is here:
current = ht[i];
while(current != NULL) {
tmp = current;
current = current->next;
free(tmp->word);
}
free(ht[i]);
You release the word but you don’t release tmp. After you release the first item in the linked list but not the others which causes a leak.
Free tmp in there and don’t free ht[i] after since it’s already freed here.
current = ht[i];
while(current != NULL) {
tmp = current;
current = current->next;
free(tmp->word);
free(tmp);
}

Segmentation fault in a list with memcpy

I'm trying to copy a list into another list with memcpy, but I'm getting a segmentation fault everytime I try to access the value I copied.
I've already tried moving pointers around, but the problem still occurs.
create_list creates a new head node for the list and returns it. Here is some of the code:
/* The n variable shows the number of elements in the list for the head */
struct list {
union{
void *data;
struct {
unsigned num;
List *end;
};
};
List *node;
};
List *
create_list()
{
List *head;
head = malloc(sizeof(List));
if (head == NULL)
return NULL;
head->num = 0;
head->end = NULL;
head->node = NULL;
return head;
}
int
cpy_list(List *l1, List **l2)
{
List *iter;
void *data_aux;
*l2 = create_list();
iter = l1->node;
while (iter != l1->end) {
memcpy(&data_aux, iter->data, sizeof(iter->data));
//printf("data_aux: %s\n", data_aux);
insert_list(*l2, data_aux, NULL);
//printf("iter->data: %s\n", iter->data);
iter = iter->node;
}
return 1;
}
void
print_list(List *head)
{
List *iter;
iter = head->node;
printf("[");
while (iter != head->end) {
printf("\"%s\",", iter->data);
iter = iter->node;
}
printf("\"%s\"", iter->data);
printf("]");
printf("\n");
}
int
main(int argc, char *argv[])
{
List *l1, *l2;
char *str[] = {"Test0", "Test1", "Test2", "Test3", "Test4"};
void *data_aux;
l1 = create_list();
for (int k = 0; k < 5; k++) {
insert_list(l1 ,str[k], NULL);
}
printf("l1: ");
print_list(l1);
cpy_list(l1, &l2);
print_list(l2);
return 0;
}
memcpy(&data_aux, iter->data, sizeof(iter->data));
I'll assume this is a typo problem (let me know if it is not and you intended to use it like that). &data_aux will return the address of variable data_aux, not the address pointed by data_aux. This code is likely causing a stack overflow as you are probably
writing data beyond the boundaries of the local variable data_aux (which have the size of a pointer - 4 bytes on x86 or 8 bytes on x64). If iter->data have a significant size you will corrupt the stack and have undefined behavior.
What you probably want is to allocate a buffer to be pointed by data_aux. Something like:
data_aux = malloc(sizeof(iter->data));
And then pass data_aux instead of &data_aux in your call to memcpy.

Understanding how to convert void* and int* in C

I have written the following code:
typedef struct List {
struct List* next;
void *value;
} List;
void freeList(List* list, void destroyElement(void*)) {
while(list != NULL) {
destroyElement(list->value);
struct List* n = list;
list = list->next;
free(n);
}
}
struct List* arr2list(void** array, int length, void* cpyElement(void*), void (*destroyElement)(void*)) {
struct List* head = NULL;
struct List** tail = &head;
for(int i = 0; i < length; i++) {
*tail = calloc(1, sizeof(struct List));
printf("array[%d] = %d\n",i,*(((int*)array)+i));
if (*tail == NULL) {
freeList(head, destroyElement);
return NULL;
}
tail[0]->value = cpyElement(array[i]);
tail = &(tail[0]->next);
}
*tail = NULL;
return head;
}
void printList(List* list, void echoElement(void*)) {
while (list != NULL) {
echoElement(list->value);
list = list->next;
}
}
void destroyElement(void* el) {
if (el != NULL) {
struct List* node = el;
node->next = NULL;
free(node);
}
}
void* cpyElement(void* el) {
int *p = malloc(sizeof(*p));
*p = *(int *) el;
return p;
}
void echoElement(void* el) {
if (el != NULL) {
printf("%d ", *(int *) el);
}
}
int main(int argc, char** argv) {
int array_length = argc - 1;
int* array = (int*) malloc(sizeof(*array) * array_length);
for (int i = 0; i < array_length; i++){
*(array + i) = atoi(argv[i + 1]);
}
struct List* root = arr2list((void*) array,array_length,cpyElement, destroyElement);
printList(root,echoElement);
freeList(root,destroyElement);
free(array);
return 0;
}
The problem is with tail[0]->value = cpyElement(array[i]);. I get a segmentation fault error for this part. If I write it cpyElement(((int*)array)+i); it works but I want the function arr2list to be generic and not to mention int. How can I solve it? I think that I understand it's impossible to convert void* to int* because it does not know which size to use so is it possible to hear some suggestions on how to approach this issue so it will work? Maybe change the array argument?
You need to create an array of pointers to ints and then pass that. Yes, it's a lot of malloc calls, but it's necessary (since you're using void *).
int main(int argc, char** argv) {
struct List *root;
int i, array_length = argc - 1;
int** array = malloc(sizeof(*array) * array_length);
for (i = 0; i < array_length; i++){
array[i] = malloc(sizeof(*array[i]));
*array[i] = atoi(argv[i + 1]);
}
root = arr2list((void **)array,array_length,cpyElement, destroyElement);
printList(root,echoElement);
freeList(root,destroyElement);
free(array);
return 0;
}
This code:
void destroyElement(void* el) {
if (el != NULL) {
struct List* node = el;
node->next = NULL;
free(node);
}
}
will then need to be changed to (in fact, it only worked before due to a platform-specific bug):
void destroyElement(void* el) {
free(el);
}
Also, do not cast the result of malloc. That means no (int *)malloc(...). Just use malloc(...), it's safer and doesn't cover up errors.
The problem with void * is that while you can freely convert other pointer types to void * and back again and get the original pointer back, you need to do that directly -- you can't pass a void ** where it points at anything other than void *'s and expect it to work.
Even worse, in your case, you're passing an array of int where an array of void * are expected. You can deal with this by casting yout ints to intptr_t and thence to void * to store in your list -- you'll have to do that double-cast back again to get them out again:
void echoElement(void* el) {
printf("%d ", (int)(intptr_t)el);
}
int main(int argc, char** argv) {
int array_length = argc - 1;
void *array = malloc(sizeof(*array) * array_length);
for (int i = 0; i < array_length; i++) {
array[i] = (void *)(intptr_t)atoi(argv[i + 1]);
}
struct List* root = arr2list((void*) array,array_length,cpyElement, destroyElement);
printList(root,echoElement);

Linked lists, operations with parameter

I'm trying to implement program in with i can create ~arbitrary number of singly linked lists dynamically and perform operations on particular one (defined by parameter). I create dynamic array of head pointers so that i can refer to the certain head node defined by paramater(index of an array + 1). Parameter is just (1,2,3..number of lists). So far I have managed to implement only initialise and push function but the program after complilation doesn't work as expected. Where is the problem?
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define CHUNK 10
typedef struct
{
char *str;
struct node *next;
} node;
node *initialise(node **array, int *amount_of_lists);
void push(node **array, int *amount_of_lists);
char *getString(void);
int main()
{
node **heads = NULL; //initially null, pointer to the dynamic array of head pointers
int amount_of_lists = 0;
int *no_of_heads = &amount_of_lists;
initialise(heads, no_of_heads);
initialise(heads, no_of_heads);
push(heads, no_of_heads);
push(heads, no_of_heads);
return 0;
}
node *initialise( node **array, int *amount_of_lists ) /*reallocate memory for another head pointer ans return the pointer to node*/
{
++(*amount_of_lists);
printf("\n%d", *amount_of_lists);
array = (node**)realloc(array, sizeof(node*)*(*amount_of_lists));
return array[(*amount_of_lists) - 1] = malloc(sizeof(node));
}
int readParameter(int *amount_of_lists)
{
int parameter = 0, control = 0;
bool repeat = 0;
do
{
if(repeat)
{
printf("\nWrong parameter, try again.");
}
printf("\n Enter list parameter: ");
control = scanf("%d", &parameter);
fflush(stdin);
repeat = 1;
}
while( control != 1 || parameter < 1 || parameter > (*amount_of_lists) );
return parameter;
}
void push(node **array, int *amount_of_lists)
{
int parameter = readParameter(amount_of_lists) - 1;
node *temp = array[parameter];
array[parameter] = malloc(sizeof(node));
array[parameter] -> next = temp;
array[parameter] -> str = getString();
}
char *getString(void)
{
char *line = NULL, *tmp = NULL;
size_t size = 0, index = 0;
int ch = EOF;
while (ch)
{
ch = getc(stdin);
/* Check if we need to stop. */
if (ch == EOF || ch == '\n')
ch = 0;
/* Check if we need to expand. */
if (size <= index)
{
size += CHUNK;
tmp = realloc(line, size);
if (!tmp)
{
free(line);
line = NULL;
break;
}
line = tmp;
}
/* Actually store the thing. */
line[index++] = ch;
}
return line;
}
As BLUEPIXY somewhat crypticly hinted at in his comment 1), in order to modify main()'s heads in initialise(), you have to pass heads by reference to initialise(), i. e. change
initialise(heads, no_of_heads);
initialise(heads, no_of_heads);
to
initialise(&heads, no_of_heads);
initialise(&heads, no_of_heads);
consequently
node *initialise( node **array, int *amount_of_lists )
changes to
node *initialise(node ***array, int *amount_of_lists)
and inside array changes to *array, i. e.
*array = realloc(*array, sizeof(node *) * *amount_of_lists);
return (*array)[*amount_of_lists - 1] = malloc(sizeof(node));

Hashmap with Linked List to find word count

I have been working on this little project for quite some time and I can't figure out why I'm not getting the results that are expected. I am a beginner to C programming so my understanding with pointers and memory allocation/deallocation is novice. Anyways, I have constructed this segment of code by originally building a hash function, then adding a count to it. However, when I test it, sometimes the count works, sometimes it doesn't. I'm not sure whether it's the fault of the hash function, or the fault of the way I set up my count. The text file is read one line at a time and is a string consisting of a hexadecimal.
struct node {
char *data;
struct node *next;
int count; /* Implement count here for word frequencies */
};
#define H_SIZE 1024
struct node *hashtable[H_SIZE]; /* Declaration of hash table */
void h_lookup(void)
{
int i = 0;
struct node *tmp;
for(i = 0; i < H_SIZE; i++) {
for(tmp = hashtable[i]; tmp != NULL; tmp = tmp->next) {
if(tmp->data != 0) {
printf("Index: %d\nData: %s\nCount: %d\n\n", i,
tmp->data, tmp->count);
}
}
}
}
/* self explanatory */
void h_add(char *data)
{
unsigned int i = h_assign(data);
struct node *tmp;
char *strdup(const char *s);
/* Checks to see if data exists, consider inserting COUNT here */
for(tmp = hashtable[i]; tmp != NULL; tmp = tmp->next) {
if(tmp->data != 0) { /* root node */
int count = tmp->count;
if(!strcmp(data, tmp->data))
count= count+1;
tmp->count = count;
return;
}
}
for(tmp = hashtable[i]; tmp->next != NULL; tmp = tmp->next);
if(tmp->next == NULL) {
tmp->next = h_alloc();
tmp = tmp->next;
tmp->data = strdup(data);
tmp->next = NULL;
tmp->count = 1;
} else
exit(EXIT_FAILURE);
}
/* Hash function, takes value (string) and converts into an index into the array of linked lists) */
unsigned int h_assign(char *string)
{
unsigned int num = 0;
while(*string++ != '\0')
num += *string;
return num % H_SIZE;
}
/* h_initialize(void) initializes the array of linked lists. Allocates one node for each list by calling h_alloc which creates a new node and sets node.next to null */
void h_initialize(void)
{ int i;
for(i = 0; i <H_SIZE; i++) {
hashtable[i] = h_alloc();
}
}
/* h_alloc(void) is a method which creates a new node and sets it's pointer to null */
struct node *h_alloc(void)
{
struct node *tmp = calloc(1, sizeof(struct node));
if (tmp != NULL){
tmp->next = NULL;
return tmp;
}
else{
exit(EXIT_FAILURE);
}
}
/* Clean up hashtable and free up memory */
void h_free(void)
{
struct node *tmp;
struct node *fwd;
int x;
for(x = 0; x < H_SIZE; x++) {
tmp = hashtable[x];
while(tmp != NULL) {
fwd = tmp->next;
free(tmp->data);
free(tmp);
tmp = fwd;
}
}
}
I assume that the count is not being incremented when it does not work. It is possible that strdup is not able to allocate memory for the new string and is returning NULL. You should check the return value to and exit gracefully if it fails.

Resources