Starý program Program s pointerom

Podobné dokumenty
Programovanie v jazyku C - to chce dynamiku

PODPROGRAMY. Vyčlenenie podprogramu a jeho pomenovanie robíme v deklarácii programu a aktiváciu vykonáme volaním podprogramu.

Úroveň strojového kódu procesor Intel Pentium. Adresovanie pamäte

Př. další použití pointerů

Dynamická alokácia pamäte a smerníky

IUJCE 07/08 Přednáška č. 6

VECIT 2006 Tento materiál vznikol v rámci projektu, ktorý je spolufinancovaný Európskou úniou. 1/4

Polia a matice v jazyku C. Michal Kvasnica

Čo ak program potrebuje pamäť, ktorej veľkosť závisí od konkrétneho vstupu?

IUJCE 07/08 Přednáška č. 4. v paměti neexistuje. v paměti existuje

Programovanie v jazyku C - pole treba poorat...

Funkcia - priradenie (predpis), ktoré každému prvku z množiny D priraďuje práve jeden prvok množiny H.

Programovanie I. Úvod do programovania Mgr. Stanislav Horal, Katedra informatiky, FPV, UCM

Programovanie v jazyku C - struktury a polia

Úvod do programování. Lekce 5

Operační systémy. Cvičení 4: Programování v C pod Unixem

Studentove t-testy. Metódy riešenia matematických úloh

8. Relácia usporiadania

Pracovné prostredie MS EXCEL 2003.

Imagine. Popis prostredia:

ALGORITMY A PROGRAMOVANIE VO VÝVOJOVOM PROSTREDÍ LAZARUS. Vývojové prostredie Lazarus, prvý program

Ak stlačíme OK, prebehne výpočet a v bunke B1 je výsledok.

To bolo ľahké. Dokážete nakresliť kúsok od prvého stromčeka rovnaký? Asi áno, veď môžete použiť tie isté príkazy.

Textový editor WORD. Práca s obrázkami a automatickými tvarmi vo Worde

M úlohy (vyriešené) pre rok 2017

Programovanie v jazyku C - funkcie a makra

RIEŠENIE NIEKTORÝCH ÚLOH LINEÁRNEJ ALGEBRY V PROSTREDÍ MS EXCEL. 1. Zadáme prvky matice A a B do buniek pracovného hárku zošita MS Excel

1. Formát exportov typu *.gpc (ABO)

7.1 Návrhové zobrazenie dotazu

Objektovo orientované programovanie v C# ERIK KUČERA METÓDY VÝPOČTOVEJ INTELIGENCIE PREDNÁŠKA 3

Prevody z pointfree tvaru na pointwise tvar

Ďalší spôsob, akým je možné vygenerovať maticu je použitie zabudovaných funkcií na generovanie elementárnych matíc.

Zvyškové triedy podľa modulu

Kvadratické funkcie, rovnice, 1

15. Príkazy vetvenia

Kombinatorická pravdepodobnosť (opakovanie)

Např.: // v hlavičkovém souboru nebo na začátku // programu (pod include): typedef struct { char jmeno[20]; char prijmeni[20]; int rok_nar; } CLOVEK;

4. Typ ukazatel, strukturované datové typy

Algoritmizace a programování

MATLAB (1) - úvod do programovania vedeckých problémov. LS 2017, 8.predn.

Operačný systém Úvodná prednáška

Program "Inventúra program.xlsm"

Základy algoritmizácie a programovania

3 Determinanty. 3.1 Determinaty druhého stupňa a sústavy lineárnych rovníc

Microsoft Outlook. Stručný prehľad základných funkcií. Ing.Anna Grejtáková, SPP DFBERG

V nej je potrebné skontrolovať správnosť prenesených a prepočítaných zostatkov z roku 2008.

Funkce, intuitivní chápání složitosti

DOBROPISY. Dobropisy je potrebné rozlišovať podľa základného rozlíšenia: 1. dodavateľské 2. odberateľské

Riešenie cvičení z 3. kapitoly

1. lekce. do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme:

Pokročilé programování v jazyce C pro chemiky (C3220) Operátory new a delete, virtuální metody

Správné vytvoření a otevření textového souboru pro čtení a zápis představuje

11a Dynamické dvourozměrné pole (obdobně vícerozměrné)

