Časté chyby

V této sekci najdete často se vyskytující chyby, na které můžete narazit, spolu s návodem, jak je vyřešit.

Záměna = a ==

  • Operátor = přiřazuje hodnotu do svého levého operandu a vyhodnotí se s hodnotou pravého operandu.
  • Operátor == porovnává dvě hodnoty a vyhodnotí se jako pravdivostní hodnota bool.

Je důležité tyto operátory nezaměňovat! Oba dva operátory jsou výrazy, takže se v něco vyhodnotí a i když je použijete špatně, tak často nedostanete chybovou hlášku, což jejich záměnu dělá ještě nebezpečnější.

int a = 0;
a = 5; // nastaví hodnotu `5` do proměnné `a`
a == 5; // porovná `a` s hodnotou `5`, vrátí hodnotu `true`, ale nic se neprovede

// podmínka se provede, pokud se `a` rovná `5`
if (a == 5) {}

// podmínka se provede vždy, výraz `a = 5` se vyhodnotí na `5` (`true`)
// zároveň při provedení podmínky se přepíše hodnota proměnné `a` na `5`
if (a = 5) {}

Záměna & s && nebo | s ||

  • Operátor & provádí bitový součin, očekává jako operandy celá čísla (např. int) a vrací celé číslo.
  • Operátor && provádí logický součin, očekává jako operandy pravdivostní hodnoty (bool) a vrací pravdivostní hodnotu.

Je důležité tyto operátory nezaměňovat. Jelikož bool lze implicitně převést na celé číslo a naopak, záměna těchto operátorů opět typicky nepovede k chybě při překladu, nicméně program nejspíše při jejich záměně nebude fungovat tak, jak má. Operátor & má zároveň větší přednost než &&, takže se výraz s tímto operátorem může vyhodnotit jinak, než očekáváte. Obdobná situace platí i u dvojice operátorů | (bitový součet) a || (logický součet).

int a = 3;
a & 4; // `0` 
a && 4; // `true`

// stejné jako a > (5 & a) < 6
if (a > 5 & a < 6) {}

Středník za for, while nebo if

Příkazy for, while nebo if za svou uzavírací závorkou ) očekávají jeden příkaz:

if (a > b) printf("%d", a);

nebo blok s příkazy:

if (a > b) {
    printf("%d", a);
    ...
}

Pokud však za závorku dáte rovnou středník (;), tak překladač to pochopí jako prázdný příkaz, který nic nedělá.

V následující ukázce se provede 10× prázdné tělo cyklu for a následně se jednou vypíše řetězec "Hello\n".

#include <stdio.h>

int main() {
    for(int i = 0; i < 10; i++); {
        printf("Hello\n");
    }
    return 0;
}

Zde opět středník za if reprezentuje prázdný příkaz, takže blok kódu s příkazem printf se provede vždy, i když je tato podmínka nesplnitelná.

#include <stdio.h>

int main() {
    if(0); {
        printf("Hello\n");
    }

    return 0;
}

Je to ekvivalentní, jako byste napsali

#include <stdio.h>

int main() {
    if (0) { /* zde není co provést */ }

    // tento blok se provede vždy
    {
      printf("Hello\n");
    }

    return 0;
}

Špatné volání funkce

Abychom zavolali funkci (tj. řekli počítači, aby začal vykonávat kód, který v ní je), napíšeme název funkce, závorky a do nich případně seznam argumentů. Při volání funkce už nezadáváme její návratový typ, ten se udává pouze u definice funkce.

int secti(int a, int b) {
    return a + b;
}
int main() {
    secti(1, 2);        // správně
    int secti(1, 2);    // špatně

    return 0;
}

Záměna ' s "

  • Apostrof (') slouží k zapsání (jednoho) znaku. Neukládejte do něj více znaků či celý text.
  • Uvozovky (") slouží k zapsání řetězce, tj. pole znaků ukončeného hodnotou 0.
char a = 'asd'; // špatně, více znaků v ''
char a = "asd"; // špatně, ukládáme řetězec do typu `char` (mělo by být `const char*`)

char a = 'x';               // správně
const char* str = "hello";  // správně

Špatná práce s ukazatelem

Ukazatele jsou čísla, která interpretujeme jako adresy v paměti. Můžete s nimi sice provádět některé aritmetické operace (například sčítání či odčítání), nicméně v takovém případě provádíte výpočet s adresou, ne s hodnotou, která je na dané adrese uložena.

Například v této funkci, která by měla přičíst hodnotu x k paměti na adrese ptr, musíte nejprve přistoupit k hodnotě na dané adrese (*ptr), a až k této hodnotě pak přičíst x:

void pricti_hodnotu(int* ptr, int x) {
    ptr += x;   // špatně, přičteme `x` k adrese `ptr`
    *ptr += x;  // správně, přičteme `x` k hodnotě na adrese `ptr` 
}

Vytváření spousty proměnných místo použití pole

Pokud potřebujete jednotně pracovat s větším počtem hodnot v paměti, použijte pole. Signálem, že jste měli použít pole, může být to, že máte ve funkci spoustu proměnných a pro rozlišení každé proměnné musíte přidat nový řádek kódu:

for (a0 = 0, a1 = 0, a2 = 0, a3 = 0, a4 = 0, a5 = 0; i < pocet; i++)
{
    if (hodnota == 1)
    {
        a0++;
    }
    else if (hodnota == 2)
    {
        a1++;
    }
    else if (hodnota == 3)
    {
        a2++;
    }
    ...
}

undefined reference to 'NAZEV'

Snažíte se zavolat funkci NAZEV, která nebyla nalezena v žádném objektovém souboru, který jste předali pro překlad. Ověřte si, že máte název volané funkce správně.