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
void
if 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