8. lekce Úvod do jazyka C 3. část Základní příkazy jazyka C Miroslav Jílek

AR, MA a ARMA procesy

Úvod do jazyka C. Ing. Jan Fikejz (KST, FEI) Fakulta elektrotechniky a informatiky Katedra softwarových technologií

Kombinatorická pravdepodobnosť (opakovanie)

Návod k servisnému programu pre fiskálny modul FM2000. manuál. (c)varos

ČÍSELNÉ RADY. a n (1) n=1

INTERNET BANKING. Popis štruktúry technických formátov exportných súborov VŠETKO, ČO JE MOŽNÉ. with.vub.sk,

Základní datové typy, proměnné - deklarujeme předem - C je case sensitive rozlišuje malá a velká písmena v názvech proměnných a funkcí

Pole a Funkce. Úvod do programování 1 Tomáš Kühr

Programovanie v jazyku C - ti to zratam...

MANUÁL K PROGRAMU MATEMATIKA 2.0 STIAHNUTIE A INŠTALÁCIA PROGRAMU:

Program převod z desítkové na dvojkovou soustavu: /* Prevod desitkove na binarni */ #include <stdio.h>

Blokové a prúdové šifry

ÚVOD DO HRY PRINCIP HRY

OCHRANA INOVÁCIÍ PROSTREDNÍCTVOM OBCHODNÝCH TAJOMSTIEV A PATENTOV: DETERMINANTY PRE FIRMY EURÓPSKEJ ÚNIE ZHRNUTIE

1. lekce. do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme:

