Module 1: Introduction to C
A Brief History of C
The C programming language was created by Dennis Ritchie at Bell Labs in the early 1970s, originally implemented on a DEC PDP-11 computer running the UNIX operating system. It evolved from earlier programming languages that influenced its design.
Language Evolution
- BCPL (Basic Combined Programming Language): Created by Martin Richards — simple, machine-independent system language.
- B: Developed by Ken Thompson, based on BCPL — used for early UNIX development.
- C: Introduced by Dennis Ritchie — added types, structures, and efficiency suitable for system programming.
- Used to rewrite UNIX: C replaced assembly language for the UNIX kernel, improving portability.
- Designed for efficiency: Offers low-level memory access with high-level language features.
- Foundation for many languages: Influenced C++, Java, C#, Objective-C, and more.
Key Milestones in C Standardization
Year | Standard | Significance |
---|---|---|
1972-1978 | Early C / K&R C | Defined by Brian Kernighan and Dennis Ritchie in "The C Programming Language" |
1989 | ANSI C (C89) | First standardized version by ANSI; introduced portability and standard libraries |
1990 | ISO C (C90) | Adopted internationally by ISO, identical to ANSI C |
1995 | Amendment 1 | Added wide-character support and new library functions |
1999 | C99 |
Introduced inline functions, variable-length arrays,
and new data types like long long
|
2011 | C11 | Added multi-threading support, Unicode, and improved memory handling |
2018 | C18 | Minor bug fixes and clarifications to the C11 standard |
- Portability: C programs can run on multiple hardware platforms with minimal changes.
- Legacy and Longevity: C remains one of the most widely used languages in system and embedded programming.
- Influence: Most modern programming languages have roots in or are heavily inspired by C.
Did You Know? Over 90% of modern operating systems, compilers, and embedded systems are written in C or C-based languages.
C as a Middle-Level Language
C combines the best elements of high-level languages with the control and flexibility of assembly language.
Programming Language Spectrum:
Level | Languages | Characteristics |
---|---|---|
High Level | Ada, Modula-2, Pascal, COBOL, FORTRAN, BASIC | Abstracted from hardware, easier to read and write |
Middle Level | Java, C++, C, FORTH, Macro-assembler | Balance between hardware control and programming convenience |
Low Level | Assembler | Direct hardware manipulation, machine-specific |
Key Characteristics of C as Middle-Level Language:
- Hardware Access: Allows manipulation of bits, bytes, and addresses
- Portability: Easy to adapt software for different systems
- Flexible Typing: Not strongly typed; permits type conversions
- Minimal Runtime Checking: No automatic array bounds checking
- Direct Memory Manipulation: Ideal for system-level programming
- Compact Keyword Set: C89 has 32 keywords, C99 adds only 5 more
C as a Structured Language
C is a structured programming language that emphasizes compartmentalization of code and data.
Structured vs. Non-structured Languages:
Non-structured Languages | Structured Languages |
---|---|
FORTRAN | Pascal |
BASIC | Ada |
COBOL | C++ |
C | |
Java | |
Modula-2 |
Key Structural Features of C:
- Compartmentalization: C allows you to isolate code and data related to specific tasks, improving clarity and reducing errors.
- Functions: Functions are the main structural unit in C, enabling modular design and reusability of code.
-
Code Blocks: Logical groups of statements are
enclosed in curly braces
{ }
, treated as one unit of execution. -
Structured Control: C supports
while
,do-while
, andfor
loops. The use ofgoto
is discouraged, unlike older languages such as BASIC or FORTRAN. - Local Variables: Subroutines and functions in C can use local variables, preventing side effects in other parts of the program.
- Modularity: Functions can be written, tested, and reused independently, making C suitable for large projects involving multiple programmers.
- Reusability of Code: Once a function is created, it can be reused in different parts of a program or even across multiple programs, without modification.
- Reduced Use of Global Variables: Unlike BASIC, which relied heavily on global variables, C promotes controlled scope to avoid unintended interactions between program sections.
- Clarity of Algorithms: Code blocks and structured constructs allow complex algorithms to be expressed with simplicity, clarity, and efficiency.
- Freedom of Layout: Unlike old FORTRAN versions, C does not require strict field positions; statements can be placed flexibly in the code for readability.
- Modern Practice: Structured languages like C are widely used today. Non-structured languages are considered outdated and rarely used for serious new projects.
Example of Code Block in C:
if (x < 10) {
printf("Too low, try again.\n");
scanf("%d", &x);
}
The two statements between curly braces form a logical code block
that executes together.
Such blocks ensure that multiple related actions are treated as one
logical unit.
C as a Programmer's Language
Unlike languages designed for non-programmers (like COBOL and BASIC), C was created by and for working programmers.
Advantages for Programmers:
- Few Restrictions: Maximum flexibility with minimal constraints
- Efficiency: Nearly achieves assembly code efficiency with high-level structure
- Stand-alone Functions: Modular programming approach
- Compact Syntax: Small set of powerful keywords
- Systems Programming: Ideal for operating systems and utilities
- Portability: Code can run on different systems with minimal changes
Historical Applications:
- Systems Programming: Operating systems, compilers, editors, linkers
- Embedded Systems: Still predominantly programmed in C
- Foundation for C++: C forms the basis for object-oriented C++
- Continuing Innovation: C99 standard shows ongoing language development
Compilers vs. Interpreters
Understanding the difference between compilation and interpretation is crucial for C programming, as C was specifically designed as a compiled language.
Comparison Table:
Aspect | Compiler | Interpreter |
---|---|---|
Execution Method | Converts entire program to machine code before execution | Reads and executes source code line by line |
Performance | Faster execution (direct machine code) | Slower execution (line-by-line processing) |
Development Cycle | Edit → Compile → Run | Edit → Run |
Error Detection | All errors reported at compile time | Errors detected during execution |
Portability | Machine-specific executable | Same source code runs on different platforms |
Memory Usage | More efficient | Less efficient |
C as a Compiled Language:
- Optimized for Compilation: C was specifically designed as a compiled language
- Object Code: Source code translated into machine-executable binary code
- Efficiency: Compiled programs run faster than interpreted ones
- Stand-alone Executables: No need for interpreter during execution
- Limited Use of Interpreters: Mainly for debugging or experimental platforms
Note: While C interpreters exist, serious C development almost always uses compilers for optimal performance and efficiency.
C Keywords and Reserved Words
C89 Standard Keywords (32 Keywords)
Complete List of C Keywords (32 Keywords)
Data Type Keywords
Control Flow Keywords
Storage Class Keywords
Type Qualifiers & Others
C99 Additional Keywords (5 Keywords)
Keyword | Purpose |
---|---|
Bool | Boolean data type |
Complex | Complex numbers support |
Imaginary | Imaginary numbers support |
inline | Function inlining optimization |
restrict | Pointer optimization qualifier |
Important Notes About Keywords:
-
Case Sensitivity: C is case-sensitive -
else
is a keyword,ELSE
is not - Reserved Usage: Keywords cannot be used as variable or function names
- Compiler Extensions: Many compilers add non-standard keywords for specific environments
Common Compiler Extension Keywords
Many C compilers include additional keywords to better exploit their specific operating environments:
Keyword | Common Usage |
---|---|
asm, asm | Inline assembly code |
cdecl, pascal | Function calling conventions |
interrupt | Interrupt service routines |
near, far, huge | Memory model specifications (8086 family) |
cs, ds, es, ss | Segment register access |
Note: These extended keywords are compiler-specific and may not be available in all C compilers. Always check your compiler documentation.
Structure of a C Program or Basic Concepts of a C Program
All C programs consist of one or more functions, with
main()
being the essential starting point.
General Form of a C Program:
[Comments]
[Preprocessor Directives]
[Global Declarations]
[Function Declarations]
[Function Definitions]
main()
{
[Declaration Section]
[Executable Section]
}
-
Comments
- At the beginning of each program is a comment with a short description of the problem to be solved.
- We can use the comments anywhere in the program.
-
The comments section is optional.
Ex: 1. /* Program1: To find the sum of two numbers*/
2. // Program2: To calculate the area and perimeter of circle - The symbol /* and ends with */ represents the multiline comment.
- The symbol // can also be used for representing single line comment.
-
Preprocessor directives
- The preprocessor statements start with # symbol.
-
These statements instruct the compiler to include some of the
files in the beginning of the program.
Ex: #include<stdio.h>
#include<math.h>
are the files that the compiler includes in the beginning of the program. - The line containing #include<stdio.h> tells the compiler to allow our program to perform standard input and output 'stdio' operations.
- The '#include' directive tells the compiler that we will be using parts of the standard function library.
- Information about these functions is contained in a series of 'header files' (stdio.h). .h says this file is a header file.
- The pointed brackets < and > tell the compiler the exact location of this header file.
-
Using the preprocessor directives the user can define the
constants also.
Ex: #define PI 3.142
-
Global Declarations
- The variables that are declared above (before) the main program are called global variables.
- The global variables can be accessed anywhere in the main program and in all the other functions.
-
Function declarations and Definitions
- In this section the functions are declared.
- Immediately after the functions are declared, the functions can be defined.
-
The program header: main()
- Every program must have a main function.
- Always the C program begins its execution from main.
-
Body of the program
-
After the header or top lines is a set of braces ({ and })
containing a series of 'C' statements which comprise the 'body'-
this is called the action portion of the program.
#include <stdio.h>
main(void) {
/* action portion of the program*/
}
- The global variables can be accessed anywhere in the main program and in all the other functions.
-
After the header or top lines is a set of braces ({ and })
containing a series of 'C' statements which comprise the 'body'-
this is called the action portion of the program.
-
Declaration section
- The variables that are used inside the function should be declared in the declaration section.
-
For example, consider the declaration shown below:
int sum=0;
int a;
float b;
Here, the variable sum is declared as an integer variable and it is initialized to zero.
The variable a is declared as an integer variable whereas the variable b is declared as a floating point variable.
-
Executable section
- They represent the instructions given to the computer to perform a specific task.
- The instructions can be input/output statements, expressions to be evaluated, simple assignment statements, control statements such as if statement, for statement etc.
-
Each executable statement ends with “;”. Example: Write a C
program to display “Hello World”.
#include <stdio.h>
void main(void) {
printf(“Hello World”);
}
Key Structural Elements:
- main() function: Required starting point of execution
- Function-based: Programs are organized around functions
-
Modular design:
main()
typically calls other functions -
Top-down organization:
main()
provides program outline
About the main() Function:
-
Although
main
is not a keyword, treat it as reserved - Don't use
main
as a variable name - Execution always begins at
main()
-
Well-written C code uses
main()
as a high-level program outline
The C Standard Library and Linking
Why Libraries Are Essential
C provides very few built-in features through its keywords alone. Most
useful tasks — such as input/output, math, or string handling — come
from the
Standard C Library. Without these libraries, even
simple programs like printf("Hello World");
wouldn’t
work!
-
Input/Output operations: Functions like
printf()
andscanf()
come from<stdio.h>
.
➤ Example:
#include <stdio.h>
printf("Enter a number: ");
scanf("%d", &n); -
Mathematical computations: Functions such as
sqrt()
,pow()
,sin()
,cos()
are in<math.h>
.
➤ Example:
#include <math.h>
double root = sqrt(25);
// root = 5.0 -
Character handling: Functions like
toupper()
,tolower()
,isdigit()
come from<ctype.h>
.
➤ Example:
#include <ctype.h>
char upper = toupper('a');
// upper = 'A' -
String manipulation: Functions like
strcpy()
,strlen()
,strrev()
(not standard everywhere) are in<string.h>
.
➤ Example:
#include <string.h>
char name[20];
strcpy(name, "C Programming"); -
Memory management: Functions such as
malloc()
,calloc()
, andfree()
come from<stdlib.h>
.
➤ Example:
#include <stdlib.h>
int *ptr = (int *)malloc(5 * sizeof(int));
free(ptr);
The Linking Process
When you compile and run your C program, the compiler and linker work together to include both your code and the necessary library functions.
Step | Description |
---|---|
1. Compilation |
The compiler converts source code (.c file) into
object code (.obj or .o ) and remembers
external function names like printf or
sqrt .
|
2. Linking |
The linker connects your object file with the appropriate library
files (e.g., stdio.lib , math.lib ).
|
3. Execution | The final executable contains both your logic and the library code, ready to run as one program. |
Library Characteristics
- Relocatable Format: Library functions use memory offsets (not fixed addresses) so they can work in any program.
-
Standard Minimal Set: Every C compiler provides
core libraries like
stdio.h
,stdlib.h
,string.h
, andmath.h
. - Compiler Extensions: Some compilers add extra libraries (e.g., graphics, sound, or system utilities).
-
Custom Libraries: You can create your own libraries
of reusable functions for future projects.
➤ Example: You can compile your ownmylib.c
intomylib.a
ormylib.lib
and reuse it.
Technical Note: During linking, the linker automatically replaces placeholder offsets with real memory addresses so that all functions are properly connected before the program runs.
Building Blocks of C Programming
Essential Components Summary
Component | Purpose | Examples |
---|---|---|
Keywords | Language fundamentals and control structures | if, while, int, return |
Standard Library | Pre-built functionality for common tasks | printf(), scanf(), strlen() |
Functions | Program organization and modularity | main(), user_defined() |
Linking | Combining program components into executable | Compiler/linker process |
Best Practices for C Program Structure
- Modular Design: Break programs into small, focused functions
- Library Usage: Leverage standard library functions when possible
- Clear main(): Use main() as a high-level program outline
- Reusable Functions: Create your own library functions for repeated tasks
- Standard Compliance: Stick to standard keywords for portability
Separate Compilation in C
What is Separate Compilation?
Separate compilation allows a C program to be divided across multiple source files, with each file compiled independently before being linked together.
Traditional vs Separate Compilation:
Aspect | Single File Compilation | Separate Compilation |
---|---|---|
Program Size | Best for small programs | Ideal for large projects |
Compile Time | Recompile entire program for any change | Only recompile changed files |
Team Development | Difficult with multiple programmers | Easy collaboration |
Code Organization | All code in one place | Logical separation of functionality |
Benefits of Separate Compilation:
- Reduced Compile Time: Only modified files need recompilation
- Team Collaboration: Multiple programmers can work on different files
- Better Organization: Logical grouping of related functions
- Code Reusability: Easily reuse compiled object files
- Modular Development: Isolate and test individual components
Example Project Structure:
project/
├── main.c (main program)
├── utils.c (utility functions)
├── math_ops.c (mathematical operations)
├── io_handlers.c (input/output functions)
└── headers/
├── utils.h
├── math_ops.h
└── io_handlers.h
The C Program Compilation Process
Three-Step Compilation Process:
Step | Description | Input | Output |
---|---|---|---|
1. Program Creation | Writing source code using a text editor | Program logic and algorithms | .c source files |
2. Compilation | Translating source code to machine code | .c source files | .o object files |
3. Linking | Combining object files with libraries | .o files + libraries | Executable file |
Compilation Environments:
Integrated Development Environment (IDE)
- Editor, compiler, and linker in one package
- Automatic project management
- Debugging tools included
- Examples: Code::Blocks, Visual Studio, Eclipse
Stand-alone Compiler
- Separate editor required
- Command-line operation
- More control over compilation process
- Examples: GCC, Clang, MSVC command line
Important Requirements:
- Text Files Only: Compilers require plain text files, not word processor documents
- No Control Codes: Files must not contain special formatting characters
- Compiler Specific: Exact commands vary between compilers
- Documentation: Always consult your compiler's documentation
C Program Memory Map
Four Logical Memory Regions:
Conceptual Memory Layout:
Function calls, local variables
(grows downward)
Dynamic memory allocation
(grows upward)
Global and static variables
Program executable instructions
Detailed Memory Regions:
Memory Region | Contents | Characteristics |
---|---|---|
Code/Text Segment | Executable program instructions | Read-only, fixed size |
Data Segment | Global variables, static variables | Fixed size, persists throughout program |
Stack |
• Function return addresses • Function arguments • Local variables • CPU state information |
LIFO structure, automatic management |
Heap | Dynamically allocated memory | Manual management, flexible size |
Quick Summary (Easy to Remember)
- The memory of a C program is divided into 4 main parts — Code, Data, Stack, and Heap.
- Code Segment → contains your compiled program instructions.
- Data Segment → stores global and static variables.
- Stack → used for function calls and local variables (works like a stack of plates).
- Heap → used for dynamic memory (malloc, calloc, etc.), can grow and shrink at runtime.
Important Points to Remember
- Code Segment: Read-only, fixed once the program starts.
-
Data Segment: Divided into two parts:
- Initialized Data → stores variables with assigned values.
- Uninitialized Data (BSS) → stores variables declared but not initialized.
-
Stack:
- Each function call creates a new stack frame.
- Automatically cleaned when the function ends.
- Too many function calls cause a stack overflow.
-
Heap:
-
Used with
malloc()
,calloc()
,free()
. -
Programmer must release memory manually using
free()
. - Not released automatically — can cause memory leaks.
-
Used with
-
Direction of Growth:
- Stack → grows downward (towards lower memory).
- Heap → grows upward (towards higher memory).
-
Lifetime:
- Code & Data → exist for the entire program.
- Stack → temporary, per function call.
-
Heap → as long as you allocate (until
free()
).
- Easy Way to Remember: "Code writes the logic, Data holds memory, Stack handles calls, Heap grows freely."
Detailed Memory Regions:
Memory Region | Contents | Characteristics |
---|---|---|
Code/Text Segment | Executable program instructions | Read-only, fixed size |
Data Segment | Global variables, static variables | Fixed size, persists throughout program |
Stack |
• Function return addresses • Function arguments • Local variables • CPU state information |
LIFO structure, automatic management |
Heap | Dynamically allocated memory | Manual management, flexible size |
Stack and Heap Memory Management
Stack Memory Characteristics:
- Automatic Management: Memory allocated and freed automatically
- Fast Access: Very efficient memory access
- LIFO Structure: Last-In-First-Out organization
- Function Scope: Tied to function calls and returns
- Limited Size: Fixed maximum size per thread
Heap Memory Characteristics:
- Manual Management: Programmer controls allocation/deallocation
- Flexible Size: Can grow as needed (within system limits)
- Global Access: Accessible from anywhere in program
- Dynamic Allocation: Memory allocated at runtime
- Slower Access: More overhead than stack
Memory Management Functions:
Function | Purpose | Memory Region |
---|---|---|
malloc() |
Allocate memory block | Heap |
calloc() |
Allocate and initialize to zero | Heap |
realloc() |
Resize allocated memory block | Heap |
free() |
Release allocated memory | Heap |
Note: The exact physical layout of memory regions varies between different CPU architectures and C implementations, but the logical structure remains consistent across platforms.
Practical Compilation Example (Fedora)
Separate Compilation Workflow:
Step 1: Create Source Files
$ gedit main.c & utils.c & utils.h
// main.c
#include <stdio.h>
#include "utils.h"
int main() {
int result = add(5, 3);
printf("Result: %d\n", result);
return 0;
}
// utils.c
#include "utils.h"
int add(int a, int b) {
return a + b;
}
// utils.h
#ifndef UTILS_H
#define UTILS_H
int add(int a, int b);
#endif
Step 2: Compile Separately
$ cc -c main.c
# Generates main.o
$ cc -c utils.c
# Generates utils.o
Step 3: Link and Run
$ cc main.o utils.o -o program
$ ./program
Key Advantages in Practice:
- Incremental Compilation: Modify only utils.c? Just recompile utils.c and relink.
-
Simple Editing: Use
gedit
or any editor to manage code easily. - Faster Build: Avoid recompiling unchanged files.
- Clear Output: Separate object files and final executable.
Review of Terms:
- Source code: The text of a program that a user can read, commonly thought of as the program. The source code is input into the C compiler.
- Object code: Translation of the source code of a program into machine code, which the computer can read and execute directly. Object code is the input to the linker.
- Linker: A program that links separately compiled modules into one program. It also combines the functions in the Standard C library with the code that you wrote. The output of the linker is an executable program.
- Library: A file containing the standard functions that your program can use. These functions include all I/O operations as well as other useful routines.
- Compile time: The time during which your program is being compiled.
- Run time: The time during which your program is executing.