0% found this document useful (0 votes)
4 views31 pages

C Programming

The document provides an in-depth explanation of the C programming language, covering essential topics such as variables, data types, I/O operations, operators, control flow statements, functions, and arrays. It emphasizes the importance of understanding these concepts for mastering C, detailing syntax, usage, and best practices. The document serves as a comprehensive guide for both beginners and experienced programmers looking to enhance their knowledge of C.

Uploaded by

bca.friends69
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views31 pages

C Programming

The document provides an in-depth explanation of the C programming language, covering essential topics such as variables, data types, I/O operations, operators, control flow statements, functions, and arrays. It emphasizes the importance of understanding these concepts for mastering C, detailing syntax, usage, and best practices. The document serves as a comprehensive guide for both beginners and experienced programmers looking to enhance their knowledge of C.

Uploaded by

bca.friends69
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 31

C Programming: In-Depth Explanation

C is a powerful, procedural programming language known for its


efficiency, low-level memory access, and use in system
programming, embedded systems, and game development.
Understanding these core concepts is fundamental to mastering C.

1. Variables and Data Types


Concept: Variables are named storage locations in memory that hold
data. Data types classify the kind of values a variable can hold and
determine the amount of memory allocated for it.
In-Depth:
• Variables:
o Declaration: dataType variableName; e.g., int age;
o Initialization: Assigning an initial value during declaration
or later. int age = 30; or float salary; salary = 50000.75;
o Naming Rules:
▪ Must start with a letter or underscore (_).
▪ Can contain letters, numbers, and underscores.
▪ Case-sensitive (age is different from Age).
▪ Cannot be a C keyword (e.g., int, for, while).
o Scope: The region of the program where a variable is
accessible.
▪ Local Variables: Declared inside a function or block.
Accessible only within that block. Their lifetime is
limited to the function's execution.
▪ Global Variables: Declared outside any function.
Accessible from anywhere in the program after their
declaration. Their lifetime is the entire program
execution.
▪ Static Variables:
▪ Local Static: Declared with static inside a
function. Retain their value between function
calls. Initialized only once.
▪ Global Static: Declared with static outside a
function. Their scope is limited to the file in
which they are declared (internal linkage).
• Data Types:
o Primary (Built-in) Data Types:
▪ int: Used for whole numbers (integers). Typically 2
or 4 bytes.
▪ short int: Smaller range, usually 2 bytes.
▪ long int: Larger range, usually 4 or 8 bytes.
▪ long long int: Even larger range, usually 8
bytes.
▪ unsigned int: Stores only non-negative values.
Doubles the positive range.
▪ float: Used for single-precision floating-point
numbers (numbers with decimal points). Typically 4
bytes.
▪ double: Used for double-precision floating-point
numbers. More precision than float, typically 8
bytes.
▪ char: Used for single characters. Stores ASCII values.
Typically 1 byte.
▪ signed char: Can store negative character
values (rarely used).
▪ unsigned char: Stores positive character values
(0-255).
▪ _Bool (or bool with <stdbool.h>): Used for boolean
values (true/false).
▪ void: An incomplete type. Cannot declare variables
of type void. Used for:
▪ Functions that don't return a value (void
func()).
▪ Generic pointers (void *ptr).
▪ Functions that take no arguments (int
func(void)).
o Derived Data Types: Arrays, Pointers, Structures, Unions
(discussed in later sections).
o sizeof Operator: Used to determine the size in bytes of a
data type or variable. printf("%zu\n", sizeof(int));

2. I/O Operations (Input/Output)


