Structured ProgrammingStructured Programming

The C language from zero: data types, loops, functions, arrays, pointers, structs, and memory — everything BUET loves to ask. C language একদম গোড়া থেকে: data type, loop, function, array, pointer, struct আর memory — BUET exam-এ যা যা আসে সবকিছু।

1. C Basics, Data Types & Operators1. C Basics, Data Types & Operators

Structured programming is a style of programming. It builds programs from three simple building blocks: sequence (do steps one after another), selection (if/else, switch), and repetition (loops). No messy goto jumps. C is the classic structured language, so this whole chapter is about C.

A C program always starts running from the main() function. Here is the smallest useful program:

Structured programming হলো programming-এর একটা style। এতে program বানানো হয় তিনটা সহজ building block দিয়ে: sequence (একটার পর একটা step), selection (if/else, switch) আর repetition (loop)। এলোমেলো goto jump নেই। C হলো classic structured language, তাই পুরো chapter টা C নিয়ে।

C program সবসময় main() function থেকে চলা শুরু করে। সবচেয়ে ছোট কাজের program টা এই রকম:

#include <stdio.h>

int main(void) {
    printf("Hello BUET\n");
    return 0;
}
/* Output:
Hello BUET
*/
The C programming language logo
C — the language of BUET admission tests. (Image: Wikimedia Commons) C — BUET admission test-এর language। (Image: Wikimedia Commons)

Data types and their sizesData type আর তাদের size

Every variable has a data type. The type decides how many bytes it takes and what values it can hold. Sizes below are the usual ones on a modern 64-bit machine (like the ones used in exams).

প্রত্যেক variable-এর একটা data type থাকে। Type ঠিক করে দেয় কত byte জায়গা লাগবে আর কী কী value রাখা যাবে। নিচের size গুলো modern 64-bit machine-এর common size (exam-এ সাধারণত এগুলোই ধরা হয়)।

TypeType Size (bytes)Size (bytes) Typical rangeসাধারণ range Format specifierFormat specifier
char1-128 toথেকে 127%c
short2-32,768 toথেকে 32,767%hd
int4-2,147,483,648 toথেকে 2,147,483,647%d
long8 (Linux)(Linux-এ)aboutপ্রায় ±9.2×1018%ld
long long8aboutপ্রায় ±9.2×1018%lld
float4~7 digits precision~7 digit precision%f
double8~15 digits precision~15 digit precision%lf
unsigned int40 toথেকে 4,294,967,295%u
Example:

Checking sizes with sizeof. Note: sizeof gives the size in bytes.

sizeof দিয়ে size বের করা। মনে রাখো: sizeof byte-এ size দেয়।

#include <stdio.h>
int main(void) {
    printf("%zu %zu %zu %zu\n",
        sizeof(char), sizeof(int), sizeof(float), sizeof(double));
    return 0;
}
/* Output:
1 4 4 8
*/
Note: A very common exam trap: in C, a character literal like 'A' has type int, not char. So sizeof('A') is 4, but sizeof(char) is always 1. (In C++ it would be 1 — C and C++ differ here!) খুব common একটা exam trap: C-তে 'A'-এর মত character literal-এর type হলো int, char না। তাই sizeof('A') হয় 4, কিন্তু sizeof(char) সবসময় 1। (C++-এ কিন্তু 1 হতো — C আর C++ এখানে আলাদা!)

Operators and precedenceOperator আর precedence

Precedence decides which operator works first. Associativity decides direction when precedence is equal. You do not need the full table — just remember these highlights (top = works first):

Precedence ঠিক করে কোন operator আগে কাজ করবে। Precedence সমান হলে associativity ঠিক করে কোন দিক থেকে হিসাব হবে। পুরো table মুখস্থ লাগবে না — শুধু এই highlight গুলো মনে রাখো (উপরেরটা আগে কাজ করে):

LevelLevel OperatorsOperators AssociativityAssociativity
1 (highestসবচেয়ে বেশি)() [] . -> x++ x--left to rightleft থেকে right
2++x --x ! ~ *(deref) &(address) sizeof (unary)right to leftright থেকে left
3* / %left to rightleft থেকে right
4+ -left to rightleft থেকে right
5<< >>left to rightleft থেকে right
6< <= > >= thenতারপর == !=left to rightleft থেকে right
7& thenতারপর ^ thenতারপর | (bitwise)left to rightleft থেকে right
8&& thenতারপর ||left to rightleft থেকে right
9?: thenতারপর = += -= ...right to leftright থেকে left
10 (lowestসবচেয়ে কম), (comma)left to rightleft থেকে right
Example:

What is the output?

Output কী হবে?

int a = 2 + 3 * 4;        /* * first: 2 + 12 = 14 */
int b = (2 + 3) * 4;      /* () first: 5 * 4 = 20 */
int c = 10 % 3 * 2;       /* same level, left to right: (10%3)*2 = 1*2 = 2 */
int d = 1 << 2 + 1;       /* + before << : 1 << 3 = 8  (tricky!) */
printf("%d %d %d %d\n", a, b, c, d);
/* Output:
14 20 2 8
*/
Example:

i++ vs ++i. Post-increment uses the old value first, then adds 1. Pre-increment adds 1 first.

i++ vs ++i। Post-increment আগে পুরনো value ব্যবহার করে, তারপর 1 যোগ করে। Pre-increment আগে 1 যোগ করে।

int i = 5, j = 5;
int x = i++;   /* x = 5, then i becomes 6 */
int y = ++j;   /* j becomes 6 first, y = 6 */
printf("%d %d %d %d\n", x, i, y, j);
/* Output:
5 6 6 6
*/
Note: Never write things like i = i++ + ++i;. Changing the same variable twice in one expression is undefined behavior in C — the answer can be anything. If an exam asks it, the safest answer is "undefined behavior". i = i++ + ++i; এই ধরনের জিনিস কখনো লিখো না। এক expression-এ একই variable দুইবার change করা C-তে undefined behavior — উত্তর যা খুশি হতে পারে। Exam-এ এলে সবচেয়ে safe উত্তর হলো "undefined behavior"।

Implicit type conversionImplicit type conversion

When two different types meet in one expression, C quietly converts the "smaller" type to the "bigger" one. The order is roughly: charintlongfloatdouble. Two big rules:

  • Integer division: int / int gives an int. 7 / 2 is 3, not 3.5.
  • Promotion: if one side is double, the whole thing becomes double. 7 / 2.0 is 3.5.

এক expression-এ দুইটা আলাদা type থাকলে C চুপচাপ "ছোট" type-কে "বড়" type-এ convert করে দেয়। Order মোটামুটি: charintlongfloatdouble। দুইটা বড় rule:

  • Integer division: int / int দিলে result int হয়। 7 / 2 হলো 3, 3.5 না।
  • Promotion: এক পাশ double হলে পুরোটা double হয়ে যায়। 7 / 2.0 হলো 3.5
Example:

What is the output?

Output কী হবে?

int a = 7, b = 2;
float f = a / b;          /* int/int = 3, then 3 becomes 3.0 */
float g = (float)a / b;   /* cast first: 7.0 / 2 = 3.5 */
char c = 'A' + 1;         /* 'A' is 65, so c = 66 = 'B' */
printf("%.1f %.1f %c\n", f, g, c);
/* Output:
3.0 3.5 B
*/

The cast (float)a converts before dividing. That is why g keeps the .5 part.

(float)a cast টা ভাগ করার আগে convert করে। এই জন্যই g-তে .5 অংশটা থেকে যায়।

Note: BUET exam often asks integer division traps like 5/2*2.0. Work left to right: 5/2 = 2 (int), then 2*2.0 = 4.0 (double). The answer is 4.0, not 5.0. BUET exam-এ প্রায়ই 5/2*2.0-এর মত integer division trap আসে। Left থেকে right হিসাব করো: 5/2 = 2 (int), তারপর 2*2.0 = 4.0 (double)। উত্তর 4.0, 5.0 না।

The signed vs unsigned comparison trapSigned vs unsigned comparison trap

When a signed int and an unsigned int meet in one expression, C uses the usual arithmetic conversions rule: the signed value is converted to unsigned. A negative number like -1 has no unsigned form, so it wraps around to a huge value: \( -1 \rightarrow 2^{32} - 1 = 4{,}294{,}967{,}295 \).

এক expression-এ signed int আর unsigned int একসাথে থাকলে C usual arithmetic conversions rule ব্যবহার করে: signed value টা unsigned-এ convert হয়ে যায়। -1-এর মত negative সংখ্যার কোনো unsigned রূপ নেই, তাই এটা ঘুরে গিয়ে বিশাল একটা value হয়ে যায়: \( -1 \rightarrow 2^{32} - 1 = 4{,}294{,}967{,}295 \)।

Example:

What is the output? (Think before you answer!)

Output কী হবে? (উত্তর দেওয়ার আগে ভাবো!)

int i = -1;
unsigned int u = 1;
if (i < u)
    printf("true branch");
else
    printf("false branch");
/* Output:
false branch
*/

Surprise! It looks like \(-1 < 1\) should be true. But i is converted to unsigned first, becoming 4,294,967,295. That is much bigger than 1, so the condition is false. Rule of thumb: signed + unsigned in the same comparison → the signed one becomes unsigned.

