CVIČENIE 4/13 (S7) Programovanie v jazyku C - funkcie a makra About co je to funkcia a procedura, rekurzivne funkcie, co je to makro TODO: ŘETĚZCE řetězec je pole znaků zakončené 0 ( \0 má ASCI-kód 0, integerový literál má hodnotu 0) A h o j \0 char * s ukazatel na první prvek byte s hodnotou 0 (escape znak) funkce pro práci s řetězci jsou v knihovně <string.h> Kde sebrat místo na řetězec? - proměnná: char str[100] pole o velikosti 100 (v C jsou pole vždy indexována od 0 prvky pole jsou: str[0]... str[99]) - můžeme inicializovat char pa[] = ahoj pokud inicializujeme, velikost se dopočte -> velikost 5... nezapomenout na koncovou 0 char* pb = babi není přiřazení, ale inicializace deklarace pointeru na char v paměti se alokuje paměť pro babi a pointer se přiřadí do proměnné b
v paměti: A h o j \0 pa... pa je konstantní pointer na 1. prvek pole pb toto se děje při inicializaci b a b i \0 tato paměť se alokuje při kompilaci pb... pointer... obsahuje adresu do paměti *pb... kam to ukazuje... první znak pole - pa je konstantní pointer a nemůže se s ním nic dělat nelze pa++ - s pb se může ukazovat i na další části řetězce lze pb++ pb pbi+ - pointer není jen sám o sobě, ale pointer na nějaký typ tedy p++ ví, o kolik se má posunout (posune se o velikost typu, na který je pointer) - něco málo z pointerové aritmetiky char* p = ahoj ; *p = getchar();... načte znak a zapíše ho na 1. z h o j \0 místo putchar(*p);... vypíše na standardní výstup 1. znak p++; posune se na další znak Délka řetězce... strlen - syntaxe: int strlen (const char* s) - funkce vrací počet znaků, které předchází \0 - př. printf( %d\n,strlen( ahoj ));... 4 printf %d\n,strlen( ));... 0 p
Priklad: naprogramovat funkci strlen Verze 1 int strlen (char* s) int i=0; while (*s!= \0 ) i++; s++; return i; Verze 2 int strlen (char* s) char *p=s; while (*p++) ; return p-s-1; Verze 3 zhuštěný zápis for(i=0;*s!= \0 ;i++) s++; Verze 4 for(i=0;*s!= \0 ;i++,s++); přibyl zde operátor čárky - oddělovač dvou podvýrazů - hodnotou je výraz nejpravějšího podvýrazu Verze 5 int i=0; for(;*s++!= \0 ;i++); uzávorkování ( (*(s++))!= ( \0 ) ) Verze 6 jiný zápis int i=0; while (*s++!= \0 ) i++; Verze 7 zhuštěnější výraz int i=0; while (*s++!=0) i++; Verze 8 ještě víc zhuštěné int i=0; while (*s++) i++; toto je z definice vždy 0
Podmínky a jejich vyhodnocování - v podmínce musí být vždy integer výraz - podmínka je splněná, pokud je výraz nenulový - testování while(x!=0) je ekvivalentní while(x)... tedy podmínka je splněna, pokud je x nenulové Kopírování řetězce... strcpy - syntaxe: char* strcpy (char* dst, const char* scr) - kopíruje řetězec scr do dst (včetně ukončovacího znaku) - funkce vrací pointer na dst char buf[100]; char* babi = babi ; : : strcpy (buf, ahoj ); strcpy (buf,babi); scr dsc! Je na programátorovi, aby cílové místo bylo dostatečně velké! char buf [3]; strcpy (buf, ahoj ); A h o j \0 Vykropí paměť Přetečení!!! překladač ani run-time na to nemůže přijít, protože se předává jen pointer Přiřazení pointerů char *x = ahoj ; char *y; y=x; x y a h o j \0 *y = *x; toto má hodnotu a
x y *x a h o j \0 a Vykropí se cizí paměť!! Priklad: naprogramovat funkci strcpy Verze 1 chybná char* strcpy (char* dst, char* scr) char* k; for (k=dst; *scr++; *k++ = *scr); return dst; zkopíruje od 2. prvku! Verze 2 chybná char* strcpy (char* dst, char* scr) char* k; for (k=dst; *scr; *k++ = *scr++); return dst; nezkopíruje koncovou 0! Verze 3 -> správné řešení char* strcpy (char* dst, char* scr) char* k; for (k=dst; *scr; *k++ = *scr++); *k = *scr; return dst; Verze 4 zhuštěnější char* strcpy (char* dst, char* scr) char* k=dst; while (*dst++ = *scr++); return k;
nejprve se zvýší pointer dst i src, pak se do *dst zkopíruje *src a pak se vyhodnotí přiřazení zda je nulové či ne (koncová nula) přiřazení je operátor a hodnotou je to, co se přiřazuje! Basic knowledge jazyk C obsahuje jednu alebo viac definicii funkcii, pricom jedna z nich sa musi vzdy menovat main(). spracovanie programu zacina jej volanim a konci jej opustenim. vo funkcii nemoze byt vnorena dalsia funkcia vsetky funkcie v C vracaju hodnotu a teda sa spravaju ako funkcie. je vsak mozne ich pouzit aj ako procedury definiciu funkcie urcuje hlavicka funkcie spolu s jej telom, zatial co deklaracia funkcie je urcena len hlavickou funkcie (meno funkcie, typ navratovej hodnoty a pripadne typ a pocet parametrov) // starsi sposob int max(a, b) int a, b; // novy sposob int max( int a, int b ) typ funkcie (navratova hodnota) moze byt vynechany. vtedy sa bude implicitne typu int max( int a, int b ) telo funkcie je je uzavrete do zlozenych zatvoriek '' a '' na odovzdanie vysledku funkcie sa pouziva prikaz return, ktory ukoncuje funkciu. int max( int a, int b ) if( a > b ) return( a ); else return( b ); existuju vsak funkcie, ktore nemaju ziadny parameter alebo nevracaju ziadnu navratovu hodnotu (procedury). tu sa vyuziva typ void. vtedy nie je nutne uvadzat ani navratovu funkciu return.
void pozdrav( void ) printf( "hello world\n" ); odovzdavanie parametrov funkcii sa vykonava hodnotou, ale hodnotou moze byt aj adresa rekurzivne funkcie su take funkcie, ktore vo svojom vnutri (tele funkcie) volaju same seba int cislo( int a ) printf( "%d\n", a ); if( a > 0 ) cislo( --a ); return(0); makra mozu byt: bez parametrov s parametrami makra bez parametrov su skor zname pod menom symbolicke konstanty. pouzivaju sa pomerne casto, pretoze nahradzuju v programe mnoho konstant. vacsinou su definovane na zaciatku programu (modulu). pisu sa velkymi pismenami. #define MAX 1000 #define PI 3.14 #define DVE_PI (2*PI) #define MOD % #define MENO_SUBORU "textak.txt" nejedna sa o konstantu - ta je definovana pomocou klucoveho slova const. makra su nahradzane v dobe prekladu svojim originalom.o makra s parametrami sa niekedy nazyvaju aj vkladane funkcie (in-line functions). syntax makra je nasledujuca: #define meno_makra(arg1, arg2,..., argn) hodnota makra na rozdiel od makier bez parametrov sa makra s parametrami pisu malymi pismenkami (ako u funkcii). priklady pouzitia: // test velkeho pismena #define je_velke(c) ((c) >= 'A' && (c) <= 'Z') existuju aj preddefinovane makra (obsah kniznie ctype.h)
Examples Ex. 1: vytvorte funkciu, ktora spocita dve cisla #include <stdio.h> int sucet( int a, int b ) // samotna funkcia int main( void ) int x = 10, y = 20; printf( "sucet cisiel x=%d a y=%d je: %d\n", x, y, sucet(x,y) ); getchar(); return( 0 ); Ex. 2: napiste funkciu trojuholnik( char c, int i), ktora zobrazi na obrazovku trojuholnik zlozeny z n riadkov vyplnenych znakom c, napriklad: * *** ***** prvy znak na poslednom riadku musi byt v prvom stlpci. Ex. 3: vytvorte program na vypocet faktorialu. vyuzite rekurzivnu funkciu. Ex. 4: vytvorte makro na vypocet absolutnej hodnoty cisla. Ex. 5: Kreslenie Kresleni.h void ctverec ( int n ); void trojuhelnik ( int n ); void domecek ( int n );
Kresleni.c #include <stdio.h> #include "D:\temp\kalibera\kresleni.h" void ctverec ( int n ) int i, j; if ( 1 == n ) printf ( "x\n" ); else for ( i = 0; i < n; i++ ) for ( i = 0; i < ( n - 2 ); i++ ) for ( j = 1; j < ( n - 1 ); j++ ) printf ( " " ); ; for ( i = 0; i < n; i++ )
void trojuhelnik ( int n ) int i, j; if ( 0 == ( n % 2) ) printf ( "spatny rozmer \n"); else for ( j = 0; j <= ( n / 2 ); j++ ) for ( i = 1; i <= n; i++ ) if ( i == ( ( n / 2 ) + 1 - j ) ) else if ( i == ( ( n / 2 ) + 1 + j ) ) else printf ( " " ); for ( i = 0; i < n; i++ ) void domecek ( int n ) int i, j; if ( 0 == ( n % 2) ) printf ( "spatne velky domecek \n"); else trojuhelnik ( n ); ; for ( j = 1; j <= ( n - 2 ); j++ ) for ( i = 0; i < n; i++ ) if ( ( 0 == i ) ( ( n - 1) == i ) ( i == j ) ( i == ( n - j - 1 ) ) ) else printf ( " " ); for ( i = 0; i < n; i++ )