64
Procedurálne programovanie: 5. prednáška Gabriela Kosková

Procedur álne programovanie: 5 . prednáška

  • Upload
    ayanna

  • View
    61

  • Download
    4

Embed Size (px)

DESCRIPTION

Procedur álne programovanie: 5 . prednáška. Gabriela Kosková. Obsah. opakovanie (2 p ríklady) ukazovatele príklady (3). #include #define PI 3.14 #define obvod_m(r) (2 * PI * (r)) #define obsah_m(r) (PI * (r) * (r)) double obvod_f(double r) { return 2 * PI * r; } - PowerPoint PPT Presentation

Citation preview

Page 1: Procedur álne programovanie: 5 . prednáška

Procedurálne programovanie:5. prednáška

Gabriela Kosková

Page 2: Procedur álne programovanie: 5 . prednáška

Obsah

1. opakovanie (2 príklady)

2. ukazovatele

3. príklady (3)

Page 3: Procedur álne programovanie: 5 . prednáška

Príklad 1#include<stdio.h>#define PI 3.14#define obvod_m(r) (2 * PI * (r))#define obsah_m(r) (PI * (r) * (r))

double obvod_f(double r) { return 2 * PI * r;}

double obsah_f(double r) { return PI * r * r;}

int main() { double polomer;

printf("Zadajte polomer kruhu: "); scanf("%lf", &polomer); printf("\nMakro: obvod: %.2f, obsah: %.2f\n", obvod_m(polomer), obsah_m(polomer)); printf("Funkcie: obvod: %.2f, obsah: %.2f\n", obvod_f(polomer), obsah_f(polomer)); return 0;}

Program vypočíta obvod a obsah kruhu pomocou makier a funkcií

Page 4: Procedur álne programovanie: 5 . prednáška

Príklad 2

Program vypíše obsah súboru naopak.

Page 5: Procedur álne programovanie: 5 . prednáška

#include<stdio.h>

int main() { int c; FILE *f;

if ((f = fopen("subor.txt", "r")) == NULL) { printf("Nepodarilo sa otvorit subor.\n"); return 1; }

vypis(f);

if (fclose(f) == EOF) { printf("Nepodarilo sa zatvorit subor.\n"); return 1; }

return 0;}

void vypis(FILE *f) { int c;

if ((c=getc(f)) != EOF) { vypis(f); putchar(c); }}

Page 6: Procedur álne programovanie: 5 . prednáška

Použitá rekurzia void vypis(FILE *f) { int c;

if ((c=getc(f)) != EOF) { vypis(f); putchar(c); }}

johaobsah súboru:

j

zásobník

o

h

a

výstup programu:

volanie vypis c: 'j'

volanie vypis c: 'o'

volanie vypis c: 'h'

volanie vypis c: 'a'

volanie vypis c: EOF

výpis c: 'a'

výpis c: 'h'

výpis c: 'o'

výpis c: 'j'

ahoj

Page 7: Procedur álne programovanie: 5 . prednáška

Procedurálne programovanie: Základy práce s ukazovateľmi

Page 8: Procedur álne programovanie: 5 . prednáška

Čo sú to ukazovatele

= pointery, smerníky

• ukazovateľ – je premenná

– jeho hodnota je adresa v pamäti

• analógia: v texte článku nie je informácia priamo uvedená, ale je tam odkaz na nejaký iný článok, kde sa informácia nachádza

Page 9: Procedur álne programovanie: 5 . prednáška

Príklad ukazovateľa

25

• ukazovateľ p:– zapísaný na adrese 73– jeho hodnota je 30 a vyjadruje adresu, kde

je uložená skutočná hodnota– na adrese 30 v pamäti je hodnota 25, ktorá

sa použije napr. pri výpočtoch

• p: ukazovateľ• *p: hodnota, kam ukazuje

30

73 30

pamäť

*p:

p:

Page 10: Procedur álne programovanie: 5 . prednáška

Ako poznáme ukazovateľ

• ukazovateľ je definovaný pomocou *• int i - „klasická“ celočíselná premenná• int *p_i - ukazovateľ na celočíselnú

premennú

• definícia ukazovateľa:

int i;int *p_i;

int i, *p_i;je ekvivalentné

Page 11: Procedur álne programovanie: 5 . prednáška

Čo urobí *p_i = i;

