Finally I have a valid reason to learn about memory management. It was also hella weird when encountering it.
Unused memory is wasted memory
You haven’t lived until you’ve produced a memory leak in JavaScript.
Not freeing your memory at all is a memory management strategy. I think some LaTeX compilers use it as well as surprisingly many Java applications.
This non-sarcastically. The operating system is better at cleaning up memory than you, and it’s completely pointless to free all your allocations if you’re about to exit the program. For certain workloads, it can lead to cleaner, less buggy code to not free anything.
It’s important to know the difference between a “memory leak” and unfreed memory. A leak refers to memory that cannot be freed because you lost track of the address to it. Leaks are only really a problem if the amount of leaked memory is unbounded or huge. Every scenario is different.
Of course, that’s not an excuse to be sloppy with memory management. You should only ever fail to free memory intentionally.
That’s the funny thing. I had a (yet) very basic Programm and did not care at all about memory management. When I did some testing I realised, that for some reason when I printed string 1 I also got characters from string 2.
Sounds interesting, want to share a minimal example?
This is the code I used:
#include <stdio.h> #include <string.h> #define MAX_ACCOUNTS 255 typedef struct { unsigned int id; char account_creation_date [10]; char first_name [255]; char last_name [255]; char country_code [2]; unsigned int iban; char password [255]; double balance; } account; account accounts_db[MAX_ACCOUNTS]; unsigned int accounts_created = 0; account get_account_id (unsigned int id) { int i = 0; while(i < MAX_ACCOUNTS) { if(accounts_db[i].id == id) { return accounts_db[i]; } i++; } account account; account.id = -1; return account; } void create_account(char first_name [255], char last_name [255], char password [255], char country_code [2]) { account new_account; new_account.id = accounts_created; strcpy(new_account.first_name, first_name); strcpy(new_account.last_name, last_name); strcpy(new_account.password, password); strcpy(new_account.country_code, country_code); strcpy(new_account.account_creation_date, ""); new_account.balance = 0.0; new_account.iban = 0; accounts_db[accounts_created] = new_account; accounts_created++; } int main() { char first_name [255] = "Max"; char last_name [255] = "Mustermann"; char country_code [2] = "DE"; char password [255]= "password"; create_account(first_name, last_name, password,country_code); account account = get_account_id(0); printf("Name: %s %s \n", account.first_name, account.last_name); printf("Account creation date: %s\n", account.account_creation_date); printf("IBAN: %s %d", account.country_code, account.iban); }``` When you run it you can see, that behind the country code of the IBAN you get the first two letters of the surename
Without getting too critical of your code (congrats BTW), never use
strcpy
instead usestrlcpy
.strcpy
will happily allow you to create buffer overflows (a common challenge with C) which will cause your application to crash.You’ll find more details here.
Good luck!
Thanks, I did not knew this. I always appreciate constructive criticism. I am quite new to C so theres a shit ton of stuff I have never done or dont even know about.
Back when I was a kid and was learning C, I used to wonder why people considered pointers hard.
My usage of pointers was like:void func (int * arg1) { // do sth with arg1 } int main () { int x; func (&x); return 0; }
I didn’t know stuff like
malloc
and never felt the need in any of the program logic for the little thingies I made.
Pointers are not hard. Memory management makes it hard.RAII.
Can’t leak what never leaves the stack frame.
Isn’t this for C++?
Classes are just pretentious structs.
How do you get destructor behavior in C?
You call the destructor. It’s simply not automatically done for you with the concept of going out of scope.
Back when C++ was simply a text pre-processor for C, you could see these normal function calls. You can still see them in the un-optimized disassembly. There’s nothing magical about a destructor other than it being inserted automatically.
being inserted automatically.
Aka the entire point of RAII
The point of RAII is that a resource is allocated and freed in the same scope.
You can free it with an explicit call to a destructor, an implicit call, or with memory allocated on the stack, just wait for the stack frame to be exited.
I’ve used C++20 on embedded devices and the generated code was simpler than the C version. Why do you still use C?
I want to learn rust and got the recommendation to learn C first.
C is useless nowadays (and has been for at least 20 years). Either learn Rust or C++.
The reason I got recommended to learn C first is so that you are getting used to handling memory by yourself. Then you switch to rust and since you are used to handling memory your rust code is usually better quality.
Another reason I want to learn C is because I regularly have to work with Arduinos.
I can’t comment whether learning C first improves your rust, but it certainly makes you appreciate what the rust compiler does.
Also learning rust improved my C.I think it’s a fair strategy. If they know what happens if you do it wrong people suddenly complain less about rust’s borrow checker. Whereas people who are only used to garbage collected language don’t usually have the slightest clue why it works the way it does.