C Quick Guide
C - Quick Guide
Section titled “C - Quick Guide”C - Language Overview
Section titled “C - Language Overview”C is a general-purpose, procedural programming language known for efficiency and low-level memory access. Developed by Dennis Ritchie at Bell Labs in 1972 for the UNIX OS.
Standardized by ANSI (C89) and ISO, with later revisions like C99, C11, C17 adding features.
Widely used for system programming, embedded systems, performance-critical applications, and foundational software.
- Efficient
- Low-level memory access (pointers)
- Structured (functions)
- Portable
- Foundation for many other languages
Facts about C
Section titled “Facts about C”- Invented to write UNIX.
- Successor to the B language.
- Standardized by ANSI (1989) and ISO.
- Core language for Linux, macOS, Windows kernels.
- Used in databases, compilers, game engines.
C - Environment Setup
Section titled “C - Environment Setup”To write, compile, and run C programs, you need: (a) A Text Editor and (b) A C Compiler.
Text Editor:
Section titled “Text Editor:”Used to write your source code (files ending in .c). Modern editors offer syntax highlighting, auto-completion, etc.
Popular Choices: Visual Studio Code (VS Code), Sublime Text, Atom, Vim, Emacs, Notepad++ (Windows).
Source files contain human-readable code. Ensure you know how to save files with the .c extension.
The C Compiler:
Section titled “The C Compiler:”Translates your .c source files into machine code (an executable program) that the computer’s CPU can run.
Common Compilers:
- GCC (GNU Compiler Collection): Free, open-source, widely available on Linux, macOS, and Windows (via MinGW-w64/MSYS2 or WSL). Supports C and C++.
- Clang: Another popular open-source compiler, known for fast compilation and good diagnostics. Often used with LLVM.
- MSVC (Microsoft Visual C++): Part of Visual Studio on Windows. Compiles C and C++.
Installation:
Section titled “Installation:”Installation varies by Operating System:
Linux:
Section titled “Linux:”Use your distribution’s package manager. Check if GCC is installed:
$ gcc --versionIf not installed, use commands like:
# Debian/Ubuntusudo apt updatesudo apt install build-essential
# Fedora/CentOS/RHELsudo dnf groupinstall "Development Tools"
# Arch Linuxsudo pacman -S base-develmacOS:
Section titled “macOS:”Install Xcode from the App Store, or just the Command Line Tools. Open Terminal and run:
$ xcode-select --installThis provides GCC (often an alias for Clang) and other development tools.
Windows:
Section titled “Windows:”- Recommended: WSL (Windows Subsystem for Linux): Install a Linux distribution (like Ubuntu) from the Microsoft Store. Then follow the Linux installation steps above within WSL.
- MSYS2/MinGW-w64: Provides an up-to-date GCC toolchain native to Windows. Download from https://www.msys2.org/, follow their instructions to install the
mingw-w64-x86_64-toolchainpackage. Ensure the MinGW bin directory (e.g.,C:\msys64\mingw64\bin) is added to your system’s PATH environment variable. - Visual Studio Community: Download from https://visualstudio.microsoft.com/vs/community/. During installation, select the “Desktop development with C++” workload, which includes the C compiler (cl.exe) and build tools.
C - Program Structure
Section titled “C - Program Structure”Let’s examine a minimal C program.
C Hello World Example
Section titled “C Hello World Example”A basic C program structure includes:
- Preprocessor Directives (e.g.,
#include) - Functions (at least
main) - Variables (optional)
- Statements & Expressions
- Comments
Example hello.c:
// Include standard input/output library for printf#include <stdio.h>
// main function: execution starts hereint main(void) { /* Multi-line comment: This program prints Hello, World! */ printf("Hello, World!\n"); // Statement calling printf function
return 0; // Indicate successful execution}Explanation:
#include <stdio.h>: A preprocessor directive telling the compiler to include the contents of the standard input/output header file, which contains the declaration forprintf.int main(void): The main function where program execution begins.intmeans it returns an integer status code;voidmeans it takes no arguments (alternativelyint main(int argc, char *argv[])for command-line arguments).// ...and/* ... */: Comments ignored by the compiler, used for explanation.printf(...): A standard library function to print output to the console.\nis an escape sequence for a newline character.return 0;: Exits themainfunction and returns 0 to the operating system, conventionally indicating successful execution.
Compile & Execute C Program:
Section titled “Compile & Execute C Program:”Steps:
- Save the code above in a file named
hello.c. - Open a terminal or command prompt.
- Navigate to the directory where you saved the file.
- Compile the code using the C compiler (e.g., GCC):
gcc hello.c -o hello(orclang hello.c -o hello). The-o hellopart specifies the name of the output executable file. - If there are no errors, an executable file named
hello(orhello.exeon Windows) will be created. - Run the program:
./hello(on Linux/macOS/WSL) orhello.exe(on Windows command prompt).
Expected Output:
$ gcc hello.c -o hello$ ./helloHello, World!Ensure the compiler (gcc, clang, etc.) is in your system’s PATH.
C - Basic Syntax
Section titled “C - Basic Syntax”Understanding the basic building blocks of C syntax.
Tokens in C
Section titled “Tokens in C”A C program is composed of tokens. Tokens are the smallest individual units in a program, such as keywords, identifiers, constants, string literals, and symbols. For example, the statement:
printf("Hello, World!\n");Consists of the following tokens:
printf("Hello, World!\n");Semicolons (;)
Section titled “Semicolons (;)”In C, the semicolon acts as a statement terminator. Each distinct statement must end with a semicolon.
Example of two statements:
printf("Hello!\n");return 0;Comments
Section titled “Comments”Comments are explanatory text ignored by the compiler. C supports two types:
/* This is a multi-line comment. It can span several lines. */
// This is a single-line comment (introduced in C99). It ends at the newline.Comments cannot be nested (a /* inside another /* ... */ block is usually problematic).
Identifiers
Section titled “Identifiers”An identifier is a name used for variables, functions, labels, and other user-defined items. Rules:
- Must start with a letter (a-z, A-Z) or an underscore (_).
- Subsequent characters can be letters, underscores, or digits (0-9).
- Cannot contain punctuation characters like @, $, %.
- Are case-sensitive:
myVarandmyvarare different identifiers. - Cannot be the same as C keywords.
Examples of valid identifiers:
count _temp value1 calculate_sum MAX_ENTRIESKeywords
Section titled “Keywords”Keywords are reserved words with special meanings in C. They cannot be used as identifiers.
| Standard Keywords (C11 and earlier) | |||
|---|---|---|---|
| auto | double | int | struct |
| break | else | long | switch |
| case | enum | register | typedef |
| char | extern | return | union |
| const | float | short | unsigned |
| continue | for | signed | void |
| default | goto | sizeof | volatile |
| do | if | static | while |
| _Bool | _Complex | _Imaginary | inline (C99) |
| restrict (C99) |
Note: Keywords starting with an underscore are often reserved or part of later standards.
Whitespace in C
Section titled “Whitespace in C”Whitespace refers to blanks (spaces), tabs, newline characters, and comments. The C compiler mostly ignores whitespace, but it’s crucial for separating tokens.
For example, in int age;, whitespace between int and age is required. However, in result = value1 + value2;, whitespace around = and + is optional but improves readability.
int age; // Whitespace needed
fruit=apples+oranges; // Works, but less readablefruit = apples + oranges; // Better readabilityBlank lines are also ignored and can be used to structure code.
C - Data Types
Section titled “C - Data Types”Data types define the kind of data a variable can hold and the operations that can be performed on it. They determine memory size and interpretation of bit patterns.
C types can be broadly classified:
| S.N. | Category | Description |
|---|---|---|
| 1 | Basic Types | Arithmetic types: Further divided into Integer Types and Floating-Point Types. |
| 2 | Enumerated Types (enum) | User-defined integer types where variables can only take values from a specific set of named integer constants. |
| 3 | Void Type (void) | Indicates absence of type/value. Used for functions returning nothing, functions with no parameters, or generic pointers (void*). |
| 4 | Derived Types | Constructed from basic types: Pointers (*), Arrays ([]), Structures (struct), Unions (union), and Function Types. |
Aggregate types (arrays and structures) group multiple data items. Function types describe a function’s return type and parameters.
Integer Types
Section titled “Integer Types”Represent whole numbers. Standard integer types include:
| Type | Minimum Size (Standard) | Minimum Range (Standard) & Common Values |
|---|---|---|
char | Typically 1 byte | Usually -128 to 127 (signed) or 0 to 255 (unsigned). Implementation-defined whether plain char is signed or unsigned. |
unsigned char | 1 byte | 0 to 255 |
signed char | 1 byte | -128 to 127 |
short (short int) | At least 2 bytes | At least -32,768 to 32,767 |
unsigned short | At least 2 bytes | At least 0 to 65,535 |
int | Typically system’s natural word size (often 4 bytes on 32-bit/64-bit systems) | At least -32,768 to 32,767 (like short), commonly larger (-2,147,483,648 to 2,147,483,647 for 4 bytes) |
unsigned int | Same size as int | At least 0 to 65,535 (like unsigned short), commonly 0 to 4,294,967,295 (for 4 bytes) |
long (long int) | At least 4 bytes | At least -2,147,483,648 to 2,147,483,647 |
unsigned long | At least 4 bytes | At least 0 to 4,294,967,295 |
long long (long long int) (C99) | At least 8 bytes | At least -(2^63) to (2^63)-1 |
unsigned long long (C99) | At least 8 bytes | At least 0 to (2^64)-1 |
The exact sizes and ranges depend on the compiler and platform. Use the sizeof operator to find the size in bytes on your system: sizeof(int), sizeof(char*).
Fixed-Width Integers (C99 - <stdint.h>)
Section titled “Fixed-Width Integers (C99 - <stdint.h>)”For portability and predictable sizes, use types from <stdint.h> when exact widths are needed:
int8_t,int16_t,int32_t,int64_t: Signed integers of exactly 8, 16, 32, 64 bits.uint8_t,uint16_t,uint32_t,uint64_t: Unsigned integers of exactly 8, 16, 32, 64 bits.intptr_t,uintptr_t: Integer types capable of holding object pointers.
Example:
#include <stdint.h>#include <stdio.h>
int main(void) { int32_t file_offset = -1024; uint8_t pixel_value = 255; printf("Offset: %d, Pixel: %u\n", file_offset, pixel_value); printf("Size of int32_t: %zu bytes\n", sizeof(int32_t)); // %zu for size_t return 0;}Floating-Point Types
Section titled “Floating-Point Types”Represent numbers with fractional parts (real numbers).
| Type | Typical Size | Typical Precision | Description |
|---|---|---|---|
float | Typically 4 bytes | ~6-7 decimal digits precision | Single-precision |
double | Typically 8 bytes | ~15-16 decimal digits precision | Double-precision |
long double | Often 10, 12, or 16 bytes | Higher precision than double (platform dependent) | Extended-precision |
The header file <float.h> defines macros (like FLT_MIN, DBL_MAX, LDBL_DIG) providing details about floating-point representation on the specific platform.
Boolean Type (C99 - <stdbool.h>)
Section titled “Boolean Type (C99 - <stdbool.h>)”C99 introduced a standard boolean type.
- Include
<stdbool.h>. - Type:
bool - Values:
true,false
Example:
#include <stdbool.h>#include <stdio.h>
int main(void) { bool is_active = true; if (is_active) { printf("System is active.\n"); } return 0;}Internally, bool is often an integer type, with false being 0 and true typically 1.
The void Type
Section titled “The void Type”void signifies the absence of a type or value. Uses:
| S.N. | Context | Description |
|---|---|---|
| 1 | Function Return Type | Indicates a function does not return a value. Example: void print_message(const char *msg); |
| 2 | Function Parameters | Indicates a function takes no parameters. Example: int get_random_number(void); |
| 3 | Generic Pointers (void *) | A pointer to void can hold the address of any data type, but cannot be dereferenced directly. It must be cast to a specific pointer type first. Example: malloc returns void *. void *ptr = malloc(100); int *int_ptr = (int*)ptr; |
Understanding void * is fundamental for dynamic memory allocation and generic functions.
C - Variables
Section titled “C - Variables”A variable is a named storage location in memory that holds a value. Programs manipulate these values. Every variable in C has a specific data type, which dictates its size, memory layout, range of possible values, and the operations applicable to it.
Variable names (identifiers) follow specific rules: start with a letter or underscore, followed by letters, digits, or underscores. C is case-sensitive (age and Age are different variables).
Basic variable types correspond to the basic data types:
| Type | Description |
|---|---|
char, signed char, unsigned char | Stores single characters or small integers. |
short, int, long, long long (and their unsigned variants) | Stores whole numbers of varying sizes. |
float, double, long double | Stores numbers with fractional parts. |
bool (from <stdbool.h>) | Stores boolean values (true or false). |
C also supports derived types like pointers, arrays, structures, etc., allowing for more complex variable definitions.
Variable Definition in C
Section titled “Variable Definition in C”A definition reserves memory for the variable and associates the name with that memory location. It specifies the data type and variable name(s):
type variable_list;type is a valid C data type (e.g., int, float, char, struct MyData). variable_list is one or more identifiers separated by commas.
Examples of definitions:
#include <stdbool.h> // For bool#include <stdint.h> // For uint8_t
int i, j, k; // Define three integerschar c, initial; // Define two charactersfloat salary, tax; // Define two single-precision floatsdouble pi; // Define one double-precision floatbool is_valid; // Define a boolean variableuint8_t status_code; // Define an 8-bit unsigned integerInitialization
Section titled “Initialization”Variables can be initialized (given an initial value) at the time of definition using the assignment operator (=):
type variable_name = value;Examples:
int count = 0; // Define and initialize count to 0char grade = 'A'; // Define and initialize grade to 'A'float temperature = 98.6f; // Define and initialize temperature (use 'f' suffix for float literals)double planck_constant = 6.62607015e-34;int x = 10, y = 20; // Define and initialize multiple variables
// Initialization for derived typesint numbers[3] = {1, 2, 3}; // Initialize an arraychar message[] = "Hello"; // Initialize a character array (string)If a variable with static storage duration (like global variables or variables declared with static) is not explicitly initialized, it’s implicitly initialized to zero (or NULL for pointers). Local variables (automatic storage duration) have undefined initial values if not explicitly initialized – using them before assignment leads to unpredictable behavior.
Variable Declaration in C
Section titled “Variable Declaration in C”A declaration introduces a variable’s name and type to the compiler but doesn’t necessarily reserve storage (though definition often implies declaration). Declarations are crucial when using variables defined in other files or before their definition point.
The extern keyword is used for declarations that refer to variables defined elsewhere:
extern int global_counter; // Declares global_counter defined in another fileextern const char *app_name; // Declares app_name defined elsewhereA variable can be declared multiple times (e.g., in multiple header files using extern), but it must be defined exactly once in one source file.
Example (Conceptual Multi-File Scenario):
Section titled “Example (Conceptual Multi-File Scenario):”// --- main.c ---#include <stdio.h>
// Declaration of variable defined in another_file.cextern int shared_value;extern void print_shared_value(void); // Function declaration
int main(void) { printf("Initial shared value (declared extern): %d\n", shared_value); shared_value = 100; // Modify the shared variable print_shared_value(); return 0;}
// --- another_file.c ---#include <stdio.h>
// Definition of the shared variableint shared_value = 42; // Definition and initialization
// Definition of the functionvoid print_shared_value(void) { printf("Current shared value (defined here): %d\n", shared_value);}To compile this, you’d typically compile both files and link them:
$ gcc main.c another_file.c -o my_program$ ./my_programExpected Output:
Initial shared value (declared extern): 42Current shared value (defined here): 100The same declaration concept applies to functions.
Lvalues and Rvalues in C
Section titled “Lvalues and Rvalues in C”Expressions in C can be categorized:
- lvalue (Locator value): Represents an object that occupies an identifiable location in memory (like a variable). An lvalue can appear on the left-hand side or right-hand side of an assignment.
- rvalue (Read value): Represents a temporary value that doesn’t necessarily have a persistent memory location (like a literal number or the result of an expression). An rvalue can appear on the right-hand side but not the left-hand side of an assignment.
Variables are lvalues.
int score = 95; // 'score' is an lvalue, '95' is an rvalueLiterals (like 10, 3.14, 'A') are rvalues.
10 = score; // Invalid: Cannot assign to an rvalue (10)Understanding this distinction helps grasp assignment rules and operator behavior.
C - Constants and Literals
Section titled “C - Constants and Literals”Constants are fixed values that a program cannot change during execution. These fixed values themselves are often called literals.
Literals can represent basic data types: integer literals, floating-point literals, character literals, and string literals. There are also enumeration constants.
Named constants, unlike literals, provide a symbolic name for a fixed value, improving readability and maintainability.
Integer Literals
Section titled “Integer Literals”Represent whole numbers. Can be specified in different bases:
- Decimal: No prefix (e.g.,
123,-5). - Octal: Prefix
0(e.g.,017which is decimal 15). Digits 0-7 allowed. - Hexadecimal: Prefix
0xor0X(e.g.,0xFFwhich is decimal 255,0x1a). Digits 0-9, a-f, A-F allowed.
Suffixes can specify the type:
Uoru: Unsigned (e.g.,100U,0xFU).Lorl: Long (e.g.,12345L,077L).LLorll: Long Long (C99) (e.g.,9876543210LL,1ULL).
Suffixes can be combined (e.g., 100UL, 50LLU). The case and order don’t matter (UL is same as lu).
Examples:
212 // int (decimal)215u // unsigned int0xFeeL // long int (hexadecimal)0123 // octal (decimal 83)123456789LL // long long int40000U // unsigned int
// Invalid Examples:// 078 // Error: 8 is not an octal digit// 032UU // Error: Cannot repeat U suffixFloating-Point Literals
Section titled “Floating-Point Literals”Represent real numbers with fractional parts. Can have an integer part, a decimal point, a fractional part, and an exponent part (using e or E).
Representation forms:
- Decimal form: Must include a decimal point, an exponent, or both (e.g.,
3.14159,123.,.456,1e5). - Exponential form: Integer/fractional part followed by
eorE, then an optionally signed exponent (e.g.,314159E-5L,1.23e+2).
Suffixes specify the type (default is double):
forF: float (e.g.,3.14f,1.0F,2.5e-3f).lorL: long double (e.g.,0.123456789L,1.2E+10L).
Examples:
3.14159 // double3.14f // float123.456L // long double1.0E6 // double (1 million)0.0 // double-1.23e-2f // float (-0.0123)
// Invalid Examples:// 510E // Incomplete exponent// 210f // No decimal point or exponent for float (needs 210.0f or similar)// .e55 // Missing integer or fractional part before exponentCharacter Literals
Section titled “Character Literals”Represent a single character, enclosed in single quotes (e.g., 'a', '%', '7'). They have an integer type (int).
Special characters can be represented using escape sequences:
| Escape Sequence | Meaning |
|---|---|
\\ | Backslash (\) character |
\' | Single quote (') character |
\" | Double quote (") character |
\? | Question mark (?) character |
\a | Alert (bell) |
\b | Backspace |
\f | Form feed |
\n | Newline (line feed) |
\r | Carriage return |
\t | Horizontal tab |
\v | Vertical tab |
\0 | Null character |
\ooo | Octal number (one to three digits) |
\xhh... | Hexadecimal number (one or more digits) |
Examples:
'A' // Plain character'\n' // Newline character'\t' // Tab character'\'' // Single quote character'\0' // Null character (integer value 0)'\x41' // Hexadecimal representation for 'A''\101' // Octal representation for 'A'String Literals
Section titled “String Literals”Represent a sequence of characters enclosed in double quotes (e.g., "Hello, World!"). They are stored as arrays of characters, automatically terminated by a null character (\0).
String literals can contain escape sequences. Long string literals can be broken across lines by ending a line with a backslash \ (the backslash and newline are ignored) or by concatenating adjacent string literals (the compiler combines them).
Examples (all represent the same string “Hello, dear”):
"Hello, dear"
"Hello, \dear"
"Hello, " "dear"Example containing escape sequences:
"First line\nSecond line\tIndented""Display a backslash: \\ and a double quote: \""Defining Named Constants
Section titled “Defining Named Constants”Using named constants makes code more readable and easier to modify. Two primary ways:
- Using the
#definepreprocessor directive. - Using the
constkeyword.
1. The #define Preprocessor
Section titled “1. The #define Preprocessor”Creates a macro that the preprocessor replaces with its value before compilation. It’s a simple text substitution.
#define PI 3.14159#define MAX_USERS 100#define GREETING "Welcome!"
// Usage:double circumference = 2 * PI * radius;if (user_count < MAX_USERS) { /* ... */ }printf("%s\n", GREETING);Conventionally, #define constant names are uppercase. Note: #define does not create typed variables; it’s pure text replacement.
2. The const Keyword
Section titled “2. The const Keyword”Declares a variable whose value cannot be changed after initialization. These are actual variables with types, providing better type safety than #define.
const type variable_name = value;Examples:
const double PI = 3.14159;const int MAX_USERS = 100;const char *GREETING = "Welcome!"; // Pointer to constant string
// Usage:double circumference = 2 * PI * radius;if (user_count < MAX_USERS) { /* ... */ }printf("%s\n", GREETING);
// Attempting to modify a const variable results in a compile-time error:// PI = 3.14; // ERROR!// MAX_USERS++; // ERROR!Best Practice: Prefer const variables over #define for defining named constants whenever possible, as they provide type checking and are integrated better into the language’s scoping rules.
C - Storage Classes
Section titled “C - Storage Classes”Storage class specifiers in C define the scope (visibility) and lifetime (duration) of variables and functions. They precede the data type in a declaration or definition.
The main storage class specifiers are:
autoregisterstaticextern
The auto Storage Class
Section titled “The auto Storage Class”auto is the default storage class for variables declared inside a function or block (local variables). It specifies automatic storage duration.
- Scope: Limited to the block where they are defined.
- Lifetime: Created when the block is entered, destroyed when the block is exited.
- Initialization: Not automatically initialized; hold undefined values unless explicitly initialized.
- Usage: Rarely used explicitly, as it’s the default for local variables.
{ int count; // Implicitly 'auto int count;' auto float sum = 0.0f; // Explicit 'auto', same effect}The register Storage Class
Section titled “The register Storage Class”register suggests to the compiler that a local variable should be stored in a CPU register for faster access, rather than in RAM.
- Scope & Lifetime: Same as
auto(local to the block, automatic duration). - Storage: Hint to use a register; the compiler is not obligated to honor it. Modern compilers often perform better register allocation automatically.
- Address: Cannot take the address (
&operator) of aregistervariable (as registers don’t have memory addresses). - Usage: Largely obsolete. Compilers usually do a better job optimizing. Historically used for frequently accessed variables like loop counters.
{ register int loop_counter; // Hint to use a register // Cannot do: &loop_counter}Because compilers ignore this hint often, its use is generally discouraged in modern C code.
The static Storage Class
Section titled “The static Storage Class”static has two main uses depending on context:
1. Inside a Function (Local Variables):
Section titled “1. Inside a Function (Local Variables):”- Scope: Limited to the block where defined (like
auto). - Lifetime: Static storage duration. The variable persists for the entire execution of the program. It retains its value between function calls.
- Initialization: Initialized only once (at compile time or first entry). If not explicitly initialized, defaults to zero (or
NULLfor pointers).
#include <stdio.h>
void counter_func(void) { static int call_count = 0; // Initialized only once call_count++; printf("Function called %d times.\n", call_count);}
int main(void) { counter_func(); // Output: Function called 1 times. counter_func(); // Output: Function called 2 times. counter_func(); // Output: Function called 3 times. return 0;}2. Outside a Function (Global Variables and Functions):
Section titled “2. Outside a Function (Global Variables and Functions):”- Scope: Restricts the visibility (linkage) of the global variable or function to the current source file (internal linkage). It cannot be accessed directly from other
.cfiles (even usingextern). - Lifetime: Static storage duration (persists for program execution).
- Initialization: Same as global variables (initialized to zero/NULL if not explicitly set).
// --- file1.c ---static int file_local_secret = 42; // Visible only within file1.c
static void internal_helper(void) { // Callable only within file1.c // ...}
void public_interface(void) { internal_helper(); file_local_secret++;}
// --- file2.c ---// extern int file_local_secret; // ERROR: file_local_secret has internal linkage// extern void internal_helper(void); // ERROR: internal_helper has internal linkage
extern void public_interface(void); // OK: public_interface has external linkage (default)
int main(void) { public_interface(); // Cannot access file_local_secret or internal_helper here return 0;}static is crucial for encapsulation in multi-file projects, hiding implementation details.
The extern Storage Class
Section titled “The extern Storage Class”extern is used to declare a global variable or function that is defined elsewhere (typically in another source file). It indicates external linkage.
- Purpose: Provides a reference to a global identifier defined in another module.
- Scope: Makes the global identifier visible in the current scope.
- Lifetime: Refers to a variable with static storage duration.
- Initialization: Cannot initialize an
externdeclaration (initialization happens at the definition).
// --- config.c ---#include <stdbool.h>const char* server_address = "192.168.1.100"; // Definitionbool logging_enabled = true; // Definition
// --- main.c ---#include <stdio.h>#include <stdbool.h>
// Declarations of variables defined in config.cextern const char* server_address;extern bool logging_enabled;
int main(void) { printf("Server: %s\n", server_address); if (logging_enabled) { printf("Logging is ON\n"); } return 0;}extern is fundamental for sharing global variables and functions across multiple source files in a C project.
C - Operators
Section titled “C - Operators”Operators are symbols that perform operations on variables and values (operands). C provides a rich set of operators.
Arithmetic Operators
Section titled “Arithmetic Operators”Perform mathematical calculations. Assume int A = 10; and int B = 20;
| Operator | Name | Description | Example |
|---|---|---|---|
+ | Addition | Adds two operands | A + B gives 30 |
- | Subtraction | Subtracts the second operand from the first | A - B gives -10 |
* | Multiplication | Multiplies both operands | A * B gives 200 |
/ | Division | Divides numerator by denominator. Integer division truncates remainder. | B / A gives 2. 10 / 3 gives 3. |
% | Modulus | Yields the remainder of an integer division. | B % A gives 0. 10 % 3 gives 1. |
++ | Increment | Increases integer value by one. Can be prefix (++A) or postfix (A++). | A++ evaluates to 10, then A becomes 11. ++A makes A become 11, then evaluates to 11. |
-- | Decrement | Decreases integer value by one. Can be prefix (--A) or postfix (A--). | A-- evaluates to 10, then A becomes 9. --A makes A become 9, then evaluates to 9. |
Relational Operators
Section titled “Relational Operators”Compare two operands and return a boolean result (1 for true, 0 for false). Assume int A = 10; and int B = 20;
| Operator | Name | Description | Example |
|---|---|---|---|
== | Equal to | Checks if values are equal. | (A == B) is false (0). |
!= | Not equal to | Checks if values are not equal. | (A != B) is true (1). |
> | Greater than | Checks if left operand is greater than right. | (A > B) is false (0). |
< | Less than | Checks if left operand is less than right. | (A < B) is true (1). |
>= | Greater than or equal to | Checks if left operand is greater than or equal to right. | (A >= B) is false (0). |
<= | Less than or equal to | Checks if left operand is less than or equal to right. | (A <= B) is true (1). |
Logical Operators
Section titled “Logical Operators”Combine or modify boolean expressions. Operands are typically treated as true if non-zero, false if zero. Assume int A = 1; (true) and int B = 0; (false).
| Operator | Name | Description | Example |
|---|---|---|---|
&& | Logical AND | True (1) if both operands are true (non-zero). | (A && B) is false (0). |
|| | Logical OR | True (1) if at least one operand is true (non-zero). | (A || B) is true (1). |
! | Logical NOT | Reverses the logical state: makes true false, and false true. | !(A && B) is true (1). !A is false (0). |
Logical AND (&&) and OR (||) perform short-circuit evaluation: If the result can be determined from the left operand, the right operand is not evaluated (e.g., in false && expression, expression is never evaluated).
Bitwise Operators
Section titled “Bitwise Operators”Perform operations directly on the binary (bit) representation of integer operands. Assume unsigned char A = 60; (0011 1100) and unsigned char B = 13; (0000 1101).
| Operator | Name | Description | Example (using 8 bits) |
|---|---|---|---|
& | Bitwise AND | Sets each bit to 1 if both corresponding bits are 1. | A & B gives 12 (0000 1100). |
| | Bitwise OR | Sets each bit to 1 if at least one corresponding bit is 1. | A | B gives 61 (0011 1101). |
^ | Bitwise XOR | Sets each bit to 1 if the corresponding bits are different. | A ^ B gives 49 (0011 0001). |
~ | Bitwise NOT (Ones’ Complement) | Flips all bits (0s become 1s, 1s become 0s). Unary. | ~A depends on size, for 8 bits: 1100 0011 (decimal 195 if unsigned, -61 if signed 2’s complement). |
<< | Left Shift | Shifts bits left, filling right with 0s. x << n is equivalent to x * 2^n. | A << 2 gives 240 (1111 0000). |
>> | Right Shift | Shifts bits right. For unsigned types, fills left with 0s (Logical Shift). For signed types, behavior is implementation-defined (can be logical or arithmetic shift - filling with sign bit). x >> n is approx x / 2^n. | A >> 2 gives 15 (0000 1111). |
Assignment Operators
Section titled “Assignment Operators”Assign values to variables.
| Operator | Name | Example |
|---|---|---|
= | Simple Assignment | Assigns value from right to left operand. |
+= | Add AND | C += A is shorthand for C = C + A |
-= | Subtract AND | C -= A is shorthand for C = C - A |
*= | Multiply AND | C *= A is shorthand for C = C * A |
/= | Divide AND | C /= A is shorthand for C = C / A |
%= | Modulus AND | C %= A is shorthand for C = C % A |
<<= | Left shift AND | C <<= 2 is shorthand for C = C << 2 |
>>= | Right shift AND | C >>= 2 is shorthand for C = C >> 2 |
&= | Bitwise AND AND | C &= 2 is shorthand for C = C & 2 |
^= | Bitwise XOR AND | C ^= 2 is shorthand for C = C ^ 2 |
|= | Bitwise OR AND | C |= 2 is shorthand for C = C | 2 |
Miscellaneous Operators
Section titled “Miscellaneous Operators”| Operator | Name | Description | Example |
|---|---|---|---|
sizeof | Sizeof operator | Returns the size (in bytes) of a data type or variable. Result type is size_t. | sizeof(int), sizeof(myVariable) |
& | Address-of operator | Returns the memory address of a variable. Unary. | &myVariable |
* | Dereference operator (Indirection) | Accesses the value stored at a memory address pointed to by a pointer. Unary. | *pointerVariable |
? : | Ternary conditional operator | Shorthand for if-else. condition ? value_if_true : value_if_false | max = (a > b) ? a : b; |
, | Comma operator | Evaluates expressions left-to-right, result is the value of the rightmost expression. Used often in for loops. | x=1, y=2, z=x+y (z becomes 3) |
Operator Precedence and Associativity
Section titled “Operator Precedence and Associativity”Precedence determines the order in which operators are evaluated in an expression (like multiplication before addition). Associativity determines the order for operators of the same precedence (e.g., left-to-right for addition/subtraction, right-to-left for assignment).
Highest precedence operators are evaluated first. Use parentheses () to override precedence or clarify order.
| Category | Operator | Associativity |
|---|---|---|
| Postfix | () [] -> . ++ -- | Left to right |
| Unary | + - ! ~ ++ -- (type)* & sizeof | Right to left |
| Multiplicative | * / % | Left to right |
| Additive | + - | Left to right |
| Shift | << >> | Left to right |
| Relational | < <= > >= | Left to right |
| Equality | == != | Left to right |
| Bitwise AND | & | Left to right |
| Bitwise XOR | ^ | Left to right |
| Bitwise OR | | | Left to right |
| Logical AND | && | Left to right |
| Logical OR | || | Left to right |
| Conditional | ?: | Right to left |
| Assignment | = += -= *= /= %= >>= <<= &= ^= |= | Right to left |
| Comma | , | Left to right |
Referencing a C operator precedence table online is common for complex expressions.
C - Decision Making
Section titled “C - Decision Making”Decision making allows a program to execute different blocks of code based on whether certain conditions are true or false. This enables programs to respond dynamically to different inputs or states.
The general flow of decision making involves evaluating a condition:
- Evaluate a condition (an expression that results in true or false).
- If the condition is true, execute a specific block of code.
- Optionally, if the condition is false, execute a different block of code (or do nothing).
- Continue with the rest of the program.
In C, any non-zero value is considered true, and zero is considered false. Relational and logical operators typically produce 1 for true and 0 for false.
C provides the following decision-making statements:
| Statement | Description |
|---|---|
if statement | Executes a block of code only if a specified condition is true. |
if...else statement | Executes one block of code if the condition is true, and another block if the condition is false. |
if...else if...else statement | Tests multiple conditions in sequence. Executes the block associated with the first true condition, or an optional else block if none are true. |
switch statement | Tests a variable against a list of constant values (cases). Executes the code block corresponding to the matching case. |
Nested if statements | Using one if or else if statement inside another. |
Nested switch statements | Using one switch statement inside another (less common). |
We will explore each of these in detail.
C - Loops
Section titled “C - Loops”Loops are used to execute a block of code repeatedly as long as a certain condition remains true. This avoids writing the same code multiple times.
Programming languages provide control structures for iteration (looping). Without loops, executing a task 100 times would require writing the code 100 times.
The general structure of a loop involves:
- Initialization: Setting up loop control variables (optional, often done before the loop).
- Condition Check: Evaluating a condition before (or sometimes after) each iteration.
- Loop Body: The block of code to be executed repeatedly.
- Update: Modifying the loop control variable after each iteration (to eventually make the condition false).
If the condition never becomes false, the loop runs forever (an infinite loop).
C provides the following loop types:
| Loop Type | Description |
|---|---|
while loop | Repeats the loop body as long as the condition is true. The condition is tested before each iteration. |
for loop | A compact loop structure often used when the number of iterations is known or easily determined. Includes initialization, condition testing, and update expressions in its header. |
do...while loop | Similar to while, but the condition is tested after the loop body executes. Guarantees the loop body runs at least once. |
| Nested loops | Placing one loop inside the body of another loop. |
Loop Control Statements
Section titled “Loop Control Statements”These statements alter the normal flow of execution within loops:
| Control Statement | Description |
|---|---|
break statement | Immediately terminates the innermost loop (for, while, do...while) or switch statement containing it. Execution continues with the statement following the terminated loop/switch. |
continue statement | Skips the rest of the current loop iteration and proceeds to the next iteration’s condition check (and update in for loops). |
goto statement | Transfers control unconditionally to a labeled statement within the same function. Use of goto is strongly discouraged in modern programming as it makes code hard to read, debug, and maintain. Use break, continue, or function calls instead. |
The Infinite Loop
Section titled “The Infinite Loop”A loop becomes infinite if its condition always evaluates to true. The for loop provides a common idiom for this:
#include <stdio.h>
int main(void) { // An infinite loop using the for construct for (;;) { // No initialization, no condition, no update printf("This loop will run forever... (Press Ctrl+C to stop)\n"); // Usually, some condition inside the loop triggers a 'break' // Or the program performs a continuous task (like a server) }
// This part is never reached return 0;}An empty condition in a for loop is implicitly treated as true. While while(1) also creates an infinite loop, for (;;) is a conventional and often preferred way to signify an intentional infinite loop in C.
You typically terminate an infinite loop externally (e.g., pressing Ctrl+C in the terminal) or by using a break statement inside the loop based on some internal condition.