2530

73 30

pamäť• ukazovateľ p_i

– p_i == 30 – *p_i == 25

• obsah pamäte, na ktorú ukazuje p_i sa prepíše hodnotou premennej i

• p_i ukazuje na to isté miesto v pamäti

28 7i:

*p_i:

p_i:

7

7

int i, p_i;...*p_i = i;

treba inicializovať p_i,napr. alokovať pamäť pre p_i

Page 12: Procedur álne programovanie: 5 . prednáška

Ako získame adresu premennej

• pomocou referenčného operátora &• int i - „klasická“ celočíselná premenná• &i – adresa premennej

• definícia ukazovateľa:

int i, *p_i;p_i = &i;

int i, *p_i = &i;je ekvivalentné

definícia ukazovateľa a súčasne inicializácia

Page 13: Procedur álne programovanie: 5 . prednáška

Čo urobí p_i = &i;

2530

73 30

pamäť• ukazovateľ p_i

– p_i == 30 – *p_i == 25

28 7i:

*p_i:

p_i:

• hodnota p_i (adresa, kam p_i ukazuje) sa prepíše adresou premennej i

• hodnota *p_i je tá istá ako hodnota i

int i, *p_i;

p_i = &i;

Page 14: Procedur álne programovanie: 5 . prednáška

Čo urobí p_i = &i;

2530

73 30

pamäť• ukazovateľ p_i

– p_i == 30 – *p_i == 25

int i, *p_i;

p_i = &i;28 7i:

*p_i:

p_i:

7

28

28

• hodnota p_i (adresa, kam p_i ukazuje) sa prepíše adresou premennej i

• hodnota *p_i je tá istá ako hodnota i

Page 15: Procedur álne programovanie: 5 . prednáška

Príklady

p_i = &i; - správne

p_i = &(i + 3); - chyba: (i + 3) nie je premenná

p_i = &15; - chyba: konštanta nemá adresu

p_i = 15; - chyba: priraďovanie absolútnej adresy

i = p_i; - chyba: priraďovanie adresy

i = & p_i; - chyba: priraďovanie adresy*p_i = 4; - správne, ak p_i bol inicializovaný

Page 16: Procedur álne programovanie: 5 . prednáška

Výpis adresy (pri ladení)

int i, *p_i;

p_i = &i;printf(„Adresa i: %p, hodnota p_i: %p\n”, &i, p_i);

• špecifikácia formátu (v printf()): %p

Page 17: Procedur álne programovanie: 5 . prednáška

Keď ukazovateľ neukazuje nikam

• Nulový ukazovateľ: NULL• NULL - symbolická konštanta definovaná v stdio.h:– #define NULL 0– #define NULL ((void *) 0)

• Je možné priradiť ho ukazovateľom na ľubovoľný typ

if (p_i == NULL) ...

Page 18: Procedur álne programovanie: 5 . prednáška

Konverzia ukazovateľov

• Vyhnúť sa jej!• Ak sa nedá vyhnúť – explicitne pretypovávať

int *p_i;char *p_c;

p_c = p_i;p_c = (char *)p_i;

nevhodné

vhodnejšie

Page 19: Procedur álne programovanie: 5 . prednáška

Funkcie: volanie odkazom

• V C nie je volanie odkazom, funkcie sa volajú len hodnotou

• Vo funkcii vzniká kópia argumentu funkcie (lokálna premenná), ktorá zaniká s ukončením funkcie

• Preto sa funkcia nevolá s premennou, ktorú chceme meniť, ale s jej adresou

Page 20: Procedur álne programovanie: 5 . prednáška

Parametre funkcií - volanie hodnotou: int A(int i)

3

zásobník

spustenie programu, volanie main()

volanie A() spustenie A(3)

koniec programu, main()

návrat do main() koniec A()4

3

dátová oblasť

vytvorí sa kópia

Page 21: Procedur álne programovanie: 5 . prednáška

Parametre funkcií - volanie odkazom : int A(int *i)

15

zásobník

spustenie programu, volanie main()

volanie A() spustenie A(15)

koniec programu, main()

návrat do main() koniec A()

dátová oblasť

adresa: 15

adresapremennej

34

Page 22: Procedur álne programovanie: 5 . prednáška

• volanie funkcie: vymen(&i, &j)

Príklad funkcie: výmena premenných

