C Programming Language
C is a general-purpose, procedural programming language developed in 1972 by Dennis Ritchie at Bell Labs. Known for its efficiency and control, it remains a cornerstone of modern programming, influencing languages like C++, Java, and Python. C is widely used in operating systems, embedded systems, and high-performance applications.
Origin
Developed between 1969-1973 at Bell Labs to rewrite the Unix operating system, replacing assembly language for better portability.
Features
Low-level memory access, minimal runtime, simple syntax, structured programming, and portability across platforms.
Limitations
Lacks object-oriented programming, no built-in exception handling, manual memory management, and no native support for namespaces.
Why Learn C?
- Foundation for understanding modern programming languages
- Critical for operating systems, embedded systems, and device drivers
- Teaches memory management and low-level system concepts
- Offers fast execution and efficient resource usage
- Standard for competitive programming and technical interviews
Did You Know?
C was created to rewrite the Unix operating system, making it one of the first portable OS kernels. Its influence extends to nearly all modern operating systems.
Getting Started with C
Basic Structure
#include // Standard I/O library
int main() { // Main function where execution begins
printf("Hello, World!\n");
return 0; // Indicates successful execution
}
Every C program requires a main() function as the entry point. The #include directive imports header files for standard library functions.
Compilation Process
- Preprocessing: Expands macros and includes header files
- Compilation: Converts C code to assembly code
- Assembly: Translates assembly to machine code (object file)
- Linking: Combines object files into an executable
gcc program.c -o program
Compile with GCC to create an executable named 'program'
Data Types in C
Basic Data Types
| Type | Size (bytes) | Range | Format Specifier |
|---|---|---|---|
| char | 1 | -128 to 127 | %c |
| int | 2 or 4 | -32,768 to 32,767 (2 bytes) or -2,147,483,648 to 2,147,483,647 (4 bytes) | %d |
| float | 4 | 1.2E-38 to 3.4E+38 | %f |
| double | 8 | 2.3E-308 to 1.7E+308 | %lf |
Example:
#include
int main() {
char grade = 'A';
int age = 25;
float height = 5.9;
double salary = 75000.50;
printf("Grade: %c\n", grade);
printf("Age: %d\n", age);
printf("Height: %.1f\n", height);
printf("Salary: %.2lf\n", salary);
return 0;
}
Type Modifiers
signed- Stores positive and negative values (default)unsigned- Stores only positive values, doubling positive rangeshort- Reduces storage size for smaller rangelong- Increases storage size for larger range
unsigned int positiveOnly = 40000;
short int smallNumber = 100;
long int bigNumber = 1234567890;
Derived Data Types
Arrays- Collection of elements of the same typePointers- Store memory addressesStructures- Group different data typesUnions- Share memory for different data types
int numbers[5]; // Array
int *ptr; // Pointer
struct student { // Structure
char name[50];
int age;
};
union data { // Union
int i;
float f;
};
Variables & Constants
Variables
Variables are named storage locations for data. They must be declared with a data type before use.
Rules for Naming Variables:
- Can contain letters, digits, and underscores
- Must begin with a letter or underscore
- Case-sensitive (age ≠ Age ≠ AGE)
- Cannot use reserved keywords (e.g., int, float)
int age = 25; // Integer variable
float price = 19.99; // Floating point
char letter = 'A'; // Character
int x, y, z; // Multiple declarations
x = y = z = 50; // Same value to multiple variables
Constants
Constants are fixed values that cannot be modified during program execution.
Types of Constants:
- Literal Constants: Direct values like 100, 3.14, 'A'
- #define Preprocessor:
#define PI 3.14159 - const Keyword:
const float PI = 3.14159;
#include
#define PI 3.14159 // Macro constant
int main() {
const int DAYS = 7; // const keyword
printf("PI: %.5f\n", PI);
printf("Days in week: %d\n", DAYS);
return 0;
}
Input & Output in C
printf() - Output Function
The printf() function outputs formatted data to the console (stdout).
Format Specifiers:
%d- Integer%f- Float%c- Character%s- String%lf- Double%x- Hexadecimal
#include
int main() {
int num = 10;
float fnum = 3.14;
char letter = 'A';
printf("Integer: %d\n", num);
printf("Float: %.2f\n", fnum); // 2 decimal places
printf("Character: %c\n", letter);
printf("All together: %d, %.2f, %c\n", num, fnum, letter);
return 0;
}
scanf() - Input Function
The scanf() function reads formatted input from the keyboard (stdin).
Important Notes:
- Requires address-of operator (&) for non-array variables
- Strings (char arrays) don't need &
- Beware of buffer overflow with strings; use width specifiers
#include
int main() {
int age;
float height;
char name[50];
printf("Enter your age: ");
scanf("%d", &age);
printf("Enter your height: ");
scanf("%f", &height);
printf("Enter your name: ");
scanf("%49s", name); // Limit input to prevent overflow
printf("\nName: %s\nAge: %d\nHeight: %.1f\n",
name, age, height);
return 0;
}
Other I/O Functions
getchar() & putchar()
Single character input/output
char c = getchar();
putchar(c);
gets() & puts()
String I/O (unsafe - use fgets() instead)
char str[100];
gets(str); // Deprecated, unsafe
puts(str);
fgets() & fputs()
Safe string input/output
char str[100];
fgets(str, 100, stdin);
fputs(str, stdout);
Operators in C
Arithmetic Operators
| Operator | Description | Example | Result |
|---|---|---|---|
| + | Addition | 5 + 2 | 7 |
| - | Subtraction | 5 - 2 | 3 |
| * | Multiplication | 5 * 2 | 10 |
| / | Division | 5 / 2 | 2 (integer division) |
| % | Modulus | 5 % 2 | 1 |
#include
int main() {
int a = 10, b = 3;
printf("Sum: %d\n", a + b);
printf("Difference: %d\n", a - b);
printf("Product: %d\n", a * b);
printf("Quotient: %d\n", a / b);
printf("Remainder: %d\n", a % b);
return 0;
}
Relational Operators
Compare values, returning 1 (true) or 0 (false)
==Equal to!=Not equal>Greater than<Less than>=Greater or equal<=Less or equal
int x = 5, y = 10;
printf("%d\n", x > y); // 0 (false)
Logical Operators
Combine multiple conditions
&&AND (both true)||OR (either true)!NOT (reverses result)
int age = 25, salary = 50000;
if (age > 21 && salary > 30000) {
printf("Eligible for loan\n");
}
Bitwise Operators
Operate on individual bits
&AND|OR^XOR~NOT<<Left shift>>Right shift
unsigned char a = 5; // 00000101
unsigned char b = 9; // 00001001
printf("%d\n", a & b); // 00000001 → 1
Assignment Operators
Assign values to variables
=Simple assignment+=Add and assign-=Subtract and assign*=Multiply and assign/=Divide and assign%=Modulus and assign
int x = 10;
x += 5; // x = x + 5 → 15
x *= 2; // x = x * 2 → 30
Other Operators
?:Ternary operator (conditional)sizeof()Returns size in bytes&Address of operator*Pointer dereference,Comma operator
int a = 5, b = 10;
int max = (a > b) ? a : b; // Ternary
printf("%zu\n", sizeof(int)); // Sizeof
int *ptr = &a; // Address
printf("%d\n", *ptr); // Dereference
Control Flow Statements
if-else Statements
Execute code based on conditions
Syntax:
if (condition1) {
// code if condition1 true
} else if (condition2) {
// code if condition2 true
} else {
// code if all false
}
Example:
#include
int main() {
int num = 10;
if (num > 0) {
printf("Positive\n");
} else if (num < 0) {
printf("Negative\n");
} else {
printf("Zero\n");
}
return 0;
}
switch Statement
Multi-way branch based on a value
Syntax:
switch (expression) {
case constant1:
// code
break;
case constant2:
// code
break;
default:
// code if no match
}
Example:
#include
int main() {
char grade = 'B';
switch (grade) {
case 'A':
printf("Excellent!\n");
break;
case 'B':
printf("Good\n");
break;
case 'C':
printf("Average\n");
break;
default:
printf("Invalid grade\n");
}
return 0;
}
while Loop
Repeats while condition is true
while (condition) {
// code to repeat
}
#include
int main() {
int i = 1;
while (i <= 5) {
printf("%d ", i);
i++;
}
// Output: 1 2 3 4 5
return 0;
}
do-while Loop
Executes at least once, then repeats while condition is true
do {
// code to repeat
} while (condition);
#include
int main() {
int i = 1;
do {
printf("%d ", i);
i++;
} while (i <= 5);
// Output: 1 2 3 4 5
return 0;
}
for Loop
Compact loop with initialization, condition, and increment
for (init; condition; increment) {
// code to repeat
}
#include
int main() {
for (int i = 1; i <= 5; i++) {
printf("%d ", i);
}
// Output: 1 2 3 4 5
return 0;
}
Loop Control Statements
break
Exits the loop immediately
#include
int main() {
for (int i = 1; i <= 10; i++) {
if (i == 5) break;
printf("%d ", i);
}
// Output: 1 2 3 4
return 0;
}
continue
Skips the current iteration
#include
int main() {
for (int i = 1; i <= 5; i++) {
if (i == 3) continue;
printf("%d ", i);
}
// Output: 1 2 4 5
return 0;
}
goto
Jumps to a labeled statement (use sparingly)
#include
int main() {
int i = 1;
start:
printf("%d ", i);
i++;
if (i <= 5) goto start;
// Output: 1 2 3 4 5
return 0;
}
Functions in C
Function Basics
Functions are reusable blocks of code that perform specific tasks, improving modularity and readability.
Function Components:
- Return Type: Data type of the returned value (use
voidif none) - Function Name: Unique identifier for calling the function
- Parameters: Input values (optional)
- Function Body: Code to execute
#include
// Function declaration (prototype)
int add(int a, int b);
int main() {
int result = add(5, 3); // Function call
printf("Sum: %d\n", result);
return 0;
}
// Function definition
int add(int a, int b) {
return a + b;
}
Parameter Passing
C supports two ways to pass parameters: by value (copy) and by reference (using pointers).
Pass by Value vs. Pass by Reference:
- Pass by Value: Copies the value; changes don't affect the original
- Pass by Reference: Passes the address; changes affect the original
#include
void swapByValue(int a, int b) {
int temp = a;
a = b;
b = temp;
}
void swapByReference(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 5, y = 10;
swapByValue(x, y);
printf("After swapByValue: x=%d, y=%d\n", x, y); // No change
swapByReference(&x, &y);
printf("After swapByReference: x=%d, y=%d\n", x, y); // Swapped
return 0;
}
Function Types
- Library Functions: Built-in functions like
printf(),scanf() - User-defined Functions: Custom functions created by the programmer
- Recursive Functions: Functions that call themselves
Recursion Example:
#include
int factorial(int n) {
if (n == 0 || n == 1) return 1;
return n * factorial(n - 1);
}
int main() {
printf("5! = %d\n", factorial(5)); // 120
return 0;
}
Storage Classes
Storage classes define the scope and lifetime of variables.
| Class | Scope | Lifetime |
|---|---|---|
| auto | Local | Function |
| register | Local | Function |
| static | Local/Global | Program |
| extern | Global | Program |
#include
void counter() {
static int count = 0; // Retains value between calls
count++;
printf("Count: %d\n", count);
}
int main() {
counter(); // Count: 1
counter(); // Count: 2
return 0;
}
Arrays in C
One-Dimensional Arrays
Arrays store multiple elements of the same data type in contiguous memory locations.
Declaration & Initialization:
// Declaration
int numbers[5];
// Initialization
int primes[5] = {2, 3, 5, 7, 11};
// Partial initialization
int arr[5] = {1, 2}; // Rest are 0
// Size from initializer
int days[] = {31, 28, 31}; // Size 3
Example:
#include
int main() {
int arr[5] = {10, 20, 30, 40, 50};
for (int i = 0; i < 5; i++) {
printf("arr[%d] = %d\n", i, arr[i]);
}
return 0;
}
Multi-Dimensional Arrays
Arrays of arrays, commonly used for matrices or tables.
2D Array Example:
#include
int main() {
int matrix[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", matrix[i][j]);
}
printf("\n");
}
return 0;
}
Array to Function:
#include
void printArray(int arr[], int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
}
int main() {
int nums[3] = {1, 2, 3};
printArray(nums, 3);
return 0;
}
Pointers in C
Pointer Basics
Pointers store memory addresses, enabling direct memory manipulation.
Key Concepts:
&- Address of operator*- Dereference operator- Pointer arithmetic (++, --, +, -)
- NULL pointer - Points to nothing
#include
int main() {
int num = 10;
int *ptr = # // ptr stores address of num
printf("Value: %d\n", num); // 10
printf("Address: %p\n", (void*)&num); // Memory address
printf("Pointer value: %d\n", *ptr); // 10
*ptr = 20; // Change value through pointer
printf("New value: %d\n", num); // 20
return 0;
}
Pointers and Arrays
Arrays and pointers are closely related; an array name is a pointer to its first element.
Array Name as Pointer:
#include
int main() {
int arr[3] = {10, 20, 30};
int *ptr = arr; // Points to first element
printf("%d\n", *ptr); // 10
printf("%d\n", *(ptr+1)); // 20
printf("%d\n", arr[1]); // 20
printf("%d\n", *(arr+1)); // 20
return 0;
}
Pointer to Pointer:
#include
int main() {
int num = 10;
int *ptr = #
int **pptr = &ptr;
printf("%d\n", **pptr); // 10
return 0;
}
Pointers and Functions
Pointers enable pass-by-reference, allowing functions to modify original variables.
#include
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 5, y = 10;
swap(&x, &y);
printf("x = %d, y = %d\n", x, y); // x=10, y=5
return 0;
}
Dynamic Memory Allocation
Allocate memory at runtime using malloc(), calloc(), realloc(), and free with free().
Functions:
malloc(size): Allocates uninitialized memorycalloc(n, size): Allocates and initializes to zerorealloc(ptr, size): Resizes allocated memoryfree(ptr): Releases memory
#include
#include
int main() {
int *arr = (int*)malloc(5 * sizeof(int));
if (arr == NULL) {
printf("Memory allocation failed\n");
return 1;
}
for (int i = 0; i < 5; i++) {
arr[i] = i + 1;
}
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}
free(arr); // Release memory
return 0;
}
Strings in C
String Basics
Strings are arrays of characters terminated by a null character (\0).
Declaration & Initialization:
char str1[10] = "Hello"; // Null-terminated
char str2[] = "World"; // Size inferred
char *str3 = "C Programming"; // String literal
Example:
#include
int main() {
char str[] = "Hello, World!";
printf("%s\n", str);
for (int i = 0; str[i] != '\0'; i++) {
printf("%c ", str[i]);
}
return 0;
}
String Functions
The string.h library provides functions for string manipulation.
Common Functions:
strlen(str): Returns string lengthstrcpy(dest, src): Copies stringstrcat(dest, src): Concatenates stringsstrcmp(str1, str2): Compares strings
#include
#include
int main() {
char str1[20] = "Hello";
char str2[20] = "World";
printf("Length of str1: %zu\n", strlen(str1));
strcat(str1, " ");
strcat(str1, str2);
printf("Concatenated: %s\n", str1);
printf("Comparison: %d\n", strcmp(str1, "Hello World"));
return 0;
}
Structures and Unions
Structures
Structures group different data types under a single name.
Syntax:
struct structureName {
type member1;
type member2;
// ...
};
Example:
#include
struct student {
char name[50];
int age;
float gpa;
};
int main() {
struct student s1 = {"John Doe", 20, 3.5};
printf("Name: %s, Age: %d, GPA: %.2f\n",
s1.name, s1.age, s1.gpa);
return 0;
}
Unions
Unions allow different data types to share the same memory location.
Syntax:
union unionName {
type member1;
type member2;
// ...
};
Example:
#include
union data {
int i;
float f;
char c;
};
int main() {
union data d;
d.i = 10;
printf("Integer: %d\n", d.i);
d.f = 3.14;
printf("Float: %.2f\n", d.f);
d.c = 'A';
printf("Char: %c\n", d.c);
return 0;
}
File Handling in C
File Operations
C provides functions to read from and write to files using stdio.h.
Key Functions:
fopen(filename, mode): Opens a filefclose(file): Closes a filefprintf(file, format, ...): Writes to a filefscanf(file, format, ...): Reads from a file
#include
int main() {
FILE *fp = fopen("example.txt", "w");
if (fp == NULL) {
printf("Error opening file\n");
return 1;
}
fprintf(fp, "Hello, File Handling!\n");
fclose(fp);
return 0;
}
Reading from Files
Read data from files using functions like fscanf() or fgets().
#include
int main() {
FILE *fp = fopen("example.txt", "r");
if (fp == NULL) {
printf("Error opening file\n");
return 1;
}
char buffer[100];
while (fgets(buffer, 100, fp) != NULL) {
printf("%s", buffer);
}
fclose(fp);
return 0;
}
Preprocessor Directives
Common Directives
Preprocessor directives are processed before compilation, starting with #.
Key Directives:
#include: Includes header files#define: Defines macros or constants#ifdef,#ifndef: Conditional compilation#undef: Undefines a macro
#include
#define MAX 100
int main() {
printf("Max value: %d\n", MAX);
return 0;
}
Conditional Compilation
Control which code is compiled based on conditions.
#include
#define DEBUG 1
int main() {
#ifdef DEBUG
printf("Debug mode enabled\n");
#else
printf("Debug mode disabled\n");
#endif
return 0;
}
Recursion in C
Recursion Basics
Recursion occurs when a function calls itself to solve a smaller instance of the same problem.
Key Components:
- Base Case: Condition to stop recursion
- Recursive Case: Function calls itself with modified input
#include
int factorial(int n) {
if (n == 0 || n == 1) { // Base case
return 1;
}
return n * factorial(n - 1); // Recursive case
}
int main() {
printf("5! = %d\n", factorial(5)); // 120
return 0;
}
Fibonacci Sequence
A common example of recursion to generate Fibonacci numbers.
#include
int fibonacci(int n) {
if (n <= 1) return n; // Base case
return fibonacci(n - 1) + fibonacci(n - 2); // Recursive case
}
int main() {
for (int i = 0; i < 10; i++) {
printf("%d ", fibonacci(i));
}
// Output: 0 1 1 2 3 5 8 13 21 34
return 0;
}
Error Handling in C
Basic Error Handling
C lacks built-in exception handling; errors are managed using return codes and errno.
#include
#include
int main() {
FILE *fp = fopen("nonexistent.txt", "r");
if (fp == NULL) {
perror("Error opening file");
printf("Error code: %d\n", errno);
return 1;
}
fclose(fp);
return 0;
}
Custom Error Handling
Use return values and conditionals to handle errors gracefully.
#include
int divide(int a, int b, int *result) {
if (b == 0) {
return -1; // Error code
}
*result = a / b;
return 0; // Success
}
int main() {
int result;
if (divide(10, 0, &result) == -1) {
printf("Error: Division by zero\n");
} else {
printf("Result: %d\n", result);
}
return 0;
}
C Programming Quiz
Test Your Knowledge
Answer the following questions to reinforce your understanding of C programming concepts.
1. What is the output of the following code?
#include
int main() {
int x = 5;
printf("%d\n", x++ + ++x);
return 0;
}
Answer: 12
Explanation: The expression x++ + ++x involves undefined behavior due to multiple modifications of x without a sequence point. However, in many compilers, ++x increments x to 6 first, then x++ uses the current value (6) and increments x to 7. Thus, the expression evaluates as 6 + 6 = 12.
2. What does the following function return for n = 3?
int recursiveSum(int n) {
if (n <= 0) return 0;
return n + recursiveSum(n - 1);
}
Answer: 6
Explanation: The function calculates the sum of numbers from 1 to n. For n = 3, it computes 3 + recursiveSum(2), where recursiveSum(2) = 2 + recursiveSum(1), and recursiveSum(1) = 1 + recursiveSum(0) = 1. Thus, 3 + 2 + 1 = 6.
3. What is wrong with this code?
#include
int main() {
char str[5];
strcpy(str, "Hello");
printf("%s\n", str);
return 0;
}
Answer: Buffer overflow
Explanation: The array str[5] can hold 4 characters plus the null terminator. The string "Hello" has 5 characters plus the null terminator (6 bytes total), causing a buffer overflow. Use char str[6] or larger.
4. What is the size of the following structure on a 32-bit system?
struct example {
char a;
int b;
};
Answer: 8 bytes
Explanation: On a 32-bit system, char is 1 byte, and int is 4 bytes. Due to padding for alignment, the structure is padded to 8 bytes (1 byte for a, 3 bytes padding, 4 bytes for b).
5. What does this code print?
#include
int main() {
int arr[] = {1, 2, 3};
int *ptr = arr;
printf("%d\n", *(ptr + 2));
return 0;
}
Answer: 3
Explanation: ptr points to the first element of arr. *(ptr + 2) accesses the third element (arr[2]), which is 3.
Learn C Programming by Tutorials Point
Download C Programming Detailed Notes PDF View C Programming Detailed Notes PDF
Try Yourself
C Compiler