Unit I: Foundations of C and C++ Programming
Table of Contents
- 1. History and Importance of C/C++
- 2. Basic Structure of a C/C++ Program
- 3. Character Set, Tokens, Keywords, and Identifiers
- 4. Execution of a C/C++ Program
- 5. Data Types (Basic, Enumerated, Derived)
- 6. Constants, Variables, and Symbolic Constants
1. History and Importance of C/C++
History of C
Development: C was developed in 1972 by Dennis Ritchie at Bell Laboratories (USA) for the Unix operating system.
It was created as a successor to the B language (developed by Ken Thompson) and BCPL. C was designed to compile using a simple compiler, provide low-level access to memory, and produce highly efficient system code, making it the language of choice for developing operating systems, drivers, and compilers.
History of C++
Development: C++ was developed by Bjarne Stroustrup in 1979 at Bell Laboratories.
Initially called 'C with Classes', it was renamed to 'C++' in 1983 (signifying the increment operator ++, denoting C++ is an enhanced step forward from C). C++ added Object-Oriented Programming (OOP) capabilities to C, such as classes, inheritance, polymorphism, and encapsulation, while retaining C's fast performance and hardware control.
Importance and Features of C and C++
C and C++ remain critically important in modern software engineering for the following reasons:
- Portability: Programs written in C/C++ can be compiled on different architectures with minimal modifications.
- Efficiency and Speed: Direct hardware access and lack of complex runtime overhead make them incredibly fast.
- System-level Control: They allow developers to manage memory and hardware components directly.
- Foundation for Modern Software: Operating systems (Windows, Linux, macOS), database engines (MySQL, Oracle), and high-performance game engines are written in C/C++.
Key Differences: C vs C++
| Feature | C Programming Language | C++ Programming Language |
|---|---|---|
| Paradigm | Procedural language. Focuses on steps and actions. | Multi-paradigm (Procedural + Object-Oriented). |
| Security | Data is exposed and insecure. No access specifiers. | Highly secure. Uses access specifiers (private, protected, public) to hide data. |
| Polymorphism & Overloading | Not supported. | Fully supported (Function and Operator Overloading). |
| Memory Management | Uses functions: malloc() and free(). |
Uses operators: new and delete. |
| Input/Output Operations | Uses scanf() and printf(). |
Uses std::cin and std::cout streams. |
2. Basic Structure of a C/C++ Program
To write high-quality applications, developers must understand the standard sections that make up a C or C++ source code file.
Structure Overview
- Documentation Section: Comments describing program name, author, or objective.
- Preprocessor Directive / Link Section: Inclusion of header files (e.g.,
#include) to use external functions. - Definition Section: Defining symbolic constants (e.g.,
#define). - Global Declaration Section: Declaring global variables and external user-defined functions.
- Main Function: The execution point where the operating system starts reading code (
int main()). - Local Statements & Expressions: Variable declarations and execution instructions within the main scope.
Structural Examples
Here are basic programs demonstrating structure in both languages:
Standard C Program Structure:/* Documentation Section: Standard Hello World in C */
#include <stdio.h> /* Link/Preprocessor Section */
int main() { /* Main Function */
printf("Hello, World!\n"); /* Statement */
return 0; /* Return Statement */
}Standard C++ Program Structure:
// Documentation Section: Hello World in C++
#include <iostream> // Link/Preprocessor Section
int main() { // Main Function
std::cout << "Hello, World!" << std::endl; // Statement
return 0; // Return Statement
}
Detailed Component Explanation
- Preprocessor Directives (
#include): Tells the compiler to load external libraries (header files) containing pre-built procedures before compiling the code. int main(): Every program must have this exact block. The return typeintindicates that the program outputs an integer status to the operating system upon termination (normally0signifies successful completion).- Braces
{}: Mark the boundary block of code logic.
3. Character Set, Tokens, Keywords, and Identifiers
Before writing code statements, you must understand the lexical elements that construct instructions.
The Character Set
The C/C++ compiler recognizes specific patterns of characters. The allowable characters are grouped as:
- Alphabets: Uppercase (A-Z) and Lowercase (a-z).
- Digits: Numbers from 0 to 9.
- Special Characters: Arithmetic, logical, and structural symbols like
+,-,*,/,=,{,},[,],&,$,%, etc. - White spaces: Blank space, horizontal tab (
), newline (), carriage return, etc.
C/C++ Tokens
Definition: A token is the smallest individual unit in a source program that the compiler can identify without further breaking down.
A compiler processes source code as a stream of tokens. There are five main categories of tokens:
- Keywords: Reserved words with system-defined behaviors.
- Identifiers: User-defined names.
- Constants: Literal values that remain unchanged.
- Operators: Symbols performing operations on inputs (e.g.,
+,-,&&). - Special Symbols: Brackets, semicolons, and commas.
Keywords
Keywords are predefined, reserved words whose meanings are hardcoded into the compiler. They cannot be redefined or used for naming identifiers.
- Standard C has 32 keywords (e.g.,
int,for,if,else,return,struct,switch). - C++ expands on C's keywords to support OOP (e.g.,
class,public,private,new,delete,virtual,this,try,catch).
Identifiers
Identifiers are user-defined names given to program elements such as variables, functions, arrays, structures, and classes.
Rules for Creating Identifiers:
- Can only contain letters (A-Z, a-z), digits (0-9), and underscores (
_).- The first character must be a letter or an underscore. It cannot be a digit.
- No white spaces or special characters (like
$,@,%) are allowed.- Keywords cannot be used as identifier names.
- Identifiers are highly case-sensitive (e.g.,
totalSalaryis completely distinct fromtotalsalary).
Comparison: Keywords vs Identifiers
| Attribute | Keywords | Identifiers |
|---|---|---|
| Definition | Predefined reserved words. | User-defined custom names. |
| Purpose | Express statements and instructions. | Identify variables, functions, structures, etc. |
| Case Format | Always written in lowercase. | Can use mixed casing (CamelCase, snake_case). |
| Special Characters | No special characters allowed. | Underscores are allowed. |
Common Mistake: Attempting to declare a variable beginning with a number, such as int 1stValue = 100;. This will throw an immediate compiler syntax error.
4. Execution of a C/C++ Program
Converting human-written source code into binary machine code requires a series of systemic steps. The compilation and execution pipeline involves several integrated tools:
- Writing Code (Source File): The developer writes code using an editor and saves it as a
.c(C) or.cpp(C++) file. - Preprocessing: The preprocessor processes lines starting with
#. It strips out program comments, expands header files, and evaluates macro replacements. This results in an expanded source code file. - Compilation: The compiler translates the preprocessed expanded source code into assembly code. During this stage, syntactical correctness and type safety are verified.
- Assembly: The assembler translates assembly language instructions into raw machine binary instructions, generating an object file (with extension
.objor.o). - Linking: The linker connects the generated object file with system libraries (like math formulas or basic print commands) and other object files. It builds a consolidated runnable executable file (
.exeon Windows,.outor extensionless on Linux). - Loading: The OS loader takes the executable file from external disk storage, loads it into system RAM, and points the processor to the starting memory address.
- Execution: The CPU executes the machine instructions, interacting with system I/O interfaces to output results.
5. Data Types (Basic, Enumerated, Derived)
Data types specify how the program stores, processes, and interprets different kinds of data in computer memory.
1. Basic Data Types (Primary / Built-in)
These are built into the C/C++ standard compilers. They represent individual values:
- Integer (
int): Used to store whole numbers. - Character (
char): Used to store a single ASCII character wrapped in single quotes (e.g.,'A'). - Float (
float): Single-precision floating-point numbers containing fractional values. - Double (
double): Double-precision floating-point numbers for high-accuracy scientific values. - Void (
void): Represents an empty or valueless data structure, typically used in function definitions to signify no return value.
Data Type Properties (Standard 32-bit Architecture)
| Data Type | Size in Bytes | Range of Values | Format Specifier (C) |
|---|---|---|---|
char |
1 Byte | -128 to 127 | %c |
int |
4 Bytes | -231 to 231 - 1 | %d |
float |
4 Bytes | 1.2 × 10-38 to 3.4 × 1038 | %f |
double |
8 Bytes | 2.3 × 10-308 to 1.7 × 10308 | %lf |
2. Enumerated Data Types (enum)
Definition: An enumerated data type is a user-defined data type used to assign names to integral constants, making program code clean and readable.
The keyword enum is used to declare an enumeration. By default, compiler values start at 0 and increment sequentially by 1.
// Syntax
enum Day { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };
// Usage
enum Day today;
today = Wednesday; // Evaluates to integer value 3 internally
3. Derived Data Types
These are built by combining basic data types. They allow programmers to handle complex data structures:
- Arrays: A collection of multiple elements of the identical data type stored sequentially in adjacent memory locations. (e.g.,
int scores[5];) - Pointers: Specialized variables that store the hexadecimal memory address of another variable rather than storing raw values. (e.g.,
int *ptr;) - Structures (
struct): A user-defined record that groups multiple variables of differing data types under a single unified name. (e.g., grouping name, age, and ID under one definition) - Unions (
union): Similar to structures, but all internal member variables share the same memory layout. The memory allocated equals the size of the largest member. - Functions: Independent modules of code defined to perform a repeatable operation.
6. Constants, Variables, and Symbolic Constants
Programs must store data elements during execution. This is managed using constants and variables.
Variables
A variable is a symbolic name pointing to a memory location in RAM where data values can be temporarily stored, retrieved, and changed during program execution.
Declaration and Assignment:
- Declaration: Declaring a variable specifies its type and name, allocating memory.
- Assignment: Stores a specific value in that memory location.
int age; // Variable Declaration
age = 21; // Value Assignment
float rate = 5.5; // Declaration and Initialization in one step
Constants (Literals)
Constants are hardcoded values assigned directly to variables. Once defined, they remain fixed during runtime execution.
- Integer Constants: E.g.,
100,-50. - Real/Float Constants: E.g.,
3.14159,-0.005. - Character Constants: E.g.,
'A',' '(single quotes). - String Constants: E.g.,
"Hello World"(double quotes).
Symbolic Constants
Definition: A symbolic constant is an alias given to a constant value, allowing you to update a parameter globally in one place rather than manually modifying values throughout the code.
There are two primary ways to declare symbolic constants in C/C++:
- Using the Preprocessor Directive (
#define):Uses text-substitution. No actual memory is allocated for variables.
#define PI 3.14159 #define LIMIT 100 - Using the
constKeyword:This is a compiler-enforced variable lock. Memory is allocated, but its value cannot be modified after declaration.
const float PI = 3.14159; const int LIMIT = 100;
Comparison: #define vs const
| Feature | #define Directive |
const Modifier |
|---|---|---|
| Type Safety | No type-checking. Simple text replacement. | Fully type-safe. Validated by the compiler. |
| Scope Control | Global replacement across the entire file. | Follows normal programming block-scoping rules. |
| Debugging | Difficult to debug since the name disappears after preprocessing. | Easy to debug. The name exists in the compiler symbol table. |
Common Mistake: Attempting to modify a constant variable later in the code. For example, the following code will trigger a compilation error:
const int taxRate = 15;
taxRate = 18; // Error: Assignment of read-only variable!