void vymen(int *p_x, int *p_y){ int pom;

pom = *p_x; *p_x = *p_y; *p_y = pom;}

i: 5 j: 7

p_x p_y

pom:

7 5

5

Page 23: Procedur álne programovanie: 5 . prednáška

Príklad funkcie: výmena premenných

• volanie funkcie: vymen(&i, &j)

vymen(i, j);

vymen(*i, *j);

chyba: vymieňa obsah adries, daných obsahom i, j: vymieňa hodnoty na adresách 5 a 7

chyba: vymieňa adresy adries z obsahu i, j: z adries 5 a 7 sa zoberú hodnoty a tie sa použijú ako adresy

Page 24: Procedur álne programovanie: 5 . prednáška

Ukazovateľ na typ void

• void: prázdny typ (napr. funkcia, ktorá nevracia typ)• void *p_void;

– neukazuje na žiaden kokrétny typ

– generický pointer: ukazovateľ na ľubovoľný typ (nezabudnúť na pretypovanie!)

Page 25: Procedur álne programovanie: 5 . prednáška

• pri priraďovaní je potrebné uviesť typ

int i;float f;void *p_void = &i; *(int *) p_void = 2;p_void = &f;*(float *) p_void = 3.5;

Príklad ukazovateľa na typ void

nastavenie i na 2

p_void ukazuje na i

p_void ukazuje na f

nastavenie f na 3.5

Page 26: Procedur álne programovanie: 5 . prednáška

void vymen(void **p_x, void **p_y){ void *p;

p = *p_x; *p_x = *p_y; *p_y = p;}

pre int *

int i = 1, *p_i = &i, j = 2, *p_j = &j;

vymen((void **) &p_i, (void **) &p_j);

Ukazovateľ na typ void: parameter funkcie

char c = 'a', *p_c = &c, d = 'b', *p_d = &d;

vymen((void **) &p_c, (void **) &p_d);

pre char *

funkcia na výmenu dvoch ukazovateľov

Page 27: Procedur álne programovanie: 5 . prednáška

Ukazovatele na funkcie

• Funkcia môže vrátiť ukazovateľ na typ:– FILE *fopen(...) vracia smerník na typ FILE

• Definovanie premennej ako ukazovateľ na funkciu: napr. double (*p_fd)();

double (*p_fd); to isté ako double *p_fd;double *p_fd();

funkcia vracajúca ukazovateľdouble (*p_fd)();

ukazovateľ na funkciu

double scitaj(double x, double y)p_fd = scitaj;

p_fd má adresu funkcie scitaj()

Page 28: Procedur álne programovanie: 5 . prednáška

double pol1(double x){ return (x * x + 3);}

Príklad ukazovateľa na funkciu

double pol2(double x){ return (x + 8);}

funkcia na výpočet hodnôt polynómov (napr. x2 + 3, x + 8) pre zadanú hornú,

dolnú hranicu a krok - najprv pomocné funkcie pre polynómy

Page 29: Procedur álne programovanie: 5 . prednáška

vypis(-1.0, 1.0, 0.1, pol1);vypis(-2.0, 2.0, 0.05, pol2);

volanie vo funkcii main():

void vypis(double d, double h, double k, double (*p_f)()) { double x; for(x=d; x<=h; x+=k) printf("%lf, %lf \n", x, (*p_f)(x));}

Príklad ukazovateľa na funkciu

funkcia vypis() na vypísanie tabuľky

Page 30: Procedur álne programovanie: 5 . prednáška

Príklady definícií

int i; - i je typu int

float *y; - y je ukazovateľ na typ float

double *z(); - z je funkcia vracajúca ukazovateľ na double

int (*v)(); - ukazovateľ na funkciu vracajúcu int

int *(*v)(); - ukazovateľ na funkciu vracajúcu ukazovateľ na int

Page 31: Procedur álne programovanie: 5 . prednáška

Ako čítať zložitejšie definície

1. Nájdeme identifikátor, od neho čítame doprava

2. pokým nenarazíme na samotnú pravú zátvorku ")". Vraciame sa k zodpovedajúcej ľavej zátvorke. Potom pokračujeme doprava (preskakujeme prečítané)

3. Ak narazíme na ";" , vraciame sa na najľavejšie spracované miesto v čítame doľava

