You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 13 Next »

Ciele cvičenia

Cvičenie je zamerané na prácu so smerníkmi, ktoré sú v programovaní C veľmi silným a užitočným nástrojom. Po osvojení si problematiky študent dokáže efektívne adresovať údaje v pamäti. Rozlišuje medzi adresou premennej a jej obsahom.

  • Hodnota, adresa a smerník
  • Smerník ako argument funkcie
  • Smerník a polia - reťazce
  • Smerníková aritmetika 

Odporúčaná literatúra a dôležité odkazy

[1] KPI-FEI-TUKE: Prednáška č. 1

[2] KPI-FEI-TUKE:  Cvičenie č. 2 - *Pointers

[3] Horovčák P.: Úvod do programovania v jazyku C- Smerníky

[4] Základy práce s knižnicou STDIO.H

[5] Reťazce v jazyku C

[6] Argumenty príkazového riadku


Čo je to smerník?

So smerníkmi sme sa už pri programovaní (na ZAP) takmer určite stretli. Spomínate si na funkciu scanf? Táto funkcia slúži na načítanie znakov z terminálu. Ak si spomíname tak volanie tejto funkcie vyzeralo nejako takto: scanf("%c", &znak) alebo scanf("%s", retazec). Na ZAP sme len konštatovali, že Funkcia scanf() pracuje s "miestom" v pamäti teda adresou premennej a nie s jej hodnotou [4] a preto ak načítavame jeden znak musíme použiť &. Neskôr sme si tiež povedali, že ak načítavame reťazce tak & nepoužívame [5].

Z uvedeného je teda zrejmé, že ak pred názov premennej dáme znak & odkazujeme sa na adresu tejto premennej. V prípade polí (teda aj reťazcov) to ale neplatí! Pri poliach sa za adresu (ide o adresu prvého prvku poľa) považuje samotný názov tohto poľa a k jeho prvkom sa potom pristupuje cez indexáciu v hranatých zátvorkách.

Smerník je údajový typ, ktorým ukazujeme na miesto v pamäti teda na adresu. Ak teda deklarujeme premennú pred ktorú dáme znak *  dáme prekladaču najavo, že v tejto premennej budú uložené adresy na premenné. 

Nasledujúcim kódom je demonštrovaný vzťah medzi adresou premennej, jej obsahom a smerníkom na túto premennú:

#include <stdio.h>
int main()
{
  int a = 5;        // Priradenie hodnoty 5 do premennej a.
  int* ptr_a = &a;  // Priradenie adresy prem. a do ptr_a. 
					// (typ smernik)	
  int c = *ptr_a;   // Priradenie obsahu do prem c.
					// Tento obsah sa nachádza na adrese kam 
					// ukazuje smerník ptr_a.   
  printf(">> a = %d \n", a);  
  printf(">> *ptr_a = %d \n", *ptr_a);
  printf(">> ptr_a = %p \n", ptr_a);
  printf(">> &a = %p \n",  &a);
  printf(">> c = %d \n", c);
  return 0;
}

Pointers in C Programming with examples

Po kompilácii a spustení kódu:

ab123cd@zapfei:CV1$ gcc ptr.c -o PTR
ab123cd@zapfei:CV1$ ./PTR
>> a = 5
>> *ptr_a = 5
>> ptr_a = 0x7ffdebd89bf8
>> &a = 0x7ffdebd89bf8
>> c = 5



Smerník ako argument funkcie

Na ZAP sme sa naučili, že výsledok vykonania ľubovoľnej funkcie môže byť vrátený pomocou jej návratovej hodnoty. K tomuto účelu slúži príkaz retrun, ktorý je spravidla posledným príkazom vykonaným volanou funkciou. Mnoho funkcií ale je typu void, teda bez návratovej hodnoty a stále dokážu "vrátiť" výsledok, napr. tak ako už spomínaná funkcia scanf.

