Forced intent to manage memory

I am new to C programming and this type of thing appears. As a simple example, suppose I have a struct http_header with some char pointers:

 struct http_header { char* name; char* value; }; 

I want to populate http_header , where value is an int string representation. I “feel” how, semantically, I should be able to write a function that takes a null header pointer, a name string and int and fills the header accordingly.

 void fill_header(struct http_header *h, char* name, int value) { h->name = name; char *value_str = malloc(100); sprintf(value_str, "%d", value); h->value = value_str; } int main(int argc, const char * argv[]) { struct http_header h; char *name = "Header Name"; int val = 42; fill_header(&h, name, val); ... free(h.value); } 

Here, the call code reads exactly as my intention, but in this case I create the value string dynamically, which means that I will have to free it later. It doesn't smell me; it seems that the caller knows too much about fill_header implementation. And in real implementations, it may not be so simple to find out what to do for free: consider populating the http_header array, where only one of them should have its own malloc ed value.

To get around this, I would need to create a string in advance:

 void fill_header2(struct http_header *h, char* name, char *value_str) { h->name = name; h->value = value_str; } int main(int argc, const char * argv[]) { struct http_header h; char *name = "Header Name"; int value = 42; char value_str[100]; sprintf(value_str, "%d", value); fill_header2(&h, name, value_str); } 

As this model continues down the chain of structures with pointers to other structures, I end up doing so much work in the top-level functions, which, apparently, are hardly worth the level that is lower than the level. In addition, I essentially donated to “fill out the headline with an int idea,” which I decided to write first. Am I missing something? Is there any choice of template or design that will make my life easier and keep my calls to functions expressing my intentions?

PS Thanks to everyone at Stackoverfow for being the best professor I have ever had.

+4
source share
4 answers

Well, I would go with the first approach (with a twist), and also provide the destroy function:

 struct http_header *make_header(char *name, int value) { struct http_header *h = malloc(sizeof *h); /* ... */ return h; } void destroy_header(struct http_header *h) { free(h->name); free(h); } 

Thus, the caller does not need to know anything about http_header .

You can also leave with a version that leaves the main selection (the structure itself) to the caller and whether it has its own distribution. Then you will need to provide clear_header which frees only fill . But this clear_header leaves you with a partially valid object.

+3
source

I think your problem is simply that you program asymmetrically. You must once and for all decide who is responsible for the line within your structure. Then you should have two functions, not just one that needs to be called as header_init and header_destroy .

For the init function, I'll be a little more careful. Check the argument 0 your pointer and completely initialize your DS, something like *h = (http_header){ .name = name } . You never know if you or someone else will be added to another field in your structure. Thus, at least all other fields are initialized with 0 .

0
source

If you are new to C programming, you might want to use the Boehm conservative garbage collector . The Boehm GC works very well in practice, and by using it systematically in your code, you can use GC_malloc instead of malloc and never worry about calling free or GC_free .

Memory leaks in C (or even C ++) are often a headache. There are tools (like valgrind ) that can help you, but you can decide not to worry using the Boehm GC.

Garbage collection (and memory management) is a global feature of the program, so if you use GC Boehm, you must solve this earlier.

0
source

The general solution to your problem is the issue of property ownership, as others have suggested. However, the easiest solution for your specific task is to use a char array for value , i.e. char value[12] . 2 ^ 32 has 10 decimal places, +1 for a character, +1 for a null terminator.

You must make sure that 1) int does not exceed 32 bits at compile time, 2) make sure that the value is within the acceptable range (HTTP codes have only 3 digits) before invoking sprintf, 3) use snprintf .

Thus, using a static array, you get rid of the property problem and you use less memory.

0
source

Source: https://habr.com/ru/post/1379758/


All Articles