Page 32: Procedur álne programovanie: 5 . prednáška

int *(*v)();*int *

Príklad: čítanie definície int *(*v)();

- v je pointer na funkciu vracajúcu

pointer na int

)

3. Doprava, preskakujeme prečítané, po ), k nej (

v

1. Nájdeme identifikátor: v, čítame doprava

v)

2. Nájdeme ), k nej zodpovedajúcu (, od nej čítame doprava: *

(*v)

4. Doprava, preskakujeme prečítané, po ;, doľava

()

Page 33: Procedur álne programovanie: 5 . prednáška

Definícia s využitím typedef

• Operátor typedef – vytvára nový typ

– najmä na definovanie zložitejších typov

typedef float *P_FLOAT;

P_FLOAT je ukazovateľ na typ float

Page 34: Procedur álne programovanie: 5 . prednáška

Príklady použitia typedef

je ekvivalentné

typedef int *P_INT;typedef P_INT *P_P_INT;

P_INT p_i;P_P_INT p_p_i;

typedef double (*P_FD)();

int *p_i, **p_p_i; p_i – ukazvateľ na intp_p_i – ukazvateľ na ukazovateľ na int

ukazovateľ na funkciu vracajúcu double

Page 35: Procedur álne programovanie: 5 . prednáška

Ukazovateľová aritmetika

• S ukazovateľmi sa dajú robiť niektoré aritmetické operácie:– Súčet ukazovateľa a celého čísla

– Rozdiel ukazovateľa a celého čísla

– Porovnávanie ukazovateľov rovnakého typu

– Rozdiel dvoch ukazovateľov rovnakého typu

• Majú zmysel len v rámci bloku dynamicky vytvorenej pamäte (POLIA)

• Ostatné operácie nedávajú zmysel

Page 36: Procedur álne programovanie: 5 . prednáška

Operátor sizeof

• Na vysvetlenie aritmetických operácií s ukazovateľmi potrebujeme operátor sizeof(): – zistí veľkosť dátového typu v Bytoch

– vyhodnotí sa v čase prekladu (nezdržuje beh)

int i, *p_i;i = sizeof(p_i);

int i, *p_i;i = sizeof(*p_i);

počet Bytov potrebných na uloženie ukazovateľa na int – nevyužíva sa

počet Bytov potrebných na uloženie typu int – využíva sa často

Page 37: Procedur álne programovanie: 5 . prednáška

(n=3)

Súčet ukazovateľa a celého čísla

int n, *p1, *p2;...

p2 = p1 + n;

p2 = (int *) p1 + sizeof(*p1)*n;

p2:

p2 = 30 + 2 * 3 = 36

130p1:

2

3

436

32

34

sizeof(*p1)==2

Page 38: Procedur álne programovanie: 5 . prednáška

Súčet ukazovateľa a celého čísla - príklady

char *p_c = 10;

int *p_i = 20;

float *p_f = 30;

p_c + 1 ==

p_i + 1 ==

p_f + 1 ==

11

2234

Potom platí:

Vieme:

sizeof(char) == 1

sizeof(int) == 2

sizeof(float) == 4

Page 39: Procedur álne programovanie: 5 . prednáška

Rozdiel ukazovateľa a celého čísla

int n, *p1, *p2;...

p1 = p2 - n;

p1 = (int *) p2 - sizeof(*p2)*n;

p2 = 36 - 2 * 3 = 30

p1:

p2:

130

2

3

436

32

34

(n=3)

sizeof(*p2)==2

Page 40: Procedur álne programovanie: 5 . prednáška

Porovnávanie ukazovateľov

• operátory: < <= > >= == != • porovnávanie má zmysel len keď ukazovatele:

– sú rovnakého typu

– ukazujú na ten istý úsek pamäte

• výsledok porovnania:– ak je podmienka splnená: 1

– inak: 0

Page 41: Procedur álne programovanie: 5 . prednáška

Porovnávanie ukazovateľov: príklad - výpis reťazca

...char *p1, *p2 , str[N];

strcpy(str, "ahoj");p1 = str;p2 = p1;while(p2 < p1+ N && *p2 != '\0') printf("%c", *p2++);

str: pole s N znakmi,

p1, p2: ukazovatele

vyisuje znaky pokiaľ: • nepresiahne dĺžku pridelenej pamäte premennej str a• pokým nedosiahne koniec zapísaného slova

Page 42: Procedur álne programovanie: 5 . prednáška

Porovnávanie ukazovateľov s konštantou NULL

• bez explicitného pretypovávania • p = NULL:

– neukazuje na žiadne zmysluplné miesto v pamäti

int n, *p;...if (n >= 0) p = alokuj(n);else p = NULL; ...if (p != NULL) ...

Page 43: Procedur álne programovanie: 5 . prednáška

Rozdiel dvoch ukazovateľov rovnakého typu

int n, *p1, *p2;...n = p1 - p2;

n = ((int *) p1 - (int *) p2) / sizeof(*p1);

char *p1, *p2 , str[N];...for (p2=p1; p2<N && *p2 != '?'; p2++) ;printf("%d", (p2 < p1+N) ? (p2-p1+1) :-1);

príklad:ak je v bloku pamäte '?', vypíše pozíciu, inak -1

Page 44: Procedur álne programovanie: 5 . prednáška

Ukazovateľová aritmetika

• aritmetické operácie:– Súčet ukazovateľa a celého čísla – Rozdiel ukazovateľa a celého čísla– Porovnávanie ukazovateľov rovnakého

typu– Rozdiel dvoch ukazovateľov rovnakého

typu

• majú zmysel len vtedy, keď: – sú ukazovatele na rovnaký typ– ukazujú na ten istý úsek pamäte (OS

nezaručí, že neskôr alokovaný blok bude na vyššej adrese)

p1: 10 1

2

3

7p2: 50

Page 45: Procedur álne programovanie: 5 . prednáška

p1: 20 1

2

3

7p2: 15

Ukazovateľová aritmetika

• aritmetické operácie:– Súčet ukazovateľa a celého čísla – Rozdiel ukazovateľa a celého čísla– Porovnávanie ukazovateľov rovnakého

typu– Rozdiel dvoch ukazovateľov rovnakého

typu

• majú zmysel len vtedy, keď: – sú ukazovatele na rovnaký typ– ukazujú na ten istý úsek pamäte (OS

nezaručí, že neskôr alokovaný blok bude na vyššej adrese)

Page 46: Procedur álne programovanie: 5 . prednáška

Dynamické prideľovanie a uvoľňovanie pamäte

• prideľovanie pamäte za chodu programu– v zásobníku (stack) - riadi operačný systém

– v hromade (heap) - riadi programátor

• pomocou run-time funkcií• životnosť dynamických dát:

– od alokovania po uvoľnenie pamäte

budeme sa zaoberať týmto prideľovaním

Page 47: Procedur álne programovanie: 5 . prednáška

Marienka, vy ste moje najlepšie pamäťové médium!

Page 48: Procedur álne programovanie: 5 . prednáška

Prideľovanie pamäte

• pomocou funkcie definovanej v stdlib.h (niekedy v alloc.h):

void *malloc(unsigned int)

počet Bytov

Adresa prvého prideleného prvku - je vhodné pretypovať. Ak nie je v pamäti dosť miesta, vráti NULL.

Page 49: Procedur álne programovanie: 5 . prednáška

Testovanie pridelenia pamäte

• kontrola, či malloc() pridelil pamäť:

int * p_i;

if((p_i = (int *) malloc(1000)) == NULL) { printf("Nepodarilo sa pridelit pamat\n"); exit;}

Page 50: Procedur álne programovanie: 5 . prednáška

Uvoľňovanie pamäte

• nepotrebnú pamäť je vhodné ihneď vrátiť operačnému systému

• pomocou funkcie: void free(void *)

char *p_c;

p_c = (char *) malloc(1000 * sizeof(char));...free(p_c);p_c = NULL;

príklad:

Page 51: Procedur álne programovanie: 5 . prednáška

char *p_c;*p_c = 'a';p_c = malloc(1);if ((p_c = (char *) malloc(1)) == NULL) ... /* chybová správa a ukončenie */

Príklad prideľovania pamäte: pre jeden char

...free(p_c);

p_c nemá pridelenú pamäť, p_c môže ukazovať kamkoľvek do pamäte - program spadne

správne, ale neošetrujeme pamäť

Page 52: Procedur álne programovanie: 5 . prednáška

int *p_i;

if ((p_i = (int *) malloc(1)) == NULL) { printf("Nie je dostatok pamate\n"); exit(1);}

Príklad prideľovania pamäte: pre jeden int

if ((p_i = (int *) malloc(1 * sizeof(int))) == NULL) { printf("Nie je dostatok pamate\n"); exit(1);}

free(p_i);

sizeof(p_i) == 2, preto nebude dostatok pamäte pre int.

Page 53: Procedur álne programovanie: 5 . prednáška

Funkcia calloc()

• rovnkako ako malloc(), len automaticky inicializuje Byty na 0:

void *calloc(unsigned int)

Page 54: Procedur álne programovanie: 5 . prednáška

Príklad: načítanie 5 čísel a vypočítanie ich súčinu

• 3 pomocné funkcie + funkcia main():– alokovanie pamäte n čísel

– načítanie n čísel z klávesnice

– vypočítanie súčinu n čísel

Page 55: Procedur álne programovanie: 5 . prednáška

Príklad: funkcia na alokovanie pamäte n čísel

int *alokuj(int n){ return ((int *) malloc(n * sizeof(int)));}

Page 56: Procedur álne programovanie: 5 . prednáška

Príklad: funkcia na načítanie n čísel z klávesnice

void nacitaj(int *p_i, int n){ int i;

for (i = 0; i < n; i++) { printf("Zadajte %d-te cislo: ", i+1); /* doplnte nacitanie i-teho cisla */}

scanf("%d", p_i + i);

Page 57: Procedur álne programovanie: 5 . prednáška

Príklad: funkcia na vypočítanie súčinu n čísel

void sucin(int *p, int n, int sucin){ int i;

sucin = 1; for (i = 0; i < n; i++) sucin *= *(p + i);}

čo je tu chybné? pozrite si kratšie napísanú funkciu v (Herout)

*

*

*

Page 58: Procedur álne programovanie: 5 . prednáška

Príklad: funkcia main

int main(){ int *cisla, suc; cisla = alokuj(N); nacitaj(cisla, N); sucin(cisla, suc); printf("Sucin je: %d\n", suc); return 0;}

&

na začiatok programu nezabudnúť: #include <stdio.h>

#include <stdlib.h>

#define N 5

doplňte, aby to bolo správne

Page 59: Procedur álne programovanie: 5 . prednáška

Procedurálne programovanie:Príklady

Page 60: Procedur álne programovanie: 5 . prednáška

Príklad 1

program vypíše načítané číslo pričom použije ukazovateľ na int a na void ako

ukazovatele na celé číslo

#include <stdio.h>

int main() { int i, *p_int = &i; void *p_void = &i;

printf("Zadajte cele cislo: "); scanf("%d", &i);

printf("i: %d, p_int: %d, p_void: %d\n", i, *p_int, (*(int *)p_void)); return 0;}

Page 61: Procedur álne programovanie: 5 . prednáška

Príklad 2

Funkcia vypočíta obvod a obsah kruhu vo funkcii kruh(). Volanie odkazom.

Page 62: Procedur álne programovanie: 5 . prednáška

#include <stdio.h>

#define PI 3.14#define na_druhu(i) ((i) * (i))

void kruh(int r, float *o, float *s){ *o = 2 * PI * r; *s = PI * na_druhu(r);}

int main() {

int polomer; float obvod, obsah;

printf("Zadaj polomer kruhu: "); scanf("%d", &polomer);

kruh(polomer, &obvod, &obsah); printf("obvod: %.2f, obsah: %.2f\n", obvod, obsah); return 0;}

Page 63: Procedur álne programovanie: 5 . prednáška

Príklad 3

Program bude načítavať písmená. Po stlačení 'A' vypíše Ahoj, po stlačení 'C' vypíše Cau, po stlačení 'K' skončí. Použijeme ukazovateľ na

funkcie.

Page 64: Procedur álne programovanie: 5 . prednáška

#include <stdio.h>#include <stdlib.h>

void ahoj() {printf("Ahoj\n");

}

void cau() {printf("Cau\n");

}

int main() { int c; void (* p_fnc)(); /* definicia ukazovatela na funkciu */

printf("Ahoj / Cau / Koniec\n"); while((c = toupper(getchar())) != 'K') { if (c == 'A') p_fnc = ahoj; else if (c == 'C') p_fnc = cau;

else continue;

(*p_fnc)(); } return 0;}