Linked List in C error -- Invalid Initalizer error - c

I am attempting to create a Linked List using C (NOT C++). The Linked List is initialized through the function llinit() which should return a list struct. However, when I compile the code I get an error stating "error: invalid initializer" in the lltester.c file. Why is this?
This is the function used to initialize the linked list in my llist.c file:
list llinit()
{
list* ll = malloc(sizeof(list));
ll->head = NULL;
ll->tail = NULL;
return *ll;
}
This is the list struct in my llist.h file:
typedef struct {
node *head;
node *tail;
} list;
This is my main function in my lltester.c file where I attempt to initialize the list:
int main()
{
list myList= llinit(); //This is the line where the error occurs on!
return 0;
}

Your code is leaking memory, since it's allocating the list with malloc() then returning that structure's content by value.
if you want to have a function that returns an empty list by value, you should do just that:
list llinit()
{
list ll;
ll.head = NULL;
ll.tail = NULL;
return ll;
}
The above is just fine, there's no risk of the value "disappearing" due to it going out of scope, this is just as safe as e.g. a function returning a local int value. The return value (all of it!) is copied to the caller's memory as needed.
It's then trivial for the caller to decide whether or not the node should be on the heap or not.
UPDATE: Here is the code on ideone, it really does compile and does not generate an error for the assignment in main().

you have to declare the structure as
typedef struct _list{
list* head; /* could have been struct node* as well */
list* tail;
} list;
Also the list is your custom struture. And the llPushBack() is not a bember of your structure.

Related

C linked list can't properly add data to list

Bit of a lengthy question so please bear with me. I am trying to create a doubly linked list in C using a dummy node as the head. For whatever reason, however, the list only saves the last node I read into it, and links the prev node pointer and the next node pointer to that last node, so if I try and iterate over the list, it gets stuck in an infinite loop.
Here is my node header file and C file. The linked list implementation isn't meant to be a full linked list implementation, so I only included the functions I need:
node.h:
#ifndef _node_h
#define _node_h
#include "task_block.h"
#include <stdio.h>
typedef struct node {
task_block_type *data;
struct node *next;
struct node *prev;
}node_t;
node_t *node_new(task_block_type *data);
void add(node_t *new, node_t *head);
#endif
node.c:
#include "node.h"
#include "task_block.h"
#include <stdlib.h>
node_t *node_new(task_block_type *data) {
node_t *node = NULL;
node = malloc(sizeof(node_t));
node->data = data;
node->next = NULL;
node->prev = NULL;
return node;
}
void add(node_t *new, node_t *head) {
node_t *current = head;
if (head->next == NULL) {
head->next = new;
head->next->prev = head;
return;
}
while(current->next != NULL) {
current = current->next;
}
current->next = new;
current->next->prev = current;
return;
}
And finally, the code that is messing up from main.c:
while (j < numTasks) {
if (tasks[j].taskID == currentID) {
*newTask = *task_block_new(tasks[j].taskID, tasks[j].period);
newTask->startTime = starts[i];
newTask->deadline = deadlines[i];
newTask->executionTime = executions[i];
*nodeNew = *node_new(newTask);
add(nodeNew, eventQueue);
}
I have already tested that my new task_block_type get the correct data form the text file and that the new node I create is initialized properly with the task block. Once I read it into my list with add(), however, it messes up. Any help would be greatly appreciated as I've been trying to fix this problem for several hours now and still haven't found a solution
EDIT:
self contained example:
*node_new is meant to be a constructer for my node objects and is supposed to return a pointer to a node object. So for example, say instead of having a node which contains the task_block_type as above, I have one that contains an int. If I wanted to initialize it with a value of 5, I would call
*newNode = (node_t *)malloc(sizeof(node_t));
*newNode = *node_new(5);
Hope that helps
Change this:
*nodeNew = *node_new(newTask);
To this:
nodeNew = node_new(newTask);
Your original code copies the (dereferenced) value returned by node_new() to the value at (dereference of) *nodeNew. Thus, the pointer nodeNew never gets updated with the address of the new node created by node_new()... so you keep overwriting the value at *nodeNew while passing its unchanging address to add().
And you get a memory leak into the bargain. You are responsible for free()ing every pointer ever returned to you by malloc(). But here, for the same reason given above, you're not keeping copies of the returned pointers to enable this... just linking to nodeNew over and over again.
You need to update the pointer nodeNew with the location of, well, each new node, before passing it on to add(). Then you'll actually be linking different nodes, and at their original addresses, rather than copying them to the same address in a leaky fashion and linking it to itself, infinitely.
You also need to free() all memory that you have dynamically allocated once you're finished using it, e.g. through a sweep of the linked list in a 'destructor' function or at the end of your program. Otherwise you're leaking memory. This is a basic error and, even in cases where it doesn't stop a program from working, wastes users' RAM, which they rightly dislike!
I highly recommend studying pointers and dynamic allocation some more before continuing trying to write code like this.

C order of elements in a struct

I am pretty new to C and I was wondering if the order of elements in a struct matter.
I have the following struct:
struct list
{
struct list_el *head;
int size;
}
I use this to make a linked list. The head points to the first element and the size shows the amount of elements in the list.
I have also have the following function to initialize the list.
typedef struct list list;
list* list_init()
{
list *list = malloc(sizeof(list));
if(list)
{
list->head = NULL;
list->size = 0;
return list;
}
return NULL;
}
The program compiles fine, without any errors, warnings or notes, but when I run the program using valgrind it says I have an invalid write of size 4 on the line in the list_init() function where I assign 0 to list->size. I have the same invalid read/write every time I access the size variable. I have no idea why. Also when I switch the two struct elements around (declare size first and then head) I get the invalid write on the line where I assign NULL to head and then the size variable is used just fine. Can anybody explain me why this happens and how I can fix it?
Last note: the struct as it is shown here is defined in an header file while the function is in the C file. Not sure if this is important.
You named the variable with the same name as the type, so sizeof(list) is implemented as the size of the variable (pointer), not the size of the struct. The struct has a pointer and a integer, so the size will be larger than a pointer, so access to not allocated place occurred.
Rename the variable.
example:
list *list_init(void)
{
list *list_data = malloc(sizeof(list));
if (list_data)
{
list_data->head = NULL;
list_data->size = 0;
return list_data;
}
return NULL;
}

Modified structs allocated in memory do not retain values after end of function

I have a couple of structs: A HashTable, which contains a table of pointers to WordNodes, and each WordNode contains a pointer to a List, which is a linked list made up of ListNodes.
I wrote a function to create a list and add list nodes to a WordNode:
int addWord(char* word, HashTable* hash_table, int id)
{
WordNode* current = calloc(1, sizeof(WordNode));
current = hash_table->table[hash];
// ...
if(current->docs == NULL){
// Create a new list, and initialize it
List* list = calloc(1, sizeof(List));
list->head = NULL;
list->tail = NULL;
int occur = 1;
ListNode* list_node = AddNode(list); // Create the first node in the list
current->docs = list; // Link the WordNode to the list
// Fill in relevant details of ListNode
list_node->id= &id;
list_node->occurrences = &occur;
list_node->next = NULL;
That is my function, but since it's been giving me trouble, I added a couple of lines inside it to test it:
printf("Testing:\n");
WordNode* wnode = calloc(1, sizeof(WordNode));
wnode = hash_table->table[hash];
List* my_list = calloc(1, sizeof(List));
my_list = wnode->docs;
ListNode* dnode = calloc(1, sizeof(ListNode));
dnode = my_list->head;
printf("Results: ocurrences: %d, id: %d\n",*((int*)dnode->occurrences),
*((int*)dnode->id));
printf("The dnode is %d\n", doc_node);
}
When called in main, the testing code inside the function produces the expected output:
Results: ocurrences: 1, id: 15
The dnode is 13867424
However, the same testing in the line immediately following the function call in main produces a weird output, even though the pointer seems to be pointing to the same address.
Results: ocurrences: 0, id: 54
The dnode is 13867424
Possibly relevant code from the function that adds a new node to the list:
ListNode* AddNode(List * list)
{
ListNode* node = calloc(1, sizeof(ListNode));
node->next = NULL;
if(list->tail == NULL){
list->head = node;
list->tail = node;
}
else{
list->tail->next = node;
list->tail = node;
}
return node;
}
I can't seem to figure out what I am doing wrong. It would seem to me that I am somehow handling the structs as local variables, even though I am allocating memory for them, which makes me think they shouldn't change after the function is done. It is probably a C-programmer's beginner mistake, but I can't seem to figure out where I am getting this wrong. Any help would be greatly appreciated.
One set of problems is in the code:
int addWord(char* word, HashTable* hash_table, int id)
{
…omitted…
int occur = 1;
ListNode* list_node = AddNode(list); // Create the first node in the list
current->docs = list; // Link the WordNode to the list
// Fill in relevant details of ListNode
list_node->id= &id;
list_node->occurrences = &occur;
You're storing a pointer to a parameter and a pointer to a local variable in your structure. Dereferencing either of those after the function returns is undefined behaviour. The space occupied by those could be reused by the compiler for any purpose at any time; they could become completely invalid (but probably won't).
Why do you have pointers in your structure for those two items? Surely, the structure should just contain a couple of int members, not int * members!
If, perchance, your code is compiling with warnings, don't submit it to SO; fix the warnings first. Or seek help on how to resolve the compiler warnings. They all matter. At this stage in your career, remember that the compiler knows a lot more about C than you do. If it warns about something in your code, the compiler is probably correct to be worried and the code is probably incorrect in some way.
Your code doesn't show where word is used — it could be that you are not copying that data either.

Trying to create an empty linked list in C

I'm trying to create an empty linked list, which asks the user for the maximum number of terms that the list can hold. (I didn't add my code for that as its simply a printf). I then have to create a new function which asks the user to insert input into the previously created list.
My question is, how do I make the create_q() function return the empty list?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct node_t {
int value;
int priority;
struct node_t *next;
}node;
typedef struct priority_linked_list {
struct name *head;
int current_size;
int max_size;
}priority_list;
typedef node *Node;
typedef priority_list *List;
void create_q(int max_terms) {
node *head = NULL;
node *next = NULL;
List *current_size = 0;
List *max_size = max_terms;
}
In C, linked lists are usually implemented as a series of nodes stored on the heap that point to eachother. The heap is a persistent memory area that runs throughout the life-cycle of the program.
When you create a variable normally in a C function, and the function returns, the variable that you created is no longer accessible. However when you create something on the heap in a function, and the function is returned, the data you allocated on the heap is still there. However, you have no way of accessing it-- unless the function returns a pointer.
So what you would do for create_q() would be to create the linked list on the heap (using a function in stdlib.h called "malloc"), and then you would return a pointer to your first node, letting the main function know where on the heap to find the first node. Then that first node would have a pointer in it, telling the program where on the heap to find the second node, and so forth.
However, you're probably approaching linked lists the wrong way. Unless this is for some sort of homework project, you probably wouldn't want to create an empty linked list. One of the benefits of a linked list is that it's a dynamic structure in which you can easily insert new nodes. You could still have some variable keeping track of the maximum size you want the list to be, but you probably wouldn't want to actually create the nodes until you had to.
Just keep in mind what a linked list is. It's a set of nodes floating on the heap (in C) that each store some data, and contain a pointer to the next node floating on the heap. All you need, to access the linked list, is a pointer to the first node. To add a new node, you simply "walk" through the list till you reach the last node, and then create a new node and have the old-last node point to it.
Is this what you had in mind?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct node_t
{
int value;
int priority;
struct node_t *next;
};
static int current_size;
static int max_size;
static struct node_t* head = NULL;
struct node_t* create_q(int);
struct node_t* create_q(int max_terms)
{
int i; // loop counter/index
current_size = max_terms;
max_size = max_terms;
if( NULL == (head = malloc(sizeof(struct node_t)*max_terms)))
{ // then, malloc failed
perror("malloc failed for struct node_t list");
exit( EXIT_FAILURE );
}
// implied else, malloc successful
// set all fields to '0,0,Null'
memset( head, 0x00, sizeof(struct node_t)*max_terms);
// set all next links, except last link
for(i=0;i<(max_terms-1);i++)
{
head[i].next = &head[i+1];
}
// set last link
head[i].next = NULL;
return( head );
} // end function: create_q
I suspect you are looking for something like the following for creating or initializing your priority linked list.
/*****
* alloc_q - allocate memory for the priority linked list
*/
struct priority_linked_list *alloc_q(void)
{
struct priority_linked_list *list;
list = malloc(sizeof(*list));
return list;
}
/******
* init_q - initialize the priority linked list
*/
void init_q(struct priority_linked_list *list, int max_terms)
{
list->head = NULL;
list->current_size = 0;
list->max_size = max_terms;
}
/******
* create_q - allocate AND initialize the priority linked list
*/
struct priority_linked_list *create_q(int max_terms)
{
struct priority_linked_list *list;
list = alloc_q();
if (list == NULL) {
return NULL;
}
init_q(list, max_terms);
return list;
}
Allocation of nodes and their addition/removal to/from the list would be handled separately.
There may be typos in the above (I have not tested it). However, it should be enough to get you on the path you want.
Hope it helps.

how to correctly initialize a LinkList

When initializing a linked list, I define parameter as *L, like:
Status InitList(LinkList *L)
{
*L=(LinkList)malloc(sizeof(struct LNode));
if(!*L)
exit(OVERFLOW);
(*L)->next=NULL;
return OK;
}
but not
Status InitList(LinkList L)
{
L=(LinkList)malloc(sizeof(struct LNode));
if(!L)
exit(OVERFLOW);
(L)->next=NULL;
return OK;
}
Why it cannot be true?
struct LNode
{
ElemType data;
struct LNode *next;
};
typedef struct LNode *LinkList;
In the second implementation, you have a local variable L that you initialize. The trouble is, it is a local variable — changing it does not change the variable in the calling code. When the function exits, you've lost the memory that was allocated — a memory leak. They're bad!
The first code gets a pointer to the variable in the calling code and carefully changes it. This does not leak memory.
You can modify the second so it works by using code like this:
LinkList NewList(void)
{
LinkList L = (LinkList)malloc(sizeof(*L));
if (L)
{
L->data = 0;
L->next = NULL;
}
return L;
}
It does a different job, so it was renamed.
Note that it ensures all elements of the structure are initialized to known values. You'd call it like this:
LinkList list = NewList();

Resources