Př. další použití pointerů char *p_ch; int *p_i; p_ch = (char *) p_i; // konverze int * na char * 8 int i = 5; int *p_i; p_i = &i; POZOR!!!! scanf("%d", p_i); printf("%d", *p_i); Obecný pointer na cokoliv: void *p_obec; - lze jej konvertovat na libolný typ pointeru - tento typ pointeru vrací funce malloc void *p_v; // univerzální pointer - jde přetypovat na pointer na cokoliv - přetypuji ho: double *p_d; p_d = (double *) p_v; - málokdy použijeme v této podobě, ale někdy spíše jako výsledek funkce: void *funkce() vrací obecný pointer, mohu přetypovat na cokoliv: double *p_d; p_d = (double *) funkce();
Operátor typedef - deklarace vlastního datového typu - je zvykem pojmenovávat nové typy velkými písmeny typedef unsigned char BYTE; /* deklaruji si nový typ BYTE */ BYTE a, b, c; // prom. a,b,c jsou typu BYTE - lze i toto (může být nepřehledné): typedef double *P_DOUBLE; P_DOUBLE p_d1, p_d2, p_d3; p_d1 až p_d3 jsou vnitřně typu double * Ovšem můžete potom omylem vytvořit: P_DOUBLE *p_d; - p_d je ale vnitřně double ** tj. double **p_d; neboli pointer na pointer na double double ** double * double: 893.67889 Pointerová aritmetika sizeof(dat_typ) - vrací kolik byte zabírá dat. typ, resp. proměnná Oba dva následující výrazy (kde deklarováno int i) vrátí velikost int:
sizeof(int); int i; sizeof(i); - přičtu-li k pointeru 1 (p_i + 1), zvětší se hodnota adresy o počet bytů, kolik má typ na který pointer ukazuje (např. u int o 4byte) - nutné u polí int *p_i; p_i bude adresa 10 - nějakým způsobem p_i = p_i + 1; p_i bude ukazovat na adresu 14 (int má 4 byte) a to vše automaticky nebo double *p_d; p_d bude adresa 10 // nějakým způsobem p_d = p_d + 1; p_d bude uk. na adresu 18 (double má 8 byte) a to vše opět automaticky atp. pro libovolný datový i uživatelem definovaný pomocí typedef Př.: #include <stdio.h> #include <stdlib.h> /* program přečte int a vypíše jeho jednotlive byty */ int main() { int *p_cislo; unsigned char *p_byte; int i;
p_cislo = (int *) malloc(sizeof(int)); if(p_cislo == NULL) { printf("\npamet dosla, nenadelas nic...\n"); return -1; printf("zadejte cele cislo, vypisu jeho byty: "); scanf("%d", p_cislo); p_byte = (unsigned char *) p_cislo; printf("\n"); for (i = (sizeof(int)-1); i >= 0 ; i--) { printf("%d ", *(p_byte + i)); free((void *) p_cislo); Dynamické přidělování paměti p_prom int *p_prom; p_prom = NULL; // dobrý zvyk, protože potom *p_prom = 78; // ohlásí chybu, jinak přepíše paměť a ani se tím nepochlubí -> nebezpečné!!! viz začátek přednášky p_prom = (int *) malloc(sizeof(int)); Co když došla paměť? Musím testovat. Při nedostatku paměti malloc vrátí NULL: p_prom = (int *) malloc(sizeof(int)); if (p_prom == NULL) { printf("mas smulu, pamet dosla ;-)");
exit(0); // např. ukončení programu - nebo totéž méně přehledně, leč takto běžnější: if ((p_prom = (int *) malloc(sizeof(int))) == NULL) { printf("mas smulu, pamet dosla ;-)"); exit(-1); // např. ukončení programu - přidělěnou paměť je třeba "hlídat" = neztratit odkaz (např. po skončení funkce), protože ji musíme ručně uvolnit. Ruční uvolnění paměti, kterou již nepotřebuji: free((void *) p_prom); p_prom = NULL; // není nutno, leč bezpečnější - důvod, proč nastavit pointer po free na NULL: v pointeru zůstane po uvolnění paměti původní adresa. Mohl bych tedy s pointerem dále pracovat, ale vlastně již s pamětí, kterou vrátil systému. Pole souvislost s pointery int *p_prom, kolik; printf("jak velke pole to bude: "); scanf("%d", &kolik); /* před., že zadáme z kláv. 100 */ p_prom = (int *) malloc(kolik * sizeof(int)); if (p_prom == NULL) { printf("mas smulu, pamet dosla ;-)"); exit(0); // např. ukončení programu *(p_prom + 0) = 10; // prvni prvek pole s indexem 0 *(p_prom + 10) = 20; // 11 prvek pole s indexem 10
*(p_prom + 99) = 54; // poslední prvek pole s indexem 99 - lze též opravdu jako pole: p_prom[0] = 10; p_prom[10] = 20; p_prom[99] = 54; zrušení tohoto pole: free((void *) p_prom); Pole souhrn a opakování - statická pole (ne dynamicky jako výše) - opakování int policko[100]; policko[5] = 7; // pozor je to 6. prvek s indexem 5 policko[99] = 2; // poslední prvek. policko[100] = 78; // C nijak neprotestuje příkaz vykoná - hodnota 78 je zapsána do paměti ZA moje pole, přepisuji paměť, kterou nemám přidělenu => pravděpodobně bude program chybovat. Může tam uložena moje jiná proměnná... - to znamená, že C nekontroluje rozsahy polí a ohlídání je na programátorovi musím si udržovat např. nějakou proměnnou, kde budu délku pole uloženu.
- dvourozměrné pole: int pol2d[5][10]; pol2d[0][0] = 4; Prolezu dvourozměrné pole: int pole2d[100][100]; for(i = 0; i < 100; i++) { for(j = 0; j < 100; j++) { pol2d[j][i] = 5; // jedu po poli po sloupcích j je číslo řádku, prolezu pro jedno I vždy všechna j for(i = 0; i < 100; i++) { for(j = 0; j < 100; j++) { pol2d[i][j] = 5; // jedu po poli po řádkách j je číslo řádku, prolezu pro jedno i vždy všechna j Prolezu jen horni trojuhelnikovou matici: for(i = 0; i < 100; i++) { for(j = i; j < 100; j++) { pol2d[i][j] = 5; Prolezu jen dolni trojuhelnikovou matici: radekkam = 1; for(i = 0; i < 100; i++) { for(j = 0; j < radekkam; j++) { pol2d[i][j] = 5; radekkam++;
Souřadnice prvků ve 2d polích int pol2d[5][10]; /* 5 řádek, 10 sloupců */ pol2d[0][0] = 4; /* prvek úplně vlevo nahoře */ pol2d[4][9] = 3; /* prvek úplně vpravo dole */ Použití konstanty lépe než přímo zapsat číslo jako rozměr pole #define MAX 10 double pold[max]; for (int i = 0; i < MAX; i++) { /* i běží od 0 do 9 */ pold[i] = 3.4;
Deklarace vlastního typu pole: typedef int VECTORPET[5]; - deklarace vlastního typu VECTOR5, který představuje pole 5ti intů. VECTORPET v1, v2, v3; v1[4] = 6; int v4[5]; /* totéž */ Lze i vícerozměrná pole: int pole3[2][3][4];
V ANSI C 89 NELZE!!!!!!!! následující konstrukci: int delka; scanf("%d", &delka); double prom_pole[delka]; - nelze ve velkém množství verzí C, záleží normě, kterou daný překladač splňuje-lze dle normy ANSI 99. - pokud toto překladač umí přeložit, zjistíte ve výsledném kódu, že použil obdobnou funkci jako je malloc - standardním řešením jsou: Dynamická pole (viz výše několikrát) int *p_pole, kolik; printf("jak velke pole to bude: "); scanf("%d", &kolik); /* před., že zadáme z kláv. 100 */ p_pole = (int *) malloc(kolik * sizeof(int)); if (p_pole == NULL) { printf("mas smulu, pamet dosla ;-)"); exit(0); // např. ukončení programu *(p_pole + 0) = 10; // prvni prvek pole s indexem 0 *(p_pole + 10) = 20; // 11 prvek pole s indexem 10 *(p_pole + 99) = 54; // poslední prvek pole s indexem 99 lze opravdu jako pole: p_pole[0] = 10; p_pole[10] = 20; p_pole[99] = 54;
- likvidace dynamického pole - jako u jiných pointerů free((void *) p_pole); p_pole = NULL; /* pro jistotu, abych ho nemohl omylem použít */ Pole může tedy vzniknou za běhu, dle potřeby: int *p_pole, delkapole; scanf("%d", &delkapole); p_pole = (int *) malloc(delkapole * sizeof(int)); Př.: #include <stdio.h> #include <limits.h> int main (void) { unsigned char *p_ch; int *p_i; p_ch = (unsigned char *) malloc(sizeof(unsigned char)); if(p_ch == NULL) { printf("\ndosla pamet, p_ch se neveslo..."); exit(-1); if((p_i = (int *) malloc(sizeof(int))) == NULL) { printf("\ndosla pamet, p_i se neveslo..."); exit(-1); *p_i = INT_MIN; p_ch = (unsigned char *) p_i; // konverze (int *) na (unsigned char *)
printf("\nint je: %d (velikost %d)", *p_i, sizeof(*p_i)); printf("\n\na jako ctyri byte: %d, %d, %d, %d", *p_ch, *(p_ch + 1), *(p_ch + 2), *(p_ch + 3)); free((void *) p_ch); free((void *) p_i); printf("\n\n\n"); system("pause");