Surprise! মনে হয় \(-1 < 1\) true হওয়ার কথা। কিন্তু i আগে unsigned-এ convert হয়ে 4,294,967,295 হয়ে যায়। এটা 1-এর চেয়ে অনেক বড়, তাই condition false। মনে রাখার নিয়ম: একই comparison-এ signed + unsigned থাকলে → signed টা unsigned হয়ে যায়

Note: Real exam alert: this exact signed/unsigned comparison output question was asked in the BUET MSc admission test in April 2024. If you see an int compared with an unsigned int and one side is negative, the answer is almost always the "surprising" branch. Real exam alert: ঠিক এই signed/unsigned comparison output প্রশ্নটাই BUET MSc admission test-এ এসেছিল April 2024-এ। কোনো int-কে unsigned int-এর সাথে compare করা হচ্ছে আর এক পাশ negative — এমন দেখলে উত্তর প্রায় সবসময়ই "surprising" branch টা।

2. Loops and Conditions2. Loops and Conditions

if / elseif / else

if runs a block only when a condition is true. In C, 0 means false and any non-zero value means true. Even -1 is true.

if শুধু তখনই block টা চালায় যখন condition true। C-তে 0 মানে false আর যেকোনো non-zero value মানে true। এমনকি -1-ও true।

int marks = 75;
if (marks >= 80)      printf("A+");
else if (marks >= 70) printf("A");
else                  printf("Try again");
/* Output: A */
Example:

A classic trap — = vs ==. What is the output?

Classic trap — = vs ==। Output কী হবে?

int x = 0;
if (x = 5)          /* assignment! x becomes 5, and 5 is true */
    printf("yes ");
printf("%d", x);
/* Output:
yes 5
*/

x = 5 is an assignment, not a comparison. The value of the whole expression is 5, which is true. So the if body runs.

x = 5 হলো assignment, comparison না। পুরো expression-এর value 5, যেটা true। তাই if-এর body চলে।

Note: Dangling else: an else always pairs with the nearest unmatched if, no matter how the code is indented. Indentation means nothing to the compiler. Dangling else: else সবসময় সবচেয়ে কাছের unmatched if-এর সাথে জোড়া লাগে, indentation যেমনই হোক। Compiler indentation দেখে না।
int a = 1, b = 0;
if (a)
    if (b) printf("one");
else printf("two");     /* this else belongs to  if (b)  ! */
/* Output: two */

switchswitch

switch jumps to the matching case. Without break, it falls through: it keeps running the next cases too. This is the number one switch question in exams.

switch matching case-এ jump করে। break না থাকলে fall through হয়: পরের case গুলোও চলতে থাকে। Exam-এ switch-এর এক নম্বর প্রশ্ন এটাই।

Example:

What is the output? (Watch the missing breaks!)

Output কী হবে? (Missing break গুলো খেয়াল করো!)

int n = 2;
switch (n) {
    case 1: printf("one ");
    case 2: printf("two ");     /* match starts here */
    case 3: printf("three ");   /* falls through */
    default: printf("done");
}
/* Output:
two three done
*/

Execution starts at case 2 and never stops, because there is no break. So cases 2, 3 and default all run.

Execution শুরু হয় case 2 থেকে আর থামে না, কারণ কোনো break নেই। তাই case 2, 3 আর default সবগুলোই চলে।

Note: switch works only on integer-like values (int, char, enum). You cannot switch on a float, double, or a string. switch শুধু integer-জাতীয় value-তে কাজ করে (int, char, enum)। float, double বা string-এর উপর switch করা যায় না।

for, while, do-whilefor, while, do-while

All three repeat a block. The big difference: for and while check the condition before each round. do-while checks after — so it always runs at least once.

তিনটাই একটা block বারবার চালায়। বড় পার্থক্য: for আর while প্রতিবার চালানোর আগে condition check করে। do-while check করে পরে — তাই এটা সবসময় অন্তত একবার চলে।

/* All three print: 0 1 2 3 4 */
for (int i = 0; i < 5; i++) printf("%d ", i);

int i = 0;
while (i < 5) { printf("%d ", i); i++; }

int j = 0;
do { printf("%d ", j); j++; } while (j < 5);
Example:

The "at least once" difference. What is the output?

"অন্তত একবার" পার্থক্যটা। Output কী হবে?

int i = 10;
while (i < 5) printf("W");
do { printf("D"); } while (i < 5);
/* Output:
D
*/

The while loop never runs (10 < 5 is false at the start). The do-while runs its body once, then checks and stops.

while loop একবারও চলে না (শুরুতেই 10 < 5 false)। do-while body একবার চালায়, তারপর check করে থেমে যায়।

break and continuebreak আর continue

break exits the loop completely. continue skips the rest of the current round and jumps to the next round. In a nested loop, break only exits the inner loop.

break loop থেকে পুরোপুরি বের হয়ে যায়। continue current round-এর বাকিটা skip করে পরের round-এ চলে যায়। Nested loop-এ break শুধু ভিতরের loop থেকে বের হয়।

Example:

What is the output? Trace it row by row.

Output কী হবে? Line ধরে ধরে trace করো।

for (int i = 1; i <= 6; i++) {
    if (i == 3) continue;   /* skip printing 3 */
    if (i == 5) break;      /* stop the loop at 5 */
    printf("%d ", i);
}
/* Output:
1 2 4
*/
iWhat happensকী হয়Printed so farএ পর্যন্ত print
1prints 11 print হয়1
2prints 22 print হয়1 2
3continueskips printprint skip হয়1 2
4prints 44 print হয়1 2 4
5breakloop endsloop শেষ1 2 4
Example:

Nested loop count. How many times does the star print?

Nested loop count। Star কয়বার print হবে?

int count = 0;
for (int i = 1; i <= 3; i++)
    for (int j = i; j <= 3; j++)
        count++;
printf("%d", count);
/* Output: 6 */

i=1 gives j=1,2,3 (3 times). i=2 gives j=2,3 (2 times). i=3 gives j=3 (1 time). Total \(3+2+1 = 6\). In general this pattern gives \( \frac{n(n+1)}{2} \) runs.

i=1 হলে j=1,2,3 (3 বার)। i=2 হলে j=2,3 (2 বার)। i=3 হলে j=3 (1 বার)। মোট \(3+2+1 = 6\)। সাধারণভাবে এই pattern-এ \( \frac{n(n+1)}{2} \) বার চলে।

Note: Watch for a semicolon right after a loop header: for (i = 0; i < 5; i++); — that semicolon IS the loop body (an empty one). The loop runs 5 times doing nothing, and the next line runs once with i = 5. BUET loves this trick. Loop header-এর ঠিক পরে semicolon আছে কি না দেখো: for (i = 0; i < 5; i++); — ওই semicolon টাই loop-এর body (একটা empty body)। Loop 5 বার কিছু না করে চলে, আর পরের line টা i = 5 নিয়ে একবার চলে। BUET-এর খুব প্রিয় trick এটা।
int i;
for (i = 0; i < 5; i++);   /* note the ; */
printf("%d", i);
/* Output: 5 */

3. Functions and Recursion3. Functions and Recursion

Functions and call by valueFunction আর call by value

A function is a named block of code that you can call again and again. C passes arguments by call by value: the function gets a copy of each argument. Changing the copy does not change the original variable.

Function হলো নাম দেওয়া একটা code block, যেটা বারবার call করা যায়। C argument পাঠায় call by value হিসেবে: function প্রতিটা argument-এর একটা copy পায়। Copy বদলালে আসল variable বদলায় না

Example:

The famous failing swap. What is the output?

বিখ্যাত fail-করা swap। Output কী হবে?

#include <stdio.h>
void swap(int a, int b) {      /* a, b are copies */
    int t = a; a = b; b = t;   /* only the copies swap */
}
int main(void) {
    int x = 3, y = 7;
    swap(x, y);
    printf("%d %d\n", x, y);
    return 0;
}
/* Output:
3 7
*/

x and y do not change. To really swap, we must pass addresses (pointers) — see the Pointers section.

x আর y বদলায় না। সত্যিকারের swap করতে হলে address (pointer) পাঠাতে হবে — Pointers section দেখো।

Scope and static variablesScope আর static variable

Scope = where a variable is visible. A local variable lives only inside its function and dies when the function returns. A global variable is visible everywhere. A static local variable is special: it keeps its value between calls, and it is initialized only once.

Scope = variable কোথায় visible। Local variable শুধু নিজের function-এর ভিতরে বাঁচে, function return করলে মরে যায়। Global variable সব জায়গা থেকে দেখা যায়। Static local variable special: এটা call-এর মাঝে নিজের value ধরে রাখে, আর initialize হয় মাত্র একবার।

Example:

What is the output?

Output কী হবে?

void counter(void) {
    static int s = 0;   /* initialized once, survives between calls */
    int n = 0;          /* re-created every call */
    s++; n++;
    printf("s=%d n=%d | ", s, n);
}
int main(void) {
    counter(); counter(); counter();
    return 0;
}
/* Output:
s=1 n=1 | s=2 n=2 | s=3 n=3 |
*/

