I have preallocated buffer (array of chars) to which strings are being written, it looks like this:
"This\0buffer\0contains\0strings\00000..."
I want to be able to remove the last string, so I came up with the idea to represent each string in the buffer as a linked list node with pointers to its start and end, so I would just find the last node and fill the region it holds with zeros.
struct node
{
char *str_start;
char *str_end;
struct node *next;
};
It looks like a very common problem, however, I failed to find such implementations anywhere.
The question is: Is there some data structure for my usecase I overlooked, or is there a better solution to do this?
Note: This is to be used in the kernel module, so maybe it's already implemented in kernel
You could use a 2 dimensional array (considering the buffer is preallocated and you know of a maximum size for every string).
That would make enforcing string sizes easier, hence your code more secure.
Related
Hello i am trying to learn and build data structures in c and i want to store integers progressively in the stack.
my struct is like this:
typedef struct STACK_NODE_s *STACK_NODE;
typedef struct STACK_NODE_s{
STACK_NODE forward;
void *storage;
} STACK_NODE_t;
typedef struct L_STACK_s{
STACK_NODE top;
} L_STACK_t, *L_STACK;
In a while loop i want to read and store my chars in integer form.
//assume that str is an proper string
//assume that we have a linked stack called LS
int i=0;
int temp;
while(str[i]!='\0'){
tmp=str[i]-'0';
push(LS,(void *)&tmp);
}
I know this won't work properly as we store the same variable's adress over and over again.
Do i need to allocate an auxiliary array in order to store them 1 by 1 or is there a better way to do this?
The answer must address two separate aspects of your question:
How to organize some collection of items, and where to get the memory from to do that.
First code snippet / Linked list format
The first code snippet is good the way it is.
It sets up a linked list, which has its pros and cons, but serves very well if you don't know the number of items in advance, if you want to be able to quickly remove or insert items somewhere in the middle of the list, and if you don't mind that looking up one certain entry inside the list costs you O(N) effort.
For a generic library-like implementation...
... void* is as good as it goes with ANSI C.
In C++, for example, you could make a template that leaves open the type that is stored in the list (or better yet, you would directly reuse the well-known STL implementation in class forward_list<int>).
Sadly, ANSI C doesn't have something comparable.
One solution is the one you picked, create int objects and hook their addresses into your list of void*.
Another solution for a generic library implementation is to use a precompiler macro for the type, and to define this macro above a header file that holds the generic implementation. This tries to resemble the clean C++ solution, but with precompiler it is not typesafe, so this approach is far from beautiful and comes with several risks.
Second code snippet / Memory allocation
Creating the list with void* instead of int (or whatever non-pointer type) requires you to allocate further memory beside the list.
I. e., it is not only that you have to allocate every list item (= variable of type STACK_NODE_t) but also the actual entry value (e. g., *(int*)(LS->storage)).
This means you have to allocate/deallocate the data in some other way that outlives the stack.
On most systems, you can use malloc/free for that, and you only have to take into account the size of the heap available for malloc and the time de-/allocating takes.
If the list shall implement real-time requirements or on embedded systems, you may not have malloc or you may not be allowed to use it.
Then you have to allocate and implement your own heap (= memory pool of storage items) for your list.
How to implement such a memory pool with desired properties is a separate question that would take us to far here.
In any case, you must not use the pointer to a stack variable (like a local variable inside a function) because the memory "behind" that variable will not be reserved for this purpose once the function exits, and the memory may be used for something different in the meantime.
This is, however, what the second code snippet does apparently.
As you noticed yourself, taking this path...
we store the same variable's adress over and over again.
Reusing the memory position for another entry of the same list is an extreme case of the risk explained above.
I solved the problem using an auxiliary array like i anticipated. If someone comes up with a better solution its more than welcome.
In the file include/linux/ieee80211.h we have:
struct ieee80211_mgmt {
...
union {
...
struct {
__le16 capab_info;
__le16 listen_interval;
/* followed by SSID and Supported rates */
u8 variable[0];
} __packed assoc_req;
...
} u;
} __packed __aligned(2);
I need to modify some fields in this struct. For instance, to modify capab_info I would do it by:
...
struct ieee80211_mgmt *mgmt_hdr = skb->data;
mgmt_hdr->u.assoc_req.capab_info = 0xABCD;
But if I want to modify/insert the "SSID" field that would be localized somewhere in variable array, I do not know where and how I should allocate and modify it.
The above code I supposing skb->data struct was already allocated by mac80211 module, and what I want to do it just insert a new field (which is not listed in the static struct).
I did not find any similar code over kernel tree to use as an example. I appreciate any points you can provide me to understand it better. Thank you very much!
Permitting a structure to have a length-zero array as its final member is a GCC extension with substantially the same semantics as a standard flexible array member. The member is accessible by name and according to the element type of the array, like any other, and you may access as many elements as the actual allocated size of the structure permits. For example, mgmt_hdr->u.assoc_req.variable[i] for i within the allowed range.
Of course, to know how much data you can access you need either to rely on a stored length somewhere or to rely on some characteristic of the data itself, such as a terminator / sentinel. If you're hoping to extend the array in-place then you may be out of luck, and if you don't know how much space was allocated then you certainly are. In such cases, your only viable alternative is to reallocate the whole object larger, and replace all pointers to the original one with pointers to the new one. If you can't be sure of doing that, then extending the array is not an option for you, but you can still modify the existing content if you can tell where it ends.
I am implementing a linked list in C and I am running into the issue where C does not implement any specific scheme for memory management other than just giving you the ability to allocate and free memory by passing a pointer. There is no concept of whether the value might be needed later on in the program.
The typical implementation I find online for a linked list basically deallocs the deleted node but does not dealloc the node's value.
Whose responsibility should it be to release the memory taken up by the value when deleted from the list ? The linked list's or the normal flow of the program ?
example:
// allocate 10 bytes
char *text = malloc(sizeof(char) * 10);
// create the linked list
LinkedList *list = list_create();
// add the text pointer to the linked list
list_append(list, text);
// remove the pointer from the linked list
list_remove_last(list);
In this case text would end up not getting deallocated as list_remove_last just frees the memory that the new node takes up. What would be the proper way to release the memory taken up by text ?
that is a very common way of container implementation in C.
basically you dynamically allocate the contents of the list and pass the pointer to the container, now the container is responsible for freeing it.
You can also pass in a function pointer to list_create() so it knows how to do list_remove_last() properly, this is especially useful for using a generic container that does not know what type of elements it will contain (it will just hold void * pointers).
think of the case where the data itself is a struct that contains other pointers. in this case list_remove() can not do a simple free() on its data field, instead it should use the function pointer that was passed in to free the data.
your approach has a small problem:
if you have list* as the return type of list_create(), then you will have to do a free(list) in your main function. alternatively, you can have list_create() return a list, as opposed to a list*, this is a logical choice because a list has its bulk of information dynamically allocated and accessible through a pointer anyway.
in the second case you would need a function list_destroy(list) that would destroy any element your list holds.
C does not implement any specific scheme for memory management other than just giving you the ability to allocate and free memory by passing a pointer
Yes, C lacks any kind of automatic memory management, so you have to be careful to deallocate any memory blocks that you instantiate.
Whose responsibility should it be to release the memory taken up by the value when deleted from the list? The linked list's or the normal flow of the program?
It's your responsibility. You can do it however you like. You can write a general purpose linked list where the caller has to be responsible for allocating and deallocating space for each value in the list because the list management functions don't know how much space each value might require, or whether the values might be needed beyond the lifetime of the node. Or, you can write a list implementation that manages every aspect of the node, including space for the value stored in the node. In some cases, a list node includes the value in the node definition, like:
struct Node {
struct Node *next;
int value;
};
and other times the node has a pointer to some other block that has the actual value:
struct Node {
struct Node *next;
void *value;
};
Another approach is to define a structure with just the part needed for the list operation (i.e. the next pointer), and then piggyback data onto that structure:
struct Node {
struct Node *next;
};
struct MyNode {
struct Node node;
int price;
int quantity;
};
So, there are lots of ways to do it, and none of them are wrong. You should choose the style that makes sense for your needs. Do you have big, complex values that you don't want to duplicate, that you want to store in a linked list, but which you want to continue to use even after they're removed from the list? Go with the first style above. Do you want to manage everything related to the linked list in one place? Then go with the second style.
The point is: C dictates a lot less than other languages do, and while that means that you have to think harder about program correctness, you also get the freedom to do things very directly and in a style of your choosing. Embrace that.
My guide line is: the one who allocates memory is also responsible for de-allocating it.
If you implement a linked list that allocates the memory for the values, the implementation should also take care of freeing this memory when the entries are removed from the list. For strings this could be done by copying the strings to a newly allocated buffer of adequate size.
If your implementation of a linked list only stores plain values (e.g. pointers) without allocating extra memory for the values, it should also avoid freeing memory it did not allocate, because it doesn't know what the allocator planned for this memory in the future.
The proper way would be to have list_remove_node() a function that would free not only the list (node) itself, but also the value that was allocated for that specific node. Also, you shouldn't need to search for a specific node according to your text as you should be able to just call free(node->text) (which can be done even in the current list_remove_last() function)
The main C logic is that you are supposed to free() anything that you allocated yourself. Certain libraries will allocate memory for their own work, which most often you are supposed to clean up as well (as you were the one who asked for it).
let's say i got a struct like this:
typedef struct myInfo {
WORD myCount;
WORD data[0];
} myInfo;
Well, i would like to use this struct (which is declare extern by the way), in another .c source file, where i've got a function like this:
void dynamic_init(struct myInfo dummy){
macroPut(5, dummy.myCount, &dummy.mydata); <- doesn't work
macroPut(5, dummy.myCount, &externalInitialized.mydata); <- works
}
This way i would dynamically use this dynamic_init without worring about the struct name...
But as u could easily see in my snippet above, it works only with the inizialized struct...but if i call the function this way:
dynamic_init(externalInitialized);
It won't work.
In other words i've got to do something like this:
dynamic_init( externalInitialized.myCount, externalInitialized.mydata);
And i have the result expected.
The main mistery is that is the "mydata" WORD that corrupt everything.
the "myCount" works as expected if i do this way:
dynamic_init( externalInitialized, externalInitialized.mydata);
and then:
void dynamic_init(struct externalInitialized dummy, WORD *dynData){
macroPut( 5, dummy.myCount, &dynData); <- works
}
I know it's dumb, but it's just to show the exact wrong part.
Thanks!
When you pass structure to function, compiler generates code to copy structure contents, so function gets its own copy of parameters that it can freely modify without affecting original. Copying is performed for sizeof struct bytes.
Your main problem here is that your structure have flexible array member, so its sizeof have very little to do with real size it will occupy.
E.g. structure's in question sizeof is 4 (last field is array of 0 elements so it doesn't increas sizeof), but when you allocating memory for structure, you actually allocating much more - and saving 'real' size in structure field. That way, accessing data array will actually get elements outside of structure itself (placed right next bytes to it); however, compiler don't know that (and cannot know, as size differs from one structure instance to another). For the same reason you cannot directly place that structure on stack and safely fill data - because that will touch bytes that doesn't belong to it and corrupt other things (technically it can be placed on stack, but you have to manually align it within on-stack array of enough size).
Flexible array member have other limitations, like you cannot make an array of that type of structures (once again - technically you can, but it makes no sense since array indexing relies on sizeof).
So, short answer is "don't pass flexible-sized structures by value". Or even think twice before passing structure by value at all - copying isn't free, after all.
I have this structure:
struct data
{
int id;
char *title;
char *description;
int year;
};
Now I have to save the list in a file, using fwrite, and then read it with fread.
What is the best way? I can't do something like
fwrite(info, sizeof(struct data), 1, ptr_file);
Because the structure has two pointers. And if I write field by field and use strlen to write the strings, how could I know the size of each string while reading?
Thanks.
You can't write structures with pointers to a file, as that will write the pointer and not what they point to to the file. This means that when you later try to read the structure, the pointers will point to "random" memory.
You might want to read about serialization.
A simple scheme is to write the id and year members separately, then the length (as a fixed-size value) of the first string, followed by the string, then the length of the second string and the actual string.
Another, even simpler, method is to have fixed-size arrays instead of pointer for the strings. This have the drawback that if you don't use all the space allocated for the arrays then you waste some memory. An even worse drawback is that you can't have strings larger than the arrays.
You have to write your own serialization function or not to use pointers. It actually depends on your tasks. I prefer using fixed length arrays everywhere it's possible.
If your task is more complex look at libraries like tpl to serialize your data structures.