C memory management

Hey my dear friends,

First of all, this is a C-question, not C++ related.

In my school-project last year we had to develop an application for a µC in C.
I think it was an AVR-controller but that does not really matter.

I ran into a problem which I couldn't really solve:
My program was to large for the µC, I think it was because I used quite large buffers but I needed large buffers so I didn't slice them off.
I solved it by slicing off some functionality instead but that wasn't very pleasuring.

So now, after having all the basics in C and C++ I decided to solve the problem, or at least I wanted to come up with a solution (at least in theory).

I came up with the following:
- I don't declare the objects on the stack.
- At the beginning of the Application I create a memory buffer, in theory it should be the size of the available memory-space.
- I pass this Memory buffer to all functions per value so after leaving the function the buffer has the same size as before.
- this is only used for array types or structs because the size of fundamental types is smaller than that of a pointer most of the time.

Now the questions I have:
- I'd like to know a few flaws in this design, I'm sure you'll find some.
- How can I prevent a user from playing around with memory_ and place_?

This is the code I have
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// api-area
#include <stdlib.h>

// never touch the members directly (how can I force that?)
typedef struct {
    void* memory_;
    void* place_;
} Memory;

Memory create_memory(unsigned int size)
{
    Memory mem;
    mem.memory_ = malloc(size);
    mem.place_ = mem.memory_;
    return mem;
}
void delete_memory(Memory* mem)
{
    free(mem->memory_); 
    mem->memory_ = 0; 
    mem->place_ = 0;
}

void* allocate(unsigned int size, Memory* mem)
{
    void* new_location = mem->place_;
    mem->place_ += size;
    return new_location;
}
// prevent deallocate by using scopes, I think this is not needed
// edit: this is actually quite dangerous.
// void deallocate(unsigned int size, Memory* mem)
// {
//     mem->place_ -= size;
// }

// test_area
#include <stdio.h>

unsigned int max(unsigned int v1, unsigned int v2)
{
    return ( (v1>v2) ? (v1) : (v2) );
}

void print_data(Memory mem) 
{
    unsigned int max_size = 0;
    {   
        Memory mem2 = mem;
        int* ints = allocate(5*sizeof(int), &mem2);
    
        int i;
        for(i = 0; i < 5; ++i)
            ints[i] = i;

        printf("%d %d %d %d %d\n", ints[0], ints[1], ints[2], ints[3], ints[4]);
        max_size = max(mem2.place_ - mem2.memory_, max_size);
    }
    {
        Memory mem2 = mem;
        char* str = allocate(5*sizeof(char), &mem2);

        str[0] = 'H';
        str[1] = 'e';
        str[2] = 'y';
        str[3] = '!';
        str[4] = 0;

        printf("%s\n", str);
        max_size = max(mem2.place_ - mem2.memory_, max_size);
    }
    printf("print_data: %d bytes\n", max_size);
}
void print_ints(Memory mem) 
{
    int* ints = allocate(5*sizeof(int), &mem);

    int i;
    for(i = 0; i < 5; ++i)
        ints[i] = i;
    printf("%d %d %d %d %d\n", ints[0], ints[1], ints[2], ints[3], ints[4]);
    printf("print_ints: %d bytes\n", mem.place_ - mem.memory_);
}
void print_str(Memory mem)
{
    char* str = allocate(5*sizeof(char), &mem);

    str[0] = 'H';
    str[1] = 'e';
    str[2] = 'y';
    str[3] = '!';
    str[4] = 0;
    printf("%s\n", str);
    printf("print_str: %d bytes\n", mem.place_ - mem.memory_);
}

int main(int argc, char** argv)
{
    Memory mem = create_memory(5000*sizeof(char)); 

    print_data(mem);
    print_ints(mem);
    print_str(mem);

    delete_memory(&mem);
  
    return 0;
}


I hope you can help me improving, even if it is "just" C and not C++

Greetings,
- Gamer2015

Edit: after rereading my post it looked a bit stupid because I could just use malloc and free.
The idea behind this is that I don't have to write free every time and so I prevent memory leaks.
I also don't have to constantly allocate and free memory so it gives a little performance boost as well.

Edit 2.0: I noticed that the deallocate function is very dangerous.
Last edited on
Allocation functions already allocate in chunks (and those chunks are in large chunks). It also holds information about alignment and size that you don't know about. You're essentially doing something that malloc already handles for you.

The real question is: Why were you running out of memory?

You're not increasing the amount of memory available to you by doing this. In a lot of cases, you can sacrifice runtime resources to reduce memory usage. Large buffers isn't something you do in limited resource programming.

Too much is missing in the context to really help your problem. You state your problem, provide a solution, and ask for help on your solution rather than your problem.
I might of misread. Was your program too big for the device or were you running into allocation problems?
Was your program too big for the device or were you running into allocation problems?
The program was to big for my device

You're essentially doing something that malloc already handles for you.
yeah but using malloc means I must not forget free, I don't want the possibility of memory leaks anywhere

You're not increasing the amount of memory available to you by doing this.
I though when I have data on the stack it increases the binary size of the application. So I if I'd do it like this I'd allways only use the space really needed at the moment.

Too much is missing in the context to really help your problem. You state your problem, provide a solution, and ask for help on your solution rather than your problem.
I'm sorry, this problem occured about 2 years ago and I don't have the code where I got the error anymore :s

If you can't answer my question because of this can you still answer this question:

How can I force that memory_ and place_ are never touched by anyone except the API?
1
2
3
4
5
// never touch the members directly (how can I force that?)
typedef struct {
    void* memory_;
    void* place_;
} Memory;


Edit: I just realized I was wrong all along.
The buffers in the functions didn't increase the binary size at all...
It looks like only the objects in global namespace affect the binary size.
Last edited on
How can I force that memory_ and place_ are never touched by anyone except the API?


You can turn Memory into an opaque pointer type and then treat it as such.
Topic archived. No new replies allowed.