Jazyk C (príklady) - Funkcie

Z Kiwiki
Skočit na navigaci Skočit na vyhledávání


Základy informatiky - jazyk C


Riešené príklady

Algoritmy

Prvé programy

Podmienky

Cykly

Polia

Funkcie

Súbor

Vzorové príklady

Neriešené príklady


zdroj: Juraj Ďuďák, Zbierka úloh z algoritmizácie pre predmet Základy informatiky

ISBN: 978-80-8075-199-9

Obsah

V tejto časti budeme pracovať s už vytvorenými programami (z predchádzajúcich častí) s dôrazom na tvorbu funkcií. Pre zvládnutie týchto príkladov je potrebné poznať, akým spôsobom sa prenášajú argumenty funkcie (odkazom, hodnotou) a použitie návratovej hodnoty funkcie.

Funkcie a návratová hodnota

Funkcie delíme podľa typu návratovej hodnoty na

funkcie s návratovou hodnotou po skončení vykonávania funkcia vráti nejakú hodnotu, ktorú môžeme priradiť do premennej.

Príklad
1 int abs(int x)
2 { // telo funkcie
3     if(x<0)
4         return -x;
5     else
6         return x
7 }
  • hlavička funkcie: typ návratovej hodnoty: int (celé číslo)
  • argumenty: funkcia má jeden argument: x (x je celé číslo)
  • telo funkcie obsahuje konkrétne príkazy
  • hodnotu, ktorú má funkcia vrátiť, špecifikujeme kľúčovým slovom return, za ktorým nasleduje hodnota, ktorú chceme vrátiť. V príklade, ak je x<0, funkcia vráti hodnotu, čo je vlastne -x (kde x<0), čiže výsledok bude +x. V opačnom prípade vráti x.

funkcie bez návratovej hodnoty Tieto funkcie nič nevracajú. Ich návratový typ je void (prázdny). V jazyku Pascal sa takéto funkcie nazývajú procedúry.

Príklad
 1 void hlasenie(int cislo_chyby)
 2 {
 3     switch(cislo_chyby)
 4     {
 5         case 0: printf("Ziadna chyba"); break;
 6         case 1: printf("Chybne vstupne hodnoty"); break;
 7         case 2: printf("Chyba pocas vypoctu"); break;
 8         default: printf("Neznama chyba");
 9     }
10 }

Dana funkcia je bez návratovej hodnoty (void) a má jeden parameter: celé číslo cislo_chyby. Táto funkcia vypíše podľa hodnoty svojho parametra nejakú chybové hlásenie.

Parametre funkcie

Parametre prenášané hodnotou
V predchádzajúcom príklade (abs, hlasenie) boli argumenty prenášané hodnotou. To znamená, že pri volaní funkcie (napr. abs(3) ) sa hodnota parametru funkcie skopíruje do novovytvorenej premennej (argumentu) / abs(int x=3) / danej funkcie. Takto sa prenášajú všetky argumenty (okrem výnimiek, a ak to neurčíme inak). Premenné vytvorené vo funkciách sú lokálne a po skončení funkcie zaniknú. Premenné definované v jednej funkcie nie sú viditeľné v inej funkcii (aj keď majú rovnaké meno).
Parametre prenášané odkazom
Pri parametroch prenášaných odkazom je špecifické to, že pri volaní funkcie sa nekopírujú ich hodnoty, ale ich adresy (čo šetrí čas pri argumentoch s väčšími pamäťovými nárokmi). Dôsledok tejto zmeny je, že zmena hodnoty vo funkcii má za následok zmenu tejto premennej aj vo funkcii, z ktorej bola táto volaná. Upravme hlavičku funkcie abs, aby parameter x bol prenášaný odkazom: int abs(int &x); Operátor & (referencia) má význam adresy premennej. Premenné sa prenášajú odkazom, ak to určíme operandom &. Polia ako parametre funkcií sa prenášajú odkazom vždy (operátor & sa neuvádza).
Poznámka
parametre prenášané odkazom (operátor refencia - &) sú definované až v jazyku C++. Aj napriek tomuto faktu, budeme tento operátor používať pre jednoduchosť jeho použitia. Jazyk C definuje operátorderefencia - *. Práca s týmto operátorom je podobná práci s operátorom &.