Wait — check again! n restarts at 0 every call, so n is always 1. s remembers: 1, 2, 3. Correct output: s=1 n=1 | s=2 n=1 | s=3 n=1 |. Tracing carefully matters — this is exactly the kind of small slip exams punish.

দাঁড়াও — আবার check করো! n প্রতি call-এ 0 থেকে শুরু হয়, তাই n সবসময় 1। s মনে রাখে: 1, 2, 3। সঠিক output: s=1 n=1 | s=2 n=1 | s=3 n=1 |। মন দিয়ে trace করা জরুরি — exam-এ ঠিক এই ছোট ভুলগুলোই ধরা হয়।

RecursionRecursion

Recursion = a function calling itself. Every recursion needs two parts:

  • Base case: the condition where it stops (no more calls).
  • Recursive case: the function calls itself with a smaller problem.

Each call gets its own frame on the call stack. When the base case returns, the frames unwind one by one.

Recursion = function নিজেই নিজেকে call করা। প্রতিটা recursion-এ দুইটা অংশ লাগবেই:

  • Base case: যে condition-এ থামে (আর call হয় না)।
  • Recursive case: function নিজেকে ছোট problem দিয়ে call করে।

প্রতিটা call call stack-এ নিজের একটা frame পায়। Base case return করলে frame গুলো একটা একটা করে খুলে আসে।

Example:

Factorial with a full stack trace. \( n! = n \times (n-1)! \) and \( 0! = 1 \).

Factorial-এর পুরো stack trace। \( n! = n \times (n-1)! \) আর \( 0! = 1 \)।

int fact(int n) {
    if (n == 0) return 1;        /* base case */
    return n * fact(n - 1);      /* recursive case */
}
/* fact(4) = 24 */
Going down (calls stack up):        Coming back (returns):
fact(4) = 4 * fact(3)               fact(0) returns 1
  fact(3) = 3 * fact(2)             fact(1) returns 1*1 = 1
    fact(2) = 2 * fact(1)           fact(2) returns 2*1 = 2
      fact(1) = 1 * fact(0)         fact(3) returns 3*2 = 6
        fact(0) = 1  (base!)        fact(4) returns 4*6 = 24
Call stack layout with stack frames
Each function call gets its own stack frame. Recursion piles frames up, then unwinds them. (Image: Wikimedia Commons) প্রতিটা function call নিজের একটা stack frame পায়। Recursion frame গুলো জমা করে, তারপর একটা একটা করে খোলে। (Image: Wikimedia Commons)
Example:

Fibonacci: \( F(n) = F(n-1) + F(n-2) \), with \( F(0)=0, F(1)=1 \). What does fib(5) return, and how many calls happen?

Fibonacci: \( F(n) = F(n-1) + F(n-2) \), যেখানে \( F(0)=0, F(1)=1 \)। fib(5) কী return করে, আর মোট কয়টা call হয়?

int fib(int n) {
    if (n <= 1) return n;
    return fib(n - 1) + fib(n - 2);
}
fib(5)
├── fib(4)
│   ├── fib(3)
│   │   ├── fib(2) ── fib(1)=1, fib(0)=0  → 1
│   │   └── fib(1) → 1
│   └── fib(2) ── fib(1)=1, fib(0)=0      → 1
└── fib(3)
    ├── fib(2) ── fib(1)=1, fib(0)=0      → 1
    └── fib(1) → 1
Answer: fib(5) = 5, total calls = 15

Note how fib(3) and fib(2) are computed again and again. That is why plain recursive Fibonacci is slow — about \( O(2^n) \) calls.

খেয়াল করো fib(3) আর fib(2) বারবার compute হচ্ছে। এই জন্যই সাধারণ recursive Fibonacci slow — প্রায় \( O(2^n) \) call।

Example:

Real exam question (April 2017): write a recursive function that separates (prints) each digit of an integer. The trick: recurse on n / 10 first, then print n % 10. That way the digits come out in the correct left-to-right order.

Real exam question (April 2017): একটা recursive function লেখো যেটা একটা integer-এর প্রতিটা digit আলাদা করে (print করে)। Trick টা হলো: আগে n / 10 নিয়ে recurse করো, তারপর n % 10 print করো। তাহলে digit গুলো ঠিক left-to-right order-এ আসে।

void printDigits(int n) {
    if (n < 10) {            /* base case: single digit */
        printf("%d ", n);
        return;
    }
    printDigits(n / 10);     /* first handle the front digits */
    printf("%d ", n % 10);   /* then print the last digit */
}
int main(void) {
    printDigits(493);
    return 0;
}
/* Output:
4 9 3
*/
Trace of printDigits(493):
printDigits(493) → calls printDigits(49), then will print 493%10 = 3
  printDigits(49) → calls printDigits(4), then will print 49%10 = 9
    printDigits(4) → 4 < 10, base case: prints 4
  back in printDigits(49): prints 9
back in printDigits(493): prints 3
Printed order: 4 9 3

If you print before the recursive call instead, the digits come out reversed: 3 9 4. Exams love asking for both versions — know which line order gives which output.

Recursive call-এর আগে print করলে digit গুলো উল্টা আসে: 3 9 4। Exam-এ দুই version-ই জিজ্ঞেস করতে ভালোবাসে — কোন line order-এ কোন output হয়, সেটা জেনে রাখো।

Recursion vs iterationRecursion vs iteration

RecursionRecursion Iteration (loop)Iteration (loop)
Ideaমূল ধারণা Function calls itself on a smaller problemFunction নিজেকে ছোট problem দিয়ে call করে Repeats a block with a loopLoop দিয়ে একটা block বারবার চালায়
MemoryMemory Uses call stack — one frame per callCall stack ব্যবহার করে — প্রতি call-এ একটা frame Constant memory (a few variables)Constant memory (কয়েকটা variable)
SpeedSpeed Function-call overhead; can be slowFunction-call overhead আছে; slow হতে পারে Usually fasterসাধারণত faster
Dangerবিপদ No base case → stack overflowBase case না থাকলে → stack overflow Wrong condition → infinite loopভুল condition → infinite loop
Best forকোথায় ভালো Trees, divide and conquer, backtrackingTree, divide and conquer, backtracking Simple counting and scanningসাধারণ counting আর scanning
Note: Exam favorite: a recursive function that prints before the recursive call prints on the way down; one that prints after the call prints on the way back (reversed order). Example: void f(int n){ if(!n) return; printf("%d ", n); f(n-1); } prints 3 2 1, but moving the printf after f(n-1) prints 1 2 3. Exam-এর প্রিয় জিনিস: recursive call-এর আগে print করলে নামার সময় print হয়; call-এর পরে print করলে ফেরার সময় print হয় (উল্টা order)। যেমন: void f(int n){ if(!n) return; printf("%d ", n); f(n-1); } print করে 3 2 1, কিন্তু printf-টা f(n-1)-এর পরে নিলে print হয় 1 2 3

4. Arrays and Strings4. Arrays and Strings

1D arrays1D array

An array is a row of boxes of the same type, sitting side by side in memory (contiguous). Indexing starts at 0. For int a[5], valid indexes are a[0] to a[4]. C does not check bounds — reading a[5] compiles but is a bug.

Array হলো একই type-এর কতগুলো box-এর সারি, memory-তে পাশাপাশি (contiguous) থাকে। Index শুরু হয় 0 থেকে। int a[5]-এর valid index হলো a[0] থেকে a[4]। C bound check করে নাa[5] পড়লে compile হবে, কিন্তু এটা bug।

int a[5] = {10, 20, 30};   /* rest become 0 → {10,20,30,0,0} */
printf("%d %d\n", a[0], a[4]);
/* Output: 10 0 */

Because elements sit side by side, the address of any element is easy math:

Element গুলো পাশাপাশি থাকে বলে যেকোনো element-এর address সহজ অঙ্ক:

\[ \text{address}(a[i]) = \text{base} + i \times \text{sizeof(type)} \]
Example:

int a[5] starts at address 1000 (int = 4 bytes). Then a[3] lives at \( 1000 + 3 \times 4 = 1012 \).

int a[5] শুরু হয় address 1000-এ (int = 4 byte)। তাহলে a[3] থাকে \( 1000 + 3 \times 4 = 1012 \)-তে।

2D arrays and memory layout2D array আর memory layout

A 2D array int m[3][4] is 3 rows and 4 columns. C stores it row-major: row 0 fully, then row 1, then row 2 — all in one flat line of memory.

2D array int m[3][4] মানে 3 row আর 4 column। C এটা রাখে row-major ভাবে: আগে পুরো row 0, তারপর row 1, তারপর row 2 — সব মিলে memory-র এক সোজা লাইনে।

\[ \text{address}(m[i][j]) = \text{base} + (i \times \text{cols} + j) \times \text{sizeof(type)} \]
Row-major and column-major order of a 2D array
Row-major vs column-major order. C uses row-major: it walks along a row first. (Image: Wikimedia Commons) Row-major vs column-major order। C ব্যবহার করে row-major: আগে একটা row ধরে এগোয়। (Image: Wikimedia Commons)
Example:

int m[3][4] at base 2000. Address of m[2][1]? \( 2000 + (2 \times 4 + 1) \times 4 = 2000 + 36 = 2036 \).

int m[3][4]-এর base 2000। m[2][1]-এর address? \( 2000 + (2 \times 4 + 1) \times 4 = 2000 + 36 = 2036 \)।

Example:

What is the output?

Output কী হবে?

int m[2][3] = {{1,2,3},{4,5,6}};
int sum = 0;
for (int i = 0; i < 2; i++)
    for (int j = 0; j < 3; j++)
        if (i == j) sum += m[i][j];
printf("%d\n", sum);
/* Output: 6  (m[0][0]+m[1][1] = 1+5) */

StringsString

In C, a string is just a char array that ends with a special character '\0' (the null terminator). "BUET" takes 5 bytes: 'B','U','E','T','\0'.

C-তে string মানে শুধুই একটা char array, যেটা শেষ হয় special character '\0' (null terminator) দিয়ে। "BUET" নেয় 5 byte: 'B','U','E','T','\0'

FunctionFunction What it doesকী করে ExampleExample
strlen(s)Length, NOT counting '\0'Length, '\0' গোনা হয় নাstrlen("BUET") = 4
strcpy(d, s)Copies s into d (d must be big enough)s-কে d-তে copy করে (d যথেষ্ট বড় হতে হবে)strcpy(d, "hi")
strcat(d, s)Appends s at the end of dd-এর শেষে s জুড়ে দেয়"ab"+"cd" → "abcd"
strcmp(a, b)0 if equal; negative if a<b; positive if a>bসমান হলে 0; a<b হলে negative; a>b হলে positivestrcmp("abc","abd") < 0
Example:

sizeof vs strlen — a guaranteed exam favorite. What is the output?

sizeof vs strlen — exam-এ আসবেই। Output কী হবে?

char s[] = "BUET";
char t[10] = "CSE";
printf("%zu %zu %zu %zu\n",
    strlen(s), sizeof(s), strlen(t), sizeof(t));
/* Output:
4 5 3 10
*/

strlen counts characters up to (not including) '\0'. sizeof gives the whole array size: 5 for s (4 letters + '\0'), 10 for t (declared size).

strlen গোনে '\0'-এর আগ পর্যন্ত character। sizeof দেয় পুরো array-র size: s-এর জন্য 5 (4 অক্ষর + '\0'), t-এর জন্য 10 (declare করা size)।

Common pitfallsCommon pitfall

  • Comparing with ==: if (s == "BUET") compares addresses, not contents. Use strcmp(s, "BUET") == 0.
  • Forgetting '\0' space: to store "hello" you need char s[6], not char s[5].
  • Off-by-one: the last valid index of a[n] is n-1.
  • gets() is dangerous: it cannot check size (buffer overflow). Use fgets() instead.
  • Arrays cannot be assigned: a = b; is illegal for arrays. Copy element by element or use strcpy/memcpy.
  • == দিয়ে compare: if (s == "BUET") content না, address compare করে। ব্যবহার করো strcmp(s, "BUET") == 0
  • '\0'-এর জায়গা ভুলে যাওয়া: "hello" রাখতে লাগবে char s[6], char s[5] না।
  • Off-by-one: a[n]-এর শেষ valid index হলো n-1
  • gets() বিপজ্জনক: এটা size check করতে পারে না (buffer overflow)। বদলে fgets() ব্যবহার করো।
  • Array assign করা যায় না: array-র জন্য a = b; illegal। Element ধরে ধরে copy করো বা strcpy/memcpy ব্যবহার করো।
Note: When an array is passed to a function, it decays to a pointer to its first element. Inside the function, sizeof(arr) gives the pointer size (8 on 64-bit), NOT the array size. That is why we always pass the length separately. Function-এ array পাঠালে সেটা প্রথম element-এর pointer-এ decay করে। Function-এর ভিতরে sizeof(arr) দেয় pointer-এর size (64-bit-এ 8), array-র size না। এই জন্যই length সবসময় আলাদা করে পাঠাতে হয়।

5. Pointers5. Pointers

Pointer basicsPointer basics

A pointer is a variable that stores an address of another variable. Two operators run the show:

  • &x — "address of x".
  • *p — "the value at the address p points to" (dereference).

Pointer হলো এমন একটা variable যেটা অন্য একটা variable-এর address রাখে। দুইটা operator-ই সব কাজ করে:

  • &x — "x-এর address"।
  • *p — "p যে address-এ point করছে, সেখানকার value" (dereference)।
A pointer variable storing the address of another variable
Pointer a stores the address of variable b. Following the arrow (*a) gives b's value. (Image: Wikimedia Commons) Pointer a-তে আছে variable b-এর address। তীর ধরে গেলে (*a) পাওয়া যায় b-এর value। (Image: Wikimedia Commons)
Example:

Basic pointer use. Say x lives at address 1000.

সাধারণ pointer ব্যবহার। ধরো x আছে address 1000-এ।

int x = 42;
int *p = &x;       /* p = 1000 (address of x) */
printf("%d\n", *p);  /* value at 1000 → 42 */
*p = 99;             /* changes x itself! */
printf("%d\n", x);
/* Output:
42
99
*/
Example:

The swap that WORKS — pass addresses instead of values.

যে swap সত্যি কাজ করে — value-র বদলে address পাঠাও।

void swap(int *a, int *b) {
    int t = *a; *a = *b; *b = t;
}
int main(void) {
    int x = 3, y = 7;
    swap(&x, &y);
    printf("%d %d\n", x, y);
    return 0;
}
/* Output:
7 3
*/

Pointer arithmeticPointer arithmetic

Pointer math is in units of the pointed type, not bytes. If p is an int*, then p + 1 moves forward by sizeof(int) = 4 bytes. If p is a double*, p + 1 moves 8 bytes.

Pointer-এর অঙ্ক হয় pointed type-এর unit-এ, byte-এ না। p যদি int* হয়, তাহলে p + 1 এগোয় sizeof(int) = 4 byte। p যদি double* হয়, p + 1 এগোয় 8 byte।

\[ p + k \;\; \text{means address} \;\; p + k \times \text{sizeof(pointed type)} \]
Example:

int a[4] at address 1000. Then a+0=1000, a+1=1004, a+2=1008, a+3=1012. Also, subtracting pointers gives the number of elements between them: &a[3] - &a[0] = 3 (not 12).

int a[4] আছে address 1000-এ। তাহলে a+0=1000, a+1=1004, a+2=1008, a+3=1012। আর দুই pointer বিয়োগ করলে মাঝের element সংখ্যা পাওয়া যায়: &a[3] - &a[0] = 3 (12 না)।

Pointers and arraysPointer আর array

The array name acts like a pointer to its first element. So these are all the same value: a[i]*(a + i)*(i + a)i[a] (yes, i[a] is legal C — a fun exam trick!).

Array-র নাম তার প্রথম element-এর pointer-এর মত কাজ করে। তাই এগুলো সব একই value: a[i]*(a + i)*(i + a)i[a] (হ্যাঁ, i[a] লেখা C-তে বৈধ — মজার একটা exam trick!)।

Example:

What is the output?

Output কী হবে?

int a[] = {5, 10, 15, 20};
int *p = a;
printf("%d %d %d %d\n", a[2], *(a+2), *(p+2), 2[a]);
/* Output:
15 15 15 15
*/

Pointers to functionsFunction-এর pointer

A function pointer stores the address of a function. It lets you pass a function as an argument (this is how qsort takes a compare function).

Function pointer একটা function-এর address রাখে। এতে function-কে argument হিসেবে পাঠানো যায় (qsort ঠিক এভাবেই compare function নেয়)।

int add(int a, int b) { return a + b; }
int mul(int a, int b) { return a * b; }

int main(void) {
    int (*op)(int, int);   /* pointer to a function taking (int,int) → int */
    op = add;  printf("%d ", op(3, 4));   /* 7 */
    op = mul;  printf("%d\n", op(3, 4));  /* 12 */
    return 0;
}
/* Output:
7 12
*/

Exam tricks: *p++ vs (*p)++ vs *++pExam trick: *p++ vs (*p)++ vs *++p

This is THE classic pointer question. Key fact: ++ (postfix) binds tighter than *, so *p++ means *(p++).

এটাই pointer-এর THE classic প্রশ্ন। মূল কথা: postfix ++-এর টান *-এর চেয়ে বেশি, তাই *p++ মানে *(p++)

ExpressionExpression Meaningমানে What moves / changesকী move/change হয়
*p++*(p++)gives value at p, THEN moves the pointer forwardp-এর value দেয়, তারপর pointer এগিয়ে যায়
(*p)++gives the value, then increments the value in memory; pointer staysvalue দেয়, তারপর memory-র value টা বাড়ে; pointer একই জায়গায় থাকে
*++p*(++p)moves the pointer FIRST, then gives the new valueআগে pointer এগোয়, তারপর নতুন value দেয়
++*p++(*p)increments the value, gives the increased value; pointer staysvalue বাড়ায়, বাড়ানো value দেয়; pointer একই জায়গায়
Example:

What is the output? Trace each line carefully.

Output কী হবে? প্রতিটা line মন দিয়ে trace করো।

