8-dars: Funksiyalar — parameter, scope va recursion
Dars haqida
Davomiyligi: 90 daqiqa Maqsad: Talaba scope (variable yashash joyi), local va global o'zgaruvchilarni, parameter passing va recursion (rekursiya) tushunchalarini bilishi kerak.
1. Scope (yashash joyi) nima?
Scope — o'zgaruvchining qayerda ko'rinadigan va qayerda ishlovchi joyi.
int x = 10; // global
void func(void) {
int y = 20; // local
}
int main(void) {
// x ko'rinadi
// y KO'RINMAYDI
}2. Local variable
Local — funksiya ichida e'lon qilingan. Faqat shu funksiyada ko'rinadi.
void func(void) {
int local_var = 100;
printf("%d\n", local_var); // OK
}
int main(void) {
func();
// printf("%d\n", local_var); // XATO! local_var ko'rinmaydi
return 0;
}3. Global variable
Global — hamma funksiyaning tashqarida e'lon qilingan. Hamma joyda ko'rinadi.
#include <stdio.h>
int global_var = 100; // global
void func1(void) {
printf("Func1: %d\n", global_var); // OK
global_var = 200; // o'zgartirish ham
}
void func2(void) {
printf("Func2: %d\n", global_var); // 200
}
int main(void) {
func1();
func2();
return 0;
}Global'dan ehtiyot
Global o'zgaruvchilar — anti-pattern. Sabab:
- Har funksiya o'zgartirishi mumkin — debugging qiyin
- Test qiyin — funksiya alohida sinab bo'lmaydi
- Multi-threading muammo
- Kodni tushunish qiyin
Iloji boricha local ishlating, parameter orqali uzating.
4. Block scope
int main(void) {
int x = 10;
{
int y = 20; // faqat bu blokda
printf("%d %d\n", x, y); // OK
}
// printf("%d\n", y); // XATO! y endi yo'q
return 0;
}{} ichida e'lon qilingan o'zgaruvchi — faqat shu blok ichida.
for sikli ichida
for (int i = 0; i < 10; i++) { // i — faqat for ichida
printf("%d\n", i);
}
// printf("%d\n", i); // XATO!5. Variable shadowing
int x = 10; // global
void func(void) {
int x = 100; // local — global'ni "yashiradi"
printf("%d\n", x); // 100 (local)
}
int main(void) {
printf("%d\n", x); // 10 (global)
func();
printf("%d\n", x); // 10 (global, o'zgarmadi!)
return 0;
}Local x global x ni funksiya ichida yashiradi.
6. Parameter passing — pass by value
C'da parameter qiymat orqali (pass by value) uzatiladi. Demak — nusxa uzatiladi.
void increment(int x) {
x = x + 1;
printf("Ichida: %d\n", x);
}
int main(void) {
int a = 10;
increment(a);
printf("Tashqarida: %d\n", a); // 10 (o'zgarmadi!)
return 0;
}Natija:
Ichida: 11
Tashqarida: 10a ning nusxasi x ga uzatiladi. x ni o'zgartirish — a ga ta'sir qilmaydi.
Pass by reference (qisqacha)
C'da haqiqiy pass-by-reference yo'q. Lekin pointer orqali shu effekt:
void increment(int *x) { // pointer
*x = *x + 1;
}
int main(void) {
int a = 10;
increment(&a); // a manzili
printf("%d\n", a); // 11
}Pointer keyingi oylarda batafsil.
7. const parameter
Funksiya o'zgartirmasligi kerak bo'lgan parameter:
double doira_yuzasi(const double radius) {
// radius = 5; // XATO! const
return 3.14 * radius * radius;
}const — compiler tomonidan tekshirish uchun.
8. Default parameter — C'da YO'Q!
// XATO — C'da default parameter yo'q
void func(int a, int b = 10) { ... }C++'da bor, C'da yo'q. Function overloading ham yo'q.
Yechim — boshqa funksiya yoki NULL/0 bilan check.
9. Recursion (rekursiya) — funksiya o'zini chaqiradi
int factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}factorial(5):
factorial(5) = 5 * factorial(4)
= 5 * 4 * factorial(3)
= 5 * 4 * 3 * factorial(2)
= 5 * 4 * 3 * 2 * factorial(1)
= 5 * 4 * 3 * 2 * 1
= 12010. Rekursiya qoidalari
1. Base case (asos) — to'xtatish sharti
if (n <= 1) return 1; // base case2. Recursive case — o'zini chaqirish
return n * factorial(n - 1); // recursiveBase case unutmang
Base case yo'q bo'lsa — cheksiz rekursiya. Stack overflow xatosi.
int bad(int n) {
return n * bad(n - 1); // hech qachon to'xtamaydi!
}11. Misol: Fibonacci rekursiv
int fib(int n) {
if (n < 2) return n; // base
return fib(n - 1) + fib(n - 2); // recursive
}fib(5):
fib(5) = fib(4) + fib(3)
= (fib(3) + fib(2)) + (fib(2) + fib(1))
= ...
= 5Fibonacci rekursiv — sekin!
fib(40) — bir necha sekund. fib(50) — bir necha daqiqa.
Sabab — bir xil hisob ko'p marta.
For sikli bilan — millisekund.
Rekursiya — chiroyli, lekin har doim eng tez emas.
12. Misol: Power rekursiv
double power(double base, int exp) {
if (exp == 0) return 1;
if (exp < 0) return 1 / power(base, -exp);
return base * power(base, exp - 1);
}13. Misol: GCD rekursiv (Euclidean)
int gcd(int a, int b) {
if (b == 0) return a;
return gcd(b, a % b);
}Bu chiroyli, qisqa va tez rekursiv yechim.
gcd(48, 18):
gcd(48, 18) = gcd(18, 12)
= gcd(12, 6)
= gcd(6, 0)
= 614. Misol: Sum to N
Sikl bilan:
int sum(int n) {
int total = 0;
for (int i = 1; i <= n; i++) {
total += i;
}
return total;
}Rekursiv:
int sum(int n) {
if (n <= 0) return 0;
return n + sum(n - 1);
}Bir xil natija, ikkita yondashuv.
15. Function static variable
void counter(void) {
static int count = 0; // bir marta initialize
count++;
printf("Count: %d\n", count);
}
int main(void) {
counter(); // Count: 1
counter(); // Count: 2
counter(); // Count: 3
return 0;
}static — o'zgaruvchi chaqirishlar orasida saqlanadi.
Local lekin yo'qolmaydi.
16. const va static parameter
void func(const int x) { ... } // x o'zgartirilmaydi
static int helper(void) { ... } // funksiya faqat shu fayl ichida17. To'liq misol: Bank hisobi (oddiy)
#include <stdio.h>
double balance = 1000.0; // global (faqat misol uchun)
void show_balance(void) {
printf("Balans: %.2f\n", balance);
}
void deposit(double amount) {
if (amount <= 0) {
printf("Xato: manfiy summa\n");
return;
}
balance += amount;
printf("Qo'shildi: %.2f\n", amount);
}
int withdraw(double amount) {
if (amount <= 0) {
printf("Xato: manfiy summa\n");
return 0;
}
if (amount > balance) {
printf("Xato: yetarli pul yo'q\n");
return 0;
}
balance -= amount;
printf("Olib chiqildi: %.2f\n", amount);
return 1;
}
int main(void) {
show_balance();
deposit(500);
show_balance();
withdraw(200);
show_balance();
withdraw(5000); // xato
show_balance();
return 0;
}Real loyiha
Global o'zgaruvchi — bu yerda misol uchun. Real ishda — struct ishlatiladi (keyinroq).
18. Misol: Math library funksiyalari
#include <stdio.h>
// Power
double power(double base, int exp) {
double result = 1;
int positive = (exp < 0) ? -exp : exp;
for (int i = 0; i < positive; i++) {
result *= base;
}
return (exp < 0) ? 1 / result : result;
}
// Square root (Newton's method)
double sqrt_my(double x) {
if (x < 0) return -1; // xato
if (x == 0) return 0;
double guess = x / 2;
for (int i = 0; i < 20; i++) {
guess = (guess + x / guess) / 2;
}
return guess;
}
// Absolute
double abs_my(double x) {
return (x < 0) ? -x : x;
}
// Round
int round_my(double x) {
return (x >= 0) ? (int)(x + 0.5) : (int)(x - 0.5);
}
int main(void) {
printf("2^10 = %.0f\n", power(2, 10));
printf("sqrt(25) = %.2f\n", sqrt_my(25));
printf("sqrt(2) = %.6f\n", sqrt_my(2));
printf("|-7.5| = %.1f\n", abs_my(-7.5));
printf("round(3.7) = %d\n", round_my(3.7));
printf("round(-3.7) = %d\n", round_my(-3.7));
return 0;
}Darsdagi topshiriqlar
Topshiriq 1 — Scope mashqi
scope.c:
#include <stdio.h>
int x = 10; // global
void func1(void) {
int x = 100; // local shadowing
printf("Func1 (local x): %d\n", x);
x = 200;
printf("Func1 (local x): %d\n", x);
}
void func2(void) {
printf("Func2 (global x): %d\n", x);
x = 50; // global'ni o'zgartirish
}
int main(void) {
printf("Main (global x): %d\n", x);
func1();
printf("Main (global x): %d\n", x); // 10
func2();
printf("Main (global x): %d\n", x); // 50
return 0;
}Natijani oldindan o'ylab toping. Keyin kompilyatsiya qiling.
Topshiriq 2 — Pass by value
pass-by-value.c:
#include <stdio.h>
void increment(int x) {
x = x + 1;
printf("Ichida: x = %d\n", x);
}
void swap_local(int a, int b) {
int temp = a;
a = b;
b = temp;
printf("Ichida: a = %d, b = %d\n", a, b);
}
int main(void) {
int n = 10;
increment(n);
printf("Tashqarida: n = %d\n\n", n);
int x = 5, y = 15;
swap_local(x, y);
printf("Tashqarida: x = %d, y = %d\n", x, y);
// swap ishlamadi! Sababini izohlang
return 0;
}Topshiriq 3 — Rekursiv funksiyalar
recursive.c:
#include <stdio.h>
long factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
long fibonacci(int n) {
if (n < 2) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
int gcd(int a, int b) {
if (b == 0) return a;
return gcd(b, a % b);
}
int sum_to_n(int n) {
if (n <= 0) return 0;
return n + sum_to_n(n - 1);
}
int main(void) {
printf("5! = %ld\n", factorial(5));
printf("10! = %ld\n", factorial(10));
printf("fib(10) = %ld\n", fibonacci(10));
printf("gcd(48, 18) = %d\n", gcd(48, 18));
printf("sum(1..100) = %d\n", sum_to_n(100));
return 0;
}Topshiriq 4 — Static variable
static-var.c:
#include <stdio.h>
void counter(void) {
static int count = 0;
count++;
printf("Count: %d\n", count);
}
int generate_id(void) {
static int id = 1000;
return id++;
}
int main(void) {
counter();
counter();
counter();
printf("\nIDs:\n");
printf("%d\n", generate_id());
printf("%d\n", generate_id());
printf("%d\n", generate_id());
return 0;
}Topshiriq 5 — Math library
my-math.c — math.h kabi o'z funksiyalaringiz:
#include <stdio.h>
double my_pow(double base, int exp) {
double result = 1;
int n = (exp < 0) ? -exp : exp;
for (int i = 0; i < n; i++) result *= base;
return (exp < 0) ? 1 / result : result;
}
double my_abs(double x) {
return (x < 0) ? -x : x;
}
double my_sqrt(double x) {
if (x < 0) return -1;
double guess = x / 2;
for (int i = 0; i < 30; i++) {
guess = (guess + x / guess) / 2;
}
return guess;
}
long my_factorial(int n) {
long r = 1;
for (int i = 1; i <= n; i++) r *= i;
return r;
}
double my_log2(double x) {
if (x <= 0) return -1;
double count = 0;
while (x > 1) {
x /= 2;
count++;
}
return count;
}
int main(void) {
printf("2^8 = %.0f\n", my_pow(2, 8));
printf("|-3.7| = %.2f\n", my_abs(-3.7));
printf("sqrt(2) = %.5f\n", my_sqrt(2));
printf("sqrt(100) = %.2f\n", my_sqrt(100));
printf("6! = %ld\n", my_factorial(6));
printf("log2(1024) = %.0f\n", my_log2(1024));
return 0;
}Topshiriq 6 — Number theory
number-theory.c — quyidagi funksiyalar:
int is_prime(int n);
int is_perfect(int n); // (6, 28, 496, ...)
int is_armstrong(int n); // (153 = 1^3 + 5^3 + 3^3)
int sum_of_divisors(int n);
int count_divisors(int n);
int main(void) {
for (int i = 1; i <= 50; i++) {
printf("%d: ", i);
if (is_prime(i)) printf("tub ");
if (is_perfect(i)) printf("mukammal ");
if (is_armstrong(i)) printf("Armstrong ");
printf("(divisors: %d, sum: %d)\n",
count_divisors(i), sum_of_divisors(i));
}
return 0;
}Hammasini siz yozing.
Mukammal son: bo'luvchilari yig'indisi o'ziga teng (6 = 1+2+3).
Armstrong: raqamlar kublari yig'indisi o'ziga teng (153 = 1+125+27).
Topshiriq 7 — Tower of Hanoi (rekursiv)
hanoi.c — klassik rekursiv masala:
#include <stdio.h>
void hanoi(int n, char from, char to, char via) {
if (n == 1) {
printf("Disk 1: %c -> %c\n", from, to);
return;
}
hanoi(n - 1, from, via, to);
printf("Disk %d: %c -> %c\n", n, from, to);
hanoi(n - 1, via, to, from);
}
int main(void) {
int n = 4;
hanoi(n, 'A', 'C', 'B');
return 0;
}Sinab ko'ring n = 3, 4, 5.
n = 10 uchun nechta harakat? (2^n - 1)
Topshiriq 8 — Helper funksiyalar
helpers.c — print uchun funksiyalar:
#include <stdio.h>
void print_line(int len, char c) {
for (int i = 0; i < len; i++) putchar(c);
putchar('\n');
}
void print_header(const char *title) {
print_line(40, '=');
printf(" %s\n", title);
print_line(40, '=');
}
void print_section(const char *name) {
printf("\n--- %s ---\n", name);
}
void print_box(int w, int h) {
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
if (i == 0 || i == h-1 || j == 0 || j == w-1) {
putchar('*');
} else {
putchar(' ');
}
}
putchar('\n');
}
}
int main(void) {
print_header("Mening dasturim");
print_section("Section 1");
printf("Mavzu: scope va recursion\n");
print_section("Section 2");
print_box(10, 5);
print_line(40, '-');
return 0;
}Topshiriq 9 — GitHub'ga
$ cd ~/c-darslari
$ mkdir 4-oy-dars-8
$ # fayllarni shu joyga
$ git add .
$ git commit -m "feat: dars 8 - scope and recursion"
$ git pushAsosiy tushunchalar (lug'at)
| Termin | Qisqacha izoh |
|---|---|
| Scope | O'zgaruvchi yashash joyi |
| Local variable | Funksiya ichidagi |
| Global variable | Hammasi uchun |
| Block scope | {} ichida |
| Shadowing | Local global ni yashiradi |
| Pass by value | Nusxa uzatish |
| Pass by reference | Manzil uzatish (pointer) |
| const parameter | O'zgartirib bo'lmaydi |
| static variable | Chaqirishlar orasida saqlanadi |
| Recursion | Funksiya o'zini chaqiradi |
| Base case | To'xtatish sharti |
| Recursive case | O'zini chaqirish |
| Stack overflow | Cheksiz rekursiya xatosi |