Príklady

Najväčší spoločný delitel

Zadanie
Podľa už známeho (Euklidovho) algoritmu hľadania NSD vytvorte:
  • funkciu: int nsd(int a, int b); ktorá vypočíta NSD týchto dvoch čísel. Funkcia vráti hodnotu, ktorá je rovná najväčšiemuspoločnému deliteľu čísel a,b
  • funkciu: int nsd(int cisla[MAX], int n); ktorá vypočíta NSD n čísel, ktoré sú uložené v poli cisla.

Program načíta z klávesnice číslo n a následne n čísel, ktoré sa uložia do poľa data. Úlohou je vypočítať NSD z týchto čísel. Funkcia nebude nič načítavať ani vypisovať. Všetky vstupné dáta budú predané ako argumenty funkcie. Hodnotu NSD funkcia vráti.

Analýza problému
Problém NSD bol už precvičený v kapitole 4. Použijeme ten istý zdrojový kód, ale úlohu urobíme ako funkciu. Funkcia vráti nsd čísel a a b. Druhú časť úlohy vyriešime pomocou už vytvorenej funkcie nsd(a,b). Ak máme zistiť nsd n čísel, budeme to zisťovať postupne. Ako prvé vypočítame n0=nsd(cisla[0],cisla[1]). Ako ďalší krok bude n0=nsd(n0, cisla[2]), atď. Výsledkom bude hodnota n0. Hlavná funkcia main znázorňuje použitie funkcie nsd.
Program
 1 #include<stdio.h>
 2 #define MAX 100
 3 
 4 int nsd(int a, int b)
 5 {
 6 
 7     while(a!=b)
 8     {    if(a>b)
 9               a=a-b;
10          else
11               b=b-a;
12     }
13     return a;
14 
15 }
16 
17 int nsd(int cisla[MAX],int n)
18 {
19      int n0,i;
20      n0=nsd(cisla[0],cisla[1]);
21      for(i=2; i<n; i++)
22           n0=nsd(n0,cisla[i]);
23      return n0;
24 }
25 
26 void main()
27 {
28 
29     int i,n,vysledok,data[MAX];
30     printf("zadaj počet cisel: ");
31     scanf("%d",&n);
32     for(i=0; i<n; i++)
33         scanf("%d",&data[i]);
34     vysledok=nsd(data,n);
35     printf("NSD nacitanych cisel je %d", vysledok);
36 
37 }

Prvočíslo

