Skip to content

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.

c
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.

c
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.

c
#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:

  1. Har funksiya o'zgartirishi mumkin — debugging qiyin
  2. Test qiyin — funksiya alohida sinab bo'lmaydi
  3. Multi-threading muammo
  4. Kodni tushunish qiyin

Iloji boricha local ishlating, parameter orqali uzating.

4. Block scope

c
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

c
for (int i = 0; i < 10; i++) {  // i — faqat for ichida
    printf("%d\n", i);
}
// printf("%d\n", i);  // XATO!

5. Variable shadowing

c
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.

c
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: 10

a 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:

c
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:

c
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!

c
// 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

c
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
             = 120

10. Rekursiya qoidalari

1. Base case (asos) — to'xtatish sharti

c
if (n <= 1) return 1;  // base case

2. Recursive case — o'zini chaqirish

c
return n * factorial(n - 1);  // recursive

Base case unutmang

Base case yo'q bo'lsa — cheksiz rekursiya. Stack overflow xatosi.

c
int bad(int n) {
    return n * bad(n - 1);  // hech qachon to'xtamaydi!
}

11. Misol: Fibonacci rekursiv

c
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))
       = ...
       = 5

Fibonacci 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

c
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)

c
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)
            = 6

14. Misol: Sum to N

Sikl bilan:

c
int sum(int n) {
    int total = 0;
    for (int i = 1; i <= n; i++) {
        total += i;
    }
    return total;
}

Rekursiv:

c
int sum(int n) {
    if (n <= 0) return 0;
    return n + sum(n - 1);
}

Bir xil natija, ikkita yondashuv.

15. Function static variable

c
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

c
void func(const int x) { ... }    // x o'zgartirilmaydi
static int helper(void) { ... }    // funksiya faqat shu fayl ichida

17. To'liq misol: Bank hisobi (oddiy)

c
#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

c
#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:

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:

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:

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:

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.cmath.h kabi o'z funksiyalaringiz:

c
#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:

c
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:

c
#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:

c
#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

bash
$ cd ~/c-darslari
$ mkdir 4-oy-dars-8
$ # fayllarni shu joyga
$ git add .
$ git commit -m "feat: dars 8 - scope and recursion"
$ git push

Asosiy tushunchalar (lug'at)

TerminQisqacha izoh
ScopeO'zgaruvchi yashash joyi
Local variableFunksiya ichidagi
Global variableHammasi uchun
Block scope{} ichida
ShadowingLocal global ni yashiradi
Pass by valueNusxa uzatish
Pass by referenceManzil uzatish (pointer)
const parameterO'zgartirib bo'lmaydi
static variableChaqirishlar orasida saqlanadi
RecursionFunksiya o'zini chaqiradi
Base caseTo'xtatish sharti
Recursive caseO'zini chaqirish
Stack overflowCheksiz rekursiya xatosi

Keyingi dars

9-dars: Input/Output — scanf va printf →

Master IT o'quv markazi — o'qitish rejasi