> See also: > - Reference # C Programming Language `echo $?` - returns error code of past output statement ### TODO Review - Static array vs pointer array ## Basic Variable Types | Name | Syntax | Byte Size | Description | | --- | --- | --- | --- | | Character | `char` | 1 | Stores a single ASCII character | | Integer | `int` | 4 | | | Float | `float` | 4 | | | Double | `double` | 8 | | Any non-zero value in C is viewed as "True" ### Arrays arrays = pointers This is important to remember when accessing a variable's values ### Strings A **string** in C is an array of `char` variables followed by a terminator `\0` element. - It's useful to write `num + 1` when defining strings to track the proper length `fgets(char *destination, int string_size, FILE *stream*)` ### Pointers `*var` - The `*` symbol indicates the value being stored (called “*dereferencing*”) `&var` - The `&` symbol indicates a memory address location Pointers are statically created, meaning that you cannot change the specific memory address f ### Structures `struct.attribute` `struct_ptr->attribute` The variables stored within a struct are typically referred to as components ## Basic Input/Output **Buffers** are generally described as temporary variables used to temporarily allocate memory for a specific task. ### String Inputs ## Dynamic Memory **Static Memory:** - A specific amount of provided to a program when it is run - This memory space cannot be increased or reduced, making it **Dynamic Memory:** - Stored in heap space Nearly all of the foundational functions for dynamic memory are within the `stdlib` library. When specifying the size of the memory, these functions use a `size_t` variable type. This is an unsigned integer (meaning that negative inputs will result in integer underflow). --- `malloc(size_t memory_size)` - It's good to use the `sizeof()` function to determine the necessary memory size as variable sizes can vary based on system architecture - Returns a void pointer (`void *`) and should be type-cast - Returns `NULL *` on fail ```c int * arr = (int *)malloc(10 * sizeof(int)); if (arr == NULL) { // handle fail state } ``` --- `realloc(void *, size_t n)` - Used when you need to modify (increase) the size of dynamically allocated memory - Fills new memory space with garbage values - Automatically frees old memory section - Returns a void pointer (`void *`) and should be type-cast ```c int * arr = (int *)realloc(void * orig_dyn_pntr, 10 * sizeof(int)) if (arr != NULL) { // desired behavior } else { // handle fail state } ``` --- `calloc(size_t num_of_items, size_t size_of_items)` - Automatically initializes the values within the memory to byte-wise `0` ```c int * arr = (int *)calloc(void * orig_dyn_pntr, size_of_items) ``` --- `free(void * ptr_to_heap_mem)` - Make sure to never free static memory ```c free(void * ptr_to_heap_mem) ``` - `free(NULL)` does nothing ### Dynamic Memory Violations > [!danger] **Memory Violations (In C Language)** > 1. Double `free()` > 2. Attempting to use a pointer > - Never free the same heap space pointer twice - Don't use a freed pointer after using the free() function - Freeing static memory - debugging: `gcc [c file] -g` `valgrind [program]`