Funkciu bez návratovej hodnoty, ktorej výsledky potrebujeme ďalej používať musí teda pracovať s premennými v pamäti  presne tam, kde ich používa aj funkcia (napr. main), ktorá danú funkciu zavolala. Toto zabezpečíme tak, že vstupnými argumentom funkcie bude priamo adresa premennej, do ktorej sa má výsledok uložiť.

V nasledujúcom príklade si ukážeme jednoduchú funkciu, ktorá vynásobí číslo, ktoré jej bude zaslané hodnotou "-1". Teda v prípade kladného čísla dostaneme číslo záporné a naopak v prípade záporného čísla zasa vo výsledku dostaneme číslo kladné. Takúto funkciu si ukážeme v dvoch prevedeniach - s návratovou hodnotou a bez nej. 

Funkcia invertovania s návratovou hodnotou 

#include <stdio.h>
int invert(int cislo); // funkcia s návratovou hodnotou int a vstup. argumentom int
int main()
{

  int a = 5;         
  int b = invert(a); // Do b je uložená návratová hodnota funkcie.
  printf(" >> b = -1 x a = -1 x %d = %d\n", a, b); 
  return 0;
}

int invert(int cislo)
{
  return -1*cislo;  
}

Funkcia invertovania bez návratovej hodnoty (s použitím smerníka)

#include <stdio.h>
void invert(int* cislo); // funkcia bez návratovej hodnoty a 
						 // so vstup. argumentom smerník na int
int main()
{

  int a = 5;
  int b = a;  // Do b je skopíprovaná hodnota z premennej a
  invert(&b); // Funkcii invert sa pošle iba adresa premennej b
  printf(" >> b = -1 x a = -1 x %d = %d\n", a, b); 
  return 0;
}

void invert(int* cislo)
{
  *cislo = *cislo * (-1);  // Cez * pred premenou cislo sa dostaneme na obsah,
						   // ktorý sa nachádza na adrese, ktorú funkcia dostala.
}

V oboch prípadoch bude po spustení programu výsledok rovnaký:

ab123cd@zapfei:CV1$ gcc invert.c -o INV
ab123cd@zapfei:CV1$ ./INV
 >> b = -1 x a = -1 x 5 = -5

Úloha 1. 

Napíšte program (aritmetika.c) pre výpočet základných aritmetických operácií "+", "-",  "*"  a "/"

  • Operácia bude zadaná ako argumentpríkazového riadku! - Zopakovať [6].
  • Vstupné čísla a, b budú vyžiadané od používateľa programom. (printf → scanf)
  • Všetky funkcie okrem main budú typu void.
  • Kostra kód je zobrazená v bloku vpravo.
    • Odporúčaný postup je taký, že najprv si sfunkčnite funkcie potom si spravíte zadávanie čísel a nakoniec vyriešite zadávanie operácie z príkazového riadku!
    • Úloha je postavená tak, že musíte doplniť kostru a nesmiete nič čo je v nej uvedené zmeniť alebo vymazať!


ab123cd@zapfei:CV1$ gcc aritmetika.c -o ARITMETIKA
ab123cd@zapfei:CV1$ ./ARITMETIKA +

 >> Zadaj čslo a = 5

 >> Zadaj čislo b = 3

 >> c = a + b = 5 + 3 = 8

#include <stdio.h>
#include <string.h>

// Tu sú deklarácie funkcii
void sucet(int* cislo1, int* cislo2, int* ans);
void rozdiel(int* cislo1, int* cislo2, int* ans);
void sucin(int* cislo1, int* cislo2, int* ans);
void podiel(int* cislo1, int* cislo2, int* ans);

int main(int argc, char *argv[])
{
	// Nezabudnuť na deklarácie premenných
	// Tu bude kód pre zadávanie hodnoty vstupných premenných 
    
   if( strcmp(argv[1],"+") == 0 )
    {
      sucet(&a, &b, &c);
      printf("\n >> c = a + b = %d + %d = %d\n", a,b,c);
    }
    // ... tu budú ďalšie možnosti 
        
 return 0;   
}

//  Tu by  mali byť definície funkcií




  • No labels