Skip to content

Chapter 11: C++ Basics for HPC

Source slides: V09_Cpp_Basics.pdf. Exercise: E09_Cpp_Basics.pdf. Code: examples_exercises/example01.cpp..example10.cpp, task_01.cpp, task_02.cpp and exercises_solutions/task_01_solution.cpp, task_02_solution.cpp (the Complex class).


1. Chapter Overview

C++ is the dominant language of CFD solvers (OpenFOAM, SU2, Code_Saturne, AMReX). It combines C-level performance with object-oriented abstractions for meshes, fields, boundary conditions. This chapter covers what an HPC user must know to read, modify and compile C++ code:

  • The build cycle: edit → compile (g++) → run.
  • Variables and primitive data types (int, char, float, double, bool).
  • Scope and namespaces (int a vs box::a vs global ::a).
  • Pointers (int *p), addresses (&x), dereferencing (*p).
  • Arrays and pointer arithmetic.
  • Conditionals (if/else, ?:), for/while loops.
  • Functions: declaration, definition, call by value vs call by reference vs call by pointer.
  • Classes and objects: class Complex { ... };, constructors, member functions, private/public.

Why it matters in HPC/CFD: every solver hot-loop is C/C++; understanding pointers and call-by-reference is essential to know why code is fast or slow and how to avoid copying multi-GB fields.

What the examiner asks (very high frequency):

  • "Compile and run example01.cpp."
  • "Predict the output of example10.cpp (call-by-value vs reference)."
  • "Difference between pointer and reference."
  • "Implement swap using pointers."
  • "Complete the Complex class."
  • "Predict size of int, char, float."

What you must master for top grade:

  • The compile command: g++ -O2 -std=c++17 file.cpp -o exe.
  • The pointer trio: & (address-of), * (declaration / dereference).
  • The 3 ways to pass to functions: by value (copy), by pointer (int*), by reference (int&).
  • Class anatomy: declaration / definition / constructor / member function / private vs public.
  • The Complex exercise — Memorise it.

2. Basics from Zero

A C++ program is a text file (.cpp) the compiler turns into a binary you can execute. Minimum example:

#include <iostream>
int main() {
    std::cout << "Hello World" << std::endl;
    return 0;
}

Compile and run:

g++ example01.cpp -o example01
./example01            # prints "Hello World"

C++ has strict typing: every variable has a fixed type known at compile time (int, char, float, double, bool). Sizes are platform-dependent but typical:

int    : 4 bytes (32-bit)
char   : 1 byte
float  : 4 bytes (32-bit IEEE-754)
double : 8 bytes (64-bit IEEE-754)
bool   : 1 byte

A pointer stores an address. int *p = &b; makes p point at b; *p reads back the value at that address.

A reference is an alias for an existing variable: int& r = b;r is just another name for b. References are like "pointers that can never be null and never re-bind".

বাংলায়: Pointer হলো এমন একটা variable যার ভেতরে মান নয়, আরেকটা variable-এর মেমরি ঠিকানা থাকে — &b দিয়ে ঠিকানা নেওয়া হয়, *p দিয়ে সেই ঠিকানায় গিয়ে মান পড়া হয়। Reference হলো একই variable-এর আরেকটা নাম — null হতে পারে না, পরে অন্য কিছুর দিকে ঘোরানোও যায় না। পরীক্ষায় "pointer vs reference" পার্থক্যটা প্রায় প্রতি বছর আসে, তিনটা পয়েন্ট মুখস্থ রাখুন: null সম্ভব কি না, re-bind সম্ভব কি না, dereference করতে * লাগে কি না।

Functions can take parameters by value (a copy is made — original untouched), by pointer (caller passes &x, callee writes *p = ...), or by reference (cleanest syntax; modifies original).

বাংলায়: Function-এ argument পাঠানোর তিনটা পথ: by value মানে কপি যায় (মূলটা অক্ষত), by pointer মানে ঠিকানা যায় (callee *p দিয়ে মূলটা বদলাতে পারে), আর by reference মানে আসল variable-টাই অন্য নামে যায়। HPC-তে এটা শুধু syntax নয়, performance-এর প্রশ্ন — কয়েক GB-র field কপি করা মানে simulation-এর সর্বনাশ। পরীক্ষায় example10.cpp-এর output predict করতে দেয়: value বদলায় না, reference বদলায়।

Classes group data + functions. The lecture's Complex class stores a real and imaginary part and provides display, add, multiply, modulus.

