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!
Related
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.
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 was looking into some memory management (pool + malloc + free) implementations using linked list, and I found that in most of them each node is something like this:
typedef struct node{
int usedSize;
node* next;
char mem[100];
}
and then the free(ptr) must be:
free(void* ptr){
node* item = (node*)((char*)ptr - sizeof(node*) - sizeof(int));
\\some code to put the "item" back to the pool
}
My question is this:
why shouldn't we put the char mem[100]; in the beginning of the structure to avoid the "pointer manipulation"?
the result is:
typedef struct node{
char mem[100]; // moved to the beginning
int usedSize;
node* next;
}
and then the free(ptr) is simpler:
free(void* ptr){
node* item = (node*)((char*)ptr);
\\some code to put "item" back to the pool
}
Thanks.
That pointer manipulation is not particularly complicated. It amounts to a decrement by a compile time constant. As noted in comments, it should actually be:
node* item = (node*)((char*)ptr - offsetof(struct node, mem));
Placing that header above the memory allows the memory to be represented by a flexible array member. A flexible array member can only occupy the last position of a structure. This was also noted in comments.
typedef struct node {
int usedSize;
node* next;
char mem[];
} node;
If the size of the memory is large, jumping over the array to reach the next pointer will likely flush data cache lines to load the bookkeeping data. However, a short jump backward from the array will likely access the data already loaded into the cache.
I'm trying to figure out how to initialize a struct if I'm passed a memory location, the situation below is what I'm trying to do, but it throws "invalid initializer" shortened to relevant code
#ifndef PAGE_ALLOC_H
#define PAGE_ALLOC_H
typedef struct listNode
{
struct listNode *prev;
struct listNode *next; // prev/next element in linked list
char * address;
} listNode;
#endif
_____________________________________________
#include "page_alloc.h"
#include <stdlib.h>
#include <stdio.h>
int main (int argc, char ** args)
{
void * memptr;
int test = posix_memalign(&memptr, 2, 128); // test is > 1, values such as 16 and 22 is this ok? It does seem to return a valid memory address though, but can't test until struct lets me initialize to it...
listNode testNode = memptr; // this throws improper initialization flag, but how else do I do tell //the struct where the eligible memory is?? Isn't that what malloc does? Return a point to acquired //memory
// Now this is what I imagine doing after telling testNode where its allocated memory
testNode ->prev = somePreviousNode; // etc.
}
I'm obviously doing something wrong but what? I'm sorry if this is a dumb question but I can't find any examples of posix_memalign nor can I find an explanation of properly initializing structs with a pointer to allocated memory. I need to dynamically add nodes because this is for a doubly linked list pointing to memory locations (used for keeping track of "pages")
Thanks for any insight!!!
testNode is an object of the structure and you are assigning a pointer (memptr) to it:
listNode testNode = memptr;
Instead create a pointer to listnode and assign the allocated memory to it:
listNode *testNode = memptr;
Note: The value of the alignment parameter should satisfy two conditions:
should be a multiple of sizeof(void*)
should be a power of 2.
For eg,
if on your machine, sizeof(void*) = 4, then the acceptable value is 4,8,16....
if on your machine, sizeof(void*) = 8, then the acceptable value is 8,16,32...
This is code for a linked list in the C programming language.
#include <stdio.h> /* For printf */
#include <stdlib.h> /* For malloc */
typedef struct node {
int data;
struct node *next; /* Pointer to next element in list */
} LLIST;
LLIST *list_add(LLIST **p, int i);
void list_remove(LLIST **p);
LLIST **list_search(LLIST **n, int i);
void list_print(LLIST *n);
The code is not completed, but I think it's enough for my question. Here at the end of struct node "LLIST" is used, and it's also used as a return type in the prototyping of the function list_add. What is going on?
That's a typedef. It's actually doing two things at once. First, it defines a structure:
struct node {
int data;
struct node *next;
}
And then does a typedef:
typedef struct node LLIST;
That means LLIST is a type, just like int or FILE or char, that is a shorthand for struct node, your linked-list node structure. It's not necessary - you could replace LLIST with struct node in all of those spots - but it makes it a bit easier to read, and helps hide the implementation from pesky end-users.
LLIST is just another type name for the struct that has been created. In general, the following format will create a type "NAME" that is a "struct x":
typedef struct x { ... } NAME;
C requires that you reference structs with a "struct" prefix, so it's common to introduce a typedef for less verbose mention.
That is, the declaration of your struct has two parts, and can be rewritten as such:
struct node {
int data;
struct node *next; /* pointer to next element in list */
};
typedef struct node LLIST;
So, LLIST is just another name for struct node (thanks Chris Lutz).
typedef creates a new "type" in your program, so the return value and types of parameters of those functions are just your struct. It is just shorthand for using struct node for the type.
If you were to create a new node, you could do it like this (using the type):
LLIST *node = malloc(sizeof(LLIST));
node->data = 4;
node->next = someOtherItem;
list_add(node, 1)
Also, with the function prototypes in your question, you don't really need the double pointers; since the data in your struct is just an int, you could do something like
LLIST *list_add(int data, int position);
then the list_add function would handle the allocation, copy the int into the struct and add it to the linked list.
Putting it in at a certain position is as simple as changing the next pointer in the node before it to the address of the newly allocated node, and the next pointer in the new node to point at the next one (the one the node before that one was originally pointing at).
Keep in mind that (given the rest of your function prototypes) you will have to keep track of pointers to every node you create in order to delete them all.
I'm not sure I understand how the search function will work. This whole thing could be implemented a lot better. You shouldn't have to provide the location of a node when you create it (what if you specify a higher number than there are nodes?), etc.
LLIST* is a pointer to a structure defined by the LLIST struct.
You should do
LLIST* myList = malloc(sizeof(LLIST)*number_of_elements);
to have some memory allocated for this list. Adding and removing items requires you to reallocate the memory using realloc. I've already written some piece of code for lists (made with arrays).
I might post the code as soon as I'm home, which is currently not the case.