for (i = 0, j = 5; i < 10; i++) { // tělo cyklu }

Automatický timer pre DX7 návod na inštaláciu a manuál

Ružové obrázkové slová skladanie slov z písmen

MANUÁL K TVORBE CVIČENÍ NA ÚLOHY S POROZUMENÍM

TomTom Referenčná príručka

Total Commander. Základné nastavenia

Ako započítať daňovú licenciu

Struktura programu v době běhu

Strojový kód, assembler, emulátor počítača

Hromadná korešpondencia v programe Word Lektor: Ing. Jaroslav Mišovych

Ukazatel (Pointer) jako datový typ - proměnné jsou umístěny v paměti na určitém místě (adrese) a zabírají určitý prostor (počet bytů), který je daný

Triedenie. Príklad T.1 Vytvorte funkciu, ktorá zistí počet rôznych hodnôt v poli.

Strukturu lze funkci předat: (pole[i])+j. switch(výraz) velikost ukazatele

Jazyk C++, některá rozšíření oproti C

Množiny, relácie, zobrazenia

Skákalka. Otvoríme si program Zoner Callisto, cesta je Programy Aplikácie Grafika Zoner Callisto.

Vytvorenie používateľov a nastavenie prístupov

P R O L U C. POZNÁMKY individuálnej účtovnej závierky pre rok 2014

Pointery II. Jan Hnilica Počítačové modelování 17

Finančné riaditeľstvo Slovenskej republiky

Zaciatok programovania na

Import Excel Univerzál

nastavenie a realizácia vzájomných zápočtov v Money S4 / Money S5

Konfigurácia IP Bell 02C Dverný vrátnik a FIBARO Home Center 2

Modré obrázkové slová skladanie slov z písmen

SKLADOVÁ INVENTÚRA 1 VYTVORENIE INVENTÚRY. 1.1 Nastavenie skladovej inventúry

Užívateľská príručka. Vytvorte 1 medzi stránkami v niekoľkých jednoduchých krokoch

STRUČNÝ NÁVOD NA OBSLUHU DATALOGERA KIMO KT110 / 150

TELCO PH 578. telefónny prístroj. Návod na obsluhu Návod na obsluhu Návod na obsluhu VLASTNOSTI:

KOMISNÝ PREDAJ. Obr. 1

INTERNET BANKING. Platby cez Internet banking VŠETKO, ČO JE MOŽNÉ. with.vub.sk, Bank of

Transkript:

VII-1

Pointery Pointery (ukazatele, smerníky) sú srdcom a dušou jazyka C. Pokiaľ ich nebudete používať, ušetríte si veľa problémov (každý algoritmus sa dá napísať bez nich, aj keď možno neefektívne). Pointer je premenná ako každá iná, ibaže definuje adresu v pamäti, a na tejto adrese sa ukrýva skutočná hodnota. hodnota 25 18 symbolická adresa poi *poi absolútna adresa 87 25 premenná poi je pointer hodnota poi je 25 (číslo uložené na symbolickej adrese poi je 25) číslo 25 sa nevyužije priamo k výpočtu, ale predstavuje absolútnu adresu v pamäti na absolútnej adrese 25 v pamäti je číslo 18 (určené na použitie k výpočtu) poi ukazuje na hodnotu 18, ale sám má hodnotu 25 VII-2

Načo sú pointery? Urýchlenie programov. "Profesionalita." Zmena hodnôt premenných dodávaných funkcii bez toho, že by museli byť definované ako globálne - volanie odkazom - pointery použijeme, keď chceme zmeniť vo funkcii hodnotu parametra natrvalo, namiesto hodnoty dáme funkcii adresu premennej. Narábanie s polom. operátor * povie prekladači, že hodnota premennej je iba adresa a k výpočtu sa má použiť hodnota na dotyčnej adrese pomocou operátoru * môžeme získať obsah na adrese, na ktorú ukazuje pointer i=*poi; ale aj opačne *poi=5; Operátor & má opačný význam ako *, teda dostane sa ním adresa pamäti, na ktorej je premenná uložená. VII-3

Starý program #include <stdio.h> #define MAX 10 void main(void) { int a[max], b[max], i; for(i=0; i<max; i++) a[i]=i; for(i=0; i<max; i++) b[i]=a[i]; for(i=0; i<max; i++) printf("%d",b[i]); Program s pointerom #include <stdio.h> #define MAX 10 void main(void) { int a[max], b[max], i, *p, *q; for(i=0; i<max; i++) a[i]=i; for(i=0,p=a,q=b; i<max; i++) *q++ = *p++; for(i=0; i<max; i++) printf("%d",b[i]); VII-4

Starý program #include <stdio.h> int x=0; void zmena_premennej(void) { x++; main() { zmena_premennej(); printf("x = %d",x); Program s pointerom #include <stdio.h> void zmena_premennej(int *premenna) { (*premenna)++; main() { int x; zmena_premennej(&x); printf("x = %d",x); VII-5

Prehodenie prvkov #include <stdio.h> void vymen(int *p_x, int *p_y) { int pom; pom=*p_x; *p_x=*p_y; *p_y=pom; main() { int i=5, j=3; vymen(&i,&j); printf("i=%d, j=%d"); VII-6

výmena adresy a dynamické priraďovanie adries sú typickým použitím pointerov Napr. namiesto výmeny dvoch veľkých "štruktúr", napr. polí, sa vymenia iba adresy ich počiatočného prvku veľmi častá chyba je vymen(i,j); bude zapisovať na absolútne adresy 3 a 5 program zmrzne vymen(*i,*j); bude zapisovať na adresy adries - program zmrzne VII-7

Pred volaním vymen(&i,&j); 5 3 i j Po zavolaní vymen(&i,&j); 5 3 i p_x pom p_y j Pred koncom vymen(&i,&j); 5 3 i p_x pom p_y j VII-8

Pozor, pamäť, na ktorú ukazuje pointer, musí byť pred zápisom na tú adresu pridelená, v prípade zápisu do nepridelenej pamäti nás prekladač neupozorní!!! int *poi; // pointer poi *poi=5; // zle!!!! Keďže pointeru nebola priradená adresa, ukazuje na náhodné miesto v pamäti, teda hodnota 5 môže prepísať inú premennú alebo príkaz v programu Pointer je vždy zviazaný s nejakým dátovým typom (napr int), ale pozor, u príkazu int *poi, poi2; iba poi je definícia pointera, poi2 je už normálne celé číslo, správne má byť int *poi, *poi2; int i, *p_i=&i; Toto je definícia p_i a jeho súčasná inicializácia adresou premennej i VII-9

Priradenie hodnoty pointerom *p_i=1; // OK *(p_i+3)=1; // podozrive, pokial // p_i nie je pole p_i=&i; // OK p_i=&(i+3); // chyba p_i=&15; // chyba p_i=3; // takmer isto chyba //p_i ukazuje na absol. adresu 3 i=p_i; // takmer isto chyba // do i je dana adresa i=&p_i; // takmer isto chyba // do i je dana adresa adresy p_i=&i; // adresa i do p_i i=3; // aj i, aj *p_i je 3 *p_i=4; // aj i, aj *p_i je 4 j=5; *p_i=j; // aj i, aj *p_i je 5 VII-10

Operátor * má vyššiu prioritu ako +, teda i=*p_i+1; je vlastne i=(*p_i)+1; #include <stdio.h> main() { int i, j, *p_i; scanf("%d %d",&i,&j); if(i>j) p_i=&i; else p_i=&j; printf("vetsi je %d \n",*p_i); VII-11

void spocti_medzery(int *p_medzery)) { int c; *p_medzery=0; while((c=getchar())!= '\n') if(c==' ') (*p_medzery)++; main() { int medzery; spocti_medzery(&medzery); printf("na riadku bolo %d medzier.", medzery); VII-12

Pointer na typ void void *p_void; takýto pointer neukazuje na žiaden konkrétny typ, preto sa dá použiť na ľubovoľný typ int i; float f; void *p_void=&i; // p_void ukazuje na i main() { *(int *) p_void=2; // i bude 2 p_void=&f; // ukazuje na f *(float *) p_void=1.2; // f je 1.1 VII-13

void ako formálny parameter funkcie #include <stdio.h> void vymen_pointery(void **p_x, void **p_y) { void *p_pom; p_pom=*p_x; *p_x=p_y; *p_y=p_pom; main() { int i=5, j=6, p_i=&i, p_j=&j; vymen_pointery((void*)&p_i, (void*)&p_j); printf("%d %d",*p_i,*p_j); Namiesto niekoľko funkcií, pre každý typ dvojice pointerov zvlášť, sa dá použiť jedna funkcia. VII-14

Pointery na funkcie double *p_fd(); znamená funkciu, ktorá vracia pointer na double double (*p_fd)(); znamená pointer na funkciu, ktorá vracia double VII-15

Tabelácia dvoch polynómov x 2 +8, x 3-3 od 0 po 1 po 0.1 double pol1(double x) { return(x*x+8); double pol2(double x) { return(x*x*x-3); main() { double x; double (*p_fd)(double x); for(int i=0;i<2;i++) { if(i==0) p_fd=pol1; else p_fd=pol2; for(x=0;x<=1;x+=0.1) printf("%lf %lf\n", x,(*p_fd)(x)); VII-16

Ako čítať komplikované definície int x; // x je typu int float *y; // y je pointer na typ float double *z(); // z je funkcia vracajúca // na typ double int *(*v)(); // v je pointer na funkciu // vracajúcu pointer na typ int nájdeme identifikátor, teda "v" a povieme v je čítame doprava, dokiaľ nenarazíme na ")", ktorá nás vracia doľava na "(", odkiaľ čítame zasa doprava, teda "*"... pointer na... preskakujeme už prečítané doprava, pokiaľ nenarazíme na ")" alebo bodkočiarku, u nás to bude (), teda...funkciu vracajúcu... bodkočiarka nás vráti doľava, pretože vpravo už sme všetko prečítali, čítame doľava "*"...pointer na... doľava "int"...int teda v je pointer na funkciu vracajúcu pointer na int VII-17

Pointerová aritmetika pre i je typu int pointer +i pointer i pointer1 <= pointer2 (aj všetky ostatné druhy porovnávania) pointer1 - pointer2 Operáror sizeof zistí veľkosť skúmaného dátového typu v Bytoch. Je vyhodnotený pri prekladu, nezdržiava teda program. Využitie pri prideľovaní dynamickej pamäti int i, *p_i; i=sizeof(*p_i); // v i bude počet Bytov // nutných pre uloženie objektu, na ktorý ukazuje // p_i, teda int (pozor, pri poliach sa musí násobiť // veľkosťou pola) VII-18

Súčet pointeru a celého čísla Výraz p+n znamená, že sa odkazujeme na n-tý prvok za prvkom, na ktorý práve ukazuje pointer p. Keď p ukazuje na char, hodnota adresy tohto prvku je (char *) p + sizeof(*p) * n teda k pointeru pričítame nie číslo n, ale násobok tohto čísla a veľkosti typu, na ktorý pointer ukazuje. char *p_c=10; // sizeof(char)==1 int *p_i=10; // sizeof(int)==2 float *p_f=10; // sizeof(float)==4 Po pričítaní jednotky platí p_c+1==11 p_i+1==12 p_f+1==14 Výraz typu p_i=p_i+5; bude ukazovať na 5-tý prvok za pôvodným prvkom časté u polí VII-19

Odčítanie celého čísla od pointeru p-i funguje podobne ako pričítanie, teda odkazuje na n-tý prvok pred prvkom, na ktorý odkazuje pointer p Porovnávanie pointerov < <= > >= ==!= má zmysel vtedy, keď obidva pointery ukazujú napr. na jedno pole Kopírovanie pamäti Keď p_c a p_d sú pointery na typ char, pričom p_c ukazuje na začiatok pole veľkosti MAX, skopírujeme toto pole nasledovne char *p_t; for(p_t=p_c; p_t<p_c+max; *p_d++=*p_c++) ; Po ukončení kopírovaní ukazuje p_d za prvý Byte za novo skopírovaným blokom, teda je dobre dať príkaz p_d -=MAX; VII-20

Odpočítavanie pointerov p_d-p_c má zmysel, keď pointery ukazujú na rovnaké pole dát k zistení počtu prvkov medzi pointerami. Sčítanie pointerov je nezmysel. Predpokladajme predchádzajúci blok dát. Nasledujúca časť programu nájde v tomto bloku znak "?" a vytlačí jeho pozíciu, alebo keď "?" nie je, vytlačí 1. for(p_d=p_c; *p_d!='?' && p_d<p_c+max; p_d++) ; printf("%d\n", (p_d<p_c+max)? p_d-p_c+1 : -1); VII-21

Práca s pamäťou Štatická alokácia keď vieme prekladači dopredu presne povedať, aké budeme mať v programu pamäťové nároky. V priebehu behu nášho programu sa nerobí žiadna manipulácia s prideľovaním pamäti. Kedy to nestačí? Napr. pri rekurzívnom volaní funkcie každé volanie vyžaduje nový blok pamäti pre svoje premenné a prekladač nevie, koľkokrát bude funkcia volaná. Alebo pri načítaní celého súboru do pamäti nevieme obecne dopredu povedať jeho dĺžku. Štatiská alokácia vymedzuje miesto v dátovej oblasti napr. všetky globálne premenné. VII-22

Dynamická alokácia vymedzuje pamäť na "hromade" (heap). Pamäť možno prideľovať v priebehu výpočtu. Nemá symbolické meno a pristupuje sa do nej pomocou pointerov. Existencia lokálnych premenných vo funkciách ("podprogramoch") začína pri vstupu do funkcie a končí pri výstupu z funkcie (potom môže byť využitá na iné účely) premennú, ktorú potrebujeme iba vo funkcii, ale musí si ponechávať hodnotu medzi volaniami tejto funkcie treba definovať špeciálne definíciou tejto premennej. VII-23

Pamäťové triedy extern pre premenné v inom moduli static pre lokálne premenné, ktoré si ponechávajú svoju hodnotu aj medzi jednotlivými volaniami funkcie #include <stdio.h> void f(void) { int x=2; static int i; printf("f bola volana %d-krat,x=%d\n",i,x); i++; x++; main() { for(j=0;j<3;j++) f(); f bola volana 0-krat, x=2 f bola volana 1-krat, x=2 f bola volana 2-krat, x=2 VII-24

Typový modifikátor const keď sa raz premenná zadefinuje, nesmie byť menená const float pi=3.14159; ale const int max=100; int pole[max]; // sa nesmie pouzit VII-25

Dynamické prideľovanie a návrat pamäti Štandardné funkcie, napr. malloc() pridelia blok pamäti potrebnej veľkosti a vráti jeho adresu. Veľkosť pridelenej dynamickej pamäti musí byť závislá na veľkosti objektu, na ktorý pointer ukazuje. Dáta existujú až do konca programu alebo do uvolnení pamäti príkazom free(). Knižnice: #include <stdlib.h> #include <alloc.h> Funkcie malloc() má jediný parameter typu unsigned int určujúci počet bytov, ktoré chceme alokovať. Vracia pointer na typ void, ktorý treba pretypovať. Keď nie je dostatok miesta, vracia hodnotu NULL je dobre testovať, či sa podarilo prideliť pamäť. VII-26

#include <stdio.h> void main(void) { int *p_i; if((p_i=(int *) malloc(sizeof(int)*1000) == NULL) { printf("malo pamati\n"); exit(1); VII-27

Uvoľňovanie pamäti Je dobré nepotrebnú pamäť ihneď vrátiť. Parametrom funkcie free() je pointer na typ void. free((void *) p_i); Keby sme chceli prideliť ďaľšiu pamäť na rovnaký pointer p_i=malloc(20); bez predchádzajúceho uvolnenia pamäti, tých 1000 predchádzajúcich integerov nám ostane "visieť" v pamäti a až do konca behu programu sa k nim nedostaneme, lebo nevieme ich pointer. Funkcia calloc() na pole calloc(n,size) odpovedá malloc(n*size) VII-28

Pole a pointery int pole[10]; // staticke pole pole[5] je totožné s *(pole+5) &pole[5] je totožné s pole+5*sizeof(int) int *pole2; // dynamicke pole pole2=(int*)malloc(10*sizeof(int)); pole aj pole2 sú pointery na int, ale pole je konštanta, jej hodnota sa už nedá meniť, zatiaľ čo pole2 je premenná, ktorej sa dá priradiť iná pamäť Je jedno, či bolo pole alokované štaticky alebo dynamicky, môže sa adresovať aj pole2[5] aj *(pole2+5) platí pole2[0]==*pole2 VII-29

Pole s rôznou dĺžkou riadkov napríklad pre polovicu matice pod diagonálou int *xx[3];//pole troch pointerov for(i=0;i<3;i++) xx[i]= (int *)malloc((i+1)*sizeof(int)); xx xx[0] xx[0][0] xx[1] xx[1][0] xx[1][1] xx[2] xx[2][0] xx[2][1] xx[2][2] POZOR, pole xx[0][1] by ukazovalo na neznámu oblasť pamäti!!! VII-30

Polia ako parametre funkcií Pole môže byť parametrom funkcie tak, že sa prenáša adresa začiatku poľa pomocou pointeru. Položky poľa potom môžu byť vo funkcii menené a túto zmenu si ponechajú aj po opustení funkcie. Nasledujúca funkcia nájde najväčší prvok z poľa o ROZSAH prvkoch. double maxim(double pole[],int rozsah) { double *p_max=pole, *p_pom; for(p_pom=pole+1; p_pom<pole+rozsah; p_pom++) if(*p_pom>*p_max) p_max=p_pom; return(*p_max); double pole[] môže byť nahradené pomocou double *pole VII-31

funkcia by bola volaná napr. max=maxim(pole, velkost_pole); Pokiaľ vo funkcii pracujeme s poľom a je nutné poznať jeho veľkosť, potom táto veľkosť musí byť daná ako ďalší formálny parameter. Predchádzajúca funkcia sa dá použiť aj na nájdenie maxima z výseku polia, napr. od tretieho do siedmeho prvku max=maxim(pole+2, 5); alebo max=maxim(&pole[2], 5); VII-32

Pointer ako skutočný parameter funkcie Program prečíta z klávesnice 10 double čísel, uloží ich do pamäti a vypočíta ich súčin #include <stdio.h> #include <stdlib.h> #define SIZE 10 double *init(void) { return ((double *) malloc(size * sizeof(double))); void citanie(double *p_f) { for(int i=0;i<size;i++) { printf("%d. cislo: ",i+1); scanf("%lf",p_f+i); // bez &! void nasob(double *p_f, int size, double *sucin) { for(size -, *sucin=*(p_f+size); size>=0; size--) *sucin *= *(p_f+size); VII-33

main() { double *p_dbl; suc; if((p_dbl=init())==null) return; // nedostatok pamati-koniec citanie(p_dbl); nasob(p_dbl,size,&suc); printf("sucin: %12.3lf \n",suc); Pri funkcii nasob() sa prvý parameter p_dbl uvádza bez &, pretože je to pointer, zatiaľ čo tretí parameter suc sa uvádza s &, pretože je to premenná. VII-34

VII-35