Concept: How a program interacts with the outside world, primarily
taking input from the user (keyboard) and displaying output (screen).
In-Depth:
• Standard I/O Library (<stdio.h>): The primary header for I/O
functions.
o printf():
▪ Purpose: Formatted output to the standard output
(console).
▪ Syntax: int printf(const char *format, ...);
▪ Format Specifiers:
▪ %d or %i: int
▪ %f: float
▪ %lf: double
▪ %c: char
▪ %s: String (array of characters)
▪ %p: Pointer address
▪ %u: unsigned int
▪ %x or %X: Hexadecimal
▪ %o: Octal
▪ Escape Sequences:
▪ \n: Newline
▪ \t: Tab
▪ \\: Backslash
▪ \": Double quote
▪ \': Single quote
▪ \b: Backspace
▪ \r: Carriage return
▪ Field Width & Precision: printf("%10.2f", 123.456);
(10 total width, 2 decimal places)
o scanf():
▪ Purpose: Formatted input from the standard input
(keyboard).
▪ Syntax: int scanf(const char *format, ...);
▪ Important: Requires the address of the variable
using the & operator (address-of operator).
▪ Example: scanf("%d", &age); scanf("%f %c",
&temperature, &unit);
▪ Return Value: Returns the number of items
successfully read. Returns EOF (End-Of-File) on error
or end of input.
▪ Common Issues: Leaves newline characters in the
input buffer, which can cause issues with
subsequent scanf("%c", ...) or fgets().
▪ Solution: Consume the newline:
scanf("%d%*c", &num); or getchar(); after
scanf().
o Character I/O:
▪ getchar(): Reads a single character from standard
input. Returns an int to accommodate EOF.
▪ putchar(): Writes a single character to standard
output.
o String I/O:
▪ gets() (Deprecated/Unsafe): Reads a line of text
until a newline. No buffer overflow check. AVOID.
▪ fgets() (Recommended for strings): Reads at most
n-1 characters or until a newline. Safer as it takes
buffer size as an argument.
▪ char str[100]; fgets(str, sizeof(str), stdin);
▪ fgets() includes the newline character if it fits
in the buffer. You might need to remove it.
▪ puts(): Writes a string to standard output,
automatically adds a newline.

3. Operators and Expressions


