Ukazatele na struktury
V minulém cvičení změnila funkce prodej_kus jen svou kopii produktu. Řešení znáte z lekce o ukazatelích: předejte funkci adresu proměnné a funkce přes ni změní originál. U struktur to funguje stejně:
typedef struct {
char nazev[20];
double cena;
int pocet;
} Produkt;
void pridej_kusy(Produkt *polozka, int navic) {
(*polozka).pocet += navic;
}Parametr polozka je ukazatel na Produkt. *polozka je produkt, na který ukazuje, a (*polozka).pocet je počet kusů tohoto produktu. Závorky jsou nutné: tečka se vyhodnocuje dřív než hvězdička, takže *polozka.pocet by znamenalo „člen pocet proměnné polozka a potom *“, jenže polozka je ukazatel, ne struktura. Proto má C kratší a přehlednější zápis, šipku ->, která se píše jako mínus a znak „větší než“:
#include <stdio.h>
typedef struct {
char nazev[20];
double cena;
int pocet;
} Produkt;
void pridej_kusy(Produkt *polozka, int navic) {
polozka->pocet += navic;
}
int main(void) {
Produkt mleko = {"Mléko", 24.9, 3};
pridej_kusy(&mleko, 2);
printf("%s: %d\n", mleko.nazev, mleko.pocet);
return 0;
}Program vypíše:
Mléko: 5polozka->pocet znamená přesně totéž co (*polozka).pocet: „člen pocet struktury, na kterou ukazuje polozka“. V praxi se píše šipka a budeme ji psát i my. Funkci voláte s adresou produktu, &mleko, jako u každého parametru, který je ukazatel.
Kdy tedy psát tečku a kdy šipku? Podívejte se, co stojí vlevo. Za strukturou (mleko, kosik[i] nebo parametr Produkt polozka) píšete tečku. Za ukazatelem na strukturu (parametr Produkt *polozka) píšete šipku. Když je spletete, překladač vás upozorní a správnou možnost vám i poradí:
main.c:10:12: error: member reference type 'Produkt *' is a pointer; did you mean to use '->'?
10 | polozka.pocet += navic;
| ~~~~~~~^
| ->Hláška říká, že Produkt * je ukazatel, a ptá se, jestli jste nechtěli použít ->. Obráceně skončí mleko->pocet chybou member reference type 'Produkt' is not a pointer; did you mean to use '.'?. A když ve volání zapomenete &, tedy pridej_kusy(mleko, 2), hláška zní passing 'Produkt' to parameter of incompatible type 'Produkt *'; take the address with &: funkce chce adresu, a tak jí ji předejte pomocí &.
Ukazatel se hodí, i když funkce strukturu nemění. Parametr typu struktura dostane při každém volání kopii celé struktury a některé struktury jsou velké. Ukazatel je jen jedna adresa. Když funkce strukturu jen čte, přidejte const, stejně jako u polí: ve funkci double cena_polozky(const Produkt *polozka) můžete číst polozka->cena, ale omylem ji nezměníte.
A co pole struktur? Funkce dostane, stejně jako u každého pole, přímo pole volajícího, ne jeho kopii. Ve funkci s parametrem Produkt kosik[] je kosik[i] struktura, a proto píšete tečku, kosik[i].pocet = 0;, a změna v poli volajícího zůstane. Když chcete funkci pridej_kusy předat jeden prvek pole, předejte jí jeho adresu: pridej_kusy(&kosik[1], 2);.
Jak psát:
Pokyny
Funkce zapis_vyhru má týmu za výhru přičíst 3 body, ale program vypíše Lvi: 5 bodů. Změňte funkci tak, aby dostala ukazatel na tým, použijte v ní -> a zavolejte ji s adresou proměnné lvi. Program pak vypíše Lvi: 8 bodů.
Pod zapis_vyhru napište funkci void zapis_zapas(Tym *tym, int vstrelene, int obdrzene) pro libovolný zápas. Když tým vstřelil víc gólů, než dostal, vyhrál a získá 3 body, za remízu (stejný počet gólů) získá 1 bod a za prohru nic. Na konci main (před return 0;) ji zavolejte dvakrát, zapis_zapas(&lvi, 2, 2) a zapis_zapas(&lvi, 3, 1), a pak tým znovu vypište stejným printf. Poslední řádek bude Lvi: 12 bodů.
Začněte programovat zdarma
7/9