chore: sync content to repo (#10141)

Co-authored-by: nilbuild <4921183+nilbuild@users.noreply.github.com>
This commit is contained in:
github-actions[bot]
2026-07-10 10:23:45 +02:00
committed by GitHub
co-authored by nilbuild
parent 70ecc31a04
commit f0facef4fb
142 changed files with 1029 additions and 264 deletions
@@ -1,3 +1,9 @@
# _Atomic
The `_Atomic` qualifier, introduced in C11, marks a variable so that reads and writes to it happen as a single, indivisible operation, even when accessed from multiple threads. This prevents data races on that variable without needing a separate lock. It is used together with the `<stdatomic.h>` header when writing concurrent C code.
The `_Atomic` qualifier, introduced in C11, marks a variable so that reads and writes to it happen as a single, indivisible operation, even when accessed from multiple threads. This prevents data races on that variable without needing a separate lock. It is used together with the `<stdatomic.h>` header when writing concurrent C code.
Visit the following resources to learn more:
- [@article@Atomic types](https://en.cppreference.com/c/language/atomic)
- [@article@What is the _Atomic keyword in C?](https://www.educative.io/answers/what-is-the-atomic-keyword-in-c)
- [@article@Understanding _Atomic Types in C](https://andrewjohnson4.substack.com/p/understanding-_atomic-types-in-c)
@@ -1,3 +1,9 @@
# ABI
An ABI (Application Binary Interface) defines the low-level conventions that compiled code must follow to be compatible with other compiled code, including how function arguments are passed, how data is laid out in memory, and how the stack is organized. Unlike a language-level API, which concerns source code compatibility, an ABI concerns binary compatibility between already-compiled pieces of code. Two libraries compiled with incompatible ABIs, for example using different compilers or settings, may not work correctly together even if their source-level interfaces match.
An ABI (Application Binary Interface) defines the low-level conventions that compiled code must follow to be compatible with other compiled code, including how function arguments are passed, how data is laid out in memory, and how the stack is organized. Unlike a language-level API, which concerns source code compatibility, an ABI concerns binary compatibility between already-compiled pieces of code. Two libraries compiled with incompatible ABIs, for example using different compilers or settings, may not work correctly together even if their source-level interfaces match.
Visit the following resources to learn more:
- [@opensource@📌 Comprehensive Guide to the Application Binary Interface (ABI) in C and C++](https://gist.github.com/MangaD/506a0f3273724ef3af26b8c085accdcb)
- [@article@Application Binary Interfaces](https://developer.arm.com/documentation/den0013/0400/Application-Binary-Interfaces)
- [@video@What Is an ABI, and Why Should You Care?](https://www.youtube.com/watch?v=90fwlfon3Hk)
@@ -1,3 +1,8 @@
# Applications
C shows up in operating system kernels (Linux, Windows internals), embedded systems and microcontrollers, device drivers, database engines, and performance-critical libraries. Many other languages, including Python and Ruby, have interpreters written in C, and most language runtimes expose a C interface for interoperability. It is also the language of choice when a program needs to run close to hardware with minimal overhead.
C shows up in operating system kernels (Linux, Windows internals), embedded systems and microcontrollers, device drivers, database engines, and performance-critical libraries. Many other languages, including Python and Ruby, have interpreters written in C, and most language runtimes expose a C interface for interoperability. It is also the language of choice when a program needs to run close to hardware with minimal overhead.
Visit the following resources to learn more:
- [@article@Applications of C Programming That Will Make You Fall In Love With C](https://data-flair.training/blogs/applications-of-c/)
- [@article@What are common uses of C in the real world outside of embedded and OS dev?](https://www.reddit.com/r/C_Programming/comments/llwg2e/what_are_common_uses_of_c_in_the_real_world/)
@@ -1,3 +1,7 @@
# Arithmetic
Arithmetic operators perform basic mathematical operations: `+` for addition, `-` for subtraction, `*` for multiplication, `/` for division, and `%` for remainder (modulo). Division between two integers truncates toward zero and discards any fractional part, which can surprise programmers expecting a decimal result. Operator precedence follows standard mathematical rules, with multiplication and division evaluated before addition and subtraction unless parentheses override it.
Arithmetic operators perform basic mathematical operations: `+` for addition, `-` for subtraction, `*` for multiplication, `/` for division, and `%` for remainder (modulo). Division between two integers truncates toward zero and discards any fractional part, which can surprise programmers expecting a decimal result. Operator precedence follows standard mathematical rules, with multiplication and division evaluated before addition and subtraction unless parentheses override it.
Visit the following resources to learn more:
- [@article@C Arithmetic Operators](https://www.w3schools.com/c/c_operators_arithmetic.php)
@@ -1,3 +1,9 @@
# Arrays
An array in C is a fixed-size, contiguous block of memory holding multiple elements of the same type, accessed using an index starting at zero. The size of an array must be known at compile time unless it is allocated dynamically on the heap. Arrays decay into pointers to their first element when passed to functions, which means the function receiving them loses information about the array's original size.
An array in C is a fixed-size, contiguous block of memory holding multiple elements of the same type, accessed using an index starting at zero. The size of an array must be known at compile time unless it is allocated dynamically on the heap. Arrays decay into pointers to their first element when passed to functions, which means the function receiving them loses information about the array's original size.
Visit the following resources to learn more:
- [@article@C Arrays](https://www.w3schools.com/c/c_arrays.php)
- [@article@C Arrays](https://www.programiz.com/c-programming/c-arrays)
- [@video@Arrays in C are easy! 🗃️](https://www.youtube.com/watch?v=6Hk2aE_SRzY)
@@ -1,3 +1,9 @@
# ASan & LSan
AddressSanitizer (ASan) and LeakSanitizer (LSan) are compiler-integrated tools, enabled with a flag like `-fsanitize=address`, that detect memory errors and leaks respectively by instrumenting the compiled code to check memory accesses at runtime. ASan catches issues such as buffer overflows, use-after-free, and use of memory after it goes out of scope, reporting the exact location of the error. Compared to tools like Valgrind, sanitizers typically run faster since the checks are built into the compiled binary itself rather than emulated externally.
AddressSanitizer (ASan) and LeakSanitizer (LSan) are compiler-integrated tools, enabled with a flag like `-fsanitize=address`, that detect memory errors and leaks respectively by instrumenting the compiled code to check memory accesses at runtime. ASan catches issues such as buffer overflows, use-after-free, and use of memory after it goes out of scope, reporting the exact location of the error. Compared to tools like Valgrind, sanitizers typically run faster since the checks are built into the compiled binary itself rather than emulated externally.
Visit the following resources to learn more:
- [@article@AddressSanitizer](https://learn.microsoft.com/en-gb/cpp/sanitizers/asan?view=msvc-170)
- [@video@find memory errors quickly. (-fsanitize, addresssanitizer)](https://www.youtube.com/watch?v=tEbV21aPSKw)
- [@video@Detect C++ Memory Leaks with ALSan:](https://www.youtube.com/watch?v=9f5hd-8suVE)
@@ -1,3 +1,9 @@
# assert.h
`<assert.h>` provides the `assert` macro, which checks that a given condition is true and, if not, prints an error message with the file and line number before terminating the program. It is commonly used during development to catch programming errors early, such as invalid function arguments, rather than letting them cause harder-to-diagnose failures later. Defining the `NDEBUG` macro before including `<assert.h>` disables all assertions, which is typically done in release builds for performance.
`<assert.h>` provides the `assert` macro, which checks that a given condition is true and, if not, prints an error message with the file and line number before terminating the program. It is commonly used during development to catch programming errors early, such as invalid function arguments, rather than letting them cause harder-to-diagnose failures later. Defining the `NDEBUG` macro before including `<assert.h>` disables all assertions, which is typically done in release builds for performance.
Visit the following resources to learn more:
- [@article@C Library - \<assert.h\>](https://www.tutorialspoint.com/c_standard_library/assert_h.htm)
- [@article@How to use assertions in C](https://ptolemy.berkeley.edu/~johnr/tutorials/assertions.html)
- [@video@Find bugs faster using assertions.](https://www.youtube.com/watch?v=1Jh9BUxIw0U)
@@ -1,3 +1,8 @@
# Binary vs Text Mode
Text mode may translate certain characters, most notably line endings, when reading or writing a file, converting between the operating system's native line-ending convention and a consistent internal representation. Binary mode performs no such translation, transferring bytes exactly as they are stored. On Unix-like systems the two modes behave identically, but on Windows the distinction matters, since text mode translates between `\n` and `\r\n`.
Text mode may translate certain characters, most notably line endings, when reading or writing a file, converting between the operating system's native line-ending convention and a consistent internal representation. Binary mode performs no such translation, transferring bytes exactly as they are stored. On Unix-like systems the two modes behave identically, but on Windows the distinction matters, since text mode translates between `\n` and `\r\n`.
Visit the following resources to learn more:
- [@article@C File Handling](https://www.programiz.com/c-programming/c-file-input-output)
- [@video@Binary File Access Introduction | C Programming Example](https://www.youtube.com/watch?v=UtckqNKZFrA)
@@ -1,3 +1,8 @@
# Bitwise
Bitwise operators manipulate individual bits within a value, including AND (`&`), OR (`|`), XOR (`^`), NOT (`~`), and the shift operators (`<<`, `>>`). They are used in low-level programming for tasks like setting flags, masking bits, or optimizing certain calculations. Because they operate at the bit level, mixing them up with logical operators, like `&` versus `&&`, is a common source of bugs.
Bitwise operators manipulate individual bits within a value, including AND (`&`), OR (`|`), XOR (`^`), NOT (`~`), and the shift operators (`<<`, `>>`). They are used in low-level programming for tasks like setting flags, masking bits, or optimizing certain calculations. Because they operate at the bit level, mixing them up with logical operators, like `&` versus `&&`, is a common source of bugs.
Visit the following resources to learn more:
- [@article@Bitwise operators](https://www.tutorialspoint.com/cprogramming/c_bitwise_operators.htm)
- [@video@C bitwise operators 🔣](https://www.youtube.com/watch?v=BGeOwlIGRGI)
@@ -1,3 +1,8 @@
# booleans
C did not originally have a dedicated boolean type, relying instead on the convention that zero means false and any nonzero value means true. Since C99, the `<stdbool.h>` header provides a `bool` type along with `true` and `false` macros for clearer code. Under the hood, `bool` is still typically implemented as a small integer type.
C did not originally have a dedicated boolean type, relying instead on the convention that zero means false and any nonzero value means true. Since C99, the `<stdbool.h>` header provides a `bool` type along with `true` and `false` macros for clearer code. Under the hood, `bool` is still typically implemented as a small integer type.
Visit the following resources to learn more:
- [@article@C Booleans](https://www.w3schools.com/c/c_booleans.php)
- [@video@Boolean and Comparison Operators in C Programming](https://www.youtube.com/watch?v=TybmJxXRV80)
@@ -1,3 +1,9 @@
# break / continue
`break` immediately exits the nearest enclosing loop or `switch` statement, skipping any remaining iterations or cases. `continue` skips the rest of the current loop iteration and jumps straight to the next one, without exiting the loop entirely. Both give finer control over loop execution beyond what the loop's own condition provides.
`break` immediately exits the nearest enclosing loop or `switch` statement, skipping any remaining iterations or cases. `continue` skips the rest of the current loop iteration and jumps straight to the next one, without exiting the loop entirely. Both give finer control over loop execution beyond what the loop's own condition provides.
Visit the following resources to learn more:
- [@article@Break Statement in C](https://www.tutorialspoint.com/cprogramming/c_break_statement.htm)
- [@article@Continue Statement in C](https://www.tutorialspoint.com/cprogramming/c_continue_statement.htm)
- [@video@C break vs continue 🥊](https://www.youtube.com/watch?v=N1twTeNMdOE)
@@ -1,3 +1,9 @@
# Buffer Overflow
A buffer overflow occurs when a program writes more data into a fixed-size buffer, like an array, than it can hold, overwriting adjacent memory. This can corrupt other variables, crash the program, or in more severe cases be exploited to execute malicious code, making it a well-known security vulnerability. Using safer alternatives to functions like `strcpy`, such as `strncpy` or `snprintf` with explicit size limits, helps prevent it.
A buffer overflow occurs when a program writes more data into a fixed-size buffer, like an array, than it can hold, overwriting adjacent memory. This can corrupt other variables, crash the program, or in more severe cases be exploited to execute malicious code, making it a well-known security vulnerability. Using safer alternatives to functions like `strcpy`, such as `strncpy` or `snprintf` with explicit size limits, helps prevent it.
Visit the following resources to learn more:
- [@article@Buffer Overflow Exploit in C. A brief overview with a hands on lab.](https://medium.com/@brendamejia/buffer-overflow-exploit-in-c-a-brief-overview-with-a-hands-on-lab-60e53d0d8d08)
- [@video@C Buffer Overflow, Heap/Stack Corruption and Analysis](https://www.youtube.com/watch?v=CQ6pGrXY1Us)
- [@video@Running a Buffer Overflow Attack](https://www.youtube.com/watch?v=1S0aBV-Waeo)
@@ -1,3 +1,3 @@
# Build & Compilation
Building and compiling a C program is the process of transforming human-readable source code into an executable binary, passing through stages including preprocessing, compilation, assembly, and linking. Understanding this pipeline helps explain common errors, like the difference between a compiler error, which happens when code is invalid, and a linker error, which happens when a function or variable cannot be found. Build tools automate this process, especially for projects with many source files.
@@ -1,3 +1,3 @@
# Build Systems
A build system automates the process of compiling and linking a project's source files into a final executable or library, tracking dependencies so that only files affected by a change need to be rebuilt. Options range from simple tools like GNU Make, which uses explicit rules in a Makefile, to higher-level generators like CMake, which produce build files for other underlying build tools. Choosing a build system matters more as a project grows beyond a handful of source files.
@@ -1,3 +1,8 @@
# C Standards
C has evolved through a series of standardized versions published by ANSI and ISO, each adding new features and clarifying existing behavior while aiming to remain largely compatible with earlier code. Notable versions include C89/C90, the first widely adopted standard, C99, which added several commonly used features, C11, which introduced multithreading and atomics, and the more recent C17 and C23. Knowing which standard a codebase or compiler targets matters because some features, like `_Atomic` or fixed-width integers, are only guaranteed to exist from a specific version onward.
C has evolved through a series of standardized versions published by ANSI and ISO, each adding new features and clarifying existing behavior while aiming to remain largely compatible with earlier code. Notable versions include C89/C90, the first widely adopted standard, C99, which added several commonly used features, C11, which introduced multithreading and atomics, and the more recent C17 and C23. Knowing which standard a codebase or compiler targets matters because some features, like `_Atomic` or fixed-width integers, are only guaranteed to exist from a specific version onward.
Visit the following resources to learn more:
- [@article@C - Standards (ANSI, ISO, C99, C11, C17)](https://www.tutorialspoint.com/cprogramming/c_standards.htm)
- [@video@8) C language GUIDE: standards (K&R, ANSI, C99, C11, C17, C2x)](https://www.youtube.com/watch?v=etJzrUzk5Rc)
@@ -1,3 +1,8 @@
# C vs Assembly
Assembly language maps almost directly to a specific CPU's instruction set, so code written for one processor architecture will not run on another without a rewrite. C sits one level above assembly: it compiles down to machine code but uses portable syntax that works across architectures with little or no change. Programmers get most of the performance benefits of assembly with far less code and much better readability. C is sometimes called "portable assembly" for this reason.
Assembly language maps almost directly to a specific CPU's instruction set, so code written for one processor architecture will not run on another without a rewrite. C sits one level above assembly: it compiles down to machine code but uses portable syntax that works across architectures with little or no change. Programmers get most of the performance benefits of assembly with far less code and much better readability. C is sometimes called "portable assembly" for this reason.
Visit the following resources to learn more:
- [@article@C versus Assembly](https://www.dspguide.com/ch28/5.htm#:~:text=Programs%20written%20in%20assembly%20can,almost%20always%20the%20first%20choice.)
- [@video@Comparing C to machine language](https://www.youtube.com/watch?v=yOyaJXpAYZQ)
@@ -1,3 +1,10 @@
# C vs C++
C is a procedural language with manual memory management and no built-in support for classes, inheritance, or exceptions. C++ extends C with object-oriented features, templates, the standard template library, and stronger compile-time checks, while remaining mostly compatible with C syntax. Programs written in C tend to be smaller and more predictable in behavior, while C++ trades some of that simplicity for abstraction and reuse. Choosing between them usually depends on whether the project needs low-level control or higher-level abstractions.
C is a procedural language with manual memory management and no built-in support for classes, inheritance, or exceptions. C++ extends C with object-oriented features, templates, the standard template library, and stronger compile-time checks, while remaining mostly compatible with C syntax. Programs written in C tend to be smaller and more predictable in behavior, while C++ trades some of that simplicity for abstraction and reuse. Choosing between them usually depends on whether the project needs low-level control or higher-level abstractions.
Visit the following resources to learn more:
- [@roadmap@Visit the Dedicated C++ Roadmap](https://roadmap.sh/cpp)
- [@article@C++ vs. C: When (and when not) to use each language](https://roadmap.sh/cpp/vs-c)
- [@article@C vs C++](https://www.reddit.com/r/C_Programming/comments/34tes5/c_vs_c/)
- [@video@C vs C++ vs C#](https://www.youtube.com/watch?v=sNMtjs_wQiE)
@@ -1,3 +1,7 @@
# C11
C11, published in 2011, introduced support for multithreading through `<threads.h>`, atomic operations via `_Atomic` and `<stdatomic.h>`, and improved Unicode support. It also added optional bounds-checking functions intended to reduce common security vulnerabilities, though these saw limited adoption across compilers. C11 was a significant step in bringing standardized concurrency support directly into the language.
C11, published in 2011, introduced support for multithreading through `<threads.h>`, atomic operations via `_Atomic` and `<stdatomic.h>`, and improved Unicode support. It also added optional bounds-checking functions intended to reduce common security vulnerabilities, though these saw limited adoption across compilers. C11 was a significant step in bringing standardized concurrency support directly into the language.
Visit the following resources to learn more:
- [@article@C11 (C standard revision) - Wikipedia](https://en.wikipedia.org/wiki/C11_(C_standard_revision))
@@ -1,3 +1,7 @@
# C17
C17, published in 2018, is primarily a bug-fix and clarification release for C11, correcting defects and ambiguities in the standard's wording without introducing significant new language features. It is sometimes referred to as C18 due to its actual publication date. Compilers that support C11 typically support C17 with little additional work, since the practical differences between the two are minor.
C17, published in 2018, is primarily a bug-fix and clarification release for C11, correcting defects and ambiguities in the standard's wording without introducing significant new language features. It is sometimes referred to as C18 due to its actual publication date. Compilers that support C11 typically support C17 with little additional work, since the practical differences between the two are minor.
Visit the following resources to learn more:
- [@article@C17 (C standard revision) - Wikipedia](https://en.wikipedia.org/wiki/C17_(C_standard_revision))
@@ -1,3 +1,7 @@
# C23
C23 is the most recent major revision of the C standard, adding features such as improved type inference with `auto` in some contexts, new attributes, and additional standard library functions, while continuing to refine areas like Unicode support. Compiler support for C23 features varies and continues to roll out gradually across GCC, Clang, and other compilers. Projects prioritizing portability often wait until a feature reaches broad compiler support before adopting it.
C23 is the most recent major revision of the C standard, adding features such as improved type inference with `auto` in some contexts, new attributes, and additional standard library functions, while continuing to refine areas like Unicode support. Compiler support for C23 features varies and continues to roll out gradually across GCC, Clang, and other compilers. Projects prioritizing portability often wait until a feature reaches broad compiler support before adopting it.
Visit the following resources to learn more:
- [@article@C23 (C standard revision) - Wikipedia](https://en.wikipedia.org/wiki/C23_(C_standard_revision))
@@ -1,3 +1,8 @@
# C89 / C90
C89, also called C90 after its later ISO ratification, was the first standardized version of C, published in 1989 by ANSI. It established the core language and standard library that later versions built on, and remains the baseline that many embedded and legacy systems still target for maximum portability. Some features considered standard today, like `//` single-line comments or declaring variables anywhere in a block, were not part of this original standard.
C89, also called C90 after its later ISO ratification, was the first standardized version of C, published in 1989 by ANSI. It established the core language and standard library that later versions built on, and remains the baseline that many embedded and legacy systems still target for maximum portability. Some features considered standard today, like `//` single-line comments or declaring variables anywhere in a block, were not part of this original standard.
Visit the following resources to learn more:
- [@article@ANSI C - Wikipedia](https://en.wikipedia.org/wiki/ANSI_C)
- [@article@Understanding the Standard](https://www.davros.org/c/understand.html)
@@ -1,3 +1,8 @@
# C99
C99, published in 1999, added several widely used features to the language, including the `bool` type via `<stdbool.h>`, variable-length arrays, `//` single-line comments, and the ability to declare variables anywhere within a block rather than only at its start. It also introduced the `restrict` keyword and improved support for floating-point behavior. Many compilers support most of C99 even when a project does not explicitly target it.
C99, published in 1999, added several widely used features to the language, including the `bool` type via `<stdbool.h>`, variable-length arrays, `//` single-line comments, and the ability to declare variables anywhere within a block rather than only at its start. It also introduced the `restrict` keyword and improved support for floating-point behavior. Many compilers support most of C99 even when a project does not explicitly target it.
Visit the following resources to learn more:
- [@article@C99 - Wikipedia](https://en.wikipedia.org/wiki/C99)
- [@article@c99 - compile standard C programs](https://pubs.opengroup.org/onlinepubs/009604499/utilities/c99.html)
@@ -0,0 +1,9 @@
# calloc
`calloc` is a function used to allocate a specified number of blocks of memory, each of a set size, and initializes every byte in that memory to zero. It takes two arguments: the number of elements to allocate and the size of each element in bytes. If the allocation is successful, it returns a pointer to the first byte of the allocated space, or a null pointer if the system lacks sufficient memory.
Visit the following resources to learn more:
- [@article@C Allocate Memory](https://www.w3schools.com/c/c_memory_allocate.php)
- [@article@C stdlib calloc() Function](https://www.w3schools.com/c/ref_stdlib_calloc.php#:~:text=The%20calloc()%20function%20allocates,our%20C%20Memory%20Management%20tutorial.)
- [@video@Calloc in C is easy! 🧹](https://www.youtube.com/watch?v=l8DU9ZeT3o8)
@@ -1,3 +1,8 @@
# char
The `char` type stores a single byte, most often used to represent a character encoded as its numeric value, such as ASCII. It can be signed or unsigned depending on the compiler and platform, which affects how negative values behave. Arrays of `char` are also the basis for how C represents strings.
The `char` type stores a single byte, most often used to represent a character encoded as its numeric value, such as ASCII. It can be signed or unsigned depending on the compiler and platform, which affects how negative values behave. Arrays of `char` are also the basis for how C represents strings.
Visit the following resources to learn more:
- [@article@Definition and Usage](https://www.w3schools.com/c/ref_keyword_char.php)
- [@video@Learn C Programming - Char Data Type and ASCII Characters](https://www.youtube.com/watch?v=7_jRj7Ce90s)
@@ -1,3 +1,8 @@
# Check
Check is a unit testing framework for C that runs each test case in its own separate process, so a crash or memory error in one test does not stop the rest of the test suite from running. It provides assertion macros and supports organizing tests into suites, similar to other C testing frameworks. Its process-isolation approach makes it particularly resilient when testing code prone to crashes or segmentation faults.
Check is a unit testing framework for C that runs each test case in its own separate process, so a crash or memory error in one test does not stop the rest of the test suite from running. It provides assertion macros and supports organizing tests into suites, similar to other C testing frameworks. Its process-isolation approach makes it particularly resilient when testing code prone to crashes or segmentation faults.
Visit the following resources to learn more:
- [@official@Check](https://libcheck.github.io/check/)
- [@opensource@check](https://github.com/libcheck/check)
@@ -1,3 +1,8 @@
# CMake
CMake is a cross-platform build system generator that reads a project description, written in its own CMake language, and produces native build files for the target platform, such as Makefiles on Linux or Visual Studio project files on Windows. This lets a single project configuration work across multiple platforms and underlying build tools without maintaining separate build scripts for each. It has become a de facto standard for larger, cross-platform C and C++ projects.
CMake is a cross-platform build system generator that reads a project description, written in its own CMake language, and produces native build files for the target platform, such as Makefiles on Linux or Visual Studio project files on Windows. This lets a single project configuration work across multiple platforms and underlying build tools without maintaining separate build scripts for each. It has become a de facto standard for larger, cross-platform C and C++ projects.
Visit the following resources to learn more:
- [@official@CMake Tutorial](https://cmake.org/cmake/help/latest/guide/tutorial/index.html)
- [@article@CMake Tutorial for Absolute Beginners](https://www.youtube.com/watch?v=NGPo7mz1oa4)
@@ -1,3 +1,8 @@
# CMocka
CMocka is a unit testing framework for C that includes support for mock objects, letting tests replace real function calls with controlled substitutes to isolate the code under test. It provides assertion macros for checking expected values and can run groups of test cases together while reporting pass/fail results. Its mocking support makes it well suited to testing code with external dependencies, like hardware interfaces or network calls.
CMocka is a unit testing framework for C that includes support for mock objects, letting tests replace real function calls with controlled substitutes to isolate the code under test. It provides assertion macros for checking expected values and can run groups of test cases together while reporting pass/fail results. Its mocking support makes it well suited to testing code with external dependencies, like hardware interfaces or network calls.
Visit the following resources to learn more:
- [@official@CMocka](https://cmocka.org/)
- [@article@Unit testing C code with CMocka](https://blog.microjoe.org/2017/unit-tests-c-cmocka-coverage-cmake.html)
@@ -1,3 +1,7 @@
# Code Editors / IDEs
C can be written in a plain text editor, a lightweight code editor, or a full IDE, and the choice affects how much tooling support you get for things like autocomplete, debugging, and build integration. Lightweight editors like vim or VSCode require some manual setup for compiling and debugging, while full IDEs bundle these features together. Beginners often start with something simple and add tooling as their projects grow more complex.
C can be written in a plain text editor, a lightweight code editor, or a full IDE, and the choice affects how much tooling support you get for things like autocomplete, debugging, and build integration. Lightweight editors like vim or VSCode require some manual setup for compiling and debugging, while full IDEs bundle these features together. Beginners often start with something simple and add tooling as their projects grow more complex.
Visit the following resources to learn more:
- [@article@what are some good, simple C IDEs for the modern day?](https://www.reddit.com/r/C_Programming/comments/1ai3chm/what_are_some_good_simple_c_ides_for_the_modern/)
@@ -1,3 +1,8 @@
# Command-Line Arguments
Command-line arguments let a program receive input when it starts, passed through `main`'s parameters: `argc`, the count of arguments, and `argv`, an array of strings containing the arguments themselves, with `argv[0]` typically being the program's own name. This is how command-line tools accept options and file paths without needing interactive input. Parsing `argv` manually or with a library like `getopt` is a common early step in building any command-line utility.
Command-line arguments let a program receive input when it starts, passed through `main`'s parameters: `argc`, the count of arguments, and `argv`, an array of strings containing the arguments themselves, with `argv[0]` typically being the program's own name. This is how command-line tools accept options and file paths without needing interactive input. Parsing `argv` manually or with a library like `getopt` is a common early step in building any command-line utility.
Visit the following resources to learn more:
- [@article@Command Line Arguments in C](https://www.tutorialspoint.com/cprogramming/c_command_line_arguments.htm)
- [@video@Command Line Arguments](https://www.youtube.com/watch?v=wa2AfzyOff0)
@@ -0,0 +1,3 @@
# Common Data Structures
Beyond the built-in array, C programmers commonly build their own data structures using structs and pointers, since the language does not provide these as ready-made library types. Common examples include dynamic arrays that grow as needed, linked lists that store elements as a chain of nodes, hash maps for fast key-based lookup, and ring buffers for fixed-size queues. Implementing these from scratch is a common exercise for understanding how higher-level languages' built-in collections work internally.
@@ -1,3 +1,8 @@
# Comparison
Comparison operators, such as `==`, `!=`, `<`, `>`, `<=`, and `>=`, evaluate two values and produce a result of 1 (true) or 0 (false). They are commonly used in conditions for `if` statements and loops to control program flow. A frequent beginner mistake is writing `=` instead of `==`, which assigns a value instead of comparing it.
Comparison operators, such as `==`, `!=`, `<`, `>`, `<=`, and `>=`, evaluate two values and produce a result of 1 (true) or 0 (false). They are commonly used in conditions for `if` statements and loops to control program flow. A frequent beginner mistake is writing `=` instead of `==`, which assigns a value instead of comparing it.
Visit the following resources to learn more:
- [@article@Comparison Opearators](https://www.tutorialspoint.com/cprogramming/c_relational_operators.htm)
- [@article@C Comparison Opearators](https://www.w3schools.com/c/c_operators_comparison.php)
@@ -1,3 +1,9 @@
# Compilers
A compiler translates C source code into machine code that can run directly on a specific processor and operating system. Popular choices include GCC and Clang, which support most platforms, and specialized compilers like TinyCC, designed for speed rather than optimization. Compilers also expose various flags controlling optimization level, warnings, and debugging information included in the output.
A compiler translates C source code into machine code that can run directly on a specific processor and operating system. Popular choices include GCC and Clang, which support most platforms, and specialized compilers like TinyCC, designed for speed rather than optimization. Compilers also expose various flags controlling optimization level, warnings, and debugging information included in the output.
Visit the following resources to learn more:
- [@article@What is a Compiler? Compilers in C Explained for Beginners](https://www.freecodecamp.org/news/what-is-a-compiler-in-c/)
- [@article@How Does C Compilation Work?](https://medium.com/@bdov_/what-happens-when-you-type-gcc-main-c-a4454564e96d)
- [@video@Why is C Compiler So Smart?](https://www.youtube.com/watch?v=juWM6saNCZk)
@@ -1,3 +1,8 @@
# Conan
Conan is a package manager for C and C++ that manages both source and prebuilt binary packages, with a focus on handling different build configurations, such as debug versus release, or different compilers. It integrates with build systems including CMake and Meson, and maintains a central repository of package recipes that describe how to build and consume each library. It is commonly used in larger, multi-platform C++ projects, though it also supports C.
Conan is a package manager for C and C++ that manages both source and prebuilt binary packages, with a focus on handling different build configurations, such as debug versus release, or different compilers. It integrates with build systems including CMake and Meson, and maintains a central repository of package recipes that describe how to build and consume each library. It is commonly used in larger, multi-platform C++ projects, though it also supports C.
Visit the following resources to learn more:
- [@official@Conan Tutorial](https://docs.conan.io/2/tutorial.html)
- [@video@Introduction to C/C++ Package Management with Conan](https://www.youtube.com/watch?v=xBLjXdyh3zs&list=PLY0Zjn5rFo4OTu5_-pErorGBm0_-UNgCV)
@@ -1,3 +1,10 @@
# Concurrency
Concurrency in C covers running multiple sequences of execution, such as threads or processes, at the same time or in an interleaved fashion. This includes using POSIX threads for shared-memory parallelism within a single process, mutexes to prevent multiple threads from corrupting shared data, and inter-process communication for separate processes that need to exchange data. Writing correct concurrent C code requires careful attention to shared state, since the language provides no automatic protection against data races.
Concurrency in C covers running multiple sequences of execution, such as threads or processes, at the same time or in an interleaved fashion. This includes using POSIX threads for shared-memory parallelism within a single process, mutexes to prevent multiple threads from corrupting shared data, and inter-process communication for separate processes that need to exchange data. Writing correct concurrent C code requires careful attention to shared state, since the language provides no automatic protection against data races.
Visit the following resources to learn more:
- [@book@Introduction to Concurrent Programming in C](https://storm-lang.org/progvis-book/book.pdf)
- [@article@Threads, Mutexes and Concurrent Programming in C](https://www.codequoi.com/en/threads-mutexes-and-concurrent-programming-in-c/)
- [@article@Concurrency in C](https://www.classes.cs.uchicago.edu/archive/2017/spring/12300-1/lab5.html)
- [@video@Introduction To Threads (pthreads) | C Programming Tutorial](https://www.youtube.com/watch?v=ldJ8WGZVXZk)
@@ -1,3 +1,9 @@
# Conditional Compilation
Conditional compilation uses preprocessor directives like `#ifdef`, `#ifndef`, `#if`, and `#endif` to include or exclude blocks of code before the compiler processes them, based on whether certain macros are defined. It is commonly used for platform-specific code, enabling debug-only sections, or preventing a header file from being included multiple times through header guards. Because this happens during preprocessing, excluded code is never even seen by the compiler.
Conditional compilation uses preprocessor directives like `#ifdef`, `#ifndef`, `#if`, and `#endif` to include or exclude blocks of code before the compiler processes them, based on whether certain macros are defined. It is commonly used for platform-specific code, enabling debug-only sections, or preventing a header file from being included multiple times through header guards. Because this happens during preprocessing, excluded code is never even seen by the compiler.
Visit the following resources to learn more:
- [@article@Conditional compilation directives in C](https://fastbitlab.com/blog/microcontroller-embedded-c-programming-lecture-182-conditional-compilation-directives/)
- [@article@Conditional compilation - Wikipedia](https://en.wikipedia.org/wiki/Conditional_compilation)
- [@video@Conditional Compilation Directives](https://www.youtube.com/watch?v=rTNDAMyRpUs)
@@ -1,3 +1,8 @@
# const
The `const` qualifier marks a variable as read-only after initialization, so any attempt to modify it later triggers a compile-time error. It is commonly used for function parameters that should not be changed by the function, and for values that are fixed for the program's lifetime, like configuration constants. Using `const` where possible helps the compiler catch accidental modifications and documents intent for other readers of the code.
The `const` qualifier marks a variable as read-only after initialization, so any attempt to modify it later triggers a compile-time error. It is commonly used for function parameters that should not be changed by the function, and for values that are fixed for the program's lifetime, like configuration constants. Using `const` where possible helps the compiler catch accidental modifications and documents intent for other readers of the code.
Visit the following resources to learn more:
- [@article@C Constants](https://www.w3schools.com/c/c_constants.php)
- [@video@Constants in C](https://www.youtube.com/watch?v=BVnNg20AuYU)
@@ -1,3 +1,9 @@
# Control Flow
Control flow determines the order in which statements in a program execute, using constructs like conditionals and loops instead of running every line top to bottom unconditionally. C provides `if`/`else` and `switch` for branching, and `for`, `while`, and `do-while` for repetition. Mastering control flow is what allows a program to make decisions and repeat work based on data rather than following a single fixed path.
Control flow determines the order in which statements in a program execute, using constructs like conditionals and loops instead of running every line top to bottom unconditionally. C provides `if`/`else` and `switch` for branching, and `for`, `while`, and `do-while` for repetition. Mastering control flow is what allows a program to make decisions and repeat work based on data rather than following a single fixed path.
Visit the following resources to learn more:
- [@article@C - Decision Making & Control Statements](https://www.tutorialspoint.com/cprogramming/c_decision_making.htm)
- [@article@C - Loops](https://www.tutorialspoint.com/cprogramming/c_loops.htm)
- [@video@Conditionals & Loops in C](https://www.youtube.com/playlist?list=PLBlnK6fEyqRgZq4a-SMViZr-V8jlvCioJ)
@@ -1,3 +1,9 @@
# Dangling Pointers
A dangling pointer points to memory that has already been freed or otherwise become invalid, but the pointer itself still holds the old address. Using a dangling pointer, whether reading or writing through it, results in undefined behavior and can corrupt unrelated data. Setting a pointer to `NULL` immediately after freeing it is a common way to reduce the risk of accidentally using it again.
A dangling pointer points to memory that has already been freed or otherwise become invalid, but the pointer itself still holds the old address. Using a dangling pointer, whether reading or writing through it, results in undefined behavior and can corrupt unrelated data. Setting a pointer to `NULL` immediately after freeing it is a common way to reduce the risk of accidentally using it again.
Visit the following resources to learn more:
- [@article@Dangling Pointers in C](https://www.tutorialspoint.com/cprogramming/c_dangling_pointers.htm)
- [@article@Dangling Pointer in C: Causes, Types, Fixes & Examples](https://www.boardinfinity.com/blog/dangling-pointer-in-c/)
- [@video@Understanding the Dangling Pointers](https://www.youtube.com/watch?v=qNgV7oAHElk)
@@ -1,3 +1,9 @@
# Data Types
A data type in C defines what kind of value a variable can hold and how much memory it occupies, such as an integer, a floating-point number, or a character. C provides a small set of basic types built into the language, along with qualifiers and extended types for more specific needs. Choosing the right type affects both correctness, since operations behave differently across types, and memory usage.
A data type in C defines what kind of value a variable can hold and how much memory it occupies, such as an integer, a floating-point number, or a character. C provides a small set of basic types built into the language, along with qualifiers and extended types for more specific needs. Choosing the right type affects both correctness, since operations behave differently across types, and memory usage.
Visit the following resources to learn more:
- [@article@C Data Types](https://www.w3schools.com/c/c_data_types.php)
- [@article@C - Data Types](https://www.tutorialspoint.com/cprogramming/c_data_types.htm)
- [@video@C data types 📊](https://www.youtube.com/watch?v=1eyf1-RU_eg)
@@ -1,3 +1,8 @@
# Data Utilities
Data utility functions, largely from `<stdlib.h>`, provide general-purpose operations such as memory allocation (`malloc`, `free`), converting strings to numbers (`atoi`, `strtol`), generating pseudo-random numbers (`rand`), and sorting or searching arrays (`qsort`, `bsearch`). They cover common tasks that come up across many kinds of programs regardless of domain. Because they are part of the standard library, they are available on any standards-compliant C implementation without extra installation.
Data utility functions, largely from `<stdlib.h>`, provide general-purpose operations such as memory allocation (`malloc`, `free`), converting strings to numbers (`atoi`, `strtol`), generating pseudo-random numbers (`rand`), and sorting or searching arrays (`qsort`, `bsearch`). They cover common tasks that come up across many kinds of programs regardless of domain. Because they are part of the standard library, they are available on any standards-compliant C implementation without extra installation.
Visit the following resources to learn more:
- [@article@C stdlib (stdlib.h) Library](https://www.w3schools.com/c/c_ref_stdlib.php)
- [@article@C Library - \<stdlib.h\>](https://www.tutorialspoint.com/c_standard_library/stdlib_h.htm)
@@ -1,3 +1,9 @@
# Debugging
Debugging in C involves finding and fixing defects in a program, often using dedicated tools since bugs like memory corruption or undefined behavior may not produce an obvious, immediate symptom. Debuggers like GDB and LLDB let a programmer pause execution, inspect variables, and step through code line by line. Other tools, like Valgrind and sanitizers, specialize in detecting specific classes of bugs such as memory errors.
Debugging in C involves finding and fixing defects in a program, often using dedicated tools since bugs like memory corruption or undefined behavior may not produce an obvious, immediate symptom. Debuggers like GDB and LLDB let a programmer pause execution, inspect variables, and step through code line by line. Other tools, like Valgrind and sanitizers, specialize in detecting specific classes of bugs such as memory errors.
Visit the following resources to learn more:
- [@article@C Debugging](https://www.w3schools.com/c/c_debugging.php)
- [@article@C/Debugging](https://www.cs.yale.edu/homes/aspnes/pinewiki/C(2f)Debugging.html)
- [@video@Debugging C Programs](https://www.youtube.com/watch?v=mfmXcbiRs0E&list=PL9IEJIKnBJjHGWPN_S9NS_Ky1-tC8ZrUI)
@@ -1,3 +1,9 @@
# Declaration vs Definition
A declaration tells the compiler that a variable or function exists and states its type, without necessarily allocating memory or providing a function body. A definition actually allocates storage for a variable or provides the function's implementation. In C, `extern int x;` is a declaration, while `int x;` is a definition. This distinction matters most when code spans multiple files and needs to share variables or functions across them.
A declaration tells the compiler that a variable or function exists and states its type, without necessarily allocating memory or providing a function body. A definition actually allocates storage for a variable or provides the function's implementation. In C, `extern int x;` is a declaration, while `int x;` is a definition. This distinction matters most when code spans multiple files and needs to share variables or functions across them.
Visit the following resources to learn more:
- [@article@C - Variables](https://www.tutorialspoint.com/cprogramming/c_variables.htm)
- [@video@Declaration vs. Definition of a variable in C](https://www.youtube.com/watch?v=TtJw4VUYsiM)
- [@video@C variables 💰](https://www.youtube.com/watch?v=aIQk1O08zpg)
@@ -1,3 +1,8 @@
# Diagnostics & Limits
Diagnostic and limit headers, such as `<assert.h>` and `<limits.h>`, provide tools for catching bugs and understanding platform constraints. The `assert` macro checks that a condition holds true during development and aborts the program with a message if it does not, while `<limits.h>` defines constants like `INT_MAX` describing the range of values each integer type can hold on the current platform. These are used more during development and debugging than in a program's normal runtime logic.
Diagnostic and limit headers, such as `<assert.h>` and `<limits.h>`, provide tools for catching bugs and understanding platform constraints. The `assert` macro checks that a condition holds true during development and aborts the program with a message if it does not, while `<limits.h>` defines constants like `INT_MAX` describing the range of values each integer type can hold on the current platform. These are used more during development and debugging than in a program's normal runtime logic.
Visit the following resources to learn more:
- [@article@C Library - \<limits.h\>](https://www.tutorialspoint.com/c_standard_library/limits_h.htm)
- [@article@C Library - \<assert.h\>](https://www.tutorialspoint.com/c_standard_library/assert_h.htm)
@@ -1,3 +1,8 @@
# double
The `double` type stores double-precision floating-point numbers, offering roughly twice the precision of `float`, around 15 to 17 significant decimal digits, and typically occupying 8 bytes of memory. It is the default floating-point type used by C's standard library functions unless `float` is specified explicitly. `double` is generally preferred over `float` when precision matters more than memory savings.
The `double` type stores double-precision floating-point numbers, offering roughly twice the precision of `float`, around 15 to 17 significant decimal digits, and typically occupying 8 bytes of memory. It is the default floating-point type used by C's standard library functions unless `float` is specified explicitly. `double` is generally preferred over `float` when precision matters more than memory savings.
Visit the following resources to learn more:
- [@article@Double In C](https://www.upgrad.com/tutorials/software-engineering/c-tutorial/double-in-c/)
- [@video@Fundamental Data Types − Float, Double & Long Double](https://www.youtube.com/watch?v=vNeOx1rQ25E)
@@ -1,3 +1,9 @@
# Dynamic Arrays
A dynamic array is an array-like structure that can grow or shrink at runtime, typically implemented by allocating memory on the heap and reallocating a larger block, often using `realloc`, when it runs out of space. Unlike a fixed-size C array, it tracks both its current length and its allocated capacity separately. This pattern underlies dynamic array types like C++'s `std::vector` or Python's list, though C requires implementing it manually.
A dynamic array is an array-like structure that can grow or shrink at runtime, typically implemented by allocating memory on the heap and reallocating a larger block, often using `realloc`, when it runs out of space. Unlike a fixed-size C array, it tracks both its current length and its allocated capacity separately. This pattern underlies dynamic array types like C++'s `std::vector` or Python's list, though C requires implementing it manually.
Visit the following resources to learn more:
- [@article@Dynamic Arrays in C](https://www.bytesbeneath.com/p/dynamic-arrays-in-c?hide_intro_popup=true)
- [@article@Dynamic arrays in C: An implementation guide](https://medium.com/@sohaib.arshid101/dynamic-arrays-in-c-an-implementation-guide-4a959de94332)
- [@video@Dynamic Arrays in C](https://www.youtube.com/watch?v=_KSKH8C9Gf0)
@@ -1,3 +1,9 @@
# Dynamic Memory Allocation
Dynamic memory allocation reserves memory on the heap at runtime, when the amount of memory needed is not known in advance or needs to outlive the function that created it. C provides `malloc`, `calloc`, and `realloc` for allocation and `free` for releasing memory back to the system. Every successful allocation must eventually be paired with exactly one `free` call, and using memory after freeing it or freeing it twice both lead to undefined behavior.
Dynamic memory allocation reserves memory on the heap at runtime, when the amount of memory needed is not known in advance or needs to outlive the function that created it. C provides `malloc`, `calloc`, and `realloc` for allocation and `free` for releasing memory back to the system. Every successful allocation must eventually be paired with exactly one `free` call, and using memory after freeing it or freeing it twice both lead to undefined behavior.
Visit the following resources to learn more:
- [@article@C Memory Management](https://www.w3schools.com/c/c_memory_management.php)
- [@article@C Programming — Dynamic Memory Allocation](https://medium.com/@acamvproducingstudio/c-programming-dynamic-memory-allocation-86221e811379)
- [@video@Dynamic Memory Allocation | C Programming Tutorial](https://www.youtube.com/watch?v=R0qIYWo8igs)
@@ -1,3 +1,9 @@
# Enums
An `enum` defines a type consisting of a set of named integer constants, making code more readable than using raw numbers to represent a fixed set of options, such as days of the week or states in a state machine. By default, enum values start at 0 and increase by one for each subsequent name, though explicit values can be assigned. Enums are just integers under the hood, so C does not prevent assigning an out-of-range integer to an enum variable.
An `enum` defines a type consisting of a set of named integer constants, making code more readable than using raw numbers to represent a fixed set of options, such as days of the week or states in a state machine. By default, enum values start at 0 and increase by one for each subsequent name, though explicit values can be assigned. Enums are just integers under the hood, so C does not prevent assigning an out-of-range integer to an enum variable.
Visit the following resources to learn more:
- [@article@C Enumeration (enum)](https://www.w3schools.com/c/c_enums.php)
- [@article@Enumerations](https://en.cppreference.com/c/language/enum)
- [@video@Learn enums in 8 minutes! 📅](https://www.youtube.com/watch?v=sU0XQ3jSsu8)
@@ -1,3 +1,9 @@
# errno
`errno` is a global variable, declared in `<errno.h>`, that many standard library functions set to a specific error code when they fail. It is not automatically reset to zero on success, so it should only be checked immediately after a function call that is documented to set it, and typically after confirming the function actually failed. Functions like `perror` or `strerror` translate an `errno` value into a human-readable message.
`errno` is a global variable, declared in `<errno.h>`, that many standard library functions set to a specific error code when they fail. It is not automatically reset to zero on success, so it should only be checked immediately after a function call that is documented to set it, and typically after confirming the function actually failed. Functions like `perror` or `strerror` translate an `errno` value into a human-readable message.
Visit the following resources to learn more:
- [@article@Errno and Error Management in C](https://www.codequoi.com/en/errno-and-error-management-in-c/)
- [@article@A Guide to Error Handling in C](https://psychocod3r.wordpress.com/2019/04/02/a-guide-to-error-handling-in-c/)
- [@video@Handling Errors in C/Unix (perror, strerror, errno)](https://www.youtube.com/watch?v=IZiUT-ipnj0)
@@ -1,3 +1,9 @@
# Error Handling
C has no built-in exception mechanism like some other languages, so error handling relies on conventions such as checking return values, setting the global `errno` variable, and in some cases using program termination through exit codes. This puts more responsibility on the programmer to consistently check for and respond to failure conditions. Non-local jumps with `setjmp`/`longjmp` provide a limited alternative for handling certain error scenarios that need to unwind multiple function calls at once.
C has no built-in exception mechanism like some other languages, so error handling relies on conventions such as checking return values, setting the global `errno` variable, and in some cases using program termination through exit codes. This puts more responsibility on the programmer to consistently check for and respond to failure conditions. Non-local jumps with `setjmp`/`longjmp` provide a limited alternative for handling certain error scenarios that need to unwind multiple function calls at once.
Visit the following resources to learn more:
- [@article@C Error Handling](https://www.w3schools.com/c/c_error_handling.php)
- [@article@The different ways to handle errors in C](https://mccue.dev/pages/7-27-22-c-errors)
- [@video@Error Handling | C Programming Tutorial](https://www.youtube.com/watch?v=OOuZLI5ingc)
@@ -1,3 +1,9 @@
# Exit Codes
An exit code is a small integer that a program returns to the operating system when it finishes, indicating whether it succeeded or failed, and if it failed, sometimes why. By convention, an exit code of 0 means success and any nonzero value indicates an error, with `EXIT_SUCCESS` and `EXIT_FAILURE` from `<stdlib.h>` providing portable constants for these. Exit codes are commonly checked by shell scripts and other programs that call a C program and need to know whether it completed successfully.
An exit code is a small integer that a program returns to the operating system when it finishes, indicating whether it succeeded or failed, and if it failed, sometimes why. By convention, an exit code of 0 means success and any nonzero value indicates an error, with `EXIT_SUCCESS` and `EXIT_FAILURE` from `<stdlib.h>` providing portable constants for these. Exit codes are commonly checked by shell scripts and other programs that call a C program and need to know whether it completed successfully.
Visit the following resources to learn more:
- [@article@Exit Codes in Linux C Programming](https://medium.com/@linuxrootroom/exit-codes-in-linux-c-programming-14dd90c4b48d)
- [@article@exit](https://en.cppreference.com/c/program/exit)
- [@video@Getting exit status code in C](https://www.youtube.com/watch?v=DiNmwwQWl0g)
@@ -1,3 +1,7 @@
# Extended Types
Extended types cover additional numeric and specialized types beyond the basic set, such as `long long` for larger integer ranges, `long double` for extended floating-point precision, and complex number types added in later C standards. They exist to handle cases where the basic types are not large or precise enough. Availability and exact behavior of some extended types can vary between compilers and standards versions.
Extended types cover additional numeric and specialized types beyond the basic set, such as `long long` for larger integer ranges, `long double` for extended floating-point precision, and complex number types added in later C standards. They exist to handle cases where the basic types are not large or precise enough. Availability and exact behavior of some extended types can vary between compilers and standards versions.
Visit the following resources to learn more:
- [@article@C Extended Types](https://www.w3schools.com/c/c_data_types_extended.php)
@@ -1,3 +1,8 @@
# extern
The `extern` keyword declares that a variable or function is defined in another file, giving the compiler the information it needs to reference it without allocating storage again. It is typically placed in a header file so multiple source files can share the same global variable or function. Using `extern` correctly avoids duplicate-definition errors that occur when a variable is accidentally defined in more than one file.
The `extern` keyword declares that a variable or function is defined in another file, giving the compiler the information it needs to reference it without allocating storage again. It is typically placed in a header file so multiple source files can share the same global variable or function. Using `extern` correctly avoids duplicate-definition errors that occur when a variable is accidentally defined in more than one file.
Visit the following resources to learn more:
- [@article@What is the Extern Keyword in C?](https://www.scaler.com/topics/c-extern/)
- [@video@Understanding the Extern Keyword in C](https://www.youtube.com/watch?v=ySY_FlA7EvA)
@@ -1,3 +1,10 @@
# File I/O
File input/output in C is done through the standard library's stream-based functions, which let a program open, read from, write to, and close files. Streams abstract away the underlying operating system details of file access behind a consistent interface. File I/O also involves choosing between binary and text mode, which affects how certain characters, like line endings, are handled.
File input/output in C is done through the standard library's stream-based functions, which let a program open, read from, write to, and close files. Streams abstract away the underlying operating system details of file access behind a consistent interface. File I/O also involves choosing between binary and text mode, which affects how certain characters, like line endings, are handled.
Visit the following resources to learn more:
- [@article@C File Handling](https://www.programiz.com/c-programming/c-file-input-output)
- [@article@Exploring File I/O in C📁](https://dev.to/angelotheman/exploring-file-io-in-c-1j07)
- [@video@File Access Basics | C Programming Tutorial](https://www.youtube.com/watch?v=HQNsriyMhtY)
- [@video@Reading and Writing Files in C, two ways (fopen vs. open)](https://www.youtube.com/watch?v=BQJBe4IbsvQ)
@@ -1,3 +1,8 @@
# File Pointers
A file pointer, of type `FILE *`, is returned by `fopen` and represents an open file along with its current read/write position and buffering state. It is passed to subsequent I/O functions like `fread`, `fwrite`, and `fclose` to identify which open file they should operate on. Every successfully opened file pointer should eventually be closed with `fclose` to flush any buffered data and release the underlying resource.
A file pointer, of type `FILE *`, is returned by `fopen` and represents an open file along with its current read/write position and buffering state. It is passed to subsequent I/O functions like `fread`, `fwrite`, and `fclose` to identify which open file they should operate on. Every successfully opened file pointer should eventually be closed with `fclose` to flush any buffered data and release the underlying resource.
Visit the following resources to learn more:
- [@article@C Files](https://www.w3schools.com/c/c_files.php)
- [@video@File Access Basics | C Programming Tutorial](https://www.youtube.com/watch?v=HQNsriyMhtY)
@@ -1,3 +1,8 @@
# Fixed-width integers
Fixed-width integer types, defined in `<stdint.h>`, such as `int32_t` or `uint8_t`, guarantee an exact bit width regardless of platform, unlike `int` or `long` whose sizes can vary. This makes them useful for writing portable code, especially in networking, file formats, and embedded systems where exact sizes matter. Using them avoids subtle bugs that arise from assuming a type's size without checking it.
Fixed-width integer types, defined in `<stdint.h>`, such as `int32_t` or `uint8_t`, guarantee an exact bit width regardless of platform, unlike `int` or `long` whose sizes can vary. This makes them useful for writing portable code, especially in networking, file formats, and embedded systems where exact sizes matter. Using them avoids subtle bugs that arise from assuming a type's size without checking it.
Visit the following resources to learn more:
- [@article@C Fixed Width Integers](https://www.w3schools.com/c/c_fixed_width_ints.php)
- [@article@Fixed width integer types (since C99)](https://en.cppreference.com/c/types/integer)
@@ -1,3 +1,8 @@
# float
The `float` type stores single-precision floating-point numbers, meaning it can represent fractional values but with limited precision, typically around 6 to 7 significant decimal digits. It follows the IEEE 754 standard on most systems and takes up 4 bytes of memory. Because floating-point representation is inherently imprecise, comparing `float` values for exact equality is generally unreliable.
The `float` type stores single-precision floating-point numbers, meaning it can represent fractional values but with limited precision, typically around 6 to 7 significant decimal digits. It follows the IEEE 754 standard on most systems and takes up 4 bytes of memory. Because floating-point representation is inherently imprecise, comparing `float` values for exact equality is generally unreliable.
Visit the following resources to learn more:
- [@article@Float Data Type in C](https://data-flair.training/blogs/float-data-type-in-c/)
- [@video@Fundamental Data Types − Float, Double & Long Double](https://www.youtube.com/watch?v=vNeOx1rQ25E)
@@ -1,3 +1,10 @@
# for / while / do while loops
C offers three loop constructs: `for`, which bundles initialization, condition, and increment in one line and suits a known number of iterations; `while`, which checks its condition before each iteration and suits an unknown number of repetitions; and `do-while`, which checks its condition after each iteration, guaranteeing the loop body runs at least once. Choosing between them mostly comes down to whether the number of iterations is known ahead of time and whether the body must run at least once.
C offers three loop constructs: `for`, which bundles initialization, condition, and increment in one line and suits a known number of iterations; `while`, which checks its condition before each iteration and suits an unknown number of repetitions; and `do-while`, which checks its condition after each iteration, guaranteeing the loop body runs at least once. Choosing between them mostly comes down to whether the number of iterations is known ahead of time and whether the body must run at least once.
Visit the following resources to learn more:
- [@article@For Loop](https://www.tutorialspoint.com/cprogramming/c_for_loop.htm)
- [@article@While Loop](https://www.tutorialspoint.com/cprogramming/c_while_loop.htm)
- [@article@Do-While Loop](https://www.tutorialspoint.com/cprogramming/c_do_while_loop.htm)
- [@video@C for loops in 3 minutes! 🔁](https://www.youtube.com/watch?v=b4DPj0XAfSg)
@@ -0,0 +1,9 @@
# free
`free` is a standard library function used to deallocate a block of memory that was previously reserved on the heap. When you call this function, it releases the specified memory back to the system so that it can be used for other purposes in the program. Passing a pointer to the start of a previously allocated memory block to `free` effectively marks that space as available, though the pointer itself remains unchanged and should ideally be set to `NULL` immediately afterward to prevent accidental use of dangling references.
Visit the following resources to learn more:
- [@article@C Deallocate Memory](https://www.w3schools.com/c/c_memory_deallocate.php)
- [@article@C library - free() function](https://www.tutorialspoint.com/c_standard_library/c_function_free.htm)
- [@video@Releasing the Dynamically Allocated Memory using free()](https://www.youtube.com/watch?v=qG0wUzuBI_A)
@@ -1,3 +1,9 @@
# Function pointers & Callbacks
A function pointer stores the address of a function, allowing that function to be called indirectly, passed as an argument, or stored in a data structure, similar to how a regular pointer stores the address of a variable. Callbacks use this to let one function invoke another that is decided at runtime, a pattern used by standard library functions like `qsort`, which takes a comparison function as a callback. This mechanism underlies more advanced patterns in C, including simulating object-oriented dispatch through structs containing function pointers.
A function pointer stores the address of a function, allowing that function to be called indirectly, passed as an argument, or stored in a data structure, similar to how a regular pointer stores the address of a variable. Callbacks use this to let one function invoke another that is decided at runtime, a pattern used by standard library functions like `qsort`, which takes a comparison function as a callback. This mechanism underlies more advanced patterns in C, including simulating object-oriented dispatch through structs containing function pointers.
Visit the following resources to learn more:
- [@article@Function Pointers](https://www.w3schools.com/c/c_functions_pointers.php)
- [@article@Making Function Pointers Usable In C](https://vandervoord.net/blog/2015/6/2/making-function-pointers-usable-in-c)
- [@video@Function Pointers in C](https://www.youtube.com/watch?v=BRsv3ZXoHto)
@@ -1,3 +1,10 @@
# Functions
A function in C is a named, reusable block of code that takes inputs (parameters), performs some computation, and optionally returns a value. Functions must be declared, either with a prototype or a full definition, before they are used, so the compiler knows their expected parameter and return types. Breaking a program into functions makes code easier to read, test, and reuse.
A function in C is a named, reusable block of code that takes inputs (parameters), performs some computation, and optionally returns a value. Functions must be declared, either with a prototype or a full definition, before they are used, so the compiler knows their expected parameter and return types. Breaking a program into functions makes code easier to read, test, and reuse.
Visit the following resources to learn more:
- [@article@Functions in C](https://www.tutorialspoint.com/cprogramming/c_functions.htm)
- [@article@C Functions](https://www.w3schools.com/c/c_functions.php)
- [@video@C functions 📞](https://www.youtube.com/watch?v=ou_G7_zodR4)
- [@video@Function Basics | C Programming Tutorial](https://www.youtube.com/watch?v=NGQoKF2Ggt8)
@@ -1,3 +1,10 @@
# GCC / Clang
GCC (GNU Compiler Collection) and Clang are two widely used, open-source C compilers, each supporting multiple platforms and largely compatible command-line interfaces. GCC has a longer history and broader platform support, while Clang is known for faster compilation, more readable error messages, and being built on the LLVM compiler infrastructure. Both support similar optimization flags and standard compliance modes, making it common for projects to test against both.
GCC (GNU Compiler Collection) and Clang are two widely used, open-source C compilers, each supporting multiple platforms and largely compatible command-line interfaces. GCC has a longer history and broader platform support, while Clang is known for faster compilation, more readable error messages, and being built on the LLVM compiler infrastructure. Both support similar optimization flags and standard compliance modes, making it common for projects to test against both.
Visit the following resources to learn more:
- [@article@A programmer's guide to GNU C Compiler](https://opensource.com/article/22/5/gnu-c-compiler)
- [@article@GNU Compiler Collection](https://en.wikipedia.org/wiki/GNU_Compiler_Collection)
- [@article@Getting Started with Clang](https://clang.llvm.org/get_started.html)
- [@video@LLVM in 100 Seconds](https://www.youtube.com/watch?v=BT2Cv-Tjq7Q)
@@ -1,3 +1,9 @@
# GDB
GDB (GNU Debugger) is a command-line debugger that lets a programmer run a C program under its control, set breakpoints to pause execution at specific lines, inspect and modify variable values, and step through code one line or instruction at a time. It works with binaries compiled with debugging information, typically added using the `-g` compiler flag. GDB is the standard debugger on most Linux systems and supports many other languages beyond C.
GDB (GNU Debugger) is a command-line debugger that lets a programmer run a C program under its control, set breakpoints to pause execution at specific lines, inspect and modify variable values, and step through code one line or instruction at a time. It works with binaries compiled with debugging information, typically added using the `-g` compiler flag. GDB is the standard debugger on most Linux systems and supports many other languages beyond C.
Visit the following resources to learn more:
- [@official@GDB Docs](https://www.sourceware.org/gdb/)
- [@article@Debugging C code With GDB](https://medium.com/havingfun/debugging-c-code-with-gdb-90adb2f3da96)
- [@video@GDB is REALLY easy! Find Bugs in Your Code with Only A Few Commands](https://www.youtube.com/watch?v=Dq8l1_-QgAc)
@@ -1,3 +1,9 @@
# GNU Make
GNU Make is a build automation tool that reads a file called a Makefile, containing rules that specify how to build targets from their dependencies, and only rebuilds the parts of a project that have actually changed. It is one of the oldest and most widely available build tools on Unix-like systems. Writing Makefiles by hand for larger projects can become complex, which is part of why higher-level tools like CMake are often used to generate them instead.
GNU Make is a build automation tool that reads a file called a Makefile, containing rules that specify how to build targets from their dependencies, and only rebuilds the parts of a project that have actually changed. It is one of the oldest and most widely available build tools on Unix-like systems. Writing Makefiles by hand for larger projects can become complex, which is part of why higher-level tools like CMake are often used to generate them instead.
Visit the following resources to learn more:
- [@official@GNU Make](https://ftp.gnu.org/old-gnu/Manuals/make-3.80/html_node/make.html)
- [@article@A Simple Makefile Tutorial](https://www.cs.colby.edu/maxwell/courses/tutorials/maketutor/)
- [@video@What is GNU Make?](https://www.youtube.com/watch?v=mQupK2oTPF4)
@@ -1,3 +1,8 @@
# Hash Maps
A hash map stores key-value pairs and uses a hash function to convert each key into an index into an underlying array, allowing average constant-time lookup, insertion, and deletion. Since C has no built-in hash map, implementing one involves writing a hash function, handling collisions when two keys hash to the same index, and managing the underlying array's resizing. Common collision-handling strategies include chaining, where colliding entries form a linked list, and open addressing, where the map probes for the next free slot.
A hash map stores key-value pairs and uses a hash function to convert each key into an index into an underlying array, allowing average constant-time lookup, insertion, and deletion. Since C has no built-in hash map, implementing one involves writing a hash function, handling collisions when two keys hash to the same index, and managing the underlying array's resizing. Common collision-handling strategies include chaining, where colliding entries form a linked list, and open addressing, where the map probes for the next free slot.
Visit the following resources to learn more:
- [@article@How to implement a hash table (in C)](https://benhoyt.com/writings/hash-table-in-c/)
- [@video@Understanding and implementing a Hash Table (in C)](https://www.youtube.com/watch?v=2Ti5yvumFTU)
@@ -1,3 +1,9 @@
# Header Files
Header files, with a `.h` extension, contain declarations, such as function prototypes, struct definitions, and macros, that are shared across multiple source files using `#include`. They let multiple `.c` files agree on the same interface without duplicating code. Header guards, or `#pragma once`, prevent the same header from being included multiple times in one compilation, which would otherwise cause duplicate-definition errors.
Header files, with a `.h` extension, contain declarations, such as function prototypes, struct definitions, and macros, that are shared across multiple source files using `#include`. They let multiple `.c` files agree on the same interface without duplicating code. Header guards, or `#pragma once`, prevent the same header from being included multiple times in one compilation, which would otherwise cause duplicate-definition errors.
Visit the following resources to learn more:
- [@article@Header Files in C](https://www.tutorialspoint.com/cprogramming/c_header_files.htm)
- [@article@C Organize Code](https://www.w3schools.com/c/c_organize_code.php)
- [@video@why do header files even exist?](https://www.youtube.com/watch?v=tOQZlD-0Scc)
@@ -1,3 +1,8 @@
# Idioms & Design Patterns
Idioms and design patterns in C are established techniques for achieving goals, like encapsulation or polymorphism, that the language does not support directly through built-in syntax the way object-oriented languages do. These patterns typically combine structs, function pointers, and careful use of pointers and headers to simulate features from higher-level languages. Recognizing them helps when reading existing C codebases, since many rely on these conventions rather than documenting the intent explicitly.
Idioms and design patterns in C are established techniques for achieving goals, like encapsulation or polymorphism, that the language does not support directly through built-in syntax the way object-oriented languages do. These patterns typically combine structs, function pointers, and careful use of pointers and headers to simulate features from higher-level languages. Recognizing them helps when reading existing C codebases, since many rely on these conventions rather than documenting the intent explicitly.
Visit the following resources to learn more:
- [@article@Idioms for C programmers](https://www.cs.tufts.edu/comp/40-2011f/idioms.html)
- [@video@Tips for C Programming](https://www.youtube.com/watch?v=9UIIMBqq1D4)
@@ -1,3 +1,10 @@
# if else / switch
The `if`/`else` statement branches execution based on whether a condition evaluates to true or false, and can be chained with `else if` for multiple conditions. The `switch` statement compares a single value against several possible cases and is often clearer than a long `if`/`else if` chain when checking one variable against many fixed values. Forgetting a `break` at the end of a `switch` case causes execution to fall through into the next case, which is a common source of bugs.
The `if`/`else` statement branches execution based on whether a condition evaluates to true or false, and can be chained with `else if` for multiple conditions. The `switch` statement compares a single value against several possible cases and is often clearer than a long `if`/`else if` chain when checking one variable against many fixed values. Forgetting a `break` at the end of a `switch` case causes execution to fall through into the next case, which is a common source of bugs.
Visit the following resources to learn more:
- [@article@If Statement](https://www.tutorialspoint.com/cprogramming/if_statement_in_c.htm)
- [@article@Switch Statement in C](https://www.tutorialspoint.com/cprogramming/switch_statement_in_c.htm)
- [@video@Conditionals (if-else, Nested if and else if)](https://www.youtube.com/watch?v=Led5aHdLoT4&list=PLBlnK6fEyqRgZq4a-SMViZr-V8jlvCioJ&index=1)
- [@video@Conditionals (Switch)](https://www.youtube.com/watch?v=-JMSaLRqsgo&list=PLBlnK6fEyqRgZq4a-SMViZr-V8jlvCioJ&index=2)
@@ -1,3 +1,7 @@
# Initialization
Initialization is giving a variable its first value at the point it is created, as in `int count = 0;`. Uninitialized local variables in C hold indeterminate values, whatever bits happened to be in that memory location before, so reading one before assigning it produces undefined behavior. Global and static variables are automatically initialized to zero if no explicit value is given, but local variables are not.
Initialization is giving a variable its first value at the point it is created, as in `int count = 0;`. Uninitialized local variables in C hold indeterminate values, whatever bits happened to be in that memory location before, so reading one before assigning it produces undefined behavior. Global and static variables are automatically initialized to zero if no explicit value is given, but local variables are not.
Visit the following resources to learn more:
- [@article@C - Variables](https://www.tutorialspoint.com/cprogramming/c_variables.htm)
@@ -1,3 +1,8 @@
# Input / Output
The standard library's I/O functions, declared mainly in `<stdio.h>`, handle reading from and writing to streams, including the console and files. Common functions include `printf` and `scanf` for formatted console I/O, and `fopen`, `fread`, and `fwrite` for file access. These functions form the primary way a C program interacts with the outside world during execution.
The standard library's I/O functions, declared mainly in `<stdio.h>`, handle reading from and writing to streams, including the console and files. Common functions include `printf` and `scanf` for formatted console I/O, and `fopen`, `fread`, and `fwrite` for file access. These functions form the primary way a C program interacts with the outside world during execution.
Visit the following resources to learn more:
- [@article@File input/output](https://cppreference.com/c/io)
- [@video@File Access Basics | C Programming Tutorial](https://www.youtube.com/watch?v=HQNsriyMhtY)
@@ -1,3 +1,8 @@
# Installing C
Installing C means installing a compiler such as GCC or Clang, since C itself is just a language specification with no official installer. On Linux, package managers like apt or dnf usually provide GCC directly. On macOS, Xcode Command Line Tools include Clang, and on Windows, options include MinGW, WSL, or MSVC. Once installed, running the compiler on a small test file confirms the setup works.
Installing C means installing a compiler such as GCC or Clang, since C itself is just a language specification with no official installer. On Linux, package managers like apt or dnf usually provide GCC directly. On macOS, Xcode Command Line Tools include Clang, and on Windows, options include MinGW, WSL, or MSVC. Once installed, running the compiler on a small test file confirms the setup works.
Visit the following resources to learn more:
- [@article@C - Environment Setup](https://www.tutorialspoint.com/cprogramming/c_environment_setup.htm)
- [@video@ES Skip navigation installing c Create Avatar image How to Set up Visual Studio Code for C and C++ Programming](https://www.youtube.com/watch?v=1PBD5qFWdq8)
@@ -1,3 +1,8 @@
# integers
Integer types in C, such as `int`, `short`, and `long`, store whole numbers without a fractional part. Their exact size in bytes is not fixed by the language and can vary between platforms, though `int` is commonly 4 bytes on modern systems. Integers can be signed, allowing negative values, or unsigned, doubling the positive range but disallowing negatives, and choosing the wrong one is a frequent source of bugs.
Integer types in C, such as `int`, `short`, and `long`, store whole numbers without a fractional part. Their exact size in bytes is not fixed by the language and can vary between platforms, though `int` is commonly 4 bytes on modern systems. Integers can be signed, allowing negative values, or unsigned, doubling the positive range but disallowing negatives, and choosing the wrong one is a frequent source of bugs.
Visit the following resources to learn more:
- [@article@Integer types](https://www.cs.yale.edu/homes/aspnes/pinewiki/C(2f)IntegerTypes.html)
- [@video@Fundamental Data Types − Integer (Part 1)](https://www.youtube.com/watch?v=_9bAlgRzlkc)
@@ -1,3 +1,10 @@
# Introduction
C is a general-purpose programming language created in the early 1970s at Bell Labs by Dennis Ritchie. It gives direct access to memory and hardware while staying close to the machine, which makes it fast and predictable but also demands more care from the programmer. Operating systems, embedded firmware, compilers, and many other languages' runtimes are built with it. Learning C teaches how computers actually manage memory and execute instructions, knowledge that carries over to almost every other language.
C is a general-purpose programming language created in the early 1970s at Bell Labs by Dennis Ritchie. It gives direct access to memory and hardware while staying close to the machine, which makes it fast and predictable but also demands more care from the programmer. Operating systems, embedded firmware, compilers, and many other languages' runtimes are built with it. Learning C teaches how computers actually manage memory and execute instructions, knowledge that carries over to almost every other language.
Visit the following resources to learn more:
- [@course@Learn C](https://www.learn-c.org/)
- [@book@The C Programming Language - 2nd Edition](https://seriouscomputerist.atariverse.com/media/pdf/book/C%20Programming%20Language%20-%202nd%20Edition%20(OCR).pdf)
- [@video@C Programming and Memory Management - Full Course](https://www.youtube.com/watch?v=rJrd2QMVbGM)
- [@article@C Programming Full Course for free ⚙️](https://www.youtube.com/watch?v=xND0t1pr3KY)
@@ -1,3 +1,3 @@
# Intrusive Data Structures
An intrusive data structure embeds the structural elements needed for a container, such as the next-pointer for a linked list, directly inside the data type being stored, rather than wrapping the data in a separate container node. This avoids extra memory allocation for container-specific nodes and lets the same piece of data belong to multiple intrusive structures simultaneously. The Linux kernel makes heavy use of this pattern for its internal linked lists.
@@ -1,3 +1,9 @@
# IPC
Inter-process communication (IPC) covers mechanisms that let separate, independent processes exchange data, since processes do not share memory the way threads within one process do. Common IPC mechanisms include pipes for streaming data between related processes, shared memory segments for faster but more manually managed data sharing, and message queues or sockets for more structured or networked communication. Choosing an IPC mechanism depends on factors like whether the processes are on the same machine and how much data needs to move between them.
Inter-process communication (IPC) covers mechanisms that let separate, independent processes exchange data, since processes do not share memory the way threads within one process do. Common IPC mechanisms include pipes for streaming data between related processes, shared memory segments for faster but more manually managed data sharing, and message queues or sockets for more structured or networked communication. Choosing an IPC mechanism depends on factors like whether the processes are on the same machine and how much data needs to move between them.
Visit the following resources to learn more:
- [@article@Inter Process communication](https://kuleuven-diepenbeek.github.io/osc-course/ch6-tasks/interprocess/)
- [@article@IPC: Inter-process communication in C programming](http://medium.com/@CesarPrz/ipc-inter-process-communication-in-c-programming-1d9069edc27f)
- [@video@Interprocess Communication](https://www.youtube.com/watch?v=dJuYKfR8vec)
@@ -1,3 +1,7 @@
# Lifetime of Objects
The lifetime of an object is the period during program execution when its memory is guaranteed to hold valid data. Local variables on the stack typically live only until the enclosing block exits, static and global variables live for the entire program, and heap-allocated memory lives until it is explicitly freed. Accessing an object outside its lifetime, such as reading a stack variable after its function has returned, produces undefined behavior.
The lifetime of an object is the period during program execution when its memory is guaranteed to hold valid data. Local variables on the stack typically live only until the enclosing block exits, static and global variables live for the entire program, and heap-allocated memory lives until it is explicitly freed. Accessing an object outside its lifetime, such as reading a stack variable after its function has returned, produces undefined behavior.
Visit the following resources to learn more:
- [@article@Lifetime](https://en.cppreference.com/c/language/lifetime#:~:text=Every%20object%20in%20C%20exists,known%20as%20this%20object's%20lifetime.)
@@ -1,3 +1,8 @@
# Linkage
Linkage determines whether a name, like a variable or function, refers to the same entity when it appears in multiple files. External linkage means the name is visible and shared across files, internal linkage restricts it to the file it is defined in, and no linkage applies to names like local variables that exist only within a block. Linkage is controlled with the `static` and `extern` keywords at file scope.
Linkage determines whether a name, like a variable or function, refers to the same entity when it appears in multiple files. External linkage means the name is visible and shared across files, internal linkage restricts it to the file it is defined in, and no linkage applies to names like local variables that exist only within a block. Linkage is controlled with the `static` and `extern` keywords at file scope.
Visit the following resources to learn more:
- [@article@Linkage in C and C++](https://www.embedded.com/linkage-in-c-and-c/)
- [@video@Storage Duration and Linkage in C and C++ - Dan Saks](https://www.youtube.com/watch?v=0kgTuWkyorc)
@@ -1,3 +1,8 @@
# Linked Lists
A linked list stores a sequence of elements as separate nodes, where each node contains a value and a pointer to the next node, rather than storing elements contiguously like an array. This makes inserting or removing elements in the middle of the list efficient, since it only requires updating a few pointers, but accessing an arbitrary element requires walking the list from the start. Variants include singly linked lists, doubly linked lists with pointers in both directions, and circular linked lists.
A linked list stores a sequence of elements as separate nodes, where each node contains a value and a pointer to the next node, rather than storing elements contiguously like an array. This makes inserting or removing elements in the middle of the list efficient, since it only requires updating a few pointers, but accessing an arbitrary element requires walking the list from the start. Variants include singly linked lists, doubly linked lists with pointers in both directions, and circular linked lists.
Visit the following resources to learn more:
- [@article@Linked lists](https://www.learn-c.org/en/Linked_lists)
- [@video@Understanding and implementing a Linked List in C and Java](https://www.youtube.com/watch?v=VOpjAHCee7c)
@@ -1,3 +1,9 @@
# Linking
Linking is the stage after compilation that combines multiple object files and libraries into a single executable, resolving references between them, such as a function called in one file but defined in another. A linker error occurs when a referenced symbol cannot be found anywhere among the provided object files and libraries. Linking can happen statically, embedding library code directly into the executable, or dynamically, where the executable references a shared library loaded at runtime.
Linking is the stage after compilation that combines multiple object files and libraries into a single executable, resolving references between them, such as a function called in one file but defined in another. A linker error occurs when a referenced symbol cannot be found anywhere among the provided object files and libraries. Linking can happen statically, embedding library code directly into the executable, or dynamically, where the executable references a shared library loaded at runtime.
Visit the following resources to learn more:
- [@article@The Four Stages of Compiling a C Program](https://www.calleluks.com/the-four-stages-of-compiling-a-c-program/)
- [@article@Compiling and Linking](https://www.cprogramming.com/compilingandlinking.html)
- [@video@Compiling, assembling, and linking](https://www.youtube.com/watch?v=N2y6csonII4)
@@ -1,3 +1,9 @@
# LLDB
LLDB is a debugger built as part of the LLVM project, offering similar functionality to GDB, including breakpoints, stepping through code, and inspecting variables, with a largely compatible but distinct command syntax. It is the default debugger bundled with Xcode on macOS and integrates closely with Clang-compiled binaries. Many IDEs use LLDB under the hood on Apple platforms.
LLDB is a debugger built as part of the LLVM project, offering similar functionality to GDB, including breakpoints, stepping through code, and inspecting variables, with a largely compatible but distinct command syntax. It is the default debugger bundled with Xcode on macOS and integrates closely with Clang-compiled binaries. Many IDEs use LLDB under the hood on Apple platforms.
Visit the following resources to learn more:
- [@official@LLDB Tutorial](https://lldb.llvm.org/use/tutorial.html)
- [@article@The LLDB debugger](https://docs.redhat.com/en/documentation/red_hat_developer_tools/1/html/using_llvm_13.0.1_toolset/assembly_the-lldb-debugger)
- [@video@Debugging C/C++ with LLDB Tutorial](https://www.youtube.com/watch?v=2GV0K9Y2MKA)
@@ -1,3 +1,7 @@
# Logical
Logical operators, `&&` (AND), `||` (OR), and `!` (NOT), combine or invert boolean conditions and are typically used in control flow statements. C uses short-circuit evaluation, meaning `&&` stops evaluating as soon as one operand is false, and `||` stops as soon as one operand is true. This behavior is often relied on deliberately, for example checking a pointer is not null before dereferencing it in the same condition.
Logical operators, `&&` (AND), `||` (OR), and `!` (NOT), combine or invert boolean conditions and are typically used in control flow statements. C uses short-circuit evaluation, meaning `&&` stops evaluating as soon as one operand is false, and `||` stops as soon as one operand is true. This behavior is often relied on deliberately, for example checking a pointer is not null before dereferencing it in the same condition.
Visit the following resources to learn more:
- [@article@Logical Operators in C](https://www.tutorialspoint.com/cprogramming/c_logical_operators.htm)
@@ -1,3 +1,9 @@
# Macros
A macro, defined with `#define`, is a preprocessor directive that gives a name to a piece of code, which is then substituted wherever that name appears before compilation. Macros can be simple constants, like `#define PI 3.14159`, or function-like, taking parameters and expanding into a code pattern. Because macro expansion is purely textual, careless macros without proper parentheses around their parameters can produce surprising results when combined with other operators.
A macro, defined with `#define`, is a preprocessor directive that gives a name to a piece of code, which is then substituted wherever that name appears before compilation. Macros can be simple constants, like `#define PI 3.14159`, or function-like, taking parameters and expanding into a code pattern. Because macro expansion is purely textual, careless macros without proper parentheses around their parameters can produce surprising results when combined with other operators.
Visit the following resources to learn more:
- [@article@What are Macros in C? Types, Examples and Benefits](https://www.almabetter.com/bytes/articles/macros-in-c)
- [@article@C/Macros](https://www.cs.yale.edu/homes/aspnes/pinewiki/C(2f)Macros.html)
- [@video@How to Write Function-Like Preprocessor Macros (C example)](https://www.youtube.com/watch?v=w3iXBUbq4NY)
@@ -0,0 +1,8 @@
# main Function
The `main` function serves as the designated entry point where the execution of every C program begins. When a program is run, the operating system calls this specific function to start the sequence of instructions defined within the code. It typically returns an integer value to the operating system upon completion, where a return value of zero indicates that the program finished successfully.
Visit the following resources to learn more:
- [@article@C main Function](https://www.tutorialspoint.com/cprogramming/c_main_function.htm)
- [@video@Details about the main function](https://www.youtube.com/watch?v=2dsSGnmbXNM)
@@ -0,0 +1,9 @@
# malloc
`malloc` is a function used to reserve a specific amount of memory during the execution of a program. When called, it allocates a block of memory of a requested size in bytes on the heap and returns a pointer to the first byte of that block. If the system cannot provide the requested memory, the function returns a null pointer to indicate that the allocation failed.
Visit the following resources to learn more:
- [@article@C Allocate Memory](https://www.w3schools.com/c/c_memory_allocate.php)
- [@article@C library - malloc() function](https://www.tutorialspoint.com/c_standard_library/c_function_malloc.htm)
- [@video@Malloc in C is easy! 🏢](https://www.youtube.com/watch?v=n_Se6bt8jM0)
@@ -1,3 +1,8 @@
# Math & Time
Math functions, from `<math.h>`, provide operations like square roots, trigonometric functions, and logarithms that go beyond the basic arithmetic operators. Time functions, from `<time.h>`, handle getting the current time, measuring elapsed time, and formatting dates. Together they cover the numerical and temporal needs that come up in many kinds of programs, from scientific calculations to logging timestamps.
Math functions, from `<math.h>`, provide operations like square roots, trigonometric functions, and logarithms that go beyond the basic arithmetic operators. Time functions, from `<time.h>`, handle getting the current time, measuring elapsed time, and formatting dates. Together they cover the numerical and temporal needs that come up in many kinds of programs, from scientific calculations to logging timestamps.
Visit the following resources to learn more:
- [@article@C math (math.h) Library](https://www.w3schools.com/c/c_ref_math.php)
- [@article@C Library - \<math.h\>](https://www.tutorialspoint.com/c_standard_library/math_h.htm)
@@ -1,3 +1,9 @@
# Memory Leakage
A memory leak happens when dynamically allocated memory is no longer needed but is never freed, so it stays reserved and unavailable for the rest of the program's execution. Leaks accumulate over time, especially in long-running programs, and can eventually exhaust available memory. Tools like Valgrind can detect leaks by tracking allocations that are never matched with a corresponding `free`.
A memory leak happens when dynamically allocated memory is no longer needed but is never freed, so it stays reserved and unavailable for the rest of the program's execution. Leaks accumulate over time, especially in long-running programs, and can eventually exhaust available memory. Tools like Valgrind can detect leaks by tracking allocations that are never matched with a corresponding `free`.
Visit the following resources to learn more:
- [@article@Finding a Memory Leak in C or C++](https://www.parasoft.com/blog/finding-memory-leaks-in-c-or-c/)
- [@article@How To Find And Fix Memory Leaks in C or C++](https://www.netdata.cloud/academy/how-to-find-memory-leak-in-c/)
- [@video@Memory Leaks And How To Prevent Them](https://www.youtube.com/watch?v=lQCLAKfcYI4)
@@ -1,3 +1,9 @@
# Memory Model
C's memory model describes how a running program's memory is organized into distinct regions: the stack for local variables and function call information, the heap for dynamically allocated memory, and separate segments for global/static variables and the compiled program code itself. Understanding this layout helps explain why some memory is automatically reclaimed and other memory must be freed manually. It also clarifies why certain bugs, like stack overflows or heap corruption, occur in specific regions.
C's memory model describes how a running program's memory is organized into distinct regions: the stack for local variables and function call information, the heap for dynamically allocated memory, and separate segments for global/static variables and the compiled program code itself. Understanding this layout helps explain why some memory is automatically reclaimed and other memory must be freed manually. It also clarifies why certain bugs, like stack overflows or heap corruption, occur in specific regions.
Visit the following resources to learn more:
- [@article@Memory model](https://en.cppreference.com/c/language/memory_model#:~:text=Defines%20the%20semantics%20of%20computer,memory%20has%20a%20unique%20address.)
- [@article@The C Memory Model](https://www.cs.toronto.edu/~strider//docs/ICS_Chapter_2.pdf)
- [@video@C Programming and Memory Management - Full Course](https://www.youtube.com/watch?v=rJrd2QMVbGM)
@@ -1,3 +1,9 @@
# Meson
Meson is a build system that emphasizes speed and a simple, readable configuration language, generating backend build files for tools like Ninja rather than compiling directly itself. It aims to make common build tasks straightforward with sensible defaults, reducing the boilerplate often needed with tools like CMake. It has gained adoption in several open-source C projects seeking a more modern build configuration experience.
Meson is a build system that emphasizes speed and a simple, readable configuration language, generating backend build files for tools like Ninja rather than compiling directly itself. It aims to make common build tasks straightforward with sensible defaults, reducing the boilerplate often needed with tools like CMake. It has gained adoption in several open-source C projects seeking a more modern build configuration experience.
Visit the following resources to learn more:
- [@official@Meson Tutorial](https://mesonbuild.com/Tutorial.html)
- [@article@Introduction to meson build system](https://twdev.blog/2022/09/meson/)
- [@video@What is Meson (and Ninja)? \[Build system for C/C++, Rust, and Java\]](https://www.youtube.com/watch?v=A3Pq3E1S8ss)
@@ -1,3 +1,9 @@
# Mutexes
A mutex (mutual exclusion lock) is a synchronization primitive that ensures only one thread can access a shared resource, like a variable or data structure, at a time, preventing race conditions. A thread acquires (locks) the mutex before accessing the shared resource and releases (unlocks) it afterward, and any other thread attempting to lock it in the meantime must wait. Forgetting to unlock a mutex, or locking the same mutex twice from the same thread without releasing it first, can cause a program to deadlock, freezing indefinitely.
A mutex (mutual exclusion lock) is a synchronization primitive that ensures only one thread can access a shared resource, like a variable or data structure, at a time, preventing race conditions. A thread acquires (locks) the mutex before accessing the shared resource and releases (unlocks) it afterward, and any other thread attempting to lock it in the meantime must wait. Forgetting to unlock a mutex, or locking the same mutex twice from the same thread without releasing it first, can cause a program to deadlock, freezing indefinitely.
Visit the following resources to learn more:
- [@article@Threads, Mutexes and Concurrent Programming in C](https://www.codequoi.com/en/threads-mutexes-and-concurrent-programming-in-c/)
- [@article@Using mutexes](https://www.ibm.com/docs/en/aix/7.1.0?topic=programming-using-mutexes)
- [@video@Mutex Introduction (pthreads) | C Programming Tutorial](https://www.youtube.com/watch?v=raLCgPK-Igc)
@@ -1,3 +1,9 @@
# Ninja
Ninja is a build system designed to run builds as fast as possible, focusing on quick incremental rebuilds rather than being written directly by hand. Its input files are typically generated by a higher-level tool like CMake rather than authored manually, since Ninja's own file format is intentionally minimal and low-level. It is often chosen as a faster backend for projects that already use CMake to generate their build files.
Ninja is a build system designed to run builds as fast as possible, focusing on quick incremental rebuilds rather than being written directly by hand. Its input files are typically generated by a higher-level tool like CMake rather than authored manually, since Ninja's own file format is intentionally minimal and low-level. It is often chosen as a faster backend for projects that already use CMake to generate their build files.
Visit the following resources to learn more:
- [@official@Ninja](https://ninja-build.org/)
- [@opensource@ninja](https://github.com/ninja-build/ninja)
- [@video@I tried Ninja Build Tool and it changed me...](https://www.youtube.com/watch?v=Z8znH5Grz7I)
@@ -1,3 +1,8 @@
# Null Pointers
A null pointer is a pointer that intentionally points to no valid memory location, conventionally written as `NULL` in C. It is used to indicate that a pointer does not currently reference anything, such as before allocation or after freeing memory. Dereferencing a null pointer is undefined behavior and typically causes a program crash, so checking for `NULL` before use is a common defensive practice.
A null pointer is a pointer that intentionally points to no valid memory location, conventionally written as `NULL` in C. It is used to indicate that a pointer does not currently reference anything, such as before allocation or after freeing memory. Dereferencing a null pointer is undefined behavior and typically causes a program crash, so checking for `NULL` before use is a common defensive practice.
Visit the following resources to learn more:
- [@article@Null pointers in C](https://www.tutorialspoint.com/cprogramming/c_null_pointer.htm)
- [@video@Understanding the Null Pointers](https://www.youtube.com/watch?v=oPScHNQDCkc)
@@ -1,3 +1,9 @@
# Object-Oriented C
Object-oriented programming techniques can be approximated in C, despite the language having no built-in classes, by combining structs to hold data with function pointers to simulate methods, often organized as a table of function pointers resembling a virtual method table. Encapsulation is typically achieved through opaque pointers, hiding a struct's internal fields from code outside the module that defines it. This style requires more manual discipline than a language with native object-oriented support, but is common in larger C codebases and libraries.
Object-oriented programming techniques can be approximated in C, despite the language having no built-in classes, by combining structs to hold data with function pointers to simulate methods, often organized as a table of function pointers resembling a virtual method table. Encapsulation is typically achieved through opaque pointers, hiding a struct's internal fields from code outside the module that defines it. This style requires more manual discipline than a language with native object-oriented support, but is common in larger C codebases and libraries.
Visit the following resources to learn more:
- [@article@Object-Oriented C: A Primer](https://aartaka.me/oop-c.html)
- [@article@Object-Oriented Programming (OOP) in C](https://www.codementor.io/@michaelsafyan/object-oriented-programming-in-c-du1081gw2)
- [@video@OOP in Pure C](https://www.youtube.com/watch?v=6Riy9hVIFDE)
@@ -1,3 +1,9 @@
# Opaque Pointers
An opaque pointer is a pointer to a struct whose full definition is hidden from the code using it, typically by only declaring the struct's existence in a header file without listing its members. This lets a library expose functions that operate on the type while keeping its internal fields inaccessible and free to change, achieving a form of encapsulation similar to private members in object-oriented languages. Code using an opaque pointer can only interact with the underlying data through the functions the library provides.
An opaque pointer is a pointer to a struct whose full definition is hidden from the code using it, typically by only declaring the struct's existence in a header file without listing its members. This lets a library expose functions that operate on the type while keeping its internal fields inaccessible and free to change, achieving a form of encapsulation similar to private members in object-oriented languages. Code using an opaque pointer can only interact with the underlying data through the functions the library provides.
Visit the following resources to learn more:
- [@article@Practical Design Patterns: Opaque Pointers and Objects in C](https://interrupt.memfault.com/blog/opaque-pointers)
- [@article@Opaque Data Pointers](https://blog.aaronballman.com/2011/07/opaque-data-pointers/)
- [@video@Make your Data Type more Abstract with Opaque Types in C](https://www.youtube.com/watch?v=TsUOhPsZk6k)
@@ -1,3 +1,8 @@
# Operators
Operators in C are symbols that perform operations on values and variables, such as addition, comparison, or bitwise manipulation. They are grouped into categories including arithmetic, comparison, logical, bitwise, and ternary operators. Each category has its own precedence and associativity rules that determine how expressions with multiple operators are evaluated.
Operators in C are symbols that perform operations on values and variables, such as addition, comparison, or bitwise manipulation. They are grouped into categories including arithmetic, comparison, logical, bitwise, and ternary operators. Each category has its own precedence and associativity rules that determine how expressions with multiple operators are evaluated.
Visit the following resources to learn more:
- [@article@C Operators](https://www.tutorialspoint.com/cprogramming/c_operators.htm)
- [@video@C Operators - C Programming for Beginners](https://www.youtube.com/watch?v=_57FcSBtJNU)
@@ -1,3 +1,9 @@
# Optimization Levels
Optimization levels, set with compiler flags like `-O0` through `-O3` in GCC and Clang, control how aggressively the compiler transforms code to improve performance, often at the cost of longer compile times and less predictable debugging behavior. `-O0` disables optimization entirely, which is useful during development since the compiled code closely matches the source. Higher levels can reorder, inline, or eliminate code in ways that make step-by-step debugging harder to follow, and can also expose undefined behavior that seemed to work correctly at lower optimization levels.
Optimization levels, set with compiler flags like `-O0` through `-O3` in GCC and Clang, control how aggressively the compiler transforms code to improve performance, often at the cost of longer compile times and less predictable debugging behavior. `-O0` disables optimization entirely, which is useful during development since the compiled code closely matches the source. Higher levels can reorder, inline, or eliminate code in ways that make step-by-step debugging harder to follow, and can also expose undefined behavior that seemed to work correctly at lower optimization levels.
Visit the following resources to learn more:
- [@article@Optimization of Computer Programs in C](https://icps.u-strasbg.fr/~bastoul/local_copies/lee.html)
- [@article@Optimizing compiler](https://en.wikipedia.org/wiki/Optimizing_compiler)
- [@video@C Compiler Optimization Fundamentals](https://www.youtube.com/watch?v=-gZpBCRaEak)
@@ -1,3 +1,7 @@
# OS & Signal Interfaces
Operating system and signal interfaces, such as `<signal.h>` and parts of `<stdlib.h>`, let a C program interact with the underlying operating system, including handling asynchronous events like interrupts (`SIGINT`) or setting up custom responses to system-generated signals. These functions provide a portable, if limited, way to write programs that respond to external events like a user pressing Ctrl+C. More extensive OS interaction, such as process creation, typically requires platform-specific APIs like POSIX functions on Unix-like systems.
Operating system and signal interfaces, such as `<signal.h>` and parts of `<stdlib.h>`, let a C program interact with the underlying operating system, including handling asynchronous events like interrupts (`SIGINT`) or setting up custom responses to system-generated signals. These functions provide a portable, if limited, way to write programs that respond to external events like a user pressing Ctrl+C. More extensive OS interaction, such as process creation, typically requires platform-specific APIs like POSIX functions on Unix-like systems.
Visit the following resources to learn more:
- [@article@C Library - \<signal.h\>](https://www.tutorialspoint.com/c_standard_library/signal_h.htm)
@@ -1,3 +1,3 @@
# Package Managers
Package managers for C, such as vcpkg and Conan, automate finding, downloading, and building third-party libraries so they can be linked into a project without manually managing source code or prebuilt binaries. This addresses a longstanding pain point in C development, since the language itself has no built-in package management or standard library distribution mechanism. They typically integrate with build systems like CMake to simplify adding dependencies to a project.
@@ -1,3 +1,9 @@
# Pointer Arithmetic
Pointer arithmetic lets you add or subtract integers from a pointer to move it to a different memory location, with the step size automatically scaled by the size of the type the pointer points to. This is the mechanism behind array indexing, since `arr[i]` is equivalent to `*(arr + i)`. Moving a pointer outside the bounds of the array or object it refers to, then dereferencing it, results in undefined behavior.
Pointer arithmetic lets you add or subtract integers from a pointer to move it to a different memory location, with the step size automatically scaled by the size of the type the pointer points to. This is the mechanism behind array indexing, since `arr[i]` is equivalent to `*(arr + i)`. Moving a pointer outside the bounds of the array or object it refers to, then dereferencing it, results in undefined behavior.
Visit the following resources to learn more:
- [@article@C Pointer Arithmetic](https://www.w3schools.com/c/c_pointers_arithmetic.php)
- [@article@Pointer Arithmetics in C](https://www.tutorialspoint.com/cprogramming/c_pointer_arithmetic.htm)
- [@video@Pointer Arithmetic (Increment & Decrement)](https://www.youtube.com/watch?v=gwqbYnxQGR8)
@@ -1,3 +1,9 @@
# Pointer Basics & Syntax
A pointer is declared with an asterisk, such as `int *p`, and holds the memory address of a value rather than the value itself. The `&` operator retrieves a variable's address, while the `*` operator, when applied to a pointer, dereferences it to access the value it points to. Pointers are central to C, used for passing large data efficiently, building dynamic data structures, and enabling functions to modify their caller's variables.
A pointer is declared with an asterisk, such as `int *p`, and holds the memory address of a value rather than the value itself. The `&` operator retrieves a variable's address, while the `*` operator, when applied to a pointer, dereferences it to access the value it points to. Pointers are central to C, used for passing large data efficiently, building dynamic data structures, and enabling functions to modify their caller's variables.
Visit the following resources to learn more:
- [@course@Learn Pointers](https://www.learn-c.org/en/Pointers)
- [@article@Pointers in C](https://www.tutorialspoint.com/cprogramming/c_pointers.htm)
- [@video@Pointers in C / C++ \[Full Course\]](https://www.youtube.com/watch?v=zuegQmMdy8M)
@@ -1,3 +1,10 @@
# Pointers & Memory
Pointers and memory concepts cover how C represents and manages memory directly, rather than hiding it behind automatic garbage collection. A pointer is a variable that stores the memory address of another value, giving direct access to and control over memory. This area also covers the layout of a program's memory, the difference between stack and heap allocation, and the risks of managing memory manually, like leaks and dangling pointers.
Pointers and memory concepts cover how C represents and manages memory directly, rather than hiding it behind automatic garbage collection. A pointer is a variable that stores the memory address of another value, giving direct access to and control over memory. This area also covers the layout of a program's memory, the difference between stack and heap allocation, and the risks of managing memory manually, like leaks and dangling pointers.
Visit the following resources to learn more:
- [@course@Pointers](https://www.learn-c.org/en/Pointers)
- [@article@C pointers](http://tutorialspoint.com/cprogramming/c_pointers.htm)
- [@video@Pointers: you will never ask about pointers again after watching this video](https://www.youtube.com/watch?v=2ybLD6_2gKM&t=438s)
- [@video@C pointers explained👉](https://www.youtube.com/watch?v=DplxIq0mc_Y)
@@ -1,3 +1,9 @@
# POSIX Threads
POSIX Threads, commonly called pthreads, is a standardized API, defined in `<pthread.h>`, for creating and managing threads on Unix-like systems, letting a single process run multiple sequences of instructions concurrently. Threads created this way share the same memory space, which enables fast communication between them but also introduces the risk of race conditions when multiple threads access the same data without coordination. Functions like `pthread_create` and `pthread_join` handle starting new threads and waiting for them to finish.
POSIX Threads, commonly called pthreads, is a standardized API, defined in `<pthread.h>`, for creating and managing threads on Unix-like systems, letting a single process run multiple sequences of instructions concurrently. Threads created this way share the same memory space, which enables fast communication between them but also introduces the risk of race conditions when multiple threads access the same data without coordination. Functions like `pthread_create` and `pthread_join` handle starting new threads and waiting for them to finish.
Visit the following resources to learn more:
- [@article@POSIX thread (pthread) libraries](https://www.cs.cmu.edu/afs/cs/academic/class/15492-f07/www/pthreads.html)
- [@article@POSIX Threads (pthreads) — The Simplest Way to Understand Real Multithreading in C](https://medium.com/@techdhaba.training/posix-threads-pthreads-the-simplest-way-to-understand-real-multithreading-in-c-c2f591ab7a03)
- [@video@How to create and join threads in C (pthreads).](https://www.youtube.com/watch?v=uA8X5zNOGw8)

Some files were not shown because too many files have changed in this diff Show More