Concept: Operators are symbols that perform operations on
variables and values. Expressions are combinations of operators,
variables, and constants that evaluate to a single value.
In-Depth:
• Arithmetic Operators: Perform mathematical calculations.
o + (Addition)
o - (Subtraction)
o * (Multiplication)
o / (Division): Integer division truncates the decimal part if
both operands are integers.
o % (Modulo): Returns the remainder of an integer division.
• Relational Operators: Compare two operands and return 1
(true) or 0 (false).
o == (Equal to)
o != (Not equal to)
o > (Greater than)
o < (Less than)
o >= (Greater than or equal to)
o <= (Less than or equal to)
• Logical Operators: Combine or modify boolean expressions.
o && (Logical AND): Returns true if both operands are true.
Short-circuits (if first is false, second isn't evaluated).
o || (Logical OR): Returns true if at least one operand is
true. Short-circuits (if first is true, second isn't evaluated).
o ! (Logical NOT): Inverts the boolean value of an operand.
• Bitwise Operators: Perform operations on individual bits of
integer operands.
o & (Bitwise AND)
o | (Bitwise OR)
o ^ (Bitwise XOR)
o ~ (Bitwise NOT/One's Complement)
o << (Left Shift): Multiplies by powers of 2.
o >> (Right Shift): Divides by powers of 2.
• Assignment Operators: Assign a value to a variable.
o = (Simple assignment)
o += (Add and assign): a += b; is a = a + b;
o -= (Subtract and assign)
o *= (Multiply and assign)
o /= (Divide and assign)
o %= (Modulo and assign)
o &=, |=, ^=, <<=, >>= (Compound assignment for bitwise)
• Increment/Decrement Operators:
o ++ (Increment): Adds 1 to the operand.
▪ Prefix: ++a (increments then uses the value).
▪ Postfix: a++ (uses the value then increments).
o -- (Decrement): Subtracts 1 from the operand.
▪ Prefix: --a (decrements then uses the value).
▪ Postfix: a-- (uses the value then decrements).
• Conditional (Ternary) Operator:
o condition ? expression_if_true : expression_if_false;
o A concise way to write simple if-else statements.
• sizeof Operator: Returns the size of a variable or data type in
bytes.
• Comma Operator (,): Evaluates expressions from left to right
and returns the value of the rightmost expression. Often used
in for loops.
• Type Casting Operator: Converts a value from one data type to
another.
o int x = (int)3.14;
o Implicit casting occurs automatically (e.g., int to float).
o Explicit casting is done by the programmer.
• Operator Precedence and Associativity:
o Precedence: Determines the order in which operators are
evaluated (e.g., * and / have higher precedence than +
and -). Parentheses () override precedence.
o Associativity: Determines the order of evaluation for
operators with the same precedence (e.g., left-to-right for
arithmetic, right-to-left for assignment).

4. Control Flow Statements


Concept: Statements that control the order in which instructions are
executed in a program.
In-Depth:
• Decision Making Statements (Conditional Statements):
o if statement: Executes a block of code if a condition is
true.
C
if (condition) {
// code to execute if condition is true
}
o if-else statement: Executes one block if true, another if
false.
C
if (condition) {
// code if true
} else {
// code if false
}
o if-else if-else ladder: Checks multiple conditions
sequentially.
C
if (condition1) {
// code if condition1 is true
} else if (condition2) {
// code if condition2 is true
} else {
// code if no condition is true
}
o switch statement: Allows selection among many
alternatives based on the value of an expression.
C
switch (expression) {
case value1:
// code for value1
break; // Important: exits the switch
case value2:
// code for value2
break;
default:
// code if no match
}
▪ break is crucial to prevent "fall-through" to the next
case.
▪ default is optional.
• Looping Statements (Iterative Statements): Execute a block of
code repeatedly.
o for loop: Used when the number of iterations is known or
can be easily determined.
C
for (initialization; condition; update) {
// code to repeat
}
▪ Initialization: Executed once at the beginning.
▪ Condition: Evaluated before each iteration. Loop
continues as long as true.
▪ Update: Executed after each iteration.
o while loop: Used when the number of iterations is not
known beforehand, and the loop continues as long as a
condition is true.
C
while (condition) {
// code to repeat
// update condition
}
▪ The condition is checked before the first iteration. If
false initially, the loop body never executes.
o do-while loop: Similar to while, but the loop body is
executed at least once before the condition is checked.
C
do {
// code to repeat
// update condition
} while (condition);
• Jump Statements: Alter the normal flow of execution.
o break: Terminates the innermost loop or switch
statement immediately. Control passes to the statement
immediately following the loop/switch.
o continue: Skips the rest of the current iteration of the
loop and proceeds to the next iteration.
o goto: Transfers control unconditionally to a labeled
statement. Generally discouraged as it can lead to
unstructured and hard-to-read "spaghetti code." Use only
in very specific, justified cases (e.g., breaking out of
nested loops).
C
goto label;
// ...
label:
// code here
o return: Terminates the execution of the current function
and returns control to the caller. Can return a value.

5. Functions
Concept: A self-contained block of code that performs a specific task.
Functions promote modularity, reusability, and easier debugging.
In-Depth:
• Advantages of Functions:
o Modularity: Break down a large program into smaller,
manageable units.
o Reusability: Call the same function multiple times from
different parts of the program.
o Abstraction: Hide implementation details from the user.
o Easier Debugging: Isolate problems to specific functions.
• Function Components:
o Function Declaration (Prototype): Tells the compiler
about the function's name, return type, and parameters
before its definition. Usually placed at the top of the file
or in a header file. returnType
functionName(parameter1Type param1Name,
parameter2Type param2Name, ...); Example: int add(int
a, int b);
o Function Definition: Contains the actual code (body) of
the function.
C
returnType functionName(parameter1Type param1Name,
parameter2Type param2Name, ...) {
// function body
// ...
return value; // if returnType is not void
}
o Function Call: Invoking the function to execute its code.
result = functionName(argument1, argument2);
• Function Parameters and Arguments:
o Parameters: Variables declared in the function's
definition that receive values from the caller.
o Arguments: Actual values passed to the function when it's
called.
• Types of Functions:
o Library Functions: Pre-defined functions available in C's
standard library (e.g., printf, scanf, sqrt).
o User-Defined Functions: Functions created by the
programmer.
• Call by Value vs. Call by Reference:
o Call by Value: A copy of the argument's value is passed to
the function. Changes made to the parameter inside the
function do not affect the original argument in the caller.
This is the default in C.
o Call by Reference (using Pointers): The memory address
of the argument is passed to the function. Changes made
to the value at that address do affect the original
argument in the caller. Achieved using pointers.
• Return Type:
o The data type of the value the function sends back to the
caller.
o void if the function does not return any value.
o A function can only return one value directly.
• Recursion: A function calling itself. Used for problems that can
be broken down into smaller, similar subproblems (e.g.,
factorial, Fibonacci series).
o Base Case: Essential to stop the recursion and prevent
infinite loops.
o Recursive Step: The function calls itself with a modified
argument.

6. Array
Concept: A collection of elements of the same data type, stored in
contiguous memory locations, and accessed using a single name and
an index.
In-Depth:
• Declaration: dataType arrayName[size];
o int numbers[10]; (declares an array numbers that can
hold 10 integers)
• Initialization:
o During declaration: int arr[] = {10, 20, 30, 40, 50}; (size is
automatically determined)
o Partial initialization: int arr[5] = {10, 20}; (remaining
elements initialized to 0)
o After declaration (element by element): arr[0] = 100;
arr[1] = 200;
• Accessing Elements:
o Using an index (subscript), starting from 0.
o arrayName[index]
o int thirdElement = numbers[2]; (accesses the 3rd
element)
o Array Out-of-Bounds Access: A common error. C does not
perform bounds checking. Accessing elements outside the
declared range can lead to undefined behavior (crashes,
corrupted data).
• Memory Layout: Elements are stored sequentially in memory.
numbers[0] is followed by numbers[1], and so on.
• Arrays and Pointers:
o The name of an array (without brackets) is a constant
pointer to its first element. int *ptr = numbers;
o numbers[i] is equivalent to *(numbers + i).
o Pointer arithmetic can be used to traverse arrays.
• Multidimensional Arrays: Arrays of arrays. Common for
matrices (2D arrays).
o Declaration: dataType arrayName[rowSize][colSize]; int
matrix[3][4]; (3 rows, 4 columns)
o Initialization: int matrix[2][3] = {{1,2,3}, {4,5,6}};
o Accessing: matrix[row_index][col_index]
o Memory layout for 2D arrays is row-major order (all
elements of the first row, then second, etc.).
• Passing Arrays to Functions:
o Arrays are always passed by reference (decay to a pointer
to their first element).
o The size of the array is lost when passed to a function;
you usually pass the size as a separate argument.
o void printArray(int arr[], int size); or void printArray(int
*arr, int size);

7. Pointers
Concept: A variable that stores the memory address of another
variable. Pointers provide direct memory access, enabling powerful
and efficient programming, but also introduce complexity and
potential for errors.
In-Depth:
• Declaration: dataType *pointerName;
o int *ptr; (declares a pointer ptr that can hold the address
of an int)
• Initialization:
o int x = 10;
o int *ptr = &x; (assigns the address of x to ptr using the &
(address-of) operator)
• Dereferencing (Indirection):
o Using the * operator (dereference operator) to access the
value stored at the address pointed to by the pointer.
o int value = *ptr; ( value will be 10)
o You can also modify the value using dereferencing: *ptr =
20; (now x is 20)
• NULL Pointer:
o A pointer that doesn't point to any valid memory location.
o int *ptr = NULL;
o Important to initialize pointers to NULL to avoid "wild
pointers" (uninitialized pointers pointing to arbitrary
memory).
o Always check for NULL before dereferencing a pointer to
prevent segmentation faults.
• Pointer Arithmetic:
o Pointers can be incremented (++), decremented (--),
added to an integer (+), or subtracted from an integer (-).
o The arithmetic is scaled by the size of the data type the
pointer points to.
▪ If ptr points to an int (4 bytes), ptr++ will increment
ptr by 4 bytes.
o Subtraction of two pointers (of the same type) yields the
number of elements between them.
• Pointers and Arrays: As discussed, array names are constant
pointers to their first element. Pointers are often used to
traverse arrays efficiently.
• Pointers and Functions:
o Used for "Call by Reference" to modify arguments in the
caller's scope.
o Returning multiple values from a function (by passing
addresses of variables).
o Passing arrays to functions.
• Pointers to Pointers (Double Pointers):
o A pointer that stores the address of another pointer.
o int **ptr_to_ptr;
o Used for dynamic 2D arrays, or when a function needs to
modify a pointer itself.
• void Pointers (Generic Pointers):
o A pointer that can point to any data type.
o void *genericPtr;
o Cannot be dereferenced directly; must be type-casted
before dereferencing.
o Used for generic functions that operate on different data
types (e.g., malloc, memcpy).
• Dynamic Memory Allocation:
o Using functions from <stdlib.h> to allocate and deallocate
memory at runtime.
o malloc(): Allocates a block of memory of a specified size
and returns a void pointer to the beginning of the block.
int *arr = (int *)malloc(5 * sizeof(int));
o calloc(): Allocates a block of memory and initializes all
bytes to zero. Takes two arguments: number of elements
and size of each element. int *arr = (int *)calloc(5,
sizeof(int));
o realloc(): Resizes an already allocated block of memory.
arr = (int *)realloc(arr, 10 * sizeof(int));
o free(): Deallocates memory previously allocated by
malloc, calloc, or realloc. Crucial to prevent memory
leaks. free(arr); arr = NULL; (set to NULL after freeing to
avoid dangling pointers)
• Dangling Pointers: Pointers that point to a memory location
that has been deallocated or freed. Dereferencing them leads
to undefined behavior.
• Memory Leaks: Occur when dynamically allocated memory is
no longer accessible (e.g., the pointer to it is lost) but has not
been freed. This wastes memory.

8. String Handling
Concept: In C, strings are arrays of characters terminated by a null
character (\0). This null terminator is crucial for functions to
determine the end of the string.
In-Depth:
• Declaration and Initialization:
o char str[20]; (declares a character array of size 20)
o char name[] = "John Doe"; (size is determined by the
length of the string + 1 for \0)
o char greeting[10] = {'H', 'e', 'l', 'l', 'o', '\0'}; (explicit null
termination)
o char message[5] = "Hi!"; (implicitly adds \0)
o Important: Make sure the array size is sufficient to hold
the string and the null terminator.
• String Input/Output:
o scanf("%s", str);: Reads a sequence of non-whitespace
characters until whitespace or EOF is encountered.
Unsafe: Prone to buffer overflow if input is larger than
array size. Does not read spaces.
o fgets(str, size, stdin);: Recommended for safe string
input. Reads up to size-1 characters or until a newline or
EOF. Includes the newline character if present and fits.
o gets(): NEVER USE. Highly unsafe.
o printf("%s", str);: Prints the string until the null
terminator is reached.
o puts(str);: Prints the string and automatically adds a
newline.
• String Library Functions (<string.h>):
o strlen(const char *str);: Returns the length of the string
(number of characters before the null terminator).
o strcpy(char *dest, const char *src);: Copies the src string
to the dest string. Unsafe if dest buffer is too small.
o strncpy(char *dest, const char *src, size_t n);: Copies at
most n characters from src to dest. Safer, but dest might
not be null-terminated if src is longer than n. Always
manually null-terminate if n characters are copied.
strncpy(dest, src, sizeof(dest) - 1); dest[sizeof(dest) - 1] =
'\0';
o strcat(char *dest, const char *src);: Concatenates src to
the end of dest. Unsafe if dest buffer is too small.
o strncat(char *dest, const char *src, size_t n);:
Concatenates at most n characters from src to the end of
dest. Safer.
o strcmp(const char *str1, const char *str2);: Compares
two strings lexicographically.
▪ Returns 0 if str1 is equal to str2.
▪ Returns a negative value if str1 comes before str2.
▪ Returns a positive value if str1 comes after str2.
o strncmp(const char *str1, const char *str2, size_t n);:
Compares at most n characters of two strings.
o strchr(const char *str, int c);: Finds the first occurrence of
character c in str. Returns a pointer to the character or
NULL.
o strstr(const char *haystack, const char *needle);: Finds
the first occurrence of substring needle in haystack.
Returns a pointer to the first character of the found
substring or NULL.

9. Structures and Unions


Concept:
• Structures (struct): User-defined data types that allow grouping
together variables of different data types under a single name.
They are used to represent a record.
• Unions (union): User-defined data types that allow storing
different data types in the same memory location. Only one
member can hold a value at any given time.
In-Depth:
• Structures (struct):
o Declaration:
C
struct structName {
dataType member1;
dataType member2;
// ...
};
Example:
C
struct Student {
int rollNo;
char name[50];
float marks;
};
o Creating Structure Variables:
▪ struct Student s1;
▪ struct Student s2 = {101, "Alice", 85.5}; (designated
initializers also possible: {.rollNo = 102, .name =
"Bob"})
▪ Anonymous structures (without structName):
Directly define and declare variables.
o Accessing Members:
▪ Dot operator (.): For accessing members of a
structure variable. s1.rollNo = 1; printf("%s\n",
s2.name);
▪ Arrow operator (->): For accessing members
through a pointer to a structure.
C
struct Student *ptrS = &s1;
ptrS->rollNo = 2; // Equivalent to (*ptrS).rollNo = 2;
o Nested Structures: A structure can contain another
structure as a member.
o Self-Referential Structures: Structures that contain a
pointer to another structure of the same type (e.g., for
linked lists, trees).
o Size of Structure: sizeof(structName) usually returns the
sum of sizes of its members, but due to padding (compiler
adds empty bytes to align members on memory
boundaries for performance), it might be slightly larger.
• Unions (union):
o Declaration:
C
union unionName {
dataType member1;
dataType member2;
// ...
};
Example:
C
union Data {
int i;
float f;
char str[20];
};
o Creating Union Variables: union Data d1;
o Accessing Members: Same as structures (. and ->).
o Key Feature: All members of a union share the same
memory location. The size of a union is determined by the
size of its largest member.
o Usage: Only one member can hold a valid value at any
given time. If you assign a value to one member, and then
to another, the first value is overwritten.
o Common Use Cases:
▪ Memory-efficient data storage where only one data
type is needed at a time.
▪ Representing different data types for the same
concept (e.g., a variant type).
▪ Low-level programming (e.g., working with
hardware registers).

10. File Handling


Concept: How C programs interact with files on a storage device
(hard disk, SSD). This allows programs to persist data beyond their
execution.
In-Depth:
• File Pointer (FILE *): A special pointer (declared in <stdio.h>)
used to manage a file. It points to a structure that contains
information about the file (e.g., current position, mode). FILE
*fp;
• Opening a File (fopen()):
o fp = fopen("filename.txt", "mode");
o Modes:
▪ "r": Read mode. File must exist.
▪ "w": Write mode. Creates a new file. If file exists, its
content is truncated (overwritten).
▪ "a": Append mode. Creates a new file if it doesn't
exist. If it exists, data is written to the end.
▪ "r+": Read and write. File must exist.
▪ "w+": Read and write. Creates a new file. If file
exists, its content is truncated.
▪ "a+": Read and write. Creates a new file if it doesn't
exist. If it exists, data is appended to the end.
o Binary Modes (add b): rb, wb, ab, rb+, wb+, ab+. Used for
non-textual data.
• Closing a File (fclose()):
o fclose(fp);
o Crucial: Flushes buffers and releases file resources. Failure
to close files can lead to data loss or resource leaks.
o Returns 0 on success, EOF on error.
• Writing to a File:
o fputc(char_to_write, fp);: Writes a single character.
o fputs(string_to_write, fp);: Writes a string. (Does not add
newline).
o fprintf(fp, "format", ...);: Formatted output to file (like
printf).
o fwrite(void *ptr, size_t size, size_t nmemb, FILE *fp);:
Writes nmemb items, each of size bytes, from the
memory location pointed to by ptr. Used for binary data.
• Reading from a File:
o fgetc(fp);: Reads a single character. Returns EOF on end of
file or error.
o fgets(buffer, size, fp);: Reads a line from the file into
buffer (up to size-1 characters or until newline/EOF).
o fscanf(fp, "format", ...);: Formatted input from file (like
scanf).
o fread(void *ptr, size_t size, size_t nmemb, FILE *fp);:
Reads nmemb items, each of size bytes, into the memory
location pointed to by ptr. Used for binary data.
• Error Handling and End-of-File:
o feof(fp);: Returns non-zero if the end-of-file indicator is
set for fp.
o ferror(fp);: Returns non-zero if the error indicator is set
for fp.
o Check fopen return value: It returns NULL on failure.
C
fp = fopen("data.txt", "r");
if (fp == NULL) {
perror("Error opening file"); // Prints system error message
exit(EXIT_FAILURE);
}
• Random Access File Functions:
o fseek(fp, offset, origin);: Moves the file pointer to a
specific position.
▪ offset: Number of bytes to move.
▪ origin: SEEK_SET (beginning of file), SEEK_CUR
(current position), SEEK_END (end of file).
o ftell(fp);: Returns the current position of the file pointer
(offset from the beginning).
o rewind(fp);: Sets the file pointer to the beginning of the
file.

11. Pre-Processor Directives


Concept: Instructions to the C preprocessor, which is a program that
processes the source code before it is passed to the compiler.
Preprocessor directives begin with a # symbol.
In-Depth:
• Macro Inclusion (#include):
o #include <filename>: Used for standard library header
files (e.g., <stdio.h>, <stdlib.h>). The preprocessor
searches in standard system directories.
o #include "filename": Used for user-defined header files.
The preprocessor searches in the current directory first,
then in standard directories.
o Purpose: Inserts the content of the specified file into the
current source file. This allows functions, macros, and
declarations to be shared across multiple source files.
• Macro Definitions (#define):
o Object-like Macros: Defines a symbolic constant.
Replaces all occurrences of MACRO_NAME with
replacement_text literally before compilation. #define PI
3.14159 #define MAX_SIZE 100
▪ No semicolon at the end.
▪ Avoid using = sign.
o Function-like Macros: Defines a macro that behaves like a
function. Can take arguments. #define SQUARE(x) ((x) *
(x))
▪ Important: Use parentheses around arguments (x)
and the entire expression ((x) * (x)) to avoid
unexpected behavior due to operator precedence
issues when the macro is expanded.
▪ Macros perform text substitution; they are not
functions. They can lead to side effects if arguments
involve increment/decrement operators (e.g.,
SQUARE(i++)).
• Conditional Compilation (#if, #ifdef, #ifndef, #else, #elif,
#endif):
o Allows parts of the code to be compiled only if certain
conditions are met. Useful for:
▪ Debugging (e.g., #ifdef DEBUG).
▪ Platform-specific code.
▪ Preventing multiple inclusions of header files.
o #if constant_expression: Compiles if constant_expression
evaluates to non-zero (true).
o #ifdef MACRO_NAME: Compiles if MACRO_NAME is
defined.
o #ifndef MACRO_NAME: Compiles if MACRO_NAME is not
defined.
o #else: Provides an alternative block if the preceding
#if/#ifdef/#ifndef condition is false.
o #elif constant_expression: "Else if" for conditional
compilation.
o #endif: Marks the end of a conditional compilation block.
o Example for Header Guard:
C
#ifndef MY_HEADER_H
#define MY_HEADER_H

// Header file content (declarations, macros, etc.)

#endif
• Other Directives:
o #undef MACRO_NAME: Undefines a previously defined
macro.
o #error "error message": Causes the preprocessor to issue
an error and stop compilation.
o #pragma: Provides compiler-specific instructions (e.g., to
suppress warnings, control optimization). Highly compiler-
dependent.

12. Command Line Arguments


Concept: Allows you to pass information to your C program when
you run it from the command line. This makes programs more
flexible as their behavior can be modified without recompiling.
In-Depth:
• main() Function Signature: To accept command-line
arguments, the main function needs two parameters: int
main(int argc, char *argv[]) or equivalently: int main(int argc,
char **argv)
• argc (Argument Count):
o An integer that stores the number of command-line
arguments.
o It always includes the name of the executable itself. So, if
you run ./myprogram, argc will be at least 1.
• argv (Argument Vector):
o An array of pointers to character arrays (strings).
o Each element argv[i] is a string representing one
command-line argument.
o argv[0] is always the name of the executable program.
o argv[1] is the first argument provided after the program
name.
o argv[2] is the second argument, and so on.
o The last element argv[argc-1] is the last argument.
o argv[argc] is guaranteed to be NULL.
• Example: If you compile myprogram.c into myprogram and run
it like this: ./myprogram hello world 123
Inside main():
o argc will be 4.
o argv[0] will point to the string "./myprogram"
o argv[1] will point to the string "hello"
o argv[2] will point to the string "world"
o argv[3] will point to the string "123"
• Parsing Arguments:
o Command-line arguments are always read as strings.
o If you need to use them as numbers, you must convert
them using functions from <stdlib.h>:
▪ atoi(): Converts string to int.
▪ atol(): Converts string to long int.
▪ atof(): Converts string to double.
▪ strtol(), strtod(), strtoul(): More robust conversion
functions that allow error checking and handle
various bases. These are generally preferred for
production code.
• Typical Use Cases:
o Providing input filenames (./myprogram input.txt
output.txt).
o Passing configuration options (./myprogram --verbose -o
results.log).
o Specifying parameters for algorithms.

You might also like