Finally I have a valid reason to learn about memory management. It was also hella weird when encountering it.
And then OP used valgrind
I did not knew this existed, so thanks for the tip.
have fun (ノಠ益ಠ)ノ彡┻━┻
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.C makes them unnecessarily confusing in my opinion. In Forth they’re as simple as can be compared to C.
It’ll be fun when you get to funny errors because you used
free
d memory.When I was learning about linked lists and decided to use them in a project, I “removed” items by making the previous item’s
next
point to this item’snext
, except I misplaced a call tofree
before using the fields, and it somehow still worked most of the time on debug builds, but on optimized builds it would cause a segmentation fault 100% of the time.Unused memory is wasted memory
Cloud providers LOVE you with this one quick trick!
Also goes for mobile. You use more memory and apps get killed.
and with a good enough leak, the amount of unused memory will become negative!
Valgrind to the rescue
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.
Absolutely. I once wrote a server for a factory machine that spawned child processes to work each job item. Intentionally we did not free any memory in the child process because it serves only one request and then exits anyway. It’s much more efficient to have the OS just clean up everything and provides strong guarantees that nothing can be left behind accidentally for a system where up time was money. Any code to manage memory was pointless line noise and extra developer effort.
In fact I think in the linker we specifically replaced free with a function that does nothing.
Upvoted. This is something I learned rather recently. Sometimes it’s more performant to slowly leak than it would be to free properly. Then take x amount of time to restart every n amount of time.
A middle ground is a memory pool or an object pool where you reuse the memory rather than free it. Instead, you free it all in one operation when that phase of your application is complete. I’ve seen this done for particle systems to reduce overhead.
.net
Anything I run in C# or similar seems to allocate 512GB of virtual address space and then just populates what it actually uses.
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.
That sounds like it could be memory corruption. That should not happen because every string should be separated by a null terminator.
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.
And understand when you can use them…
I’ve seen too much code following this advice blindly that just does something like
strncpy(dst, src, strlen(src))
I found the mistake. Since the country code char array only has a size of 2 it overwrites the \0 char causing the memory to leak.
Usually what’s meant by a memory leak is memory that’s allocated but never freed. Writing outside of array allocation would usually be considered an overflow. Which sounds kinda similar but is not the same.
Bingo. I thought something probably happened to your terminator.
This could make for a fun reverse engineering CTF challenge.
You haven’t lived until you’ve produced a memory leak in JavaScript.
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
Congratulations! Now you can get a job at Fortinet.
(Fortinet is a network security vendor…think firewalls, HLBs, etc. They get an ungodly amount of memory leak bugs, or at least far more than you would expect from an enterprise firewall)
Get a job playing Fortnite, got it
(Insert image of Kronk here)
is this some genX meme that I’m too millennial to understand?
No. I am just learning C and was curious how long it would take to get my first memory leak.
I think the confusion comes from this not exactly being a positive thing. It reads almost like a new driver saying, “Thank God I finally got my first speeding ticket!”
I did my first “that one thing where you park and want to press breaks but press gas instead by accident.”
Gen-x likes to call it “right of passage.”
Learn some C you whippersnapper! You ain’t gonna become a proper programmer unless you understand your basic low level concepts well!
The youth nowadays, always hiding behind abstractions of abstractions that 90% of the time are just C wrappers anyway /j
(written by an early 20s PHP dev LOL. Although I do plan on learning C quite a bit before I move to C++ and ultimately Rust)
You’re not a “real” programmer unless you started with FORTRAN :p
Pfft compilers. Just use assembler.
Fortran
:3
Cruft can be a hard thing to debug. Mainly when you’re not used to memory issues and haven’t learned all the best practices.
There’s also zig if you want to play with memory. You’ll know a lot about allocation, that’s for sure.
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.
That’s a nice recommendation.
For a beginner without experience in using libraries, the additional requirements in Rust would feel unnecessary and frustrating.
If you take up Rust after learning programming using C (which won’t require all that extra stuff and let you learn the basics easily), that would make it easier for you to appreciate the results of the extra work it makes you do.C is a 100% valid language to spend your time on.
Probably a good idea. I decided to learn Rust after using Python for a couple years. I took a semester of C++ but barely remember anything. Maybe I should write a project in C and rewrite later in Rust. I personally only learn when I get inspiration to make a program, which means I learn on the spot. I don’t think it is the best way to do things (if I knew the language better I may make better decisions), but it is the only way I can motivate myself to learn.
Everyone learns differently. Go with what works for you.
I tend to learn the same way,
C is useless nowadays (and has been for at least 20 years). Either learn Rust or C++.
Lol, what?
C is eternal brother.
This is such an incorrect take for real. C is far from useless and still used all over the place in all kinda of professional projects. And I’m talking new projects started this year, not just legacy maintenance.
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.
FWIW you can use C++ on Arduino.
Yeah, but I kinda dont want to learn/use C++
I don’t blame you. I have to use a professionally sometimes and I am not a fan. It’s an absolute behemoth of the language filled with warts and cruft.
Sometimes it is the best choice for a project, but I prefer languages with simple, orthogonal concepts.
it is good to learn C, even if you’re never gonna touch it again. It teaches you what other languages abstract away.
I’m the tech lead on a three-year-old project that’s entirely in C. It is my full time job to write C89.