int a[] = {10, 20, 30};
int *p = a;
printf("%d ", *p++);    /* prints 10, p now points to a[1] */
printf("%d ", (*p)++);  /* prints 20, then a[1] becomes 21 */
printf("%d ", *p);      /* prints 21 (same position) */
printf("%d ", *++p);    /* p moves to a[2], prints 30 */
printf("%d\n", ++*p);   /* a[2] becomes 31, prints 31 */
/* Output:
10 20 21 30 31
*/
Note: More pointer facts BUET asks: (1) a NULL pointer points to nothing; dereferencing it crashes. (2) int *p; *p = 5; is a wild pointer bug — p was never given a valid address. (3) char *s = "hi"; points to a string literal; writing through it (s[0]='H') is undefined behavior, while char s[] = "hi"; is a modifiable copy. BUET আরো যে pointer fact জিজ্ঞেস করে: (1) NULL pointer কিছুতেই point করে না; dereference করলে crash। (2) int *p; *p = 5; হলো wild pointer bug — p-কে কখনো valid address দেওয়া হয়নি। (3) char *s = "hi"; point করে একটা string literal-এ; ওটার ভিতরে লেখা (s[0]='H') undefined behavior, কিন্তু char s[] = "hi"; হলো modifiable copy।

6. Structures and Unions6. Structures and Unions

struct basicsstruct basics

A struct groups variables of different types into one package. Each member gets its own memory. Use the dot operator . to reach a member.

struct আলাদা আলাদা type-এর variable-গুলোকে এক package-এ বাঁধে। প্রতিটা member নিজের memory পায়। Member ধরতে dot operator . ব্যবহার হয়।

struct Student {
    int id;
    char name[20];
    float cgpa;
};

int main(void) {
    struct Student s = {101, "Rahim", 3.85f};
    s.cgpa = 3.90f;
    printf("%d %s %.2f\n", s.id, s.name, s.cgpa);
    return 0;
}
/* Output:
101 Rahim 3.90
*/

typedeftypedef

typedef gives a type a shorter name. With it, you can drop the word struct everywhere.

typedef একটা type-কে ছোট নাম দেয়। এটা থাকলে সব জায়গায় struct শব্দটা লিখতে হয় না।

typedef struct {
    int x, y;
} Point;

Point p = {3, 4};              /* no "struct" needed */
printf("%d %d\n", p.x, p.y);   /* Output: 3 4 */

struct vs unionstruct vs union

A union looks like a struct, but all members share the same memory. Only one member is valid at a time. Writing one member overwrites the others.

union দেখতে struct-এর মত, কিন্তু সব member একই memory share করে। এক সময়ে শুধু একটা member valid। একটা member-এ লিখলে বাকিগুলো overwrite হয়ে যায়।

structstruct unionunion
MemoryMemory Each member has its own spaceপ্রতিটা member-এর নিজের জায়গা All members share one spaceসব member এক জায়গা share করে
SizeSize ≥ sum of member sizes (padding may add more)Member size-গুলোর যোগফলের সমান বা বেশি (padding যোগ হতে পারে) = size of the largest member (plus padding)= সবচেয়ে বড় member-এর size (padding সহ)
Valid membersValid member All at onceসব একসাথে Only the last one writtenশুধু শেষ যেটাতে লেখা হয়েছে
Useব্যবহার Records (student, point, node)Record (student, point, node) Saving memory when only one field is needed at a timeএক সময়ে একটা field লাগলে memory বাঁচাতে
Example:

Size comparison — the classic MCQ. What is the output?

Size তুলনা — classic MCQ। Output কী হবে?

struct S { int i; char c; double d; };
union  U { int i; char c; double d; };
printf("%zu %zu\n", sizeof(struct S), sizeof(union U));
/* Output (typical 64-bit):
16 8
*/

Struct: 4 (int) + 1 (char) + 3 (padding) + 8 (double) = 16. Union: just the largest member, the 8-byte double. Padding exists because the compiler aligns members to their size boundaries.

Struct: 4 (int) + 1 (char) + 3 (padding) + 8 (double) = 16। Union: শুধু সবচেয়ে বড় member, মানে 8-byte double। Padding থাকে কারণ compiler member-গুলোকে তাদের size boundary-তে align করে।

Example:

Union members overwrite each other. What is the output?

Union-এর member-রা একে অপরকে overwrite করে। Output কী হবে?

union U { int i; char c; };
union U u;
u.i = 65;                 /* 65 = ASCII 'A' */
printf("%c ", u.c);       /* same bytes read as char → 'A' */
u.c = 'B';                /* overwrites the low byte */
printf("%d\n", u.i);      /* low byte now 66 → prints 66 */
/* Output:
A 66
*/

Nested structs and struct pointersNested struct আর struct pointer

A struct can contain another struct (nested). With a pointer to a struct, use the arrow operator ->: p->x is short for (*p).x.

একটা struct-এর ভিতরে আরেকটা struct থাকতে পারে (nested)। Struct-এর pointer হলে arrow operator -> ব্যবহার হয়: p->x হলো (*p).x-এর short form।

typedef struct { int x, y; } Point;
typedef struct {
    Point topLeft;      /* nested struct */
    Point bottomRight;
} Rect;

int main(void) {
    Rect r = {{0, 10}, {5, 0}};
    Rect *p = &r;
    int width  = p->bottomRight.x - p->topLeft.x;   /* 5 - 0 */
    int height = p->topLeft.y - p->bottomRight.y;   /* 10 - 0 */
    printf("%d\n", width * height);
    return 0;
}
/* Output: 50 */
Example:

Structs with pointers are how linked lists are built — this connects to the Data Structures chapter.

Pointer-ওয়ালা struct দিয়েই linked list বানানো হয় — এটা Data Structures chapter-এর সাথে যুক্ত।

typedef struct Node {
    int data;
    struct Node *next;   /* pointer to the same struct type */
} Node;

Node b = {20, NULL};
Node a = {10, &b};
printf("%d %d\n", a.data, a.next->data);
/* Output: 10 20 */
Note: Unlike arrays, structs CAN be assigned (s2 = s1; copies all members) and can be passed to and returned from functions by value. Also remember: p->x needs p to be a pointer; using . on a pointer or -> on a plain struct is a compile error exams like to show. Array-র মত না — struct assign করা যায় (s2 = s1; সব member copy করে), আর value হিসেবে function-এ পাঠানো ও return করা যায়। আরো মনে রাখো: p->x-এর জন্য p-কে pointer হতে হবে; pointer-এ . বা সাধারণ struct-এ -> দিলে compile error — exam-এ এটা প্রায়ই দেখানো হয়।

7. Memory Concepts7. Memory Concepts

Memory layout of a C programC program-এর memory layout

When a C program runs, its memory is divided into regions:

  • Text (code): the compiled machine instructions. Read-only.
  • Data: global/static variables that are initialized (e.g., int g = 5;).
  • BSS: global/static variables that are uninitialized — set to 0 at start.
  • Heap: memory you ask for with malloc. Grows upward.
  • Stack: local variables and function-call frames. Grows downward.

C program চলার সময় তার memory কয়েকটা region-এ ভাগ থাকে:

  • Text (code): compile-করা machine instruction। Read-only।
  • Data: initialize করা global/static variable (যেমন int g = 5;)।
  • BSS: initialize না-করা global/static variable — শুরুতে 0 করে দেওয়া হয়।
  • Heap: malloc দিয়ে চাওয়া memory। উপরের দিকে বাড়ে।
  • Stack: local variable আর function-call frame। নিচের দিকে বাড়ে।
Stack local variables, call frames grows down ↓ free memory grows up ↑ Heap malloc / calloc / realloc BSS (uninitialized globals → 0) Data (initialized globals) Text (program code) high addr low addr
Memory layout of a running C program: text, data, BSS, heap (grows up), stack (grows down). চলমান C program-এর memory layout: text, data, BSS, heap (উপরে বাড়ে), stack (নিচে বাড়ে)।

Stack vs heapStack vs heap

StackStack HeapHeap
Who manages itকে manage করে Automatic (compiler)Automatic (compiler) You (malloc / free)তুমি (malloc / free)
LifetimeLifetime Dies when the function returnsFunction return করলেই শেষ Lives until you call free()free() call করা পর্যন্ত বাঁচে
SizeSize Small (a few MB)ছোট (কয়েক MB) Large (limited by RAM)বড় (RAM যতটা দেয়)
SpeedSpeed Very fastখুব fast Slower (allocator work)তুলনায় slow (allocator-এর কাজ)
Typical bugTypical bug Stack overflow (deep recursion)Stack overflow (গভীর recursion) Memory leak, dangling pointerMemory leak, dangling pointer

malloc, calloc, realloc, freemalloc, calloc, realloc, free

FunctionFunction What it doesকী করে Initializes?Initialize করে?
malloc(n)Allocates n bytesn byte allocate করেNo — garbage valuesনা — garbage value থাকে
calloc(k, size)Allocates k×size bytesk×size byte allocate করেYes — all zerosহ্যাঁ — সব 0
realloc(p, n)Resizes an old block to n bytes, keeps old dataপুরনো block-কে n byte-এ resize করে, পুরনো data রাখেNew part: noনতুন অংশ: না
free(p)Returns the block to the systemBlock টা system-কে ফেরত দেয়
Example:

