If I have a long char array[100], which store a list of structs in it, and if I want to add one one struct in the end, how do I check if it exceeds the boundary or not?
For example,
static char arr[100];
typedef NODE* node_ptr;
typedef struct node
{
char a;
char b;
int size;
node_ptr next;
}NODE;
//arr already contains few node in it.
//size: the new node size, I want to add in the end
node_ptr add_node(node_ptr last, size_t size)
{
node_ptr new;
if(last+2*sizeof(NODE)+size<arr+100)
//add new node
return new;
}
How can I check if new node exceed the array boundary?
this is COMMENT
do not upvote - but feel free to DV.
You ask difficult question and it is not easy to answer. You need also to consider some more complex cases like
or
or
Small array will become fragmented in a very short time. This is one of the reasons why uC developers try to avoid this kind of memory allocation. There are other techniques like pools used in the embeedded programming.
Related
First time asking a question but I did look around Google and stackoverflow to see if someone has asked something similar before. In malloc, recasting and free, it looked like the OP asked something similar for example. But it was more complicated.
I was wondering whether it's possible to create a generic function for a list structure in C that traverses the list given that you know that the different types of structures will always have a "next" field.
For example, given these two list-type structures:
typedef struct _list1 {
int value;
list1 *next;
} list1;
typedef struct _list2 {
int value;
char *string;
list2 *next;
} list2;
Is it possible to create a generic void freeList((void *) list) function or something which looks something like the below? I am aware it's a simple thing to write both free functions for each individual list separately.
void freeList((void *) list) {
// Included this because the structs would have different sizes
// so I thought it would be possible to cast it in order to properly dereference the field.
if (sizeof *list == sizeof list1)
*list = (list1) list;
else if (sizeof *list == sizeof list2)
*list = (list2) list;
if (!list) return;
else {
free(list->next);
free(list);
}
}
So far, my experiments with the code shown above didn't fare well given that gcc would complain about dereferencing a void * pointer.
Making a heterogeneous list can be achieved by the use of a tagged union, or just a tag and casting:
struct list_item {
struct list_item *next;
enum datatype type;
void *contents;
};
or
struct list_item {
struct list_item *next;
enum datatype type;
union {
int some_int;
char some_char;
} contents;
};
Then while traversing the list you just have to verify the type stored in type before using the contents of the element.
This check:
if (sizeof *list == sizeof list1)
*list = (list1) list;
else if (sizeof *list == sizeof list2)
*list = (list2) list;
doesn't work because sizeof is a static construct: its value is defined at compilation time. You're just asking for the sizeof void.
is it possible to create a generic function for a list structure in C that traverses the list given that you know that the different types of structures will always have a "next" field.
Yes, as mentioned before; you must be careful that every structure starts with the "next" field; the two structures in your post should therefore be reordered like this:
typedef struct _list1 {
list1 *next;
int value;
} list1;
typedef struct _list2 {
list2 *next;
int value;
char *string;
} list2;
It is not clean code, because the compiler could reorder (and pad) the fields of the structure, but in general it should work.
Is it possible to create a generic void freeList((void) *list) function or something which looks something like...
This is possible if your structs do not refer malloced memory; or they do, but in a uniform (and known) way (note the first case is a sub-case of this last).
If the structs contain pointers pointing to memory that has to be freed, in fact, while freeing the struct the freeList() function should also free the referenced memory. A few solutions come to my mind:
1 - If all the different structs contain the same "pointers" layout, the routine can free those pointers in a uniform manner, knowing in advance what to do. In such scenario, one can also use pointer fields that are not used by all the structs, but only some.
2 - Every single instance of a struct could contain some helper field describing the pointer's layout. For example, just after the "next" field, another "mempntcnt" field could tell how many pointers (to be freed) follow the "next" field. Or, this "mempntcnt" could be passed as a parameter to freeList().
3 - This problem could be managed by a totally separated mechanism, outside the scope of freeList(). Much depends on the final usage: I mean, for a given (kind of) linked list, first call a routine that frees all the memory referenced by the list itself, then free the list by calling the common freeList(). After all, if different structs are needed, then different routines are used on them...
I hope I've been clear enough...
If you ensure that the next pointer is the first member of the struct then this is possible.
typedef struct list1 {
// next pointer must be first
struct list1 *next;
int value;
} list1;
typedef struct list2 {
// next pointer must be first
struct list2 *next;
int value;
char *string;
} list2;
void freeList(void *list) {
if (list) {
freeList(*(void**)list);
free(list);
}
}
A uni project I have involves sorting a very large set of data into two different lists, one which has a bunch of data on a city or country, and another which has that same data (on a city, this time), but also with some coordinates, like so:
//used for cities and countries in the textual mode
typedef struct node{
int year;
int month;
float temp;
char* name;
struct node* next;
struct node* prev;
} node_t;
//used for cities in the graphical mode
typedef struct City{
node_t data;
float latitude;
float longitude;
} City;
That is the way I set this up, but it doesn't allow me to use the same functions, because the pointers I have are to 'node', not 'City'. I could make them both like the second one, but putting half a million entries in memory, each with two empty floats would be kind of unnecessary and problematic.
I'm looking to use the same functions for both of them. The functions are your usual linked list ones, like sorted insertion and such. I was trying to use void pointers before, casting them as needed, but that means my functions must have two parts to them.
I'm looking to change the uhh... structure of my structs, so that they allow me to use the same functions simply, without the need for casts, or with a minimal one at least.
They are quite similar as you can see, but nothing comes to mind. Any ideas would be greatly appreciated. Cheers!
You could modify your linked list implementation to use void* as a data pointer.
struct Node
{
void *data;
struct Node *next;
}
The insert function should look something like:
Node * insert (struct Node *h, void *data, size_t data_size)
{
Node *node = malloc(sizeof(Node));
node->data = malloc(data_size);
memcpy(node->data, data, data_size);
node->next = h;
h = node;
return h;
}
When inserting City or any other type:
City* city = malloc(sizeof(City));
insert(head, city, sizeof(City));
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 am implementing Dijkstra's algorithm using a heap data structure. I also use an array that keeps track of the "probable minimum distances" of the nodes. The problem is when I am updating the array, how to update the corresponding values in the heap?
ok here's the code
typedef struct temp
{
int nodeTag;
int weight;
struct temp *next;
}myStruct; //this structure corresponds to the elements of the linked list
typedef struct temp *link;
typedef struct
{
int nodeTag; //each node has an integer nodeTag associated with it
link l;
}head; //the head of the elements of the adjacency list
typedef struct {
head *adjList;
int numNodes;
int numEdges;
} Graph;
typedef struct {
int possibleMinWeight;
int minFound; //minFound==1 if true min is found
} dummy;
dummy *dijkstraSSSP(Graph G, int nodeTag)
{
minHeap H=createEmptyHeap(G.numNodes);
while(i=0;i<G.numNodes;i++)
{
if(i!=nodeTag)
H.A[i].priority=INFINITY;
else
H.A[i].priority=0;
H.A[i].nodeTag=i;
}
convertIntoHeap(H);
int min;
dummy *A=(dummy *)malloc(sizeof(int)*G.numNodes);
A[nodeTag-1].possibleMinWeight=0;
A[nodeTag-1].minFound=1;
while(!isEmpty(H))
{
element e=findMin(H); H=deleteMin(H);
A[e.nodeTag-1].minFound=1;
link l=G.adjList[e.nodeTag-1].l;
while(l!=NULL)
{
if(A[l->nodeTag-1].minFound==0); //its true minimum distance is yet to be found
{
if(A[l->nodeTag-1].possibleMinWeight>A[x-1].possibleMinWeight+(l->weight))
A[l->nodeTag-1].possibleMinWeight=A[x-1]+(l->weight);
}
l=l->next;
}
}
return A;
}
To write DecreaseKey, you need the priority-queue implementation to maintain a map from nodeTags to locations in the queue. That means updating this map whenever the binary-heap data structure calls for a swap or perhaps choosing a pointer-based implementation like pairing heaps that never moves nodes in memory.
Unless you have a large, somewhat dense graph, DecreaseKey isn't worth it; just insert a node multiple times and ignore duplicate results from ExtractMin. (To detect duplicates: every time I've implemented Dijkstra, I've needed either the distances or the tree. In my programming languages of choice, it's easy enough to shake loose a bit from either array to remember whether each node has been visited.)
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.