This is for school.
I'm working on an implementation of the Unix 'ls' command. For this I'm using linked lists each time I'm reading a directory (so only one time if the -R option is not set). For this I have to use the linked lists functions and nodes (or elements, I'm not sure what's the correct name.) that we had to code on a previous project. Those nodes looks like this:
typedef struct s_list
{
void *content;
size_t content_size;
struct s_list *next;
}t_list;
In my ls program, I use these to store, for each file in the directory I'm listing, it's name and it's stats, obtained with the stat() function. So the 'content' pointer of my t_list is this structure:
typedef struct s_entry
{
char *filename;
struct stat filestat;
}t_entry;
Everything works fine, the only problem I got is that Valgrind tell me there's a leak comming from the malloc() used to allocate those t_entry structures. So I guess I'm freeing them up wrong.. here's how I do it:
void free_list(t_list *entries)
{
t_list *n_node;
if (!entries)
return ;
while (entries)
{
n_node = entries->next;
free(entries->content);
free(entries);
entries = n_node;
}
}
I'm guessing it is not enough to just free the *content pointer, but I tried other ways and it wont works. If I try to free like
free(entries->content->filename);
for example, it doesn't works and the fact that the content is a void pointer seems to be a problem in some ways that I tried to resolve the problem, but that's the way we had to code those linked list functions.
If someone could give me an hint on how to free these lists correctly, It would be awesome as I'm really stuck on this. Thanks in advance.
Sorry if my english or explanation isn't clear enough.
ps: Just in case, the whole project (far from finished) can be found here:
https://github.com/Zestx/ft_ls
You need to cast data so that the compiler knows where to find struct members, here is a full example:
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
typedef struct s_list
{
void *content;
size_t content_size;
struct s_list *next;
}t_list;
typedef struct s_entry
{
char *filename;
struct stat filestat;
}t_entry;
int main(void)
{
t_list *foo = malloc(sizeof *foo);
t_entry *bar = malloc(sizeof *bar);
bar->filename = malloc(10);
foo->content = bar;
free(((t_entry *)foo->content)->filename);
free(foo->content);
free(foo);
return 0;
}
If you have your list of ls entries for each file within a directory where content is a pointer to an allocated t_entry containing the filename and stat information, e.g.
typedef struct s_list {
void *content;
size_t content_size;
struct s_list *next;
} t_list;
and
typedef struct s_entry {
char *filename;
struct stat filestat;
} t_entry;
A freelist (t_list *head) function would need to iterate over each node, and:
free the filename allocated within each t_entry;
free the allocated t_entry; and finally
free the t_list node itself.
You could do something similar to the following:
void freelist (t_list *head)
{
t_list *node = head; /* temporary node to iterate list */
/* (you could use head, but don't) */
while (*node) {
t_list *victim = node; /* pointer to current node to free */
t_entry *entry = node->content; /* pointer to content */
free (entry->filename) /* free content->filename */
free (entry); /* free t_entry struct itself */
node = node->next; /* advance before freeing victim */
free (victim); /* free current t_list node (victim) */
}
}
Note above, instead of using node, you could simply use head to iterate since freelist receives a copy that would not alter the list address anyway -- and since there will be no list left when you are done, but it is a far better habit to use a temporary node to iterate the list (in any function) so you do not confuse the circumstances when you are handling the actual list address (e.g. the parameter was t_list **) or a copy of the pointer (the parameter was t_list *).
Look things over and let me know if you have further questions.
Related
Let's assume there is an employee ADT, such as
//employee.h
typedef struct employee_t employee_t;
employee_t* employee_create(char* company, char* department, char* position);
void employee_free(employee_t* me);
, and client code would be
#include "employee.h"
employee_t* Kevin = employee_create("Facebook", "Marketing", "Sales");
employee_t* John = employee_create("Microsoft", "R&D", "Engineer");
Now client wanted to use list ADT to insert Kevin and John to list for some task.
//list.h
typedef struct list_t list_t;
list_t* list_create(/*might have some arguments*/);
So client code would then be
#include "employee.h"
#include "list.h"
employee_t* Kevin = employee_create("Facebook", "Marketing", "Sales");
employee_t* John = employee_create("Microsoft", "R&D", "Engineer");
list_t* employee = list_create(/*might have some arguments*/);
list_insert(employee, Kevin);
list_insert(employee, John);
employee_free(Kevin);
employee_free(John);
list_print(employee); //Oops! How to print structure that you can't see?
Because employee is encapsulated by opaque pointer, there is no way for list to copy it.
How to write ADT and implementation for list?
The usual way to do this is to have your list structure store the data as a void*. For example, assmuming your list is a singly linked list:
struct list_t
{
void *data;
struct list_t *next;
};
Now list_insert whould be something like this:
list_t *list_insert(list_t *head, void *data)
{
list_t *newHead = (list_t*)malloc(sizeof(list_t));
newHead->data;
newHead->next = head;
return newHead;
}
If you want to hide away the implementation of the struct then you can add methods to extract the data. For example:
void *list_get_data(list_t *head)
{
return head->data;
}
How do you write generic list without knowing the implementation of structure?
Create functions that handle the structure abstractly.
How to write ADT and implementation for list?
list_create(); needs to pass in helper function pointers for the particular object type to perform various tasks abstractly.
A copy function like void *employee_copy(const void *emp) so list_insert(employee, Kevin); knows how to copy Kevin.
A free function like void employee_free(void *emp) so list_uninsert(employee_t) can free the list when destroyed or members removed one-by-one.
A print function int employee_print(void *emp) so list_print(employee_t) knows how to print each member of its list.
Possibly others.
Rather than pass in 3+ function pointers, consider passing in a struct that contains these pointers, then the list only needs the overhead of 1 pointer: list_create(employee_t_function_list)
You are taking your first steps toward re-writing C++
You can use something called intrusive list. This concept is heavily used in Linux kernel.
All you need is to embed the node into the struct and let the generic code operate only on this struct member.
#include <stddef.h>
struct list_node {
struct list_node *next;
};
struct list_head {
struct list_node *first;
};
/* translates pointer to a node to pointer to containing structure
* for each pointer `ptr` to a `struct S` that contain `struct list_node node` member:
* list_entry(&ptr->node, S, node) == ptr
*/
#define list_entry(ptr, type, member) \
(type*)((char*)ptr - offsetof(type, member))
void list_insert(struct list_head *head, struct list_node *node) {
node->next = head->first;
head->first = node;
}
#define LIST_FOREACH(it, head) \
for (struct list_node *it = (head)->first; it; it = it->next)
The interface can be easily extended by other helpers like list_is_empty, list_first, list_remove_first, embed size to struct list_head.
Exemplary usage:
typedef struct {
char *name;
struct list_node node;
} employee_t;
typedef struct {
char *name;
struct list_head employees;
} employer_t;
employer_t company = { .name = "The Company" };
employee_t bob = { .name = "Bob" };
employee_t mark = { .name = "Mark" };
list_insert(&company.employees, &bob.node);
list_insert(&company.employees, &mark.node);
printf("Employees of %s:\n", company.name);
LIST_FOREACH(n, &company.employees) {
employee_t *e = list_entry(n, employee_t, node);
printf("%s\n", e->name);
}
Prints:
Employees of The Company:
Mark
Bob
Note that the list_* interface can easily used for other types as well.
See article for more information about using this concept for double-linked list.
Edit
Note that list_entry invokes a subtle Undefined Behavior.
It is related to performing pointer arithmetics outside of the struct member object but still within a parent object.
Note that any objects can be treated as an array of chars.
This code will work on all major compilers and it very unlikely to ever fail because it would break a lot of existing and heavily used code (like Linux kernel or Git).
This program is strictly conforming if struct node is a first member of the embedding struct because C standard allows safe conversion between any structure and its first member.
To be strictly conforming if node is not a first member,
The issue could be circumvented by forming a pointer to struct list_node not as &bob.node but rather using a pointer arithmetics on a pointer to bob. The result would be:
(struct list_node*)((char*)&bob + offsetof(employee_t, node))
However, this syntax is really nasty, so personally I would go for &bob.node.
as for a little project, my aim is to add a node at the head of a linked-list and allocate "width" bytes of data for the struct Node structure. Normally, this would be simple as malloc accomplishes this task; however, I've been instructed to use a function called newmalloc, which essentially does the same thing. The newmalloc function returns an integer which is what will be used as the number of bytes to allocate the structure. I have provided my header file which contains the struct, as well as the function in which I am working.
Header.h:
#include <stdio.h>
struct Node {
int data;
int next;
};
void push(int*node_ptr, void*pie, size_t width );
Function.c:
void push(int *node_ptr, void *pie, size_t width) {
struct Node *next, *prev, *head, *p;
newmalloc(width); //Returns number of bytes
}
How do I actually go about allocating memory for the struct Node structure using the returned integer from newmalloc, without using malloc? Thanks for the help!
I am having issues with my code. I am supposed to have 4 files. list.h, listAdders.c, listMovers.c, and listRemovers.c.
I am supposed to statically declare 2 blocks of memory for lists and nodes of sizes minList and minNodes. And Malloc() is only allowed to be used at runtime (which means I am not allocating memory as a per-list or per-node basis).
listRemovers.c and listMovers.c will need access to the memory block I allocate using malloc() for my lists and nodes.
There is no init() function, and I don't know how I can malloc() a global variable array which will hold the Lists and Nodes.
Just in case my question is unclear. How do I malloc an initial block of memory for my struct of lists and nodes? So that when I create a list or add a node, they're stored on the memory I allocated.
Here's what I have:
list.h
#ifndef __LIST__
#define __LIST__
#define MIN_LISTS 3
#define MIN_NODES 30
typedef struct NODE{
struct NODE* next;
struct NODE* prev;
} NODE;
typedef struct LIST{
struct NODE* head;
struct NODE* cursor;
int size;
} LIST;
extern NODE *node_block;
extern LIST *list_block;
LIST *ListCreate();
int ListAdd(LIST *list, void* item);
#endif // __LIST__
listAdders.c
#include "list.h"
#include <stdlib.h>
#include <stdio.h>
NODE *node_block = malloc(MIN_NODES * sizeof(struct NODE));
LIST *list_block = malloc(MIN_LISTS * sizeof(struct LIST));
LIST *ListCreate()
{
}
int ListAdd(LIST * list, void* item)
{
}
There is no init() function, and I don't know how I can malloc() a global variable array which will hold the Lists and Nodes.
C does not allow executable code outside of actual functions.
So this code will not compile:
NODE *node_block = malloc(MIN_NODES * sizeof(struct NODE));
LIST *list_block = malloc(MIN_LISTS * sizeof(struct LIST));
Given your problem statement:
I am supposed to statically declare 2 blocks of memory for lists and nodes of sizes minList and minNodes.
Replacing your code above with this code would be a "static declaration":
NODE node_block[ MIN_NODES ];
LIST list_block[ MIN_LIST ];
You could also do something like this:
NODE *node_block;
LIST *list_block;
static void init_memory()
{
node_block = malloc(MIN_NODES * sizeof( *node_block ));
list_block = malloc(MIN_LISTS * sizeof( *list_block ));
}
int main( int argc, char **argv )
{
init_memory();
.
.
.
}
Note that starting with a fixed number of allocated nodes and lists will result in needlessly complex code should you need more nodes and/or lists than you start out with.
Either statically allocate all of your memory, or dynamically allocate all of it. That way your code will be a lot simpler.
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.
I'm not sure how specific I have to be but I'll give the breakdown best I can. I'm taking a typedef struct:
typedef struct {
char name[21];
int life;
} pcb_t;
inputting values for the name & life, then storing it in a doubly linked-list.
the linked-list structs in the header file are:
typedef struct list_node {
void *data;
struct list_node *next;
struct list_node *prev;
} List_node_t;
typedef struct {
List_node_t *head;
List_node_t *tail;
} List_t;
In my main I have the first struct variables initialized as:
char name[BUF_MAX];
int life;
pcb_t *pcb;
The input is all correct and the pcb struct is stored as a new node in the list. I tried to run a simple loop after the initial input to print out the Name & Lifetime values for each of the pcb structs. The loop I used is this:
void *context = NULL;
void *data;
while( List_next_node( &the_list, &context, &data) && (data != NULL))
{
printf("Name: %s\n", (char *)data);
printf("Lifetime: %d\n", (int )data);
}
Where the List_next_node function transverses the list. the_list is the list, context is what keeps track of where we are in the list, and data is the data.
I'm not sure how to access the information I want as my while loop correctly prints out the Name of the pcb struct, but the lifetime is not.
Lists, doubly linked or otherwise, are a complete red herring, here. The issues are (1) accessing struct members, which hopefully is trivial; and (2) doing that when all you have is a void *, which is possibly a little less intuitive.
This is the simplest way:
void *data;
while( List_next_node( &the_list, &context, &data) && (data != NULL))
{
pcb_t * current_data = data;
printf("Name: %s\n", current_data->name);
printf("Lifetime: %d\n", current_data->life);
}
The only reason your current code "works" for printing out the name is because name is the first element of your struct, and so the address of name happens to be the same as the address of the whole struct, so when you cast the address of the struct to char * you get the result you're expecting, even though you're not really getting there the right way.
As ojblass's answer shows, you can do it with a cast and avoid the use of a temporary variable, but I think a temporary variable makes things a lot clearer.
printf("Lifetime: %d\n", ( (pcb_t *) data) ->life);