A dynamic array the safe way. Always check for NULL, always free.

Dynamic array-এর safe নিয়ম। সবসময় NULL check করো, সবসময় free করো।

#include <stdio.h>
#include <stdlib.h>
int main(void) {
    int n = 5;
    int *a = (int *)malloc(n * sizeof(int));
    if (a == NULL) return 1;        /* allocation can fail! */
    for (int i = 0; i < n; i++) a[i] = i * i;
    printf("%d %d\n", a[2], a[4]);
    free(a);                        /* give it back */
    a = NULL;                       /* avoid dangling pointer */
    return 0;
}
/* Output:
4 16
*/

Dangling pointer and memory leakDangling pointer আর memory leak

Dangling pointer: a pointer that still points to memory that was freed (or to a dead local variable). Using it is undefined behavior.

Memory leak: heap memory you allocated but never freed, and you lost the pointer to it. The program's memory use keeps growing.

Dangling pointer: এমন pointer যেটা এখনো point করছে free-করা memory-তে (বা মরে যাওয়া local variable-এ)। এটা ব্যবহার করা undefined behavior।

Memory leak: heap-এ allocate করা memory যেটা কখনো free করা হয়নি, আর তার pointer-ও হারিয়ে গেছে। Program-এর memory ব্যবহার বাড়তেই থাকে।

Example:

Three classic bugs — find them in exam code:

তিনটা classic bug — exam-এর code-এ এগুলো খুঁজে বের করতে হয়:

/* BUG 1: dangling pointer (use after free) */
int *p = malloc(sizeof(int));
free(p);
*p = 10;              /* p is dangling! undefined behavior */

/* BUG 2: returning address of a local variable */
int *bad(void) {
    int x = 5;
    return &x;        /* x dies when bad() returns */
}

/* BUG 3: memory leak */
void leak(void) {
    int *q = malloc(100 * sizeof(int));
    /* no free(q); pointer lost when function returns */
}
Note: Quick answers BUET expects: uninitialized global variables are 0 (BSS), but uninitialized local variables are garbage. free() does not set the pointer to NULL — you should do that yourself. Freeing the same block twice ("double free") is also undefined behavior. BUET যে ছোট উত্তরগুলো আশা করে: initialize না-করা global variable হয় 0 (BSS), কিন্তু initialize না-করা local variable-এ থাকে garbage। free() pointer-কে NULL করে না — সেটা নিজে করতে হয়। একই block দুইবার free করাও ("double free") undefined behavior।

8. Shell/Bash Basics (Asked in 2024!)8. Shell/Bash Basics (2024-এ এসেছে!)

The April 2024 BUET admission test asked to find the output of a bash script. So a compact bash toolkit is now a must. Bash is the shell language of Linux — small scripts made of commands.

April 2024-এর BUET admission test-এ একটা bash script-এর output বের করতে বলা হয়েছিল। তাই ছোট্ট একটা bash toolkit এখন must। Bash হলো Linux-এর shell language — command দিয়ে বানানো ছোট script।

The core rulesমূল rule গুলো

  • Variables: x=5NO spaces around =. x = 5 is an error (bash thinks x is a command). Read a variable with $x or ${x}.
  • echo: prints its arguments: echo "Hello $x" prints Hello 5. Single quotes stop expansion: echo '$x' prints $x literally.
  • Command substitution: $(command) runs the command and pastes its output: d=$(date), n=$(wc -l file).
  • Arithmetic: only inside $((...)): echo $((3 + 4)) prints 7. Outside it, 3 + 4 is just text!
  • if: if [ "$x" -gt 3 ]; then echo big; fi. Numeric tests: -eq -ne -lt -le -gt -ge. String test: =. Spaces inside [ ] are required.
  • for: for i in 1 2 3; do echo $i; done — loops over a list of words.
  • while read: while read line; do ...; done — reads input line by line.
  • Variables: x=5=-এর দুই পাশে space দেওয়া যাবে নাx = 5 লিখলে error (bash ভাবে x একটা command)। Variable পড়তে $x বা ${x}
  • echo: argument গুলো print করে: echo "Hello $x" দেয় Hello 5। Single quote expansion বন্ধ করে: echo '$x' আক্ষরিক $x-ই print করে।
  • Command substitution: $(command) command টা চালিয়ে তার output বসিয়ে দেয়: d=$(date), n=$(wc -l file)
  • Arithmetic: শুধু $((...))-এর ভিতরে: echo $((3 + 4)) দেয় 7। এর বাইরে 3 + 4 শুধুই text!
  • if: if [ "$x" -gt 3 ]; then echo big; fi। Numeric test: -eq -ne -lt -le -gt -ge। String test: =[ ]-এর ভিতরে space দিতেই হবে।
  • for: for i in 1 2 3; do echo $i; done — একটা word-এর list-এর উপর ঘোরে।
  • while read: while read line; do ...; done — input line ধরে ধরে পড়ে।
Example:

Trace 1 — a for loop building a string. What is the output?

Trace 1 — for loop দিয়ে string বানানো। Output কী হবে?

#!/bin/bash
s=""
for i in 1 2 3; do
    s="$s$i-"
done
echo "$s done"
# Output:
# 1-2-3- done

Each round glues the current $i and a dash onto s: "" → "1-" → "1-2-" → "1-2-3-". Then echo prints it with " done".

প্রতি round-এ current $i আর একটা dash s-এর সাথে জোড়া লাগে: "" → "1-" → "1-2-" → "1-2-3-"। তারপর echo সেটা " done" সহ print করে।

Example:

Trace 2 — arithmetic vs text. What is the output?

Trace 2 — arithmetic vs text। Output কী হবে?

#!/bin/bash
x=5
y=hello
echo $((x + 2))
echo $((y + 2))
echo "$x + 2"
# Output:
# 7
# 2
# 5 + 2

Line 1: real math, 5+2=7. Line 2: y is "hello", which is not a number — inside $((...)) it counts as 0, so 0+2=2. Line 3: inside quotes there is no math; $x just becomes 5, and " + 2" stays as text.

Line 1: সত্যিকারের অঙ্ক, 5+2=7। Line 2: y হলো "hello", কোনো সংখ্যা না — $((...))-এর ভিতরে এটা 0 ধরা হয়, তাই 0+2=2। Line 3: quote-এর ভিতরে কোনো অঙ্ক হয় না; $x শুধু 5 হয়ে যায়, আর " + 2" text হিসেবেই থাকে।

Example:

Trace 3 — the pipeline subshell trap. What is the output?

Trace 3 — pipeline subshell trap। Output কী হবে?

#!/bin/bash
count=0
printf "a\nb\nc\n" | while read line; do
    count=$((count + 1))
done
echo $count
# Output:
# 0

