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-এ যা যা আসে সবকিছু।
- C Basics, Data Types & OperatorsC Basics, Data Types & Operators
- Loops and ConditionsLoops and Conditions
- Functions and RecursionFunctions and Recursion
- Arrays and StringsArrays and Strings
- PointersPointers
- Structures and UnionsStructures and Unions
- Memory ConceptsMemory Concepts
- Shell/Bash Basics (Asked in 2024!)Shell/Bash Basics (2024-এ এসেছে!)
- Practice QuestionsPractice Questions
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
*/
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 |
|---|---|---|---|
char | 1 | -128 toথেকে 127 | %c |
short | 2 | -32,768 toথেকে 32,767 | %hd |
int | 4 | -2,147,483,648 toথেকে 2,147,483,647 | %d |
long | 8 (Linux)(Linux-এ) | aboutপ্রায় ±9.2×1018 | %ld |
long long | 8 | aboutপ্রায় ±9.2×1018 | %lld |
float | 4 | ~7 digits precision~7 digit precision | %f |
double | 8 | ~15 digits precision~15 digit precision | %lf |
unsigned int | 4 | 0 toথেকে 4,294,967,295 | %u |
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
*/
'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 |
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
*/
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
*/
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: char → int → long → float → double. Two big rules:
- Integer division:
int / intgives anint.7 / 2is3, not 3.5. - Promotion: if one side is
double, the whole thing becomesdouble.7 / 2.0is3.5.
এক expression-এ দুইটা আলাদা type থাকলে C চুপচাপ "ছোট" type-কে "বড়" type-এ convert করে দেয়। Order মোটামুটি: char → int → long → float → double। দুইটা বড় rule:
- Integer division:
int / intদিলে resultintহয়।7 / 2হলো3, 3.5 না। - Promotion: এক পাশ
doubleহলে পুরোটাdoubleহয়ে যায়।7 / 2.0হলো3.5।
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 অংশটা থেকে যায়।
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 \)।
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 হয়ে যায়।
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 */
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 চলে।
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-এর এক নম্বর প্রশ্ন এটাই।
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 সবগুলোই চলে।
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);
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 থেকে বের হয়।
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
*/
| i | What happensকী হয় | Printed so farএ পর্যন্ত print |
|---|---|---|
| 1 | prints 11 print হয় | 1 |
| 2 | prints 22 print হয় | 1 2 |
| 3 | continue — skips printprint skip হয় | 1 2 |
| 4 | prints 44 print হয় | 1 2 4 |
| 5 | break — loop endsloop শেষ | 1 2 4 |
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} \) বার চলে।
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 বদলায় না।
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 হয় মাত্র একবার।
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 গুলো একটা একটা করে খুলে আসে।
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
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।
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 |
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 সহজ অঙ্ক:
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-র এক সোজা লাইনে।
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 \)।
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 হলে positive | strcmp("abc","abd") < 0 |
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. Usestrcmp(s, "BUET") == 0. - Forgetting
'\0'space: to store "hello" you needchar s[6], notchar s[5]. - Off-by-one: the last valid index of
a[n]isn-1. gets()is dangerous: it cannot check size (buffer overflow). Usefgets()instead.- Arrays cannot be assigned:
a = b;is illegal for arrays. Copy element by element or usestrcpy/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ব্যবহার করো।
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)।
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
*/
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।
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!)।
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 একই জায়গায় |
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
*/
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 বাঁচাতে |
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 করে।
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 */
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 */
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 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-কে ফেরত দেয় | — |
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 ব্যবহার বাড়তেই থাকে।
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 */
}
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=5— NO spaces around =.x = 5is an error (bash thinksxis a command). Read a variable with$xor${x}. - echo: prints its arguments:
echo "Hello $x"printsHello 5. Single quotes stop expansion:echo '$x'prints$xliterally. - Command substitution:
$(command)runs the command and pastes its output:d=$(date),n=$(wc -l file). - Arithmetic: only inside
$((...)):echo $((3 + 4))prints7. Outside it,3 + 4is 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 ধরে ধরে পড়ে।
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 করে।
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 হিসেবেই থাকে।
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-র মতই ব্যাপার!)
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 খোলো।
sizeof('A') in a C program?
sizeof('A')-এর value কত?
Show Answerউত্তর দেখুন
'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.'A'-এর মত character literal-এর type হলো int, তাই এর size 4 byte। খেয়াল রেখো sizeof(char) হলো 1, আর C++-এ sizeof('A')-ও 1 হতো। C-vs-C++ এই পার্থক্যটা প্রিয় trap।printf("%.1f", 5 / 2 * 2.0);?
printf("%.1f", 5 / 2 * 2.0);-এর output কী?
Show Answerউত্তর দেখুন
/ 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./ আর *-এর precedence সমান, হিসাব হয় left থেকে right। আগে 5 / 2 = 2 (integer division-এ .5 বাদ যায়)। তারপর 2 * 2.0 = 4.0 (double-এ promote হয়)। তাই 4.0।Show Answerউত্তর দেখুন
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.do-while body চালানোর পরে condition check করে, তাই body অন্তত একবার চলবেই। for আর while আগে check করে, তাই শূন্যবারও চলতে পারে।int n = 1;
switch (n) {
case 1: printf("A");
case 2: printf("B"); break;
case 3: printf("C");
default: printf("D");
}
int n = 1;
switch (n) {
case 1: printf("A");
case 2: printf("B"); break;
case 3: printf("C");
default: printf("D");
}
Show Answerউত্তর দেখুন
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.case 1-এ, A print হয়। break নেই, তাই fall through করে case 2-তে গিয়ে B print হয়। B-এর পরের break switch থামিয়ে দেয়। Output: AB।int s = 0;
for (int i = 1; i <= 8; i++) {
if (i % 2 == 0) continue;
if (i > 6) break;
s += i;
}
printf("%d", s);
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উত্তর দেখুন
char s[] = "Dhaka";, what are strlen(s) and sizeof(s)?
char s[] = "Dhaka"; হলে strlen(s) আর sizeof(s) কত?
Show Answerউত্তর দেখুন
strlen = 5 (it stops before '\0'). The array stores those 5 letters plus the '\0', so sizeof = 6.strlen = 5 ('\0'-এর আগে থামে)। Array-তে ওই 5 অক্ষর + '\0' থাকে, তাই sizeof = 6।int array a starts at address 5000 (int = 4 bytes). Which expression equals a[3], and what is the address of a[3]?
int array a শুরু হয় address 5000-এ (int = 4 byte)। কোন expression টা a[3]-এর সমান, আর a[3]-এর address কত?
Show Answerউত্তর দেখুন
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]".a[3] ≡ *(a+3) (value টা)। এর address \(5000 + 3 \times 4 = 5012\)। Option (c) আর (d) হলো address/pointer, element-এর value না — তাই ওগুলো "a[3]-এর সমান" না।void f(int n) {
if (n == 0) return;
f(n - 1);
printf("%d ", n);
}
int main(void) { f(4); return 0; }
void f(int n) {
if (n == 0) return;
f(n - 1);
printf("%d ", n);
}
int main(void) { f(4); return 0; }
Show Answerউত্তর দেখুন
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)?
fun(4) call করলে fun(2) মোট কয়বার call হয়, যেখানে fun হলো সাধারণ recursive Fibonacci (fun(n)=fun(n-1)+fun(n-2), base case n=0,1)?
Show Answerউত্তর দেখুন
int a[] = {1, 2, 3, 4, 5};
int *p = a + 1;
printf("%d ", *p++);
printf("%d ", (*p)++);
printf("%d ", *p);
printf("%d", *(p + 1));
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উত্তর দেখুন
p 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}.p শুরু করে 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}।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)?
struct S { char c; int i; }; আর union U { char c; int i; }; হলে sizeof(struct S) আর sizeof(union U) কত?
Show Answerউত্তর দেখুন
Show Answerউত্তর দেখুন
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;
}
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উত্তর দেখুন
depth 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.depth 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।int sumDigits(int n) that returns the sum of the digits of a positive integer. Example: sumDigits(493) returns 16.int sumDigits(int n) লেখো, যেটা positive integer-এর digit-গুলোর যোগফল return করে। যেমন: sumDigits(493) return করবে 16।Show 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.
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।
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;
}
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উত্তর দেখুন
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 */
}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) করতে হবে */
}#!/bin/bash
x=3
y=$((x * 2))
for i in 1 2; do
y=$((y + i))
done
echo "$x-$y"
#!/bin/bash
x=3
y=$((x * 2))
for i in 1 2; do
y=$((y + i))
done
echo "$x-$y"
Show Answerউত্তর দেখুন
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.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 হতো।#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;
}
#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;
}
Show Answerউত্তর দেখুন
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.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।