Zadanie
podľa známeho algoritmu (časť cykly, úloha "test na prvočíslo“) naprogramujte funkciu int prvocislo(int a); ktorá otestuje, či je číslo a prvočíslo. Ak áno, funkcia vráti hodnotu 1, ak nie, funkcia vráti hodnotu 0. Vo funkcii sa nebude nič načítavať ani vypisovať.
Analýza problému
Algoritmus riešenia je už známy. Teda použijeme už hotový kód a vytvoríme funkciu. Vstupné dáta sa načítajú v hlavnej funkcii. Taktiež výpis výsledku bude vo funkcii main.
Program
 1 #include<stdio.h>
 2 
 3 int prvocislo(int a)
 4 {
 5      int del=2,prvocislo=1,podiel,zv;
 6      do
 7     {
 8        podiel=n/del;
 9        zv=n%del;
10        del++;
11        if(zv==0)
12           {    del=podiel+1;
13                prvocislo=0;
14           }
15      }while(podiel>del);
16      return prvocislo;
17 }
18 
19 void main()
20 {
21     int n;
22     printf("Zadaj cislo, ktore chces testovat na prvocislo\n");
23     scanf("%d",&n);
24     if(prvocislo(n)==1)
25           printf("%d je prvocislo",n);
26     else
27           printf("%d nie je prvocislo",n);
28 }

Maximálna hodnota 2

Zadanie
Naprogramujte funkciu, ktorá zistí maximum z dvoch čísel. Funkcia max bude mať dva parametre: čísla x a y. Funkcia vráti hodnotu maxima. Ďalej naprogramujte funkciu max, ktorá zistí maximálny prvok z n čísel. Funkcia bude mať parametre: pole cisla, v ktorom budú uložené dané čísla a premennú n, ktorá vyjadruje počet čísel v poli cisla. Počet čísel bude maximálne 100.
Analýza problému
Problém hľadania maxima z dvoch čísel bol vyriešený v časti "podmienky“. Tento zdrojový kód použijeme a vytvoríme funkciu: int max(int x, int y); V druhej časti úlohy máme použiť práve vytvorenú funkciu na zistenie maxima z n čísel. Budeme teda vytvárať funkciu, ktorá (podľa zadania) má nasledujúci funkčný prototyp: int max(int cisla[MAX], int n); kde MAX je (konštanta) max. počet prvkov v poli. Pri zisťovaní maximálneho prvku poľa musíme porovnať všetky prvky poľa. Ako prvé porovnáme prvé dva prvky (m=max(cisla[0],cisla[1];). Ďalej budeme vždy porovnávať aktuálne maximum (m) s nasledujúcim prvkom (ďalší krok bude m=max(m,cisla[2]);, atď). Ukážeme si ešte druhú možnosť hľadania maxima bez použitia prvej funkcie max (funkcia max2). Princíp je veľmi podobný. Na začiatku do premennej m priradíme prvý prvok poľa cisla. Následne prehľadávame celé pole. Každý prvok poľa testujeme, či je väčší ako aktuálne maximum. Ak áno, tak do premennej m priradíme aktuálne porovnávaný prvok poľa.
Program
 1 #include<stdio.h>
 2 #define MAX 100
 3 
 4 int max(int x, int y)
 5 {
 6      int m;
 7      if(x>y)
 8           m=x;
 9      else
10           m=y;
11      return m;
12 }
13 
14 int max1(int p[MAX], int n)
15 {
16      int m;
17      m=max(p[0],p[1]);
18      for(int i=2; i<n; i++)
19           m= max(m,p[i]);
20      return m;
21 }
22 
23 int max2(int p[MAX], int n)
24 {
25      int m = p[0];
26      for(int i=1; i<n; i++) //nemusime zacat od 0, pretoze 0-ty prvok je v premennej m
27           if(p[i] > m)
28                 m = p[i];
29      return m;
30 }
31 
32 void main()
33 {
34 
35     int n,cisla[MAX];
36     printf("Zadaj pocet nacitanych cisel\n");
37     scanf("%d",&n);
38     for(int i=0;i<n;i++)
39     scanf("%d",&cisla[i]);
40     printf("Maximum z nacitanych cisel: %d",max1(cisla,n));
41 
42 }

Maticová kalkulačka

Zadanie
Vytvorte program, ktorý bude pracovať s maticami. Program bude vedieť načítavať matice, sčítavať, odčítavať, násobiť a vypísať maticu na monitor. Každú jednu operáciu urobte ako funkciu. Výpis funkcií:
  • void NacitajMaticu(int &r, int &s, int M[MAX][MAX]);
  • void ScitajMatice(int r1, int s1, int M[MAX][MAX], int r2, int s2, int N[MAX][MAX], int O[MAX][MAX]));
  • void OdcitajMatice(int r1, int s1, int M[MAX][MAX], int r2, int s2, int N[MAX][MAX] , int O[MAX][MAX]));
  • void NasobMatice(int r1, int s1, int M[MAX][MAX], int r2, int s2, int N[MAX][MAX] , int O[MAX][MAX]));
  • void VypisMaticu(int r, int s, int M[MAX][MAX]);