Shocking but true: the answer is 0, not 3. Each part of a pipeline (|) runs in a subshell — a child copy of the shell. The while loop increments the subshell's copy of count. When the pipeline ends, the copy dies, and the parent's count is still 0. (Same spirit as C's call by value!)

অবাক লাগলেও সত্যি: উত্তর 0, 3 না। Pipeline-এর (|) প্রতিটা অংশ চলে একটা subshell-এ — shell-এর একটা child copy। while loop টা subshell-এর count-এর copy বাড়ায়। Pipeline শেষ হলে copy টা মরে যায়, আর parent-এর count তখনো 0। (C-এর call by value-র মতই ব্যাপার!)

Note: Quick exam checklist for bash output questions: (1) x=5 no spaces; (2) math only in $((...)); (3) single quotes = literal, double quotes = expand $var; (4) $(cmd) pastes the command's output; (5) a variable changed inside a pipeline does NOT survive outside it. Bash output প্রশ্নের quick exam checklist: (1) x=5 space ছাড়া; (2) অঙ্ক শুধু $((...))-এ; (3) single quote = literal, double quote = $var expand হয়; (4) $(cmd) command-এর output বসিয়ে দেয়; (5) pipeline-এর ভিতরে বদলানো variable বাইরে বাঁচে না।

Practice Questions (Admission Style)Practice Questions (Admission Style)

17 questions, easy to hard. Try each one on paper first, then open the answer. 17টা প্রশ্ন, সহজ থেকে কঠিন। আগে খাতায় নিজে চেষ্টা করো, তারপর answer খোলো।

Q1. On a typical 64-bit system, what is the value of sizeof('A') in a C program?
  • (a) 1
  • (b) 2
  • (c) 4
  • (d) 8
Q1. সাধারণ 64-bit system-এ, C program-এ sizeof('A')-এর value কত?
  • (a) 1
  • (b) 2
  • (c) 4
  • (d) 8
Show Answerউত্তর দেখুন
Answer: (c) — In C, a character literal like 'A' has type int, so its size is 4 bytes. Note that sizeof(char) is 1, and in C++ sizeof('A') would also be 1. This C-vs-C++ difference is a favorite trap.
Answer: (c) — C-তে 'A'-এর মত character literal-এর type হলো int, তাই এর size 4 byte। খেয়াল রেখো sizeof(char) হলো 1, আর C++-এ sizeof('A')-ও 1 হতো। C-vs-C++ এই পার্থক্যটা প্রিয় trap।
Q2. What is the output of printf("%.1f", 5 / 2 * 2.0);?
  • (a) 5.0
  • (b) 4.0
  • (c) 2.5
  • (d) 2.0
Q2. printf("%.1f", 5 / 2 * 2.0);-এর output কী?
  • (a) 5.0
  • (b) 4.0
  • (c) 2.5
  • (d) 2.0
Show Answerউত্তর দেখুন
Answer: (b)/ and * have the same precedence and go left to right. First 5 / 2 = 2 (integer division drops the .5). Then 2 * 2.0 = 4.0 (promoted to double). So 4.0.
Answer: (b)/ আর *-এর precedence সমান, হিসাব হয় left থেকে right। আগে 5 / 2 = 2 (integer division-এ .5 বাদ যায়)। তারপর 2 * 2.0 = 4.0 (double-এ promote হয়)। তাই 4.0।
Q3. Which loop is guaranteed to execute its body at least once?
  • (a) for
  • (b) while
  • (c) do-while
  • (d) none of them
Q3. কোন loop-এর body নিশ্চিতভাবে অন্তত একবার চলে?
  • (a) for
  • (b) while
  • (c) do-while
  • (d) কোনোটাই না
Show Answerউত্তর দেখুন
Answer: (c)do-while checks its condition after running the body, so the body always runs at least once. for and while check first and may run zero times.
Answer: (c)do-while body চালানোর পরে condition check করে, তাই body অন্তত একবার চলবেই। for আর while আগে check করে, তাই শূন্যবারও চলতে পারে।
Q4. What is the output?
int n = 1;
switch (n) {
    case 1: printf("A");
    case 2: printf("B"); break;
    case 3: printf("C");
    default: printf("D");
}
  • (a) A
  • (b) AB
  • (c) ABD
  • (d) ABCD
Q4. Output কী হবে?
int n = 1;
switch (n) {
    case 1: printf("A");
    case 2: printf("B"); break;
    case 3: printf("C");
    default: printf("D");
}
  • (a) A
  • (b) AB
  • (c) ABD
  • (d) ABCD
Show Answerউত্তর দেখুন
Answer: (b) — Execution starts at case 1 and prints A. There is no break, so it falls through to case 2 and prints B. The break after B stops the switch. Output: AB.
Answer: (b) — Execution শুরু হয় case 1-এ, A print হয়। break নেই, তাই fall through করে case 2-তে গিয়ে B print হয়। B-এর পরের break switch থামিয়ে দেয়। Output: AB।
Q5. (Written) What is the output? Trace the loop step by step.
int s = 0;
for (int i = 1; i <= 8; i++) {
    if (i % 2 == 0) continue;
    if (i > 6) break;
    s += i;
}
printf("%d", s);
Q5. (Written) Output কী হবে? Loop টা step by step trace করো।
int s = 0;
for (int i = 1; i <= 8; i++) {
    if (i % 2 == 0) continue;
    if (i > 6) break;
    s += i;
}
printf("%d", s);
Show Answerউত্তর দেখুন
Answer: 9 — i=1: odd, not >6, s=1. i=2: even, continue. i=3: s=4. i=4: continue. i=5: s=9. i=6: continue. i=7: odd but 7>6, so break. Total s = 1+3+5 = 9.
Answer: 9 — i=1: odd, 6-এর বেশি না, s=1। i=2: even, continue। i=3: s=4। i=4: continue। i=5: s=9। i=6: continue। i=7: odd কিন্তু 7>6, তাই break। মোট s = 1+3+5 = 9।
Q6. If char s[] = "Dhaka";, what are strlen(s) and sizeof(s)?
  • (a) 5 and 5
  • (b) 5 and 6
  • (c) 6 and 6
  • (d) 6 and 5
Q6. char s[] = "Dhaka"; হলে strlen(s) আর sizeof(s) কত?
  • (a) 5 আর 5
  • (b) 5 আর 6
  • (c) 6 আর 6
  • (d) 6 আর 5
Show Answerউত্তর দেখুন
Answer: (b) — "Dhaka" has 5 letters, so strlen = 5 (it stops before '\0'). The array stores those 5 letters plus the '\0', so sizeof = 6.
Answer: (b) — "Dhaka"-তে 5টা অক্ষর, তাই strlen = 5 ('\0'-এর আগে থামে)। Array-তে ওই 5 অক্ষর + '\0' থাকে, তাই sizeof = 6।
Q7. An int array a starts at address 5000 (int = 4 bytes). Which expression equals a[3], and what is the address of a[3]?
  • (a) *(a+3), address 5003
  • (b) *(a+3), address 5012
  • (c) &a[3], address 5012
  • (d) a+3, address 5012
Q7. একটা int array a শুরু হয় address 5000-এ (int = 4 byte)। কোন expression টা a[3]-এর সমান, আর a[3]-এর address কত?
  • (a) *(a+3), address 5003
  • (b) *(a+3), address 5012
  • (c) &a[3], address 5012
  • (d) a+3, address 5012
Show Answerউত্তর দেখুন
Answer: (b)a[3]*(a+3) (the value). Its address is \(5000 + 3 \times 4 = 5012\). Options (c) and (d) are addresses/pointers, not the element's value, so they do not "equal a[3]".
Answer: (b)a[3]*(a+3) (value টা)। এর address \(5000 + 3 \times 4 = 5012\)। Option (c) আর (d) হলো address/pointer, element-এর value না — তাই ওগুলো "a[3]-এর সমান" না।
Q8. (Written) What is the output?
void f(int n) {
    if (n == 0) return;
    f(n - 1);
    printf("%d ", n);
}
int main(void) { f(4); return 0; }
Q8. (Written) Output কী হবে?
void f(int n) {
    if (n == 0) return;
    f(n - 1);
    printf("%d ", n);
}
int main(void) { f(4); return 0; }
Show Answerউত্তর দেখুন
Answer: 1 2 3 4 — The print happens after the recursive call, so nothing prints on the way down (f(4)→f(3)→f(2)→f(1)→f(0) returns). Printing happens while unwinding: f(1) prints 1, then f(2) prints 2, then 3, then 4.
Answer: 1 2 3 4 — Print হয় recursive call-এর পরে, তাই নামার সময় কিছু print হয় না (f(4)→f(3)→f(2)→f(1)→f(0) return করে)। ফেরার সময় print হয়: f(1) দেয় 1, তারপর f(2) দেয় 2, তারপর 3, তারপর 4।
Q9. How many times is fun(2) called (including the first call) when we call fun(4), where fun is plain recursive Fibonacci (fun(n)=fun(n-1)+fun(n-2), base cases n=0,1)?
  • (a) 1
  • (b) 2
  • (c) 3
  • (d) 4
Q9. fun(4) call করলে fun(2) মোট কয়বার call হয়, যেখানে fun হলো সাধারণ recursive Fibonacci (fun(n)=fun(n-1)+fun(n-2), base case n=0,1)?
  • (a) 1
  • (b) 2
  • (c) 3
  • (d) 4
Show Answerউত্তর দেখুন
Answer: (b) — fun(4) calls fun(3) and fun(2). fun(3) calls fun(2) and fun(1). So fun(2) is reached twice: once from fun(4), once from fun(3). This repeated work is exactly why naive Fibonacci is exponential.
Answer: (b) — fun(4) call করে fun(3) আর fun(2)। fun(3) call করে fun(2) আর fun(1)। তাই fun(2) আসে দুইবার: একবার fun(4) থেকে, একবার fun(3) থেকে। এই repeated কাজের জন্যই naive Fibonacci exponential।
Q10. (Written) What is the output?
int a[] = {1, 2, 3, 4, 5};
int *p = a + 1;
printf("%d ", *p++);
printf("%d ", (*p)++);
printf("%d ", *p);
printf("%d", *(p + 1));
Q10. (Written) Output কী হবে?
int a[] = {1, 2, 3, 4, 5};
int *p = a + 1;
printf("%d ", *p++);
printf("%d ", (*p)++);
printf("%d ", *p);
printf("%d", *(p + 1));
Show Answerউত্তর দেখুন
Answer: 2 3 4 5p starts at a[1]. *p++ prints 2 and moves p to a[2]. (*p)++ prints 3 and changes a[2] to 4 (p does not move). *p prints the updated 4. *(p+1) prints a[3] = 5. Array is now {1,2,4,4,5}.
Answer: 2 3 4 5p শুরু করে a[1]-এ। *p++ 2 print করে p-কে a[2]-তে নেয়। (*p)++ 3 print করে a[2]-কে 4 বানায় (p নড়ে না)। *p updated 4 print করে। *(p+1) print করে a[3] = 5। Array এখন {1,2,4,4,5}।
Q11. Given struct S { char c; int i; }; and union U { char c; int i; }; on a typical 64-bit machine, what are sizeof(struct S) and sizeof(union U)?
  • (a) 5 and 4
  • (b) 8 and 4
  • (c) 5 and 5
  • (d) 8 and 8
Q11. সাধারণ 64-bit machine-এ struct S { char c; int i; }; আর union U { char c; int i; }; হলে sizeof(struct S) আর sizeof(union U) কত?
  • (a) 5 আর 4
  • (b) 8 আর 4
  • (c) 5 আর 5
  • (d) 8 আর 8
Show Answerউত্তর দেখুন
Answer: (b) — Struct: char (1) + 3 padding bytes so the int starts at a 4-byte boundary + int (4) = 8. Union: members share memory, so size = largest member = 4. Padding is why the struct is not 5.
Answer: (b) — Struct: char (1) + 3 padding byte (যাতে int টা 4-byte boundary-তে শুরু হয়) + int (4) = 8। Union: member-রা memory share করে, তাই size = সবচেয়ে বড় member = 4। Padding-এর কারণেই struct 5 হয় না।
Q12. Which statement about memory is FALSE?
  • (a) Uninitialized global variables are stored in BSS and start as 0
  • (b) calloc initializes the allocated memory to zero
  • (c) Local variables of a function live on the heap
  • (d) Memory from malloc stays allocated until free is called
Q12. Memory নিয়ে কোন কথাটা FALSE?
  • (a) Initialize না-করা global variable BSS-এ থাকে আর 0 দিয়ে শুরু হয়
  • (b) calloc allocate করা memory zero করে দেয়
  • (c) Function-এর local variable heap-এ থাকে
  • (d) malloc-এর memory free call করা পর্যন্ত allocated থাকে
Show Answerউত্তর দেখুন
Answer: (c) — Local variables live on the stack, not the heap. They are created when the function is called and destroyed when it returns. (a), (b) and (d) are all true facts.
Answer: (c) — Local variable থাকে stack-এ, heap-এ না। Function call হলে তৈরি হয়, return করলে ধ্বংস হয়। (a), (b) আর (d) সবগুলোই সত্যি।
Q13. (Written) What is the output? Explain why.
int mystery(int n) {
    static int depth = 0;
    depth++;
    if (n <= 1) return depth;
    return mystery(n / 2);
}
int main(void) {
    printf("%d", mystery(8));
    return 0;
}
Q13. (Written) Output কী হবে? কেন, ব্যাখ্যা করো।
int mystery(int n) {
    static int depth = 0;
    depth++;
    if (n <= 1) return depth;
    return mystery(n / 2);
}
int main(void) {
    printf("%d", mystery(8));
    return 0;
}
Show Answerউত্তর দেখুন
Answer: 4depth is static, so all calls share it. Calls: mystery(8) → depth=1, mystery(4) → depth=2, mystery(2) → depth=3, mystery(1) → depth=4 and n≤1, so it returns 4. In general this counts \( \lfloor \log_2 n \rfloor + 1 \) calls — the same idea as binary search depth.
Answer: 4depth static, তাই সব call এটা share করে। Call গুলো: mystery(8) → depth=1, mystery(4) → depth=2, mystery(2) → depth=3, mystery(1) → depth=4 আর n≤1, তাই return করে 4। সাধারণভাবে এটা \( \lfloor \log_2 n \rfloor + 1 \) টা call গোনে — binary search-এর depth-এর মত idea।
Q14. (Written) Write a recursive C function int sumDigits(int n) that returns the sum of the digits of a positive integer. Example: sumDigits(493) returns 16.
Q14. (Written) একটা recursive C function int sumDigits(int n) লেখো, যেটা positive integer-এর digit-গুলোর যোগফল return করে। যেমন: sumDigits(493) return করবে 16।
Show Answerউত্তর দেখুন
Answer:
int sumDigits(int n) {
    if (n == 0) return 0;              /* base case */
    return n % 10 + sumDigits(n / 10); /* last digit + rest */
}

Reasoning: n % 10 gives the last digit; n / 10 removes it. Trace of 493: 3 + sumDigits(49) = 3 + 9 + sumDigits(4) = 3 + 9 + 4 + sumDigits(0) = 16.

Answer:
int sumDigits(int n) {
    if (n == 0) return 0;              /* base case */
    return n % 10 + sumDigits(n / 10); /* শেষ digit + বাকিটা */
}

ব্যাখ্যা: n % 10 শেষ digit দেয়; n / 10 সেটা ফেলে দেয়। 493-এর trace: 3 + sumDigits(49) = 3 + 9 + sumDigits(4) = 3 + 9 + 4 + sumDigits(0) = 16।

Q15. (Written) The function below has TWO memory bugs. Find both, name them, and write a fixed version.
int *makeArray(int n) {
    int a[n];
    for (int i = 0; i < n; i++) a[i] = i;
    int *extra = malloc(n * sizeof(int));
    return a;
}
Q15. (Written) নিচের function-এ দুইটা memory bug আছে। দুটোই খুঁজে বের করো, নাম বলো, আর ঠিক-করা version লেখো।
int *makeArray(int n) {
    int a[n];
    for (int i = 0; i < n; i++) a[i] = i;
    int *extra = malloc(n * sizeof(int));
    return a;
}
Show Answerউত্তর দেখুন
Answer:

Bug 1 — dangling pointer: a is a local (stack) array. It dies when the function returns, so the returned pointer points to dead memory.

Bug 2 — memory leak: extra is allocated with malloc but never freed and never returned — the pointer is lost.

Fixed version — allocate the result on the heap and remove the useless allocation:

int *makeArray(int n) {
    int *a = malloc(n * sizeof(int));  /* heap: survives return */
    if (a == NULL) return NULL;
    for (int i = 0; i < n; i++) a[i] = i;
    return a;   /* caller must free(a) later */
}
Answer:

Bug 1 — dangling pointer: a একটা local (stack) array। Function return করলেই এটা মরে যায়, তাই return করা pointer টা মৃত memory-তে point করে।

Bug 2 — memory leak: extra malloc দিয়ে allocate হয়েছে কিন্তু free-ও হয়নি, return-ও হয়নি — pointer টা হারিয়ে গেছে।

ঠিক-করা version — result টা heap-এ allocate করো আর অকাজের allocation বাদ দাও:

int *makeArray(int n) {
    int *a = malloc(n * sizeof(int));  /* heap: return-এর পরেও বাঁচে */
    if (a == NULL) return NULL;
    for (int i = 0; i < n; i++) a[i] = i;
    return a;   /* caller-কে পরে free(a) করতে হবে */
}
Q16. (Real exam style — asked April 2024) What is the output of this bash script?
#!/bin/bash
x=3
y=$((x * 2))
for i in 1 2; do
    y=$((y + i))
done
echo "$x-$y"
  • (a) 3-6
  • (b) 3-9
  • (c) x-y
  • (d) 3-$y
Q16. (Real exam style — April 2024-এ এসেছে) এই bash script-এর output কী?
#!/bin/bash
x=3
y=$((x * 2))
for i in 1 2; do
    y=$((y + i))
done
echo "$x-$y"
  • (a) 3-6
  • (b) 3-9
  • (c) x-y
  • (d) 3-$y
Show Answerউত্তর দেখুন
Answer: (b)y=$((3 * 2)) makes y=6. The for loop runs with i=1 (y=6+1=7), then i=2 (y=7+2=9). Double quotes expand variables, so echo "$x-$y" prints 3-9. If the script had used single quotes, option (d)-style literal text would print instead.
Answer: (b)y=$((3 * 2)) দেয় y=6। For loop চলে i=1 (y=6+1=7), তারপর i=2 (y=7+2=9)। Double quote-এ variable expand হয়, তাই echo "$x-$y" print করে 3-9। Script-এ single quote থাকলে option (d)-এর মত literal text print হতো।
Q17. (Real exam style — asked April 2024) What is the output of this C program?
#include <stdio.h>
int main(void) {
    int i = -1;
    unsigned int u = 1;
    if (i < u)
        printf("A");
    else
        printf("B");
    printf(" %u", (unsigned int)i);
    return 0;
}
  • (a) A 1
  • (b) A 4294967295
  • (c) B 4294967295
  • (d) B -1
Q17. (Real exam style — April 2024-এ এসেছে) এই C program-এর output কী?
#include <stdio.h>
int main(void) {
    int i = -1;
    unsigned int u = 1;
    if (i < u)
        printf("A");
    else
        printf("B");
    printf(" %u", (unsigned int)i);
    return 0;
}
  • (a) A 1
  • (b) A 4294967295
  • (c) B 4294967295
  • (d) B -1
Show Answerউত্তর দেখুন
Answer: (c) — By the usual arithmetic conversions, comparing int with unsigned int converts the signed side to unsigned. So i becomes \(2^{32}-1 = 4{,}294{,}967{,}295\), which is NOT less than 1 — the else branch prints B. The second printf prints that same huge value with %u: 4294967295. So the output is B 4294967295.
Answer: (c) — Usual arithmetic conversions অনুযায়ী int-কে unsigned int-এর সাথে compare করলে signed পাশটা unsigned হয়ে যায়। তাই i হয়ে যায় \(2^{32}-1 = 4{,}294{,}967{,}295\), যেটা 1-এর চেয়ে ছোট না — else branch-এ B print হয়। পরের printf %u দিয়ে ওই বিশাল value-টাই print করে: 4294967295। তাই output B 4294967295