Skip to content

11-dars: Funksiyalar

Dars haqida

Davomiyligi: 90 daqiqa Maqsad: Talaba C tilida funksiya yaratishi, chaqirishi, qiymat qaytarishni bilishi hamda parameter, scope (local/global) va recursion tushunchalarini tushunishi kerak.

1. Funksiya nima?

Funksiya — qayta ishlatish mumkin bo'lgan kod bloki.

c
int qoshish(int a, int b) {
    return a + b;
}

// Chaqirish
int natija = qoshish(5, 3);  // 8

2. Nima uchun funksiya?

Funksiyasiz

c
int main(void) {
    int a = 5, b = 3;
    int sum = a + b;
    printf("Yig'indi: %d\n", sum);
    
    // har yangi juftlik uchun shu kodni qayta yozish...
}

Funksiya bilan

c
int qoshish(int a, int b) {
    return a + b;
}

int main(void) {
    printf("%d\n", qoshish(5, 3));
    printf("%d\n", qoshish(10, 7));
    printf("%d\n", qoshish(100, 200));
}

Foydalari:

  • DRY (Don't Repeat Yourself) — takrorlanish yo'q
  • Modular — bo'lakli
  • Test — alohida sinash mumkin
  • Reuse — boshqa joyda ishlatish

3. Funksiya tuzilmasi

c
return_type function_name(parameters) {
    // body
    return value;
}

Misol:

c
int qoshish(int a, int b) {
    int sum = a + b;
    return sum;
}

Qismlar:

QismTushuntirish
intReturn type — qaytaradigan tur
qoshishFunksiya nomi
(int a, int b)Parametrlar
{ ... }Body (kod)
return sum;Qiymat qaytarish

4. main funksiyasi

Har C dasturda main bor:

c
int main(void) {
    // dastur kodi
    return 0;
}
  • int — main 0 qaytaradi (success)
  • void — argument yo'q
  • return 0 — muvaffaqiyatli tugash

5. Misol: kvadrat va kalkulyator funksiyalari

c
int square(int n) {
    return n * n;
}

// square(5) → 25, square(10) → 100

Bir nechta funksiya:

c
#include <stdio.h>

int qoshish(int a, int b) {
    return a + b;
}

int ayirish(int a, int b) {
    return a - b;
}

int kopaytirish(int a, int b) {
    return a * b;
}

int bolish(int a, int b) {
    if (b == 0) {
        printf("Xato: nolga bo'lish\n");
        return 0;
    }
    return a / b;
}

int main(void) {
    int a = 10, b = 3;
    
    printf("Yig'indi: %d\n", qoshish(a, b));
    printf("Ayirma: %d\n", ayirish(a, b));
    printf("Ko'paytma: %d\n", kopaytirish(a, b));
    printf("Bo'linma: %d\n", bolish(a, b));
    
    return 0;
}

6. void funksiyalar

Hech narsa qaytarmaydigan funksiya:

c
void salomlash(void) {
    printf("Salom!\n");
}

void chiqar_qator(int n) {
    for (int i = 0; i < n; i++) {
        printf("%d ", i);
    }
    printf("\n");
}

void return type — funksiya qiymat qaytarmaydi.

void parameter — funksiya hech qanday argument olmaydi:

c
void salomlash() { ... }      // OK
void salomlash(void) { ... }  // Yaxshiroq (C uslubi)

7. Funksiyani chaqirish: argument vs parameter

c
int sum = qoshish(5, 3);
  • qoshish — funksiya nomi
  • (5, 3)arguments (argumentlar)
  • Qiymat — natija
c
int qoshish(int a, int b) {  // a va b — parameterlar
    return a + b;
}

qoshish(5, 3);  // 5 va 3 — argumentlar

8. Function prototype

c
#include <stdio.h>

// Prototype — funksiya qayerda yozilishini e'lon qilish
int qoshish(int a, int b);

int main(void) {
    printf("%d\n", qoshish(5, 3));
    return 0;
}

// Funksiya tanasi (main'dan keyin)
int qoshish(int a, int b) {
    return a + b;
}

Nima uchun prototype?

C tartibga bog'liq. Funksiya main'dan keyin yozilsa — prototype kerak.

Yoki funksiyalarni main'dan oldin yozing — prototype shart emas.

9. return — qaytarish

c
int kattaroq(int a, int b) {
    if (a > b) {
        return a;  // funksiya shu yerda tugaydi
    }
    return b;
}

return — funksiya tugaydi va qiymat qaytaradi. Bir funksiyada bir nechta return bo'lishi mumkin — qaysi biri birinchi ishlasa, o'sha qaytadi.

Void return

c
void chiqar(int n) {
    if (n < 0) {
        printf("Manfiy raqam\n");
        return;  // qiymat yo'q, lekin funksiya tugaydi
    }
    printf("Musbat: %d\n", n);
}

10. Misollar: tub son va funksiyalar zanjiri

Tub son tekshirish

c
#include <stdio.h>

int is_prime(int n) {
    if (n < 2) return 0;
    for (int i = 2; i * i <= n; i++) {
        if (n % i == 0) return 0;
    }
    return 1;
}

int main(void) {
    printf("1 dan 30 gacha tub sonlar:\n");
    for (int i = 2; i <= 30; i++) {
        if (is_prime(i)) {
            printf("%d ", i);
        }
    }
    printf("\n");
    return 0;
}

is_prime1 (true) yoki 0 (false) qaytaradi.

Funksiyalar bir-birini chaqiradi

c
int square(int n) {
    return n * n;
}

int sum_of_squares(int a, int b) {
    return square(a) + square(b);
}

// sum_of_squares(3, 4) → 9 + 16 = 25

sum_of_squares — ichida square chaqiradi.

11. Nomlash va yaxshi funksiya qoidalari

c
// Yaxshi
int qoshish(int a, int b)
double circle_area(double r)
int is_prime(int n)
void print_menu(void)

// Yomon
int f()
int Add()
int compute_the_sum_of_two_numbers()

Qoidalar: snake_case (C standart), aniq nom, qisqa, ish bildiruvchi fe'l bilan.

Yaxshi funksiya

  1. Bitta vazifa qiladi (Single Responsibility)
  2. Qisqa — 20–30 qator
  3. Aniq nom
  4. 3-4 dan ko'p parameter yo'q
  5. Side effect'sizroq (faqat olib, qaytaradi)

12. 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
}

13. Local va global o'zgaruvchilar

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;
}

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. Kodni tushunish qiyin

Iloji boricha local ishlating, parameter orqali uzating.

14. 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!

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

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

17. const parameter va default 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.

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.

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

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

19. Rekursiv misollar

Fibonacci

c
int fib(int n) {
    if (n < 2) return n;  // base
    return fib(n - 1) + fib(n - 2);  // recursive
}

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.

GCD (Euclidean)

10-darsda while bilan yozgan Euclidean GCD — rekursiv ko'rinishda:

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

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

21. 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).

22. Common pitfalls

1. Return unutish

c
int qoshish(int a, int b) {
    int sum = a + b;
    // return yo'q!
}

Kompiler warning beradi, lekin kompilyatsiya qiladi. Natija — noma'lum.

2. Return type to'g'rimas

c
int doira_yuzasi(int r) {
    return 3.14 * r * r;  // float, lekin int qaytaradi
}

doira_yuzasi(5);  // 78 (78.5 emas — kasr tashlanadi!)

To'g'ri:

c
double doira_yuzasi(double r) {
    return 3.14 * r * r;
}

3. Prototype yo'q

c
int main(void) {
    qoshish(5, 3);  // qoshish hali e'lon qilinmagan!
    return 0;
}

int qoshish(int a, int b) {
    return a + b;
}

Kompiler xato beradi. Prototype qo'shing yoki funksiyani main'dan oldin yozing.

Darsdagi topshiriqlar

Topshiriq 1 — Asosiy funksiyalar

functions.cqoshish, ayirish va kopaytirish nomli uchta funksiya yozing. Har biri ikkita int qabul qilib, natijani return qilsin. mainda har birini chaqirib, natijalarni chiqaring.

Topshiriq 2 — Geometrik shakllar

shapes.c — har bir shakl yuzasi uchun alohida funksiya yozing:

  • Doira: PI * r * r
  • To'rtburchak: w * h
  • Uchburchak: 0.5 * base * height
  • Trapesiya: (a + b) * h / 2
  • Romb: d1 * d2 / 2

Hammasi double qaytarsin. main'da har birini sinab, natijani %.2f bilan chiqaring.

Topshiriq 3 — Eng katta / eng kichik

max-min.cmax(a, b) va min(a, b) funksiyalarini yozing. So'ng ularni ishlatib max3(a, b, c) va min3(a, b, c) funksiyalarini quring (funksiya ichida funksiya chaqirish). mainda bir necha misolda sinang.

Topshiriq 4 — 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);
    func2();
    printf("Main (global x): %d\n", x);
    return 0;
}

Har bir printf nima chiqaradi — natijani oldindan o'ylab daftarga yozing. Keyin kompilyatsiya qilib tekshiring.

Topshiriq 5 — 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 6 — Rekursiv funksiyalar

recursive.c — quyidagi funksiyalarni rekursiya bilan (o'zini chaqirish orqali) yozing:

  • factorial(n) — n!
  • fibonacci(n) — Fibonachchi qatorining n-hadi
  • gcd(a, b) — eng katta umumiy bo'luvchi (Evklid usuli)
  • sum_to_n(n) — 1 dan n gacha yig'indi

Har birida base case (to'xtash sharti) borligiga e'tibor bering. mainda sinang.

Topshiriq 7 — Static variable

static-var.cstatic lokal o'zgaruvchidan foydalanib ikkita funksiya yozing:

  • counter() — har chaqirilganda o'sib boradigan hisoblagichni chiqaradi (1, 2, 3...)
  • generate_id() — 1000 dan boshlab har safar navbatdagi ID ni qaytaradi

mainda har birini bir necha marta chaqirib, static oddiy lokal o'zgaruvchidan qanday farq qilishini kuzating.

Topshiriq 8 — GitHub'ga

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

Asosiy tushunchalar (lug'at)

TerminQisqacha izoh
FunctionQayta ishlatish kod bloki
Return typeQaytaradigan tur
ParameterFunksiya kiruvchi
ArgumentChaqirayotgan qiymat
ReturnQiymat qaytarish
voidBo'sh, qiymat yo'q
PrototypeFunksiya e'lon (oldindan)
main()Asosiy funksiya
DRYDon't Repeat Yourself
Single ResponsibilityBir funksiya — bir vazifa
Function callFunksiyani chaqirish
Side effectFunksiyaning tashqi holatni o'zgartirishi
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

12-dars: Oylik imtihon →

Master IT o'quv markazi — o'qitish rejasi