Real-life analogy. Pointers = postal addresses (you can copy the address; everyone holding the address visits the same house). References = nicknames (Mr. President = Joe Biden — both refer to the same person; you can't make "Mr President" point to someone else later). Classes = forms with fields plus filing instructions stapled together.

Real-life HPC use. A CFD field of 1e9 cells is 8 GB; passing it by value to a function would copy 8 GB; by reference passes a 8-byte address. Wrong choice = simulation 1000× slower.

What if you misunderstand? You write int *p; *p = 5; without setting p first → segmentation fault. Or you use = for compare in if(a=5) → always true (assignment). Or you forget ; after class definition → cryptic compile errors.


3. Hard English Made Easy

Hard Term Simple English বাংলা Example
Compiler Translates source to binary উৎস → বাইনারিতে অনুবাদ g++
Linker Joins object files into binary অবজেক্ট ফাইল যোগ করা ld
Header file Declarations ঘোষণাপত্র ফাইল <iostream>
Namespace Naming scope নাম-পরিধি std::cout
Scope Where a name is visible পরিধি local / global
Pointer Variable holding address অ্যাড্রেস ধরে রাখা ভেরিয়েবল int *p
Reference Alias for an existing var বিদ্যমান ভেরিয়েবলের নামান্তর int& r
Dereference Access value at pointer পয়েন্টার থেকে মান পড়া *p
Address-of Get the memory address মেমরির ঠিকানা নেওয়া &x
Stack / Heap Auto / dynamic memory অটো / ডায়নামিক মেমরি int x; / new int
Class Blueprint for objects অবজেক্টের নকশা class Complex
Object Instance of class ক্লাসের উদাহরণ Complex c(3,4)
Member Variable/function inside class ক্লাসের সদস্য c.real()
Constructor Special init function ইনিশিয়াল ফাংশন Complex(float,float)
Destructor Cleanup function ক্লিনআপ ফাংশন ~Complex()
Public / Private Access level পাবলিক / প্রাইভেট private:
Function declaration Signature only শুধু সিগনেচার bool is_prime(int);
Function definition Body বডি bool is_prime(int n){…}
Pass by value Copy the argument কপি পাঠানো void f(int)
Pass by reference Share the argument শেয়ার পাঠানো void f(int&)
Pass by pointer Address of argument অ্যাড্রেস পাঠানো void f(int*)
Inline Compiler may substitute body কম্পাইলার বডি বসাতে পারে inline int sq(int)
Optimisation flag Compiler speed setting অপটিমাইজেশন স্তর -O2, -O3
std::endl Newline + flush নতুন লাইন + ফ্লাশ cout<<endl;

4. Deep Theory Explanation

4.1 Build cycle

hello.cpp ── preprocess ──▶ hello.i  (#include resolved)
           ── compile   ──▶ hello.s  (assembly)
           ── assemble  ──▶ hello.o  (object)
           ── link      ──▶ hello    (executable)

g++ does all four steps by default: g++ hello.cpp -o hello. To stop earlier: -E preprocess, -S assembly, -c object only.

বাংলায়: g++ এক কমান্ডে চারটা ধাপ চালায়: preprocessor (#include বসানো), compiler (C++ থেকে assembly), assembler (assembly থেকে machine code), আর linker (সব জোড়া লাগিয়ে executable)। -E, -S, -c flag দিয়ে যেকোনো ধাপে থেমে যাওয়া যায় — কোন flag কোন ফাইল (.i, .s, .o) বানায় সেটা পরীক্ষার নিশ্চিত প্রশ্ন, Chapter 12-তে এর পূর্ণ বিবরণ আছে।

Useful flags:

Flag Meaning
-O0/-O1/-O2/-O3 Optimisation level
-Ofast Beyond -O3, may break IEEE-754
-g Debug info
-Wall -Wextra -Wpedantic Warnings
-std=c++17 / -std=c++20 Language standard
-march=native Tune for current CPU
-fopenmp Enable OpenMP
-I<dir> Add include path
-L<dir> -lname Library paths

4.2 Variables, types, sizeof

(example02.cpp)

int   a = 34;       // 4 bytes
char  b = 'k';      // 1 byte
float c = 32.56;    // 4 bytes
std::cout << sizeof(int);   // → 4

4.3 Scope & namespaces

(example03.cpp, example04.cpp)

int a = 34;          // global

int main() {
    int a = 23;          // local — shadows global
    std::cout << a;       // 23
    std::cout << ::a;     // 34 — global qualifier
}

Namespaces:

namespace box {
    int a = 0;
}

int main() {
    int a = 23;
    box::a = 34;
    std::cout << a << " " << box::a;   // 23 34
}

std:: is the namespace of the C++ standard library; using namespace std; makes names unqualified (avoid in headers).

বাংলায়: Scope মানে একটা নাম কোথা থেকে দেখা যায়। Local variable একই নামের global-কে ঢেকে দেয় (shadowing); তখন ::a লিখে global-টা ধরতে হয়, আর box::a লিখে box namespace-এরটা। using namespace std লিখলে সব std:: নাম খালি হয়ে যায় — header ফাইলে এটা করা খারাপ অভ্যাস, কারণ নামের সংঘর্ষ হতে পারে। পরীক্ষায় shadowing-এর output predict (23 নাকি 34?) খুব প্রিয় প্রশ্ন।

4.4 Pointers

(example05.cpp)

int b = 23;
int *a = &b;          // a holds &b
std::cout << a;       // address (e.g. 0x7ffd...)
std::cout << *a;      // 23 — dereference

Three operators:

  • &x — address of x.
  • *p — value pointed to by p (as expression).
  • int *p — declaration of pointer to int.

Null pointer: int *p = nullptr;. Dereferencing it crashes the program.

Pointer diagram — two boxes in memory, the pointer's value is the other box's address:

        int b = 23;                        int *p = &b;

   address: 0x7ffc1000                address: 0x7ffc1008
   ┌─────────────────────┐            ┌─────────────────────┐
   │     b  =  23        │ ◄──────────│  p = 0x7ffc1000     │
   └─────────────────────┘  "points   └─────────────────────┘
                              to"
   &b  ─►  0x7ffc1000     (address-of operator)
    p  ─►  0x7ffc1000     (the value stored in p IS that address)
   *p  ─►  23             (dereference: follow the arrow, read the box)

   *p = 5;   writes 5 into b's box  ─►  b is now 5

বাংলায়: ছবিটা মাথায় গেঁথে নিন: b একটা বাক্স যাতে 23 আছে, আর p আরেকটা বাক্স যাতে b-র ঠিকানা লেখা আছে। &b মানে "b-র ঠিকানা দাও", p-এর ভেতরের মানটাই সেই ঠিকানা, আর p মানে "তীরচিহ্ন ধরে গিয়ে বাক্সটা খোলো"। p = 5 লিখলে আসলে b-ই বদলায় — কারণ দুজনে একই বাক্সের কথা বলছে। উদ্যোগহীন (uninitialised) pointer dereference করলেই segfault — পরীক্ষার প্রিয় bug।

4.5 Arrays and pointer arithmetic

(example06.cpp, example07.cpp)

int a[5] = {34,76,48,55,7};
for (int i=0; i<5; ++i)
    std::cout << a[i] << "\n";

int *b = &a[0];        // points at a[0]
for (int i=0; i<5; ++i)
    std::cout << (b+i) << " : " << *(b+i) << "\n";  // pointer + int = next int
  • a[i] is sugar for *(a+i).
  • Pointer arithmetic moves by sizeof(type) bytes per step.
  • Be careful not to read past a[4] — undefined behaviour.

বাংলায়: Array-র নামটা আসলে প্রথম element-এর ঠিকানায় "ক্ষয়" (decay) হয়ে যায়, তাই a[i] আর *(a+i) হুবহু একই জিনিস। Pointer-এ +1 করলে 1 byte নয়, sizeof(type) byte এগোয় — int-এ 4, double-এ 8। ঠিক কত byte এগোবে সেই হিসাবটা §4.11-এ hex ঠিকানা দিয়ে করা আছে; পরীক্ষায় ঠিকানা মেলাতে দেওয়া হয়।

4.6 Conditionals & loops

(example08.cpp)

for (int i=0; i<5; ++i) {
    if (a[i] % 2 == 0) {
        std::cout << "a[" << i << "] = " << a[i] << "\n";
    }
}

Other forms: if (...) {} else if (...) {} else {}, switch, while, do-while, for.

Ternary: cout << (n>0 ? "pos" : "non-pos");.

4.7 Functions

(example09.cpp)

bool is_prime(int num);          // declaration

bool is_prime(int num)           // definition
{
    if (num<2) return false;
    for (int i=2; i<num; ++i)
        if (num%i==0) return false;
    return true;
}

A declaration (prototype) tells the compiler the signature; a definition gives the body. You can put declarations in .h files and definitions in .cpp files.

4.8 Call by value / pointer / reference

(example10.cpp)

void callByValue(int a)        { a++; }       // copy → caller's var unchanged
void callByPointer(int* a)     { (*a)++; }    // modify via address
void callByReference(int& a)   { a++; }       // alias → modifies caller

Modern C++ prefers int&; pointers (int*) are needed when you may pass nullptr or arrays. Const-references (const T&) are the fast read-only idiom for big objects (CFD fields).

CALL BY VALUE:  void f(int a)           CALL BY REFERENCE:  void f(int& a)
──────────────────────────────────      ──────────────────────────────────
caller                                  caller
┌────────────────┐                      ┌────────────────┐
│  x = 34        │                      │  x = 34 ─► 35  │◄──────────┐
└───────┬────────┘                      └────────────────┘           │
        │ the VALUE 34 is COPIED                 ▲                   │
        ▼                                        │ alias: a IS x    │
callee f                                callee f │                   │
┌────────────────┐                      ┌────────┴──────────────────┐│
│  a = 34 ─► 35  │  separate box!       │ a has NO box of its own — ││
└────────────────┘                      │ it refers straight into   ├┘
  a++ changes only the copy             │ the caller's box          │
  copy destroyed at return              └───────────────────────────┘
  caller still sees x = 34                a++ ─► caller sees x = 35

বাংলায়: By value মানে callee নিজের আলাদা বাক্সে কপি পায় — সেখানে যা-ই করুক, caller-এর x অক্ষত থাকে আর return-এর সময় কপিটা মুছে যায়। By reference মানে a-র নিজের কোনো বাক্সই নেই, ওটা caller-এর x-এরই আরেক নাম — a++ করলেই x বদলে যায়। বড় object-এর জন্য const T& হলো সেরা সমাধান: কপিও হয় না, ভুলে বদলানোও যায় না। পরীক্ষায় example10.cpp-এর "34 নাকি 35" প্রশ্নটা এই ছবির ওপরেই দাঁড়িয়ে।

4.9 Classes and objects

(task_02_solution.cpp — Complex class, full)

class Complex {
private:
    float a;
    float b;
public:
    Complex(float x, float y) : a(x), b(y) {}    // constructor with init list
    void display();
    float real();
    float img();
    Complex add(Complex c1, Complex c2);
    Complex multiply(Complex c1, Complex c2);
    float modulus();
};

void Complex::display()  { std::cout << a << "+" << b << "i\n"; }
float Complex::real()    { return a; }
float Complex::img()     { return b; }

Complex Complex::add(Complex c1, Complex c2) {
    return Complex(c1.real()+c2.real(), c1.img()+c2.img());
}

Complex Complex::multiply(Complex c1, Complex c2) {
    float r = c1.real()*c2.real() - c1.img()*c2.img();
    float i = c1.real()*c2.img() + c1.img()*c2.real();
    return Complex(r, i);
}

float Complex::modulus() { return std::sqrt(a*a + b*b); }

Concepts:

  • class { private: …; public: …; }; — members default to private.
  • Constructor Complex(float, float) — no return type, automatically called when an object is created.
  • Member functions accessed via obj.method().
  • Complex::method definition syntax outside the class.

বাংলায়: Class মানে data আর function একসাথে বেঁধে রাখা: a, b হলো private (বাইরে থেকে ছোঁয়া যায় না), আর display, add-এর মতো method গুলো public। Constructor-এর নাম class-এর নামের সমান এবং কোনো return type নেই — void-ও নয়, এটা লিখলেই compile error। আর class-এর শেষের ; (semicolon) ভুলে গেলে পরের লাইনে অদ্ভুত error আসে। Complex class-টা পরীক্ষার সবচেয়ে দামি প্রশ্ন — পুরোটা মুখস্থ করে হাতে লিখে প্র্যাকটিস করুন।

4.10 Diagrams from V09

  • Memory layout diagramint a; int *p=&a; showing two boxes with arrow.
  • Call-by-value vs call-by-reference table — caller's a vs callee's a.
  • Class diagramComplex with private fields, public methods.

4.11 Memory mathematics — sizeof, pointer arithmetic, copy cost

The sizeof table (x86-64 Linux, LP64 model) — memorise:

Type sizeof (bytes) Notes
char 1 by definition
bool 1
int 4 32-bit two's complement
float 4 IEEE-754 single precision
long 8 on Linux x86-64
double 8 IEEE-754 double precision
any pointer T* 8 a 64-bit address — independent of T

Pointer arithmetic rule. For a pointer p of type T* and integer \(k\):

\[ \mathrm{address}(p + k) = \mathrm{address}(p) + k \cdot \mathrm{sizeof}(T) \]

Worked example 1 — int array. Let int a[5] start at address 0x7ffc2000. With \(\mathrm{sizeof(int)} = 4\):

Expression Computation Address
a + 0 \(\texttt{0x7ffc2000} + 0\cdot 4\) 0x7ffc2000
a + 1 \(\texttt{0x7ffc2000} + 1\cdot 4\) 0x7ffc2004
a + 2 \(\texttt{0x7ffc2000} + 2\cdot 4\) 0x7ffc2008
a + 4 \(\texttt{0x7ffc2000} + 4\cdot 4 = +16 = \texttt{0x10}\) 0x7ffc2010

Worked example 2 — double array. Let double d[5] start at 0x7ffc3000. With \(\mathrm{sizeof(double)} = 8\):

Expression Computation Address
d + 1 \(+1\cdot 8 = \texttt{0x8}\) 0x7ffc3008
d + 3 \(+3\cdot 8 = 24 = \texttt{0x18}\) 0x7ffc3018
d + 4 \(+4\cdot 8 = 32 = \texttt{0x20}\) 0x7ffc3020

Same +1, different byte step — that is the whole point of typed pointers. Pointer difference works backwards: (a+4) - a = 4 elements = \(4 \cdot 4 = 16\) bytes.

Copy cost: pass-by-value vs pass-by-reference. A struct holding \(N\) doubles occupies \(8N\) bytes. Passing it to a function costs:

\[ C_{\text{value}} = 8N \ \text{bytes copied}, \qquad C_{\text{ref}} = 8 \ \text{bytes (one address)} \]

Worked numbers for a CFD field with \(N = 10^6\) cells: by value, every call copies \(8 \cdot 10^6 = 8\,\mathrm{MB}\); at a memory bandwidth of \(10\,\mathrm{GB/s}\) that is \(8\cdot 10^6 / 10^{10} = 0.8\,\mathrm{ms}\) per call — inside a loop over \(10^4\) timesteps that is 8 seconds of pure copying. By reference the cost stays at 8 bytes, a ratio of \(10^6\). Hence the HPC idiom void solve(const Field& f).

Process memory layout — where everything lives:

 high addresses
┌────────────────────────────────┐  ~0x7fffffffffff
│             STACK              │  function frames & locals:
│  main() frame: int x; p; ...   │    int x;  double y[10];
│  f() frame: params, locals     │  every call PUSHES a frame,
│             │                  │  every return POPS it
│             ▼   grows DOWN     │  (size limit ~8 MB!)
├────────────────────────────────┤
│         (unused gap)           │
├────────────────────────────────┤
│             ▲   grows UP       │
│             │                  │
│             HEAP               │  new double[N] lives HERE;
│   new double[1000000] = 8 MB   │  survives until delete[];
│   block sits here; only the    │  the POINTER to it sits in a
│   pointer to it is on the stack│  stack frame
├────────────────────────────────┤
│          DATA + BSS            │  globals & statics:
│   int g = 34;     (data)       │  initialised  -> data
│   static int cnt; (bss, zeroed)│  uninitialised -> bss
├────────────────────────────────┤
│             TEXT               │  the machine code itself:
│   main, swap, Complex::add ... │  read-only
└────────────────────────────────┘  low addresses

বাংলায়: Stack হলো ছোট আর স্বয়ংক্রিয় — প্রতিটা function call-এ একটা frame জমে, return করলেই মুছে যায়; সাধারণ local variable এখানেই থাকে। Heap হলো বড় কিন্তু manual — new দিয়ে নিতে হয়, delete দিয়ে ফেরত দিতে হয়, না দিলে memory leak। মনে রাখুন: stack-এর সীমা মোটে ~8 MB, তাই কোটি cell-এর CFD field সবসময় heap-এ (new বা std::vector) রাখতে হয় — stack-এ নিলেই stack overflow।

4.12 Complex-number mathematics and the Complex class

For \(z_1 = a + bi\) and \(z_2 = c + di\) (with \(i^2 = -1\)):

\[ z_1 + z_2 = (a + c) + (b + d)i \]
\[ z_1 \cdot z_2 = (ac - bd) + (ad + bc)i \]
\[ |z| = \sqrt{a^2 + b^2}, \qquad \bar{z} = a - bi, \qquad z\bar{z} = a^2 + b^2 = |z|^2 \]

Worked example by hand: \((3+4i)\cdot(1-2i)\). Here \(a=3,\ b=4,\ c=1,\ d=-2\):

  • Real part: \(ac - bd = 3\cdot 1 - 4\cdot(-2) = 3 + 8 = 11\)
  • Imaginary part: \(ad + bc = 3\cdot(-2) + 4\cdot 1 = -6 + 4 = -2\)
  • Result: \(11 - 2i\).

Also: \((3+4i) + (1-2i) = 4 + 2i\); \(\ |3+4i| = \sqrt{9+16} = \sqrt{25} = 5\); \(\ \overline{3+4i} = 3-4i\) and \((3+4i)(3-4i) = 9 + 16 = 25 = |z|^2\).

The code that produces exactly this (complete, compilable Complex class with constructor, operator+, operator*, abs, conj, print):

#include <iostream>
#include <cmath>

class Complex {
private:
    double re, im;
public:
    Complex(double r = 0.0, double i = 0.0) : re(r), im(i) {}   // constructor

    Complex operator+(const Complex& o) const {                 // (a+c) + (b+d)i
        return Complex(re + o.re, im + o.im);
    }
    Complex operator*(const Complex& o) const {                 // (ac-bd) + (ad+bc)i
        return Complex(re * o.re - im * o.im,
                       re * o.im + im * o.re);
    }
    Complex conj() const { return Complex(re, -im); }           // a - bi
    double  abs()  const { return std::sqrt(re*re + im*im); }   // sqrt(a^2+b^2)

    void print() const {
        std::cout << re << (im >= 0 ? "+" : "") << im << "i\n";
    }
};

int main() {
    Complex z1(3.0, 4.0), z2(1.0, -2.0);
    Complex s = z1 + z2;     // 4+2i
    Complex p = z1 * z2;     // 11-2i
    s.print();
    p.print();
    std::cout << "abs(z1) = " << z1.abs() << "\n";   // 5
    z1.conj().print();                                // 3-4i
    return 0;
}

Compile and run: g++ -O2 -std=c++17 -Wall complex.cpp -o complex && ./complex

4+2i
11-2i
abs(z1) = 5
3-4i

বাংলায়: Complex গুণের সূত্রটা \((ac-bd) + (ad+bc)i\) মুখস্থ রাখুন — মাইনাসটা real part-এ, কারণ \(i\cdot i = -1\)। Modulus মানে মূলবিন্দু থেকে দূরত্ব: \(\sqrt{a^{2}+b^{2}}\), আর conjugate মানে শুধু imaginary অংশের চিহ্ন উল্টে দেওয়া। হাতে হিসাব করে তারপর কোড মিলিয়ে দেখুন — পরীক্ষায় দুটোই চাওয়া হয়: হাতের হিসাব এবং operator overload — দুটোই প্রস্তুত রাখুন।

4.13 Pointer & call diagrams

(a) Pointer ↔ variable:

        int a = 5;            int *p = &a;
   ┌──────────────┐        ┌──────────────┐
   │  a            │        │  p           │
   │  value: 5     │◄───────┤ value:0x7ffc │   p stores a's ADDRESS
   │  addr: 0x7ffc │        │ addr: 0x7ff4 │
   └──────────────┘        └──────────────┘
   *p  reads/writes the box p points to:  *p = 7  ⇒  a == 7
   &a  asks for a's address:              &a == 0x7ffc

(b) Pass-by-value vs pass-by-reference:

   void f(int x)  — BY VALUE          void g(int& x) — BY REFERENCE
   caller: a=5                        caller: a=5
   ┌────────┐   copy   ┌────────┐     ┌────────┐  alias   ┌────────┐
   │ a = 5  │ ───────► │ x = 5  │     │ a = 5  │◄────────►│   x    │
   └────────┘          └────────┘     └────────┘          └────────┘
   x++ → x=6, a STILL 5               x++ → a == 6  (same box!)
   copy dies at return                no copy, no extra memory

বাংলায়: ছবি দুটো মাথায় গেঁথে নাও: pointer হলো আলাদা একটা বাক্স যাতে অন্য বাক্সের ঠিকানা লেখা; reference হলো একই বাক্সের দ্বিতীয় নাম। value-তে পাঠালে ফটোকপি যায় — আসল কাগজ অক্ষত; reference/pointer-এ পাঠালে আসল কাগজটাই যায়। CFD-তে কোটি-cell-এর array ফটোকপি করা অসম্ভব — তাই সব বড় জিনিস const T& বা pointer দিয়ে যায়।


5. Command / Syntax / Code Breakdown

g++ src.cpp -o exe

Compile + link to exe. Use -O2 -Wall -std=c++17 in production.

#include <iostream>

Bring in the iostream header so std::cout works.

int main() { … return 0; }

Program entry point. 0 indicates success.

int a = 5;

Variable declaration + init.

int& r = a;

Reference declaration. Must be initialised.

int *p = &a;

Pointer declaration + init. &a = address of a.

*p = 7;

Write through pointer.

for (int i=0; i<n; ++i) { … }

C-style loop.

class C { public: int x; };

Trivial class.

void f(int); then void f(int x){…}

Declaration + definition.

Complex c(3,4);

Construct an object via constructor.


6. Mandatory Practical Examples

Example 6.1 — Hello world (example01.cpp)

Expected output: Hello World

  • #include <iostream> brings in the IO library.
  • int main() mandatory entry.
  • std::cout << "Hello World" << std::endl; print + newline + flush.
  • return 0; exit success.

Example 6.2 — Sizes (example02.cpp)

Size of int : 4
Size of char : 1
Size of float : 4

(Note: the lecture's example03 prints sizeof(c) (a float) under "Size of int" — typo. Exam-tip: mention this.)

Example 6.3 — Local vs global, scope resolution (example03.cpp)

a = 23
a = 34

::a accesses the global.

Example 6.4 — Namespace (example04.cpp)

a = 23
a = 34

Example 6.5 — Pointers (example05.cpp)

address(b) = 0x7ffe...            ← actual address varies
value(address(b)) = 23

Example 6.6 — Array iteration (example06.cpp)

a[0] = 34
a[1] = 76
a[2] = 48
a[3] = 55
a[4] = 7

Example 6.7 — Pointer arithmetic over array (example07.cpp)

0x7ffe...0 : 34
0x7ffe...4 : 76
0x7ffe...8 : 48
0x7ffe...c : 55
0x7ffe...10 : 7

(Each address is +4 bytes apart since int is 4 bytes.)

Example 6.8 — Conditional filter (example08.cpp)

a[0] = 34
a[2] = 48

(Only even values printed.)

Example 6.9 — Function: is_prime (example09.cpp)

a[1] = 2
a[2] = 3
a[4] = 5
a[6] = 7

Example 6.10 — Call by value vs reference (example10.cpp)

a after call by value:34
a after call by reference:35

By value: copy is incremented locally and discarded. By reference: original is modified.

Example 6.11 — Swap (E09 Task 1, solution)

#include <iostream>
void swap(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}
int main() {
    int a=34, b=25;
    std::cout << "Before: a=" << a << " b=" << b << "\n";
    swap(&a, &b);
    std::cout << "After: a=" << a << " b=" << b << "\n";
    return 0;
}

Output:

Before: a=34 b=25
After: a=25 b=34

Real-Life HPC/CFD Meaning. Swap-by-pointer demonstrates how solvers pass fields by address — never copy multi-MB arrays.

Written Exam Relevance. "Implement swap" appears in nearly every C++ basics exam.

Example 6.12 — Complex class (E09 Task 2, full solution)

#include <iostream>
#include <cmath>

class Complex {
private:
    float a, b;
public:
    Complex(float x, float y) : a(x), b(y) {}
    void display() { std::cout << a << "+" << b << "i\n"; }
    float real()     { return a; }
    float img()      { return b; }
    Complex add(Complex c1, Complex c2) {
        return Complex(c1.real()+c2.real(), c1.img()+c2.img());
    }
    Complex multiply(Complex c1, Complex c2) {
        return Complex(c1.real()*c2.real() - c1.img()*c2.img(),
                       c1.real()*c2.img() + c1.img()*c2.real());
    }
    float modulus() { return std::sqrt(a*a + b*b); }
};

int main() {
    Complex c1(3,4), c2(4,5), c3(0,0);
    c1.display();
    c2.display();
    c3 = c3.add(c1,c2);      c3.display();          // 7+9i
    c3 = c3.multiply(c1,c2); c3.display();          // -8+31i
    std::cout << "Modulus of c3 = " << c3.modulus() << "\n"; // sqrt(64+961) ≈ 32.02
    return 0;
}

Expected output:

3+4i
4+5i
7+9i
-8+31i
Modulus of c3 = 32.0156

Check the multiplication by hand: \((3+4i)(4+5i) = (3\cdot4 - 4\cdot5) + (3\cdot5 + 4\cdot4)i = -8 + 31i\). Modulus: \(\sqrt{(-8)^2+31^2} = \sqrt{64+961} = \sqrt{1025} \approx 32.0156\).

Real-Life Meaning. The same OO pattern is used in CFD for Vector, Tensor, Field, BoundaryCondition classes.

Written Exam Relevance. Top-mark question often: "Complete the class so that c3 = c3.add(c1,c2) works." Provide the constructor + member function definitions.


7. Real HPC/CFD Workflow

# 1. Edit
vim solver.cpp

# 2. Compile fast
g++ -O3 -march=native -std=c++17 -fopenmp solver.cpp -o solver

# 3. Run (single-thread)
./solver in.dat > out.log

# 4. Run (8 OpenMP threads)
OMP_NUM_THREADS=8 ./solver in.dat > out.log

# 5. Profile
g++ -O2 -g -pg solver.cpp -o solver_prof
./solver_prof in.dat
gprof solver_prof gmon.out | head

# 6. Debug (Ch.13)
g++ -O0 -g solver.cpp -o solver_dbg
gdb ./solver_dbg

8. Exercises and Solutions

E09 Task 1 (swap) — see 6.11.

Marking scheme (8 marks):

  • 1 declaration void swap(int*, int*).
  • 2 use of *a, *b to read/write.
  • 1 temporary variable.
  • 2 main: call as swap(&a,&b).
  • 2 correct output before/after.

Common mistake. Writing void swap(int a, int b){ int t=a; a=b; b=t; } (call-by-value) — does nothing.

Harder version. Use references: void swap(int& a, int& b){ int t=a; a=b; b=t; } and call swap(a,b).

E09 Task 2 (Complex class) — see 6.12.

Marking scheme (12 marks):

  • 1 private: data members.
  • 2 constructor.
  • 1 display.
  • 1 real/img getters.
  • 2 add correctness.
  • 2 multiply correctness.
  • 1 modulus formula.
  • 1 main: construct + invoke.
  • 1 expected output.

Common mistakes.

  • Forgot ; after class definition.
  • Constructor with void return type → compile error (constructors have no return type).
  • Used pow(a,2)+pow(b,2) instead of a*a+b*b — works but slower in HPC; prefer multiplication.
  • class default access is private; forgot public: → main can't call methods.

Harder version. Add an operator+ / operator* overload so c3 = c1 + c2. Use a const-ref signature to avoid copies:

Complex operator+(const Complex& other) const {
    return Complex(a + other.a, b + other.b);
}

বাংলায়: operator overloading-এর তিনটা exam-checkpoint: (১) parameter const Complex& — copy এড়াতে, (২) ফাংশনের শেষে const — নিজের object বদলায় না বোঝাতে, (৩) নতুন object return। এই তিনটা লিখলেই "harder version" -এর পুরো নম্বর।


9. Written Exam Focus

9.1 Short Answers

Q. Difference between pointer and reference. A. A pointer holds an address — can be null, can be re-assigned, requires * to dereference. A reference is an alias to an existing variable — cannot be null, cannot be re-bound, used like the original.

Q. What does & do in C++? A. As a unary operator on a value (&x), it returns the address. In a type declaration (int& r), it indicates a reference type.

Q. Why use call-by-reference? A. Avoids copying the argument and lets the function modify the caller's variable. Crucial for large CFD fields.

Q. Difference between class declaration and definition. A. A declaration introduces the name (class Complex;); a definition provides the full body (class Complex { … };).

Q. What is std::endl? A. Inserts '\n' AND flushes the stream. For performance use '\n' alone.

9.2 Medium Answers

Q. (8 marks) Explain pointers and arrays in C++ with code.

A. A pointer (int *p) stores a memory address. &x yields the address of x; *p accesses the value at the address. An array int a[5] is contiguous memory; the name decays to a pointer to its first element. Pointer arithmetic *(a+i) is equivalent to a[i]. Example:

int a[5]={1,2,3,4,5};
int* b=&a[0];
for(int i=0;i<5;++i) std::cout<<*(b+i)<<" ";

Common mistake: dereferencing past the end → undefined behaviour.

Q. (5 marks) Compare call by value vs reference vs pointer.

A. Value: a copy is made; original untouched (void f(int)). Reference: alias to original; modifications propagate (void f(int&)). Pointer: caller passes the address (f(&x)), callee modifies via *p (void f(int*)). References are cleanest; pointers are needed when nullability or array passing is required.

9.3 Long Answer (12 marks)

Q. Walk through the Complex class implementation.

A.

Introduction. The Complex class encapsulates a complex number with real (a) and imaginary (b) parts and provides operations.

Main concept. OO encapsulation: data is private, methods are public. A constructor Complex(float, float) initialises the state.

Step-by-step.

  1. Headers <iostream>, <cmath> for std::sqrt.
  2. class Complex { private: float a,b; public: … };
  3. Constructor with member-init list: Complex(float x,float y) : a(x), b(y) {}.
  4. Member functions defined outside with Complex::name.
  5. add: \((c_1.a+c_2.a) + (c_1.b+c_2.b)i\).
  6. multiply: \((ac-bd) + (ad+bc)i\).
  7. modulus: \(\sqrt{a^2+b^2}\).

Example. \((3+4i)(4+5i) = (12-20) + (15+16)i = -8+31i\).

Real HPC/CFD link. The same OO pattern wraps Vector, Tensor, Field, BoundaryCondition in OpenFOAM. Composition + inheritance = the C++ way to model physics.

Conclusion. Classes provide reusable, type-safe abstractions central to HPC code.

9.4 Output Prediction

int a=10, *p=&a;
*p = 20;
std::cout << a;           // 20
int a=10; int& r=a; r=30; std::cout<<a;        // 30

example10.cpp predicted output:

a after call by value:34
a after call by reference:35

9.5 Comparison

Pointer Reference
Syntax int *p; *p int& r; r
Reseat yes no
Null yes no
Indirection explicit implicit
Use nullable, array, dynamic safer alias
class struct
Default access private public
Used for rich objects POD

9.6 Templates

Compile template: g++ -O2 -std=c++17 -Wall -fopenmp file.cpp -o exe; ./exe

Pointer template: int x=5; int *p=&x; *p=7; cout<<x; → 7.

Class template:

class T {
    private: /* data */;
    public:
        T(args) : /* init list */ {}
        ret method(args);
};
ret T::method(args) { /* ... */ }

Swap-by-pointer template: see 6.11.

9.7 Marking Scheme — "Complex class with operator+" (10 marks)

  • 2 class skeleton (private/public).
  • 2 constructor.
  • 1 display.
  • 2 add/multiply/modulus.
  • 2 operator+ overload (const Complex&).
  • 1 expected output.

10. Very Hard Questions

Beginner

  1. Compile hello.cpp. → g++ hello.cpp -o hello.
  2. Print "hi". → std::cout<<"hi"<<std::endl;
  3. Declare an int. → int a=5;
  4. Address of a. → &a.
  5. Pointer to a. → int *p=&a;

Intermediate

  1. Loop over array length 5. → for(int i=0;i<5;++i) ...
  2. Pass int by reference. → void f(int& a).
  3. Class with public method display(). → see Complex.
  4. Constructor with init list. → T():a(0){}.
  5. Why is using namespace std bad in headers? → name pollution.

Hard

  1. Why does f(int) not modify the caller's variable? → call-by-value copies.
  2. What's wrong with int *p; *p=5;? → uninitialised pointer (UB/segfault).
  3. Difference between delete and delete[]. → single object vs array.
  4. Why is endl slow? → flushes the buffer.
  5. Write a function returning an object of class C. → return by value uses copy/move.

Very Hard

  1. Why do CFD solvers prefer const Field& over Field? → avoid expensive copies.
  2. Difference between stack and heap allocation. → automatic vs new/delete, lifetime.
  3. What happens if you forget ; after class? → cascading errors at the next declaration.

Deep Integration

  1. How does pointer arithmetic underpin SIMD vectorisation? → contiguous memory, stride 1.
  2. Compare RAII to manual new/delete. → constructor acquires, destructor releases — exception-safe.

Coding/Command

  1. Implement swap(int& a, int& b). → see harder version in §8.
  2. Add operator+ to Complex. → see 9.7.

Debugging

  1. *p=10; placed before int a; p=&a; — what happens? → p is dereferenced uninitialised; segfault/UB.
  2. class C{int x;}; C c; c.x=5; — error? → x is private by default; need public: or an accessor.

Long Written

  1. (250 words) Discuss why HPC kernels avoid copying data — call-by-reference vs pointer trade-offs.

11. Debugging and Mistake Analysis

Mistake Why wrong Correct Explanation
if(a=5) assignment, not equality if(a==5) classic
int *p; *p=5; uninitialised int a; int *p=&a; *p=5; dereference safe pointer
swap(a,b) by value no-op swap(&a,&b) (ptr) or int& version reference types
Forgot ; after class cascade errors class X { … }; semicolon
private: accessed outside error accessor or public: encapsulation
Mismatched new/delete leak / UB delete[] for arrays RAII / smart pointers
using namespace std in .h symbol clashes qualify std:: hygiene
cout << endl in tight loop slow flushes '\n' performance
int vs unsigned compare warnings/UB-ish bugs be consistent -Wsign-compare
Forgot return 0 UB pre-C++11 always return habit

বাংলায়: পরীক্ষায় "find the bug" এলে আগে এই চারটা খোঁজো: if(a=5) (একটা =), uninitialised pointer, value-passed swap, আর class-এর পরে ; নেই। এই চারটাই সব exam-এর ৮০% bug।


12. Mini Project for Mastery

Goal: Implement a vector-of-Complex with sum and modulus.

#include <iostream>
#include <vector>
#include <cmath>

class Complex {
private:
    float a, b;
public:
    Complex(float x=0, float y=0) : a(x), b(y) {}
    float real() const { return a; }
    float img() const { return b; }
    float modulus() const { return std::sqrt(a*a+b*b); }
    Complex operator+(const Complex& o) const { return {a+o.a, b+o.b}; }
    friend std::ostream& operator<<(std::ostream& os, const Complex& c){
        return os << c.a << (c.b>=0?"+":"") << c.b << "i";
    }
};

int main() {
    std::vector<Complex> v = { {1,2}, {3,4}, {5,6} };
    Complex sum;
    for (const auto& c : v) sum = sum + c;
    std::cout << "sum = "     << sum << "\n";
    std::cout << "modulus = " << sum.modulus() << "\n";
}

Compile: g++ -O2 -std=c++17 mini.cpp -o mini && ./mini

Output:

sum = 9+12i
modulus = 15

Hand-check: \((1+3+5) + (2+4+6)i = 9+12i\), \(|9+12i| = \sqrt{81+144} = \sqrt{225} = 15\).

Connection to exam: class, constructor with defaults, const-correctness, operator overload, friend, range-based for — all top-mark idioms.


13. Final Chapter Cheat Sheet

Item Memorise
Compile g++ -O2 -std=c++17 -Wall src.cpp -o exe
Print std::cout << x << '\n';
Read std::cin >> x;
Types int 4B, char 1B, float 4B, double 8B, bool 1B, ptr 8B
Pointer int *p = &a; *p = 7;
Reference int& r = a; r = 7;
Array int a[5]={…}; a[i] == *(a+i)
Pointer arithmetic p+1 advances by sizeof(T) bytes
Function decl/def ret name(args); / ret name(args){…}
Pass by val/ref/ptr f(int), f(int&), f(int*)
Class class C{ private:…; public:…; };
Constructor C(args):member(args){}
Member def ret C::method(args){…}
Modulus \(\sqrt{a^2+b^2}\)
Complex add \((a+c)+(b+d)i\)
Complex mul \((ac-bd)+(ad+bc)i\)
Optimisation -O2 -march=native
Debug -O0 -g, gdb
Trap if(a=5) (assignment)
Top phrase "References are aliases, pointers are addresses; both avoid copying — vital for HPC."

14. Mock Exam — Four Levels

Level 1 — Basic (definitions & syntax)

Q1. Declare a pointer to double and make it point to variable t.

Solution: double *p = &t;

Q2. What is printed? int a=3; int& r=a; r=8; std::cout<<a;

Solution: 8 — r is an alias for a.

Q3. Give the g++ command compiling main.cpp with warnings and C++17.

Solution: g++ -std=c++17 -Wall main.cpp -o main

Q4. What are the sizes of char, int, double, and a pointer on x86-64?

Solution: 1, 4, 8, 8 bytes.

Q5. Write the signature of a function norm that takes a Complex by const reference and returns float.

Solution: float norm(const Complex& c);

Level 2 — Intuitive (predict the output / explain why)

Q1. Predict:

int a[4] = {10,20,30,40};
int *p = a;
std::cout << *(p+2) << " " << p[1];

Solution: 30 20*(p+2)a[2]; p[1]a[1]. Identical notations.

Q2. Why does this NOT compile? int& r;

Solution: References must be bound at initialisation — there is no "null reference".

Q3. Predict:

void f(int x){ x=99; }
int main(){ int a=1; f(a); std::cout<<a; }

Solution: 1 — f gets a copy; the 99 dies with the copy.

Q4. double* q = new double[1000]; — where do q and the 1000 doubles live?

Solution: q itself is a local variable on the STACK; the 8000-byte block lives on the HEAP until delete[] q.

Q5. For int a[5] at address 0x1000, what is the address of a[3]? Show the math.

Solution: \(0x1000 + 3 \times 4 = 0x100C\) — pointer arithmetic scales by sizeof(int)=4.

Level 3 — Hard (exam level)

Q1. (8 marks) Compute \((2-3i)(1+4i)\) by hand using the multiplication formula, then write the two lines of C++ using the Complex class of 6.12 that compute and print it.

Solution: \((ac-bd) = 2\cdot1-(-3)(4) = 2+12 = 14\); \((ad+bc) = 2\cdot4+(-3)(1) = 8-3 = 5\)\(14+5i\).

Complex z = c3.multiply(Complex(2,-3), Complex(1,4));
z.display();    // 14+5i
বাংলা ইঙ্গিত: মাইনাস-চিহ্নগুলো সাবধানে: \(-bd = -(-3)(4) = +12\) — sign-এর ভুলেই বেশিরভাগ নম্বর যায়।

Q2. (8 marks) This compiles but crashes. Find the bug and fix it:

int* make_array(int n){
    int arr[n];
    for(int i=0;i<n;++i) arr[i]=i*i;
    return arr;
}

Solution: arr is a stack array that dies when the function returns — the returned pointer dangles. Fix: heap-allocate int* arr = new int[n]; (caller must delete[]), or better return std::vector<int>. বাংলা ইঙ্গিত: function-এর ভেতরের local array return করা মানে ভাড়া-বাড়ির চাবি ফেরত দিয়ে ঠিকানা বিলি করা — stack frame শেষ, মেমরিও শেষ।

Q3. (10 marks) Write a function scale(double* v, int n, double k) that multiplies an array in place, and explain why it must take a pointer (or reference) rather than by value. Then show the call for double f[3]={1,2,3} with k=2 and the resulting array.

Solution:

void scale(double* v, int n, double k){
    for(int i=0;i<n;++i) v[i] *= k;
}
scale(f, 3, 2.0);   // f becomes {2,4,6}
Arrays decay to pointers; by-value copying is impossible for raw arrays and would anyway modify only a copy. The pointer gives direct access to the caller's memory. বাংলা ইঙ্গিত: array নাম নিজেই first element-এর pointer হয়ে যায় (decay) — তাই scale(f, …) লেখা যায়, &f[0] লিখতে হয় না।

Q4. (10 marks) Add to the Complex class: Complex conj() const and bool operator==(const Complex&) const. Write both, with one line of test code each.

Solution:

Complex conj() const { return Complex(a, -b); }
bool operator==(const Complex& o) const { return a==o.a && b==o.b; }
// tests:
Complex(3,4).conj().display();              // 3-4i
std::cout << (Complex(1,2)==Complex(1,2));  // 1
(Float equality is acceptable here; mention an epsilon-compare std::fabs(a-o.a)<1e-6 for bonus.) বাংলা ইঙ্গিত: getter/conj-জাতীয় "পড়া-শুধু" method-এর শেষে const — না দিলে const object থেকে ডাকা যায় না; এই খুঁটিনাটিই top marks আলাদা করে।

Q5. (10 marks) Predict the exact output and justify each line:

int x = 5;
int* p = &x;
int& r = x;
*p = *p + 1;
r = r * 2;
std::cout << x << " " << *p << " " << r << "\n";

Solution: 12 12 12 — all three names refer to ONE box: *p+1 → x=6; r*2 → x=12; printing x, p, r reads the same 12. বাংলা ইঙ্গিত:* pointer আর reference দুটোই থাকলে মাথায় একটাই ছবি আঁকো — বাক্স একটা, নাম তিনটা।

Level 4 — Beyond the lecture (transfer + coding)

Q1. Implement a minimal RAII wrapper DynArray holding double* with constructor (allocates n), destructor (frees), operator[], and a deleted copy constructor. Explain why copying must be forbidden (or deep-copied).

Solution:

class DynArray {
    double* data; int n;
public:
    explicit DynArray(int n_) : data(new double[n_]), n(n_) {}
    ~DynArray() { delete[] data; }
    DynArray(const DynArray&) = delete;            // no shallow copies!
    DynArray& operator=(const DynArray&) = delete;
    double& operator[](int i) { return data[i]; }
    int size() const { return n; }
};
A default (shallow) copy would duplicate the pointer; both objects would delete[] the same block → double free. Either delete copying or implement a deep copy. বাংলা ইঙ্গিত: "rule of three"-র মর্ম: destructor-এ delete থাকলে copy constructor/assignment-ও সামলাতে হবে — নাহলে double free।

Q2. An OpenMP loop (Ch 14 preview) over std::vector<double> v computes a sum. Why does for(auto x : v) sum += x; copy each element, and what is the zero-copy form? Write the OpenMP version.

Solution: auto x deduces a value type → element copy each iteration. Zero-copy: for (const auto& x : v). OpenMP:

double sum = 0.0;
#pragma omp parallel for reduction(+:sum)
for (size_t i = 0; i < v.size(); ++i) sum += v[i];
বাংলা ইঙ্গিত: range-for-এ & না দিলে প্রতি iteration-এ কপি — ছোট double-এ সস্তা, কিন্তু বড় class-এ মারাত্মক; অভ্যাসটা const auto&

Q3. Memory math: a CFD field stores 3 velocity components + pressure as doubles for \(10^8\) cells. Compute the memory in GiB, and state whether passing this Field by value 4 times during one time step is feasible on a 64 GiB node.

Solution: \(4 \times 8\,\text{B} \times 10^8 = 3.2\times10^9\) B \(= 3.2/1.0737 \approx 2.98\) GiB per copy. Four by-value copies = ~11.9 GiB extra traffic + peak allocation — wasteful and possibly fatal alongside solver workspace; pass by const Field& (0 copies). বাংলা ইঙ্গিত: GiB-এ ভাগ \(2^{30} = 1.0737\times10^9\) দিয়ে — আর সিদ্ধান্তের যুক্তি সবসময় "কপি × সাইজ বনাম RAM"।

Q4. Combine with bash (Ch 8): write a script-friendly main that reads n from argv[1], fills an array with squares, prints the sum, and returns 1 on bad input — then the one-line bash test that checks the program fails on "abc".

Solution:

#include <iostream>
#include <cstdlib>
int main(int argc, char** argv){
    if (argc < 2) { std::cerr << "usage: prog n\n"; return 1; }
    char* end;
    long n = std::strtol(argv[1], &end, 10);
    if (*end != '\0' || n <= 0) { std::cerr << "bad n\n"; return 1; }
    long long sum = 0;
    for (long i = 1; i <= n; ++i) sum += i*i;
    std::cout << sum << "\n";
    return 0;
}
Bash test: ./prog abc >/dev/null 2>&1 && echo BAD || echo "correctly failed" বাংলা ইঙ্গিত: atoi চুপচাপ 0 দেয় — validation চাইলে strtol-এর end-pointer দেখতেই হবে; আর exit code-ই bash-এর সাথে C++-এর চুক্তিপত্র।


End of Chapter 11.