I'm a C beginner experimenting with linked lists and I found a Github repo for one. the create function is written like this:
Node* ListCreate(void* data) {
Node *head = malloc(sizeof(Node));
if ( head != NULL) {
head->next = NULL;
head->data = data;
}
return head;
}
I was able to use it by changing the void* to int and then in main doing:
Node *root = ListCreate(5);
But then I read a little about void pointers and it seems like they can be used as generic types sort of like C++ templates, which would be useful if I could figure out how they work. I tried several things, and the closest I've got to getting it to work is no errors, but one warning:
incompatible integer to pointer conversion passing 'int' to parameter of type 'void *'
Am I missing a step here? I first felt like I should add something to the function definition, but I'm assuming the person who wrote it knows what they're doing and I just didn't use it properly in main. So is there a different way I'm supposed to pass an argument to this function?
As is mentioned by others in comment, it is more suitable to create different list for different types.
But if you want to use the same function definition, then use can pass the pointer to your data (int or char) and cast them as void *.
/* main: start */
int main(void)
{
Node *list_head; /* Points to first element in list */
Node *node_tmp; /* Just a temporary pointer */
int *pint;
char *pchar;
/* create an empty list */
list_head = NULL;
/* Note that there is no error checking done for
* malloc, which is not good
*/
/* Create a node which points to int */
pint = malloc(sizeof(int));
*pint = 10;
node_tmp = ListCreate((void *) pint);
/* Add this node to list */
list_head = add(node_tmp, list_head);
/* Create a node which points to char */
pchar = malloc(sizeof(char));
*pchar = 'c';
node_tmp = ListCreate((void *) pchar);
/* Add this node to list */
list_head = add(node_tmp, list_head);
/* print total number of nodes in list */
print_tot_nodes(list_head);
return 0;
}
Code for add and print_tot_nodes ommited are for brevity.
Note, that functions like print_tot_nodes or add will have not much issues if data points to different data types. But if you need to implement function like Node *smallest(Node *head), which returns pointer to the node having smallest element, then it may get complicated.
So, it is easier to use different list for different types. However you can cast the actual pointer to some datatype to void * if you need to use the same function definition as seen in your original post.
I think that there is a need to wrap for numeric literals(or cast?).
Like this:
void *BOX_VAR;//Not require if use GCC extension
#define BOX(type, value) ((*(type *)(BOX_VAR=malloc(sizeof(type))) = value), BOX_VAR)
#define UNBOX(type, value) (*(type *)(value))
Node *list = ListCreate(BOX(int, 5));
int v = UNBOX(int, list->data);
printf("%d\n", v);
Related
I am working with linked lists and determined that it would be really beneficial to have a global variable with the address of the first "root" link in the list.
I then have several other functions that make use of this "root" link by using it as a starting reference.
How can this be done?
My attempt was (in general):
int rootAddress = 0;
int main(){
//EDIT float *ptr = 5; -> my mistake there is not 'float' in my code
int *ptr = 5; //but I still get these warnings
rootAddress = ptr;
return 0;
}
int laterFunction(){
// float *ptr = rootAddress;
int *ptr = rootAddress;
return 0;
}
Although I get two warnings:
warning: initialization makes pointer from integer without cast
warning: assignment makes integer from pointer without cast
What is the proper way to do this, or what is the best way to go about saving this "root" pointer in general if this approach is not efficient?
Instead of using global variables and polluting the namespace consider using a wrapper structure. You would have one structure for a linked list and another for a node, and you would pass around a pointer to the linked list structure. It would be done as follows:
struct linkedlist {
struct node *front;
int len;
};
struct node {
int item;
struct node *next;
};
... where item is the item you want to store in each node. You can change this to be the datatype you wish or use void pointers to create a generic linked list. Be sure to add a field for a free function that the client will provide if you decide to implement a generic linked list.
instead of int rootAddress = 0; make it float *rootAddress = 0 and instead of rootAddress = &ptr use rootAddress = ptr. You are getting warnings because your types don't match.
float * rootAddress = NULL;
int main(){
float *ptr = (float *)malloc(sizeof(float));
*ptr = 5.0;
rootAddress = ptr;
return 0;
}
int laterFunction(){
float *ptr = rootAddress;
return 0;
}
Just need to make sure that all the pointers of the same type. Beware of forcefully casting from one type to another.
I have a struct as follows:
typedef struct Node {
void* data;
unsigned long id;
NodePtr next;
NodePtr prev;
} Node;
It is meant to be a node in a linked list ADT. I have 2 different constructors depending on what the Node needs to hold in data. One constructor uses:
NodePtr TempNode;
TempNode = malloc( sizeof(Node) );
/* Other stuff */
TempNode->data = newList();
return (TempNode);
And this seems to work just fine for letting me access that list by returning (List->current->data) where current is a Node pointer in the List Struct
However, I want to make a version of the constructor where (data) points to an int. I've read that I can do this by doing the following
void* ptr;
int x = 0;
*((int*)ptr) = x;
But with the way my constructor is set up, that would mean I have to do something like this?
*((int*)TempNode->data) = 1; // data starts at 1
And this doesn't work. I'm very new to C so I don't understand much of the terminology. I read that dereferencing (using the -> notation?) cannot be done with void*'s, but it seems to work fine in my list version of the constructor. How can I rewrite my other constructor to cast this void* to an int?
I strongly counsel against doing this, but if you really want to use the void * member to hold an integer, you can do:
Node *constructor_int(int n)
{
Node *tmp = malloc(sizeof(*tmp));
/* Other stuff */
tmp->data = (void *)n;
return(tmp);
}
This involves the minimum number of casts and avoids most problems with relative sizes of types.
The obvious, logical way to do it is to allocate an integer for the data member to point at:
Node *constructor_int(int n)
{
Node *tmp = malloc(sizeof(*tmp));
/* Other stuff */
tmp->data = malloc(sizeof(int));
*(int *)temp->data = n;
return(tmp);
}
You just have to remember to free the two memory allocations.
The code should also check that the memory allocations succeeded before using the results.
Let's talk about this
When you do something like
NodePtr TempNode;
TempNode = malloc( sizeof(Node) );
you have asked the library to reseve you some dynamic storage which is big enough for a Node. The initial values of that memory are undefined, so right now the pointer TempNode->data could point anywhere and probably does not point at memory reserved for your use.
When you do
TempNode->data = newList();
you give the pointer a (presumably, as long as newList() does something legal and sensible) valid value;
If instead you do
*((int*)TempNode->data) = 1;
you instruct the compiler to
treat TempNode->Data as a pointer-to-int,
de-reference it and
set the value of what every memory is at the other end to 1 (notice that at no point have you set data itself, just whatever it points at)
But you don't know what it points to! De-referencing it is undefined behavior and strictly a bad thing.
You are always responsible for ensuring that you do not de-reference a pointer unless it points to memory that you are entitled to use.
"How can I make data point to an area I can use?"
I'm not sure if you mean what I'm going to explain below (and it won't be short :P), but if you are asking how you can distinguish the type of the data stored in Node->data, then with that implementation you cannot.
You leave it up to the end-programmer to remember what type of data he has stored into the list (which is not a bad thing btw.. on the contrary, it is the norm). In other words, you trust the end-programmer that he/she will apply the proper casts when say printing the Node->data.
If for some reason you wish to provide a more managed API for your list, you could add one more field in a List struct, for identifying the type of the data stored in your list.
For example...
enum DataType {
DT_INVALID = 0,
DT_PTR
DT_CHAR,
DT_INT,
DT_FLOAT,
DT_DOUBLE,
...
/* not a data-type, just their total count */
DT_MAX
};
#define DT_IS_VALID(dt) ( (dt) > DT_INVALID && (dt) < DT_MAX )
typedef struct List List;
struct List {
enum DataType dt;
Node *head;
};
Of course you are free to support less or more data-types than the ones I listed in the enum, above (even custom ones, say for strings, or whatever you see fit according to your project).
So first you'll need a constructor (or initializer) for a list, something like this...
List *new_list( enum DataType dt )
{
List *ret = NULL;
if ( !DT_IS_VALID(dt) )
return NULL;
ret = malloc( sizeof(List) );
if ( NULL == ret )
return NULL;
ret->dt = dt;
ret->head = NULL;
return ret;
}
and instantiate it, say like this...
int main( void )
{
List *listInt = new_list( DT_INT );
if ( NULL == list ) {
/* handle failure here */
}
Now that you have already stored the intended data-type into the list meta-data, you are free to choose how you will implement the Node constructors. For example, a generic one could look something like this...
int list_add_node( List *list, const void *data )
{
Node *node = NULL;
size_t datasz = 0;
/* sanity checks */
if ( !list || !data || !DT_IS_VALID(list->dt) )
return 0; /* false */
node = malloc( sizeof(Node) );
if ( NULL == node )
return 0; /* false */
/* when data points to mem already reserved say for an array (TRICKY) */
if ( DT_PTR == list->dt ) {
node->data = data;
}
/* when data points to mem reserved for a primitive data-type */
else {
datasz = dt_size( list->dt ); /* implement dt_size() according to your supported data-types */
node->data = malloc( datasz );
if ( NULL == node->data ) {
free( node );
return 0; /* false */
}
memcpy(node->data, data, datasz );
}
/* add here the code dealing with adding node into list->head */
...
return 1; /* true */
}
For DT_PTR (which I flagged as TRICKY in the example) it is more safe to implement a different Node constructor, perhaps accepting 2 extra arguments, lets say elemsz and nelems, so the function can allocate elemsz * nelems bytes for copying the data contents into them, in case data points to an array, a struct or any other non-primitive type. Or you can provide an extra DT_ARR enum value specifically for arrays. You are free to do whatever suits you best.
In any case, for DT_PTR the example above relies on the caller of list_add_node to have properly allocated the passed data, and in general context this is not a good thing at all.
The code is more complicated, but you know the data-type stored in your list. So for at least the primitive data-types you can add say a printing routine that automatically casts its output according to list->dt (for non-primitive data types you should provide support for custom printing routines, usually via callback functions).
You can even take it to the extreme, and move the dt field from List to Node. In that case you implement a list of heterogeneous data in the nodes, but it gets much more complicated and also its rarely useful (if ever).
All this ADT stuff via (void *) pointers have serious performance issues, that's why speed critical implementations utilize (or abuse if you prefer) the pre-processor instead, for this kind of stuff.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
unsigned length;
} List;
void init(List *l) {
l = (List *) malloc(sizeof(List));
l->length = 3;
}
int main(void) {
List *list = NULL;
init(list);
if(list != NULL) {
printf("length final %d \n", list->length);
return 0;
}
return 1;
}
This is a simplified version of the code that is giving me problems. I am trying to construct the pointer *list from a method where *list is passed as an parameter.
I know I can make void init(List *l) work by changing it to void init(List **l) but this is for a class tutorial. I can't change the method arguments. I have spent four hours working on this.
I want to ensure that there is no way to make void init(List *l) work before I confront my professor.
Thanks in advance
You're passing a copy of the pointer to init, which is allocating memory, storing it in its local copy, and promptly leaking it when init returns. You cannot pass data back to the calling function this way. You need to either return the allocated data, or pass in a pointer to the pointer you want to modify, both of which involve modifying the function signature.
void init(List **l) {
*l = (List *) malloc(sizeof(List));
(*l)->length = 3;
}
init(&list);
Did the assignment specify that you have to allocate the List from within init? If not, you could always pass a pointer to an already allocated List object, and perform whatever initialization length = 3 is a place-holder for:
void init(List *l) {
l->length = 3;
}
List list;
init(&list);
printf("length final %d \n", list.length);
The problem is that the pointer is passed by value, so you're changes are discarded. You really need a pointer to a pointer to do this correctly. As in you would do:
void init(List** l) {
*l = (List*) malloc(sizeof(List));
// ...
}
And when you call it, you would use init(&list) instead of init(list). Of course, in this case, it makes sense to just go ahead and return the result instead of using a pointer to a pointer:
List* init() {
List* result = (List *) malloc(sizeof(List));
result->length = 3;
return result;
}
And then, with the above, you could simply use list = init();.
Note that in C++, you can use references instead of pointers, but mixing references and pointers is incredibly messy. Here, using a return-type is really the neatest thing to do.
If you absolutely have to use the existing signature, you can be sneaky and initialize the list, then in the init() function you can make the passed-in list's next pointer point to the list you actually want to create. Then, after init() has been called, you can take the next pointer and dispose of the original list object you created. Or you could always just have the first element by some dummy element.
this assignment is probably a good way to teach in a class the pass by value and pass by reference. If you want to maintain the constructor's signature you need to modify the main function.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
unsigned length;
} List;
void init(List *l) {
l->length = 3;
}
int main(void) {
List list;// x = NULL;
memset(&list,0,sizeof(List));
init(&list);
printf("length final %d \n", list.length);
return 1;
}
Now here list is of type List and not address to List. the init() method passed the address of list and inside init you can change the value of the structure contents.
./a.out
length final 3
init needs to be passed a pointer to an existing List. I suspect that the real problem here is with your data structure. You have something called a List, that contains a length, but there's no list to be seen anywhere. List should probably contain a pointer to an array of the given length, and init should malloc that array and set the pointer. You will probably find this out when you ask the professor to correct his requirements which aren't broken -- if they were, he probably would have heard about it from past students and corrected them by now.
I have a linked List c file/head as an independent library i am using for a project. I dont yet have a add ordered method in the library. My problem is writing a compare function because i want to compare on different items for different projects. How do i create a compare function in my main for whatever project i am using then pass and use that function into the add_ordered method in my linked list library? I cant seem to find a workable solution to passing in the function and using it within my linked list.
here is a uncompiled version of my add_ordered and compareto methods (compare to method will be different for each file):
void ll_add_ordered(ll_node *head, void *d){
ll_node *cur;
ll_node *temp;
if(head->size == 0){
ll_add_first(head, d);
}else{
temp = (ll_node *)malloc(sizeof(ll_node));
temp->data = d;
for(cur = head->next; cur->data != NULL && compareTo(temp->data, cur->data); cur = cur->next)
;
temp->next = cur;
temp->prev = cur->prev;
cur->prev->next = temp;
cur->prev = temp;
head->size++;
}
}
int compareTo(proc *first, proc *second){
if(first->arrival < second->arrival)
return -1;
else if(first->arrival > second->arrival)
return 1;
else
return 0;
}
One approach is to pass in a pointer to a function that takes void * arguments,e.g. int (*cmp) (void * lhs, void * rhs). In this case, it would be the responsibility of cmp to cast its arguments to the right type.
You might be able to do something a little more type safe with macros and token pasting but personally I find that to be overkill. If you are instantiating the linked list, then you know what the types are and can pass in a suitable comparison function.
This will define a type called compareFunc:
typedef int(*compareFunc)(void *first, void *second);
Now you would rewrite ll_add_ordered as:
void ll_add_ordered(ll_node *head, void *d, compareFunc compareTo) {
.
.
.
This will allow you to pass in any function that matches your compareTo function signature into ll_add_ordered and have it called when doing the comparison.
A simple solution would be to use a function pointer, and pass the pointer to the function.
I would recommend you declare an alias for the function signature as well, lest you get crazy after a while :)
I'm assuming ll_node.data is of type void *. Thus your linked list requires two things:
The comparison function takes two void pointers, compares them (using insider knowledge). The comparison function must know how to deal with the data. This requirement is of course implicitly enforced on the person/code/evil co-worker calling ll_add_ordered.
The comparison function returns 1, 0 or -1.
The type alias for such a function pointer would be:
typedef int (*ll_comp_func)(void *, void*);
If you think this looks crazy, you're totally right. It serves to make you crazyhomicidial late nights when nothing works. Anyhow, what it really does is create a typedef for a function pointer and it calls the alias ll_comp_func.
You would then alter your ll_add_ordered into the following form:
void ll_add_ordered(ll_node *head, void *d, ll_comp_func comparison){
// Do stuff.
int order = comparison(temp->data, cur->data);
// Do even more stuff.
}
I have a simple assignment that the professor wants us to do.
Basically to pull in some numbers from a text file and load into a linked list.
I don't want to get to much into the details but I have a basic question.
He provided us with a function like so:
INTLIST* init_intlist( int n )
{
INTLIST *lst;
lst = (INTLIST *)malloc(sizeof(INTLIST));
lst->datum = n;
lst->next = NULL;
return lst;
}
This function is used to initialize the linked list with the first element. Then he asked us to define a function with this signature:
int insert_intlist( INTLIST *lst, int n )
So I assume he just wants us to add to the linked list so I tried this:
int insert_intlist( INTLIST *lst, int n )
{
INTLIST* lstTemp;
lstTemp = (INTLIST *)malloc(sizeof(INTLIST));
lstTemp->datum = n;
lstTemp->next = lst;
lst = lstTemp;
free(lstTemp);
}
So what my thought process was is that it creates a temporary node, assigns the data value (Datum) and assigns the next pointer to point to where the current pointer is pointing at. Then I reassign the main pointer to this newly created temp node.
That way we have for instance 2 nodes:
[New Temp Node] -> [Prev Initialized Node]
When I step through the code it looks great...
Then back in main I have just a function to print the list:
while (lst!=NULL)
{
printf("The value is:%d", lst->datum);
lst=lst->next;
}
The problem is this only seems to print one digit (namely the first digit that I am reading in from the file, which I think is the last one in the list or at least I thought it was the last one in the list).
But it should keep going through as I have 10 digits in the file. I know the code is very dirty and I will clean it up...here is my entire main function if anyone needs more info:
#include <stdio.h>
#include <stdlib.h>
#include "intlist.h"
int main(int argc, char *argv[])
{
char c; /* Character read from the file. */
FILE* ptr; /* Pointer to the file. FILE is a
structure defined in <stdio.h> */
int index=0;
//INTLIST* aList[10]; //will use later
/* Open the file - no error checking done */
ptr = fopen("1.txt","r");
/* Read one character at a time, checking
for the End of File. EOF is defined
in <stdio.h> as -1 */
if(ptr==NULL) {
printf("Error: can't open file.\n");
/* fclose(file); DON'T PASS A NULL POINTER TO fclose !! */
return 1;
}
//aList[index] = malloc(sizeof(INTLIST)); WE NEED THIS LATER ON....
INTLIST *lst=NULL;
while ((c = fgetc(ptr)) != EOF)
{
if (c != ' ')
{
//make sure it isnt a space
int i = c - '0'; //get the value from the text file
if(c=='\n')
{
// aList[index]=lst;
// index++;
// aList[index] = malloc(sizeof(INTLIST));
while (lst!=NULL)
{
printf("The value is:%d", lst->datum);
lst=lst->next;
}
free(lst);
free(aList[index]);
return 0;
//new line in the file
//create another linked list
}
if (lst==NULL)
lst = init_intlist(i);
else
insert_intlist( lst, i);
}
}
fclose(ptr);
system("PAUSE");
return 0;
}
Here is intlist.h for anyone who may need it:
#ifndef __intlist_h__
#define __intlist_h__
/* each entry in the list contains an int */
typedef struct intlist {
int datum;
struct intlist *next;
} INTLIST;
INTLIST *init_intlist( int n ); /* initializes the intlist with initial datum n */
int insert_intlist( INTLIST *lst, int n ); /* Inserts an int (n) into an intlist from the beginning*/
void list_append(INTLIST *list, void *datum); /* Inserts entry to the end of the list */
INTLIST* list_front(INTLIST *list); /*return the element at the front of the list, and remove it
from the list*/
void list_map( INTLIST *list, void (*f)(void *) ); /*Applies a function to each element of the list */
void list_delete( INTLIST *list ); /* Deletes (and frees) all entries in the list */
#endif
A couple of issues here.
I'll start with a BAD bug:
int insert_intlist( INTLIST *lst, int n )
{
INTLIST* lstTemp;
lstTemp = (INTLIST *)malloc(sizeof(INTLIST));
lstTemp->datum = n;
lstTemp->next = lst;
lst = lstTemp;
free(lstTemp); // <<<<< NO!
}
You are still using that memory, so you can't free it.
Secondly, the proto-type supplied to you for insertion has no way to return a new front of the list, so you can not change the front of the list. This implies that you must add new nodes to the back, rather than to the front as you have done.
Also, the supplied return type of int probably means that he expects out the number of nodes in the list, which is no problem as you're going to have to walk the list to find the back anyway.
Have another go at it, you're not doing badly at all.
Working with code like:
int insert_intlist( INTLIST *lst, int n )
{
INTLIST* lstTemp;
lstTemp = (INTLIST *)malloc(sizeof(INTLIST));
lstTemp->datum = n;
lstTemp->next = lst;
lst = lstTemp;
free(lstTemp);
}
This has a couple of problems. First of all, the free(lstTemp) seems to be freeing the node that you just inserted in the list, which you probably don't want to do.
Second, you're passing the pointer to the list into the function -- which means the function can't modify that pointer, so when you assign to the pointer, you're only changing your local copy of it.
You have two choices: you can either pass in a pointer to that pointer (so you can modify the original pointer) or you can get clever and figure out a way to avoid needing to (but I won't give away the secret right away...)
This line:
lst = lstTemp;
Only changes the value of lst inside the function. It won't propagate back to the copy of the pointer that the caller has.
You can either use a pointer-to-a-pointer, or if you can't change the function signature, insert somewhere other than the head of the list.
Though the typical way of handling this is to not point to the first element in the list - rather, you have some sort of list structure that holds a pointer to the first element, and some other information about the list (say, how many elements it has). Then you pass a pointer to that structure around.
In C, parameters are passed to functions "by value", meaning they are copied when you enter the function and any changes you make to them are not reflected back to the caller. That means that when you modify lst to point to your newly allocated memory it doesn't actually modify the caller's pointer to the list.
EDIT: As dmckee pointed out, you shouldn't free the memory in your insert function as you are still using it. That's definitely a bug, but it's not the one causing your problem.
In C, everything is passed by value. If you want a function to change something, you need to pass its address to the function. Since in int insert_intlist( INTLIST *lst, int n ), you want to change the list head, you need to pass a pointer to it, i.e., the first parameter should be INTLIST **lst (see below too, though). But the function prototype is given and cannot be changed.
What that means is that you can't add a number to the beginning of the list—the caller can't know that you did so. So, you have to traverse the list pointed to by lst, and then add the new node anywhere down the chain. The professor probably wants you to add the node at the end, but he might have asked for some other condition.
With that information, let's look at the comments for the prototypes:
/* Inserts an int (n) into an intlist from the beginning*/
int insert_intlist( INTLIST *lst, int n );
The comment or the prototype is wrong. If your professor has given you this file, insert_intlist() cannot be written to satisfy the comment, since it can't return to the caller the new head. The prototype should be either:
/* Inserts an int (n) into an intlist from the beginning
and returns the new head */
INTLIST *insert_intlist( INTLIST *lst, int n );
Or:
/* Inserts an int (n) into an intlist from the beginning */
int insert_intlist( INTLIST **lst, int n );
(Note the **.)
The header also has:
/*return the element at the front of the list, and remove it from the list*/
INTLIST* list_front(INTLIST *list);
This is correct. Note that you need to modify the list's head in list_front(), so you're returning the new head.
Finally, you don't want to free() anything in insert_intlist(). You want to keep the new node in the list, don't you? Once the caller is done with the list, he will have to call list_delete(), which will traverse the linked list, and free each node.
I Agree with Alok. I Have the same problem/ Professor. I am new to C programming and I have been looking all over the web for forms and C webpages for help. I have came across a source that supports Alok.
I used
INTLIST *list_add(INTLIST **p, int i){
INTLIST *n;
n = (INTLIST *) malloc(sizeof(INTLIST));
if (n == NULL)
return NULL;
n->next = *p; /* the previous element (*p) now becomes the "next" element */
*p = n; /* add new empty element to the front (head) of the list */
n->datum = i;
return p; }
From my main I can pass in
INTLIST *list
list_add(&list, 1);
list_add(&list, 2);
so when i print the list it prints 2 1
The professor suggested this:
INTLIST *mylist[N];
Where N is the number of rows of your
input file. Then mylist[i] is a
pointer to the ith linked list.
Okay Fine: create for testing purposes INTLIST *mylist[2];
I call the same functions:
list_add(&list[0], 1);
list_add(&list[0], 2);
This prints out 2 1 ... Great,
But when I do this:
list_add(&list[1], 3);
list_add(&list[1], 4);
I get a Segmentation fault..