Analýza problému
Práca s maticami bola vysvetlená v časti polia. Teraz sa zameriame na prácu funkcií. Všetky funkcie sú bez návratovej hodnoty (void), keďže funkcia nemôže vrátiť typ pole. Avšak, polia ako parametre funkcií sú predávané pomocou odkazu (referencie), takže všetky zmeny vykonané v týchto funkciách sa prejavia aj v hlavnej funkcii. Vo funkcii NacitajMaticu sa aj premenné r a s prenášajú pomocou odkazu, lebo vo funkcii sa tieto hodnoty budú načítavať a budeme ich potrebovať aj v ďalších funkciách. Matice sa dajú sčítavať (odčítavať) iba ak r1=r2 a zároveň s1=s2. Ak toto neplatí, nech sa vypíše chybová hláška a funkcia sa ukončí. Výsledná matica bude mať rozmery r1×s1. Násobenie matíc je definované pre 2 matice, pre rozmery ktorých platí: s1=r2. Ak toto neplatí, postupujte podobne ako pri sčítaní. Výsledná matica bude mať rozmery r1×s2. Pri operáciách s maticami vždy platí: O=M+N, O=M-N, O=M*N
  1 #include<stdio.h>
  2 #define MAX 100
  3 
  4 void NacitajMaticu(int &r, int &s, int M[MAX][MAX])
  5 {
  6 
  7     printf("Zadaj rozmery matice (r,s)\n");
  8     scanf("%d %d",&r,&s);
  9     int i,j;
 10     for(i=0; i<r; i++) // nacitavanie matice A
 11          for(j=0; j<s; j++)
 12          {  
 13              printf("\nZadaj prvok M[%d][%d] ",i,j);
 14              scanf("%d",&M[i][j]); // nacitavanie prvku Ai,j
 15          }
 16 
 17 }
 18 
 19 void ScitajMatice(int r1,int s1, int M[MAX][MAX],int r2,int s2,int N[MAX][MAX],int O[MAX][MAX])
 20 {
 21 
 22     if((r1!=r2) || (s1!=s2))
 23     {
 24         printf("\nMatice musia mat rovnake rozmery");
 25         return;
 26     }
 27     int i,j;
 28     for(i=0; i<r1; i++) // scitanie O=M+N
 29         for(j=0; j<s1; j++)
 30             O[i][j]=M[i][j]+N[i][j];
 31 
 32 }
 33 
 34 void OdcitajMatice(int r1,int s1, int M[MAX][MAX],int r2,int s2,int N[MAX][MAX],int O[MAX][MAX])
 35 {
 36 
 37     if((r1!=r2) || (s1!=s2))
 38     {
 39         printf("\nMatice musia mat rovnake rozmery");
 40         return;
 41     }
 42     int i,j;
 43     for(i=0; i<r1; i++) // odcitanie O=M-N
 44         for(j=0; j<s1; j++)
 45             O[i][j]=M[i][j]-N[i][j];
 46 
 47 }
 48 
 49 void NasobMatice(int r1,int s1, int M[MAX][MAX],int r2,int s2,int N[MAX][MAX],int O[MAX][MAX])
 50 {
 51 
 52     if(s1!=r2)
 53     {
 54         printf("\nPri nasobeni musí platit: s1==r2 ");
 55         return;
 56     }
 57     int i,j,k;
 58     for(i=0; i<r1; i++) // nasobenie O=M*N
 59         for(j=0; j<s2; j++)
 60         {
 61             O[i][j]=0;
 62             for(k=0; k<s1; k++)
 63                 O[i][j]+=M[i][k]*N[k][j];
 64         }
 65 
 66 }
 67 
 68 void VypisMaticu(int r, int s, int M[MAX][MAX])
 69 {
 70 
 71     printf("Vypis matice: \n");
 72     int i,j;
 73     for(i=0; i<r; i++) // vypis matice M
 74     {    for(j=0; j<s; j++) 
 75              printf("%6d",M[i][j]);
 76           printf("\n");
 77     }
 78     printf("\n");
 79 
 80 }
 81 
 82 void main()
 83 {
 84 
 85     int A[MAX][MAX], B[MAX][MAX], C[MAX][MAX];
 86     int rr1,ss1,rr2,ss2;
 87     NacitajMaticu(rr1,ss1,A);
 88     NacitajMaticu(rr2,ss2,B);
 89  
 90     ScitajMatice(rr1,ss1,A,rr2,ss2,B,C);
 91     printf("C=A+B\n");
 92     VypisMaticu(rr1,ss1,C);
 93 
 94     OdcitajMatice(rr1,ss1,A,rr2,ss2,B,C);
 95     printf("C=A-B\n");
 96     VypisMaticu(rr1,ss1,C);
 97   
 98     NasobMatice(rr1,ss1,A,rr2,ss2,B,C);
 99     printf("C=A*B\n");
100     VypisMaticu(rr1,ss2,C);
101     
102 }

Prevod celých čísel

Zadanie
Navrhnite a vytvorte program na prevod celých čísel z desiatkovej sústavy do ľubovoľnej inej (od dvojkovej po deviatkovú). Túto úlohu riešte pomocou funkcie s týmto funkčným prototypom:

long prevod(int N, int z);

kde N je číslo v desiatkovej sústave, ktoré budeme prevádzať do sústavy so základom z (2<=z<10). Funkcia vráti číslo N v sústave so základom z.

Analýza problému
Algoritmus prevodu desiatkového čísla sme si rozobrali v časti algoritmy/prevod čísel. Pre zopakovanie, uvedieme slovný popis algoritmu:
  • vstup: N – číslo v desiatkovej sústave, z – základ novej sústavy, i=0 (pomocná premenná)
  • m10=1, vysledok=0
  • podiel = N / Z
  • zvyšok = N % Z
  • vysledok = vysledok + zvysok * m10
  • m10=m10 * 10
  • N = podiel
  • ak je podiel > 1, choď na 3
  • výstup: vysledok
Príklad

N=34, z=4

I N Z podiel=N/z Zvysok po delení N/z vysledok
0 39 4 0 0 0
0 39 4 9 3 0+3*1=3
1 9 4 2 1 3+1*10=13
2 2 4 0 2 13+2*100=213
Výsledok prevodu
vysledok=213

Polynóm

Zadanie
Podľa úlohy "hodnota polynómu“ vytvorte funkciu h_polynom, ktorá vráti funkčnú hodnotu polynómu v bode x0. Funkčný prototyp funkcie je tento: float h_polynom(float koeficienty[MAX], int stupen, float x0); Daný polynóm je stupňa stupen a koeficienty pri mocninách x sú definované v poli koeficienty. Funkcia vráti funkčnú hodnotu polynómu v bode x0.
Analýza problému
Riešený polynóm má tvar f(x)=anxn+an-1xn-1+...+a1x1+a0x0. Pri zápise pomocou poľa koeficienty to bude vyzerať nasledovne: f(x)= koeficienty[n]xn+ koeficienty[n-1]xn-1+...+ koeficienty[1]x1+ koeficienty[0]x0. Čiže i-ty koeficient ai zodpovedá i-temu prvku poľa koeficienty. Počet koeficientov v poli koeficienty nám určuje premenná stupen (hovorí nám o stupni polynómu). Funkcia vypočíta funkčnú hodnotu polynómu v bode x0 (teda za x dosadíme x0). Túto hodnotu funkcia vráti.
 1 #include<stdio.h>
 2 #define MAX 50
 3 
 4 float h_polynom(float koeficienty[MAX], int stupen, float x0)
 5 {
 6 
 7     float f_hodnota=0; // funkcna hodnota polynomu v x0
 8     float x=1;
 9     for(int i=0 ; i<= stupen ; i++)   // vypocet hodnoty polynomu v bode x0
10     {
11         f_hodnota += koeficienty [i] * x;  // ai*x0^i
12         x*=x0;
13     }
14     return f_hodnota;
15 
16 }
17 
18 void main()
19 {  
20 
21     int n,i;
22     float polynom[100],x1;
23     printf("Zadaj stupen polynomu\n");
24     scanf("%d",&n);
25     for(i=0 ; i<=n ; i++)
26     {  
27         printf("\nZadaj prvok a[%d]",i);
28         scanf("%f",&polynom[i]);  // nacitavanie prvkov do pola
29     }
30     printf("Zadaj bod, v ktorom sa bude pocitat hodnota polynomu\n");
31     scanf("%f",&x1);  // bod x1
32     float fh= h_polynom(polynom,n,x1);
33     printf("Polynom ma v bode %f hodnotu %f\n",x1,fh);
34 
35 }


Párne čísla

Zadanie
Vytvorte funkciu, ktoré by zistila, koľko je párnych čísel v jednorozmernom poli. Funkcia bude mať nasledujúci funkčný prototyp: int pocet_parnych(int cisla[MAX], int n) funkcia vráti počet párnych čísel v poli cisla (v poli cisla je n čísel). Na určenie párnosti jedného čísla naprogramujte funkciu int je_parne(int x); ktorá vráti 1, ak je x párne, v opačnom prípade vráti 0.
Analýza problému
Párnosť, resp., nepárnosť celého čísla zistíme podľa toho, či je dané číslo delitelné bezo zvyšku číslom 2. Ak po delení nie je žiadny zvyšok, číslo je párne. Ak je zvyšok 1, číslo je nepárne. Najskôr naprogramujeme funkciu je_parne. Potom pokračujeme s funkciou pocet_parnych. Tu musíme každý prvok poľa testovať na párnosť. Ak je prvok poľa párny, tak zväčšíme počítadlo párnych čísel parne o 1.
 1 #include<stdio.h>
 2 #define MAX 50
 3 
 4 int je_parne(int x)
 5 {
 6     if(x%2)   // cislo je neparne
 7          return 0;
 8     else      // inak je cislo parne
 9          return 1;
10 }
11 
12 int pocet_parnych(int cisla[MAX], int n)
13 {
14     int parne=0;
15     for(int i=0; i<n; i++)
16          if(je_parne(cisla[i]))
17               parne++;
18     return parne;
19 }
20 
21 void main()
22 {  
23 
24     int n,i,data[MAX];
25     printf("Zadaj pocet cisel\n");
26     scanf("%d",&n);
27     for(i=0 ; i<n ; i++)
28     {  
29         printf("\nZadaj %d. prvok",i+1);
30         scanf("%d",&data[i]);  // nacitavanie prvkov do pola
31     }
32     int pp= pocet_parnych(data,n);
33     printf("počet parnych cisel: %d \n",pp);
34 
35 }

Kombinatorika

Zadanie
V kombinatorike pracujeme variáciami, kombináciami a permutáciami. Variácie k-tej triedy z n-prvkov variacie (k, n) sú definované ako: variacie (k,n)=n× (n-1) ×... × (n-k+1)
Špeciálnym prípadom variácie je faktoriál čísla n, ktorý je definovaný ako
n!=faktorial(n)=n× (n-1) ×...×2×1
Kombinácie kombinnacie(k,n) k-tej triedy z n-prvkov sú definované ako
kombinacie(k,n)=n!/( (n-k)!×k! )

Vytvorte postupne funkcie variacie, faktorial a kombinacie tak, že na naprogramovanie nasledujúcej funkcie využijete predchádzajúcu funkciu. Uvažujme n<40, k<=n.

Analýza problému

float variacie(int n,int k);

Návratovú hodnotu zvolíme float (aj keď funkcia bude vždy vracať celé číslo) kvôli väčšiemu číselnému rozsahu typu float v porovnaní s int. Výpočet hodnoty variácie je jednoduchý, postupne budeme robiť čiastočné násobenia. Označme si hodnotu n-k+1 ako: hranica=n-k+1. Potom výpočet variácie bude: n×(n-1)×(n-2)...hranica.

float faktorial(int n);

Tu využijeme už naprogramovanú funkciu variacie. Vieme že: faktorial(n)= variacie (n,n). Dôkaz: n!=n×(n-1)×(n-2)×...×2×1. Variacie(n,n)=[hranica=n-n+1=1]= n×(n-1)×(n-2)×...×2×1

int kombinacie(int k,int n);

Tu stači len využiť funkciu kombinácie.

Priklad
 1 #include<stdio.h>
 2 
 3 float variacie(int n,int k)
 4 {
 5      float var=1; // hodnota variacie(n,k)
 6      int hranica=n-k+1;
 7      for( ; n>=hranica ; n--)
 8           var*=n;
 9      return var;
10 }
11 
12 float faktorial(int n)
13 {
14      return variacie(n,n);
15 
16 }
17 
18 int kombinacie(int k,int n)
19 {
20      float komb;
21      komb= faktorial(n)/( faktorial(n-k)* faktorial(k));
22      return (int)komb;
23 }
24 
25 int main()
26 {
27     int n,k;
28     printf("Zadaj cisla n a k:\n");
29     scanf("%d %d",&n,&k);
30     printf("variacie(n,k)= %.0f \n", variacie(n,k));
31     printf("faktorial(n)= %.0f \n", faktorial(n));
32     printf("kombinacie(n,k)= %d \n", kombinacie (n,k));
33     return 1;
34 }