# A Comprehensive Guide to Format Specifiers, Literals, and String Functions in C for Embedded Systems This document provides a comprehensive guide to key concepts in C programming, particularly for embedded systems development. It covers Format Specifiers, Literals, and functions such as sprintf, snprintf, and sscanf. These functions and concepts help programmers efficiently and safely format, read, and process data in embedded applications. Additionally, the document highlights important considerations for memory optimization and performance in resource-constrained environments like microcontrollers. # Format Specifiers in C for Microcontrollers Format specifiers are essential tools used in C to control the formatting of output data in functions like `printf`, `sprintf`, `snprintf`, `sscanf`, and others. They are used to define how variables are displayed, such as their data type, precision, width, alignment, etc. In embedded systems and microcontroller programming, format specifiers help ensure that data is presented in a readable and structured way, whether it's for debugging, logging, or communication. ## Commonly Used Format Specifiers Below is a list of commonly used format specifiers in C, particularly in the context of embedded systems and microcontroller programming. ### Integer Format Specifiers - **`%d`** or **`%i`**: Signed integer (decimal) - **Example**: `printf("%d", -45);` will output `-45`. - **`%u`**: Unsigned integer (decimal) - **Example**: `printf("%u", 45);` will output `45`. - **`%x`** or **`%X`**: Unsigned integer (hexadecimal, lowercase/uppercase) - **Example**: `printf("%x", 255);` will output `ff`, and `printf("%X", 255);` will output `FF`. - **`%o`**: Unsigned integer (octal) - **Example**: `printf("%o", 8);` will output `10`. ### Floating-Point Format Specifiers - **`%f`**: Floating-point number (default precision is 6 decimal places) - **Example**: `printf("%f", 3.14159);` will output `3.141590`. - **`%e`** or **`%E`**: Floating-point number (scientific notation, lowercase/uppercase) - **Example**: `printf("%e", 12345.678);` will output `1.234568e+04` (scientific notation). - **`%g`** or **`%G`**: Floating-point number (either `f` or `e` format, depending on the number) - **Example**: `printf("%g", 0.00012345);` will output `1.2345e-04`. ### String Format Specifiers - **`%s`**: String - **Example**: `printf("%s", "Hello World");` will output `Hello World`. - **`%c`**: Single character - **Example**: `printf("%c", 'A');` will output `A`. ### Pointer Format Specifiers - **`%p`**: Pointer (address in memory) - **Example**: `printf("%p", &variable);` will output the memory address of the variable. ### Width and Precision Modifiers You can use width and precision modifiers to control the minimum width and number of digits after the decimal point for floating-point numbers. #### Width - Specifies the minimum number of characters to be printed. - **Example**: `printf("%5d", 42);` will output ` 42` (with leading spaces to meet the width of 5). #### Precision (for floating-point) - Specifies the number of digits after the decimal point. - **Example**: `printf("%.2f", 3.14159);` will output `3.14`. #### Width and Precision Together You can use both width and precision modifiers together, especially for floating-point numbers. - **Example**: `printf("%8.2f", 3.14159);` will output ` 3.14`. ### Sign Modifiers - **`+`**: Forces the sign to be printed for positive numbers as well as negative ones. - **Example**: `printf("%+d", 45);` will output `+45`. - **`-`**: Left-justifies the output within the specified width. - **Example**: `printf("%-5d", 45);` will output `45 ` (left-aligned). - **`0`**: Pads the output with zeros instead of spaces. - **Example**: `printf("%05d", 45);` will output `00045`. ## Examples of Format Specifiers ### Example 1: Basic Integer Format Specifiers ```c #include int main() { int value = -1234; unsigned int uValue = 1234; printf("Signed Integer: %d\n", value); /**< Output: -1234 */ printf("Unsigned Integer: %u\n", uValue); /**< Output: 1234 */ printf("Hexadecimal (lowercase): %x\n", uValue); /**< Output: 4d2 */ printf("Hexadecimal (uppercase): %X\n", uValue); /**< Output: 4D2 */ return 0; } ``` ### Example 2: Floating-Point Format Specifiers ```c #include int main() { float fValue = 3.14159; printf("Floating-point value (default): %f\n", fValue); /**< Output: 3.141590 */ printf("Scientific notation (lowercase): %e\n", fValue); /**< Output: 3.141590e+00 */ printf("Scientific notation (uppercase): %E\n", fValue); /**< Output: 3.141590E+00 */ printf("Shorter scientific notation: %g\n", fValue); /**< Output: 3.14159 */ return 0; } ``` ### Example 3: String and Character Format Specifiers ```c #include int main() { char character = 'A'; char *message = "Hello, World!"; printf("Character: %c\n", character); /**< Output: A */ printf("String: %s\n", message); /**< Output: Hello, World! */ return 0; } ``` ### Example 4: Pointer Format Specifier ```c #include int main() { int num = 10; printf("Pointer address: %p\n", (void*)&num); /**< Output: 0xAddress (depends on system) */ return 0; } ``` ### Example 5: Width and Precision Modifiers ```c #include int main() { float pi = 3.14159; printf("Width 10: %10.2f\n", pi); /**< Output: " 3.14" */ printf("Left-aligned: %-10.2f\n", pi); /**< Output: "3.14 " */ printf("Zero-padded: %010.2f\n", pi); /**< Output: "0000003.14" */ return 0; } ``` ### Example 6: Sign Modifiers ```c #include int main() { int positive = 45; int negative = -45; printf("With + sign: %+d\n", positive); /**< Output: +45 */ printf("With + sign: %+d\n", negative); /**< Output: -45 */ return 0; } ``` ## Special Notes for Microcontrollers - **Memory Considerations**: When working with limited memory in microcontrollers, be cautious when using complex format specifiers that may increase memory usage. For instance, formatting large floating-point numbers may use more memory. - **Floating Point Support**: Some embedded systems may lack full support for floating-point operations due to hardware limitations. Ensure that your microcontroller's compiler supports floating-point formatting if required. - **Precision Control**: In resource-constrained environments, be mindful of the precision required for floating-point operations to avoid unnecessary calculations and memory usage. ## Conclusion Format specifiers in C are powerful tools that allow you to control how data is displayed. They are essential in embedded systems for debugging, logging, and communication. Understanding the correct usage of these specifiers can help you manage memory effectively and ensure that data is displayed or transmitted in the desired format. --- # Literals in C for Microcontrollers In C, literals are fixed values that are directly written into the source code. They represent constant data used in expressions and assignments. Literals can be of various types, such as integers, floating-point numbers, characters, and strings. Understanding literals is important in embedded systems programming, especially for tasks like configuration settings, sensor data manipulation, or setting initial values in microcontroller applications. ## Types of Literals in C ### 1. Integer Literals An integer literal is a whole number without any decimal point. Integer literals can be specified in decimal, octal, or hexadecimal formats. #### Decimal Integer Literals - Decimal integer literals are the most common and represent numbers in the base-10 system. - **Example**: `int value = 123;` #### Octal Integer Literals - Octal literals start with a leading `0` and represent numbers in base-8. - **Example**: `int value = 075;` (equivalent to decimal `61`) #### Hexadecimal Integer Literals - Hexadecimal literals start with a leading `0x` or `0X` and represent numbers in base-16. - **Example**: `int value = 0x7F;` (equivalent to decimal `127`) #### Binary Integer Literals (C11 and beyond) - Binary literals are introduced in C11 and start with a leading `0b` or `0B`. - **Example**: `int value = 0b1010;` (equivalent to decimal `10`) ### 2. Floating-Point Literals Floating-point literals represent real numbers with a decimal point or in scientific notation. #### Standard Floating-Point Literals - Represented with a decimal point or exponent notation. - **Example**: `float pi = 3.14;` or `float pi = 3.14e0;` #### Exponential Floating-Point Literals - Represented in scientific notation using `e` or `E` to indicate the exponent. - **Example**: `float value = 2.5e3;` (equivalent to `2500`) #### Long Double Literals - To specify a long double literal, you can append `L` or `l` to the number. - **Example**: `long double value = 3.14159265358979L;` ### 3. Character Literals Character literals represent single characters enclosed in single quotes (`'`). - **Example**: `char letter = 'A';` - A character literal represents the ASCII value of the character, so the value of `'A'` is `65` in decimal. ### 4. String Literals String literals are sequences of characters enclosed in double quotes (`"`). They are used to represent a sequence of characters, typically for text output, logging, or communication. - **Example**: `char *message = "Hello, World!";` - String literals in C are automatically null-terminated, meaning the last character is always `'\0'` (null character). ### 5. Wide Character Literals Wide character literals represent wide characters (16-bit or 32-bit, depending on the platform) enclosed in single quotes and prefixed by `L`. - **Example**: `wchar_t wideChar = L'Ω';` - Wide character literals allow the representation of characters from extended character sets such as Unicode. ### 6. Boolean Literals (C99 and beyond) In C99 and beyond, the boolean type `_Bool` is available, and literals can be represented using `true` and `false` (via the `stdbool.h` header). - **Example**: `bool isActive = true;` or `bool isFinished = false;` ### 7. Null Pointer Literal The null pointer literal in C is represented by `NULL`, which is used to indicate that a pointer does not point to any valid memory location. - **Example**: `int *ptr = NULL;` ## Usage of Literals in Embedded Systems In microcontroller programming, literals are used extensively for: - **Configuration values**: Setting initial values for registers, flags, or device settings. - **Initial values for variables**: Defining default or initial values for global variables or data structures. - **Debugging**: Logging or printing constant values for status messages or sensor readings. - **Memory addresses**: Defining specific addresses for memory-mapped registers or peripherals. ### Example 1: Using Integer Literals in Embedded Systems In embedded systems, we often set hardware registers or flags using integer literals. ```c #include #define GPIO_PORT 0x40025000 /**< GPIO base address (example) */ int main() { unsigned int *gpioData = (unsigned int *)GPIO_PORT; /**< Pointer to the GPIO register */ *gpioData = 0x01; /**< Set GPIO pin 0 to HIGH (binary literal) */ return 0; } ``` **Explanation**: - `GPIO_PORT` is defined as a hexadecimal literal representing the base address of the GPIO port. - `0x01` is an integer literal used to set pin 0 to HIGH. ### Example 2: Using Floating-Point Literals In embedded systems, floating-point literals are often used for sensor calibration or timing calculations. ```c #include int main() { float voltage = 3.3; /**< Voltage in floating-point literal */ float resistance = 10.0; float current = voltage / resistance; /**< Ohm's law: I = V / R */ printf("Current: %.2f A\n", current); /**< Output: Current: 0.33 A */ return 0; } ``` **Explanation**: - `3.3` and `10.0` are floating-point literals used to calculate the current using Ohm’s law. ### Example 3: Using String Literals in Communication String literals are often used for UART communication in embedded systems. ```c #include #include "uart.h" /**< UART communication library */ int main() { char *message = "Sensor reading: OK"; /**< String literal for communication */ uart_puts(message); /**< Send message via UART */ return 0; } ``` **Explanation**: - `"Sensor reading: OK"` is a string literal that is sent via UART to a remote system. ## Special Notes for Microcontroller Use: 1. **Memory Constraints**: - Microcontrollers often have limited memory. Be mindful of using large string literals or extensive floating-point operations, as they can consume significant memory resources. 2. **Precision of Floating-Point Literals**: - Some microcontrollers may not support high precision for floating-point literals. If precision is critical, consider using fixed-point arithmetic or integer-based calculations. 3. **String Handling**: - When working with string literals in embedded systems, remember that they are null-terminated. Ensure that the destination buffer has enough space to handle the string plus the null terminator. 4. **Integer Size**: - Integer literals, especially in large systems or 32-bit microcontrollers, can be of varying sizes. Ensure that you choose the correct data type for your literals (`int`, `long`, `short`, etc.) to match the required memory and performance. ## Conclusion Literals in C provide a way to express constant values in the code. They are fundamental in embedded systems programming for tasks like initializing variables, configuring hardware, and simplifying calculations. Understanding how to use different types of literals effectively is crucial for writing efficient and readable embedded code. --- # `sprintf` in C for Microcontrollers The `sprintf` function in C is part of the standard library and is used to format and store a series of characters and values into a string. It works similarly to `printf`, but instead of printing the formatted output to the console, it writes it into a string buffer. This function is commonly used in embedded systems and microcontroller programming to generate formatted text for debugging, logging, or user interfaces (e.g., LCD screens, UART communication). ## Syntax ```c int sprintf(char *str, const char *format, ...); ``` ### Parameters: - **`str`**: A pointer to the buffer where the resulting string will be stored. The buffer must be large enough to hold the resulting formatted string. - **`format`**: A string that contains the format specifiers. These are placeholders that specify how to format the following arguments. - **`...`**: The values to be formatted according to the specifiers in `format`. ### Return Value: - Returns the number of characters written (excluding the null terminator) if successful. - If there is an error (e.g., buffer overflow), it returns a negative value. ## Usage in Microcontrollers In microcontroller programming, especially when working with embedded systems, `sprintf` is useful for generating readable strings, such as status messages or formatted data to be sent over communication peripherals like UART or displayed on an LCD screen. However, it's important to be cautious of the memory usage, as `sprintf` can be inefficient in constrained environments due to its reliance on the standard library. ### Example 1: Basic `sprintf` Usage In this example, we will format an integer into a string. ```c #include int main() { char buffer[50]; /**< Declare a buffer to store the formatted string */ int value = 123; /**< Example integer value */ /* Format the integer into the string */ sprintf(buffer, "The value is %d", value); /* Print the formatted string */ printf("%s", buffer); return 0; } ``` **Explanation**: - We declare a buffer `char buffer[50];` to store the formatted string. - The `sprintf` function formats the integer value `123` and stores the result as `"The value is 123"` into the `buffer`. - Finally, the `printf` function prints the content of the buffer. ### Example 2: Using Multiple Format Specifiers You can format different types of data into a single string. ```c #include int main() { char buffer[100]; /**< Buffer to hold the formatted string */ int temperature = 25; float voltage = 3.3; /* Format multiple types into the string */ sprintf(buffer, "Temperature: %d°C, Voltage: %.2fV", temperature, voltage); /* Output the formatted string */ printf("%s", buffer); return 0; } ``` **Explanation**: - Here, we format both an integer (`temperature`) and a floating-point number (`voltage`) into a single string. - The format specifier `%.2f` is used to print the floating-point number with two decimal places. ### Example 3: Formatting Hexadecimal Formatting integers in hexadecimal is common in embedded systems, especially for debugging or displaying memory addresses. ```c #include int main() { char buffer[50]; /**< Buffer to store the formatted string */ unsigned int address = 0x1A2B3C; /* Format the hexadecimal address into the string */ sprintf(buffer, "Memory address: 0x%X", address); /* Output the formatted string */ printf("%s", buffer); return 0; } ``` **Explanation**: - The format specifier `%X` is used to format the unsigned integer `address` in hexadecimal (uppercase). ### Example 4: Using `sprintf` for UART Communication (Microcontroller Example) In many microcontroller projects, `sprintf` is used to generate strings for UART communication. Below is an example of how it can be used to prepare a message for transmission. ```c #include #include "uart.h" /**< Custom UART library for the microcontroller */ int main() { char message[100]; /**< Buffer for the message */ int sensorData = 50; /**< Example sensor data */ /* Format the message to send over UART */ sprintf(message, "Sensor reading: %d", sensorData); /* Send the message over UART */ uart_puts(message); return 0; } ``` **Explanation**: - The `sprintf` formats the sensor data into a string. - The formatted string is sent over UART using a custom `uart_send_string` function (assumed to be defined elsewhere in your project). ## Important Notes for Microcontroller Use: 1. **Memory Considerations**: - `sprintf` can be memory-intensive, especially in environments with limited memory (e.g., small RAM in microcontrollers). Ensure the buffer size is sufficient for the data you are formatting. - Avoid using large buffers in very constrained environments as it might lead to memory overflows. 2. **Performance Considerations**: - `sprintf` can be relatively slow for microcontrollers with limited processing power. If performance is critical, consider using more lightweight formatting methods or avoid `sprintf` entirely in time-sensitive code. 3. **Security Concerns**: - Always ensure that the buffer passed to `sprintf` is large enough to accommodate the formatted string. If the buffer is too small, a buffer overflow could occur, leading to undefined behavior or crashes. ## Conclusion The `sprintf` function is a powerful tool for formatting and storing strings in embedded systems and microcontroller programming. However, due to potential performance and memory concerns, it's essential to use it carefully, especially in resource-constrained environments. ### Best Practices: - Always ensure buffers are large enough to handle the formatted output. - If performance is a concern, consider alternatives such as manually constructing strings or using lightweight formatting libraries. --- # `snprintf` in C for Microcontrollers The `snprintf` function in C is a safer version of `sprintf`. It formats a string and stores it in a buffer, but with the added feature that it prevents buffer overflow by specifying the maximum number of characters to write, including the null terminator. This function is particularly useful in embedded systems and microcontroller programming, where memory is limited, and avoiding buffer overflows is critical for system stability and security. ## Syntax ```c int snprintf(char *str, size_t size, const char *format, ...); ``` ### Parameters: - **`str`**: A pointer to the buffer where the resulting string will be stored. - **`size`**: The maximum number of characters to write to the buffer, including the null terminator. This ensures that `snprintf` does not write more than `size-1` characters. - **`format`**: A format string that specifies how subsequent arguments (if any) should be formatted. - **`...`**: The values to be formatted according to the format string. ### Return Value: - Returns the number of characters that would have been written if enough space had been available (not counting the null terminator). - If the output was truncated due to the size limit, it can be used to determine the required buffer size. - If an error occurs, it returns a negative value. ### Example: Preventing Buffer Overflow with Truncation If the buffer size is smaller than the formatted string, `snprintf` will truncate the string and return the number of characters that would have been written. ```c #include int main() { char buffer[20]; /**< Small buffer */ int largeValue = 123456; /* Format the large integer into a small buffer */ int written = snprintf(buffer, sizeof(buffer), "Value: %d", largeValue); /* Output the truncated string */ printf("Formatted: %s\n", buffer); printf("Total characters would be: %d\n", written); return 0; } ``` **Explanation**: - The buffer is too small to hold the full formatted string `"Value: 123456"`, so `snprintf` truncates the string to fit within the 20-character limit and returns the total number of characters that would have been written (including the null terminator). ## Important Notes for Microcontroller Use: 1. **Memory Considerations**: - `snprintf` is more memory-efficient than `sprintf` because it allows you to specify the maximum buffer size. Always ensure that the buffer is large enough to store the formatted string, including the null terminator. - Use `sizeof(buffer)` to ensure the correct size is passed to `snprintf` and avoid buffer overflows. 2. **Performance Considerations**: - While `snprintf` is safer, it may still be slower than manual string formatting or direct data manipulation, especially in performance-critical or real-time systems. Consider performance trade-offs when deciding to use `snprintf` in time-sensitive applications. 3. **Error Handling**: - Always check the return value of `snprintf`. If the return value is greater than or equal to the specified buffer size, this indicates that the string was truncated. This can help you ensure that the buffer was large enough. - If the return value is negative, an error occurred during formatting. 4. **Security Concerns**: - The primary benefit of `snprintf` over `sprintf` is its ability to prevent buffer overflow. By specifying the buffer size, you protect against writing more data than the buffer can hold. - Always validate the buffer size before using `snprintf` in systems with limited resources. ## Conclusion The `snprintf` function is a safer and more controlled version of `sprintf` in C. It allows for formatted string creation while ensuring that buffer overflows are prevented by specifying the maximum number of characters to write. This function is particularly useful in embedded systems and microcontroller programming, where memory and performance constraints must be carefully managed. ### Best Practices: - Always specify a buffer size limit with `snprintf` to avoid buffer overflows. - Check the return value to ensure that the string was written successfully and was not truncated. - Use `snprintf` for formatting strings in memory-constrained environments to prevent unsafe memory operations. --- # `sscanf` in C for Microcontrollers The `sscanf` function in C is used to read formatted input from a string. It is similar to the `scanf` function, but instead of reading input from the standard input (keyboard or other streams), `sscanf` reads data from a string and stores the parsed values into variables. This function is useful in embedded systems and microcontroller programming when parsing data from strings, such as received messages over UART, reading sensor data from a formatted string, or extracting values from log files. ## Syntax ```c int sscanf(const char *str, const char *format, ...); ``` ### Parameters: - **`str`**: A pointer to the string that contains the data to be parsed. - **`format`**: A string that defines the format specifiers, similar to the ones used in `printf`. These specifiers guide how the data should be interpreted and stored. - **`...`**: A list of pointers to variables where the parsed values will be stored. ### Return Value: - Returns the number of input items successfully matched and assigned. If an error occurs or no matching data is found, it returns `EOF` (typically `-1`). ## Usage in Microcontrollers In microcontroller programming, `sscanf` is often used to extract values from data received over communication peripherals such as UART or stored in memory. For example, when parsing data from sensor readings or extracting parameters from a formatted message. ### Example 1: Basic `sscanf` Usage In this example, we will parse an integer from a string. ```c #include int main() { char input[] = "Value: 123"; /**< String containing the value */ int value; /* Parse the integer from the string */ sscanf(input, "Value: %d", &value); /* Output the parsed value */ printf("Parsed value: %d", value); return 0; } ``` **Explanation**: - The `sscanf` function reads the string `input` and looks for the integer after the "Value: " part. - The format specifier `%d` is used to extract the integer `123`, which is stored in the variable `value`. ### Example 2: Parsing Multiple Values from a String You can parse multiple values from a string in a single call to `sscanf`. ```c #include int main() { char input[] = "Temperature: 25, Voltage: 3.3"; int temperature; float voltage; /* Parse multiple values from the string */ sscanf(input, "Temperature: %d, Voltage: %f", &temperature, &voltage); /* Output the parsed values */ printf("Temperature: %d°C, Voltage: %.2fV", temperature, voltage); return 0; } ``` **Explanation**: - The `sscanf` function extracts both the integer (`temperature`) and the floating-point number (`voltage`) from the formatted string. ### Example 3: Parsing Hexadecimal Values Often, data transmitted in embedded systems is represented in hexadecimal format. Here's an example of how to parse a hexadecimal value from a string. ```c #include int main() { char input[] = "0x1A2B3C"; /**< Hexadecimal string */ unsigned int address; /* Parse the hexadecimal value */ sscanf(input, "0x%X", &address); /* Output the parsed address */ printf("Parsed address: 0x%X", address); return 0; } ``` **Explanation**: - The `%X` format specifier is used to read the hexadecimal number `1A2B3C` from the string `input` and store it in the variable `address`. ### Example 4: Parsing Data from UART (Microcontroller Example) In many microcontroller applications, `sscanf` is used to parse data received over UART. Below is an example of how to use `sscanf` to extract a sensor value from a formatted message received via UART. ```c #include #include "uart.h" /**< Custom UART library for the microcontroller */ int main() { char input[100]; /**< Buffer for the UART message */ int sensorData; char unit[10]; /* Read a message from UART (e.g., "Sensor: 50 units") */ uart_receive_string(input, 100); /* Parse the sensor data and unit from the message */ sscanf(input, "Sensor: %d %s", &sensorData, unit); /* Output the parsed data */ printf("Sensor reading: %d %s", sensorData, unit); return 0; } ``` **Explanation**: - The `uart_receive_string` function (assumed to be defined elsewhere in your project) is used to read a message from UART into the `input` buffer. - The `sscanf` function is then used to extract the integer `sensorData` and the string `unit` from the received message, which is in the format `"Sensor: 50 units"`. ## Important Notes for Microcontroller Use: 1. **Memory Considerations**: - `sscanf` can be memory-intensive because it stores parsed values in variables. Ensure that the buffer provided is large enough to hold the string to be parsed. - The buffer size should be carefully managed to avoid memory overflows, especially in memory-constrained microcontroller environments. 2. **Performance Considerations**: - `sscanf` can be slower than manual parsing, especially on resource-constrained systems. If parsing needs to be fast and efficient, consider implementing a custom parser instead of relying on `sscanf`. 3. **Error Handling**: - Always check the return value of `sscanf`. If it returns `EOF`, this means that parsing failed (e.g., due to a format mismatch or incorrect input). - In embedded systems, robust error handling is critical, especially when receiving data over communication channels. 4. **Security Concerns**: - Be cautious of buffer overflow vulnerabilities when using `sscanf` in embedded systems. Ensure that the input string is appropriately validated, and the buffer size is sufficient to handle the parsed data. ## Conclusion The `sscanf` function is useful for extracting values from formatted strings in embedded systems and microcontroller programming. It allows easy parsing of data, such as sensor readings or communication messages, from strings. However, care must be taken with memory and performance constraints, and custom parsing solutions may be more efficient in certain scenarios. ### Best Practices: - Always ensure buffers are large enough to hold the data being parsed. - Check the return value of `sscanf` to detect errors. - Consider custom parsing functions for performance-critical applications. # 🌟 Support Me If you found this repository useful: - Subscribe to my [YouTube Channel](https://www.youtube.com/@aKaReZa75). - Share this repository with others. - Give this repository and my other repositories a star. - Follow my [GitHub account](https://github.com/aKaReZa75). # ✉️ Contact Me Feel free to reach out to me through any of the following platforms: - 📧 [Email: aKaReZa75@gmail.com](mailto:aKaReZa75@gmail.com) - 🎥 [YouTube: @aKaReZa75](https://www.youtube.com/@aKaReZa75) - 💼 [LinkedIn: @akareza75](https://www.linkedin.com/in/akareza75)