Black Friday je tu! Využij jedinečnou příležitost a získej až 80 % znalostí navíc zdarma! Více zde
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 1 - Úvod do programovacího jazyka C

Vítejte u první lekce on-line kurzu programování v jazyce C. Budeme se učit postupně, od úplných začátků až po složité konstrukce, ukazatele a např. práci se soubory. S trochou trpělivosti a vytrvalosti se z tebe tak stane dobrý programátor.

Hned na úvod je dobré zmínit, že jazyk C je již poměrně historický a i když se v praxi někde stále používá, jeho účely jsou velmi specifické. V akademické sféře se ještě často vyučuje jako prazáklad dnešních programovacích jazyků. Jeho naučením jistě nic nezkazíte, ale pokud nemáte nařízeno "odpíchnout se" právě od Céčka, myslíme si, že je možné a dokonce i vhodnější začít rovnou s nějakým moderním programovacím jazykem, jako jsou např. Java, C# .NET nebo na webu PHP.

Zrození jazyka C

Céčko navrhl Dennis Ritchie, tvůrce operačního systému UNIX, v 70. letech 20. století. Právě celý UNIXový kernel je v céčku naprogramovaný, což pravděpodobně stojí za jeho velkým rozšířením a také poukazuje na extrémní výkonnost tohoto jazyka. Céčko bylo dále portováno na nejrůznější platformy a vyvinula se z něj prakticky naprostá většina dnešních moderních programovacích jazyků. Těmto jazykům se někdy říká C-like, protože vycházejí z céčka a podobají se mu svou syntaxí (zápisem).

Abychom plně porozuměli jazyku C, ohlédněme se v dnešním dílu do minulosti a na to, jak se programovací jazyky vyvíjely. Bude pro nás totiž důležité pochopit, jak jazyk C pracuje a v čem je jeho přínos. Ke konci nahlédneme i do budoucnosti a vysvětlíme si, jaké má céčko oproti modernějším jazykům nevýhody.

Vývoj programovacích jazyků

1. generace jazyků - Strojový kód

Procesor počítače umí vykonávat jen omezené množství jednoduchých instrukcí, které jsou uloženy jako sekvence bitů - jsou to tedy čísla. Ta se mu obvykle zadávají v hexadecimální (šestnáctkové) soustavě. Instrukce jsou tak elementární, že umožňují pouze např. sčítání adres nebo skoky mezi instrukcemi. Nelze např. jednoduše sečíst dvě čísla, musíme se na čísla dívat jako na adresy v paměti a takové sečtení čísel zabere několik instrukcí. Program sčítající dvě čísla by vypadal např. takto:

2104
1105
3106
7001
0053
FFFE
0000

Instrukce se procesoru předloží v binární podobě. Takovýto kód je samozřejmě extrémně nečitelný a závisí na instrukční sadě daného CPU. Určitě v tomto jazyce nebude jednoduché tvořit nějaké programy, bohužel každý program musí být nakonec do tohoto jazyka přeložen, aby mohl být na procesoru počítače spuštěn.

Strojový kód

2. generace jazyků - Assembler

Assembler (zkráceně ASM) není o nic jednodušší, než strojový kód, ale je lidsky čitelný. Jedná se o strojový kód, ve kterém mají instrukce slovní označení (kód), čili si člověk nemusí pamatovat čísla. Kódy instrukcí se poté přeloží na výše uvedený strojový kód. Stejný program by v ASM vypadal takto:

ORG 100
LDA A
ADD B
STA C
HLT
DEC 83
DEC –2
DEC 0
END

Vidíme, že je to poněkud lidštější, ale stále nezasvěcení lidé vůbec netuší, jak program funguje (včetně mě).

3. generace jazyků

Jazyky třetí generace konečně nabízí uživateli určitou abstrakci nad tím, jak program vidí počítač. Zaměřují se na to, jak program vidí člověk. Naše čísla jsou vnímána již jako proměnné, zdrojový kód připomíná matematický zápis.

Sečtení dvou čísel by v jazyce C vypadalo takto:

int main(void)
{
    int a, b, c;
    a = 83;
    b = -2;
    c = a + b;
    return 0;
}

Všichni asi tušíme, co program dělá, sečte čísla 83 a -2 a výsledek uloží do proměnné c. U všech jazyků třetí generace je samozřejmě výhodou vysoká čitelnost a určitě si dokážete představit, jakou revoluci v programování jazyk přinesl, i když nebyl zdaleka prvním jazykem tohoto typu.

Kompilované jazyky

Kompilované jazyky mají tedy svůj zdrojový kód v jazyce, kterému lidé dobře rozumí. Tento zdrojový kód se samozřejmě musí přeložit do strojového kódu, aby ho bylo možné na procesoru spustit. Tento překlad zajišťuje překladač (kompiler), který přeloží najednou celý program do stroj. kódu.

Kompiler

Objektově orientované programování a Garbage Collector

V čem céčko bohužel zaostává je tzv. objektově orientované programování (zkráceně OOP), které umožňuje programovat aplikace velmi přehledně tak, že je rozdělíme do objektů, které spolu komunikují. Naprostá většina moderních jazyků OOP využívá a i když v céčku můžeme některé jeho principy nasimulovat, nedosáhneme všech jeho výhod. Naše programy budou bez OOP o něco rychlejší, ale na dnešních počítačích a při dnešní složitosti aplikací je stále důležitější čitelnost zdrojového kódu než úspora výkonu.

Podobná situace nastává u absence tzv. Garbage Collectoru, který se stará o čištění paměti po programu. Céčko nic takového nemá, čímž je rychlejší, ale mnohem, mnohem nebezpečnější, protože si po sobě musí uklízet sám programátor.

Jazyk C se někdy přirovnává k závodní formuli, se kterou byste do ulic běžně také nevjeli a použili byste ji jen na závodě, kde by ji řídil zkušený závodník. Pro běžné použití je vhodné použít klasické auto (rozumějte modernější programovací jazyk).

Specifika jazyka C

Zmiňme si v bodech ještě nějaké přednosti jazyka C:

  • Céčko je extrémně rychlý jazyk a proto se používá nejčastěji k tvorbě operačních systémů nebo vyšších programovacích jazyků (v Céčku je naprogramované např PHP nebo kompilátor C++).
  • Céčko je plně multiplatformní a dostupné na většině operačních systémů.
  • Céčko je jazyk se syntaxí (zápisem) podobnou naprosté většině dnešních programovacích jazyků.

Mnohem více je ovšem nevýhod:

  • Céčko není vysokoúrovňový jazyk, jak uvádějí některé starší materiály, i když jím v minulosti býval. Z dnešního pohledu je vnímán naopak jako jazyk nízký, tedy s vyšším výkonem, ale nízkým komfortem pro programátora. Proto není vhodné na běžné projekty, které nevyžadují extrémní výkon (a i tam se spíše hodí nástupce céčka, C++).
  • Céčko jako jazyk neumožňuje práci s textovými řetězci, což se obchází poněkud nepříjemně přes pole znaků a využívání dynamické paměti.
  • Céčko je jazyk neřízený a s přímým přístupem do paměti. To znamená, že se program můžete díky malé nepozornosti rozbít a může se to projevit v jeho úplně jiné části, která s chybou vůbec nesouvisí. Tyto chyby se velmi špatně hledají.
  • Céčko v sobě neobsahuje žádnou standardní knihovnu pro práci v grafickém rozhraní, avšak existují knihovny třetích stran.
  • Céčko nepodporuje objektově orientované programování, ale obsahuje struktury a hlavičkové soubory, s nimiž můžeme některé z výhod OOP nasimulovat.

V příští lekci, Instalace NetBeans a kompilátoru C, si nainstalujeme nástroje potřebné k programování v céčku a vytvoříme svůj první program.


 

Všechny články v sekci
Základní konstrukce jazyka C
Přeskočit článek
(nedoporučujeme)
Instalace NetBeans a kompilátoru C
Článek pro vás napsal David Čápka
Avatar
Uživatelské hodnocení:
139 hlasů
David je zakladatelem ITnetwork a programování se profesionálně věnuje 13 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David se informační technologie naučil na Unicorn University - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity

 

 

Komentáře
Zobrazit starší komentáře (25)

Avatar
DarkCoder
Člen
Avatar
DarkCoder:16.4.2019 12:48

Tvoje aplikace je rychlejší, ale typicky méně stabilní.

Nesmysl. Proč by musela být aplikace nutně méně stabilní?! Implementace vlastního ošetření na míru bude vždy lepší, jen si vyžaduje dokonalou znalost toho co se požaduje, což v některých případech ale může být velmi obtížné a časově náročné. Vše má své pro a proti.

Odpovědět
16.4.2019 12:48
"Chceš-li předávat své znalosti, měj kvalitní podklady."
Avatar
Ondra Hájek
Člen
Avatar
Ondra Hájek:27.6.2020 15:01

Ahoj, všiml jsem si, že jste rozdělili C/C++ na dva samostatné kurzy.
Bude někde k přečtení článek o přechodu z jazyka C na jazyk C++?
Zrovna když jsem to začal číst, tak jste to předělali a už to nemohu najít.
Díky moc, Ondra.

 
Odpovědět
27.6.2020 15:01
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Ondra Hájek
DarkCoder:27.6.2020 15:23

Článek se nachází v sekci C++
Přechod od C k C++

Odpovědět
27.6.2020 15:23
"Chceš-li předávat své znalosti, měj kvalitní podklady."
Avatar
Magda
Člen
Avatar
Magda :3.10.2020 20:38

Ahoj, díky za Váš web, myslím, že mi moc pomáhá. V "jarní koroně", kdy jsem musela zůstat s dětmi doma jsem postupně přišla více do styku s počítačem, tabletem... a taky na nápad, že bych to zkusila s programováním. Tak jsem se přihlásila po letech zase do školy ( VŠB obor informatika) a taky objevila tenhle web. Podle zdejší rady jsem začala s PHP, ale ve škole chtějí C a Haskell, tak to snad s Vaší pomocí zvládnu :-) Díky!

 
Odpovědět
3.10.2020 20:38
Avatar
Josef Jana Aulikovi:15.10.2020 23:04

Zdravím.
Rozhodl jsem se na starý kolena naučit programovat mikroprocesory a tak jsem se pro začátek pustil do céčka. Programování mne celkem baví, ale nějak jsem se s ním v životě míjel.
Kdysi dávno ještě na škole jsem začínal s historickým Fortranem a tím to skončilo. Až v nedávné době jsem dělal pro syna různé aplikace ve Visual Basicu v Excelu. Takže nějaké zkušenosti mám, ale potřebuji si osvojit další jazyk a tento kurz se mi pro tento účel zamlouvá.
Zatím jsem dloubnul i do C++ a C#, ale nejdříve se pustím do tohoto.
Takže díky za tuto možnost. Pepa.

 
Odpovědět
15.10.2020 23:04
Avatar
Jozef Vendel
Člen
Avatar
Jozef Vendel:9.12.2021 19:32

Ahoj potreboval by som poradit alebo naviest ak mozes, s myslienkou ako by som mohol urobit to ze, mam napr. pole

int numbers[] = {5, 16, 34, 60, 61, 52, 32};

A ja by som potreboval ich v C pod sebou scitat, takto:
32

52
                  61
                 60
                34
               16
               5
              --------
               7006652

Problem mam stym, ze neviem ako mam riesit to, ked pristupim k prvku napr. numbers[0] co je 61, ako mam pouzit len 1 pre pripocitanie ku numbers[1] ale len 0.

Editováno 9.12.2021 19:32
 
Odpovědět
9.12.2021 19:32
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Jozef Vendel
DarkCoder:9.12.2021 22:09

Výsledek je dán součtem čísel v poli braných odzadu, kde každé číslo je modifikováno násobkem hodnoty 10 na (velikost pole - index - 1).
Tedy:
32x10na0 + 52x10na1 + 61x10na2 + 60x10na3 + 34x10na4 + 16x10na5 + 5x10na6 = 7006652

Odpovědět
9.12.2021 22:09
"Chceš-li předávat své znalosti, měj kvalitní podklady."
Avatar
Jozef Vendel
Člen
Avatar
Odpovídá na DarkCoder
Jozef Vendel:9.12.2021 22:59

Nevies preco mi vypocitava zly vysledok ?

#include <stdio.h>
#include <math.h>

#define SIZE 7

int main()
{
    int numbers[] = {5, 16, 34, 60, 61, 52, 32};
    int pomocny;
    int vysledok = 0;


    for(int i = 0; i < SIZE; i++){
        numbers[i] = numbers[i] * 10;
    }


   for(int i = 0; i < SIZE; i++){
        pomocny = pow(numbers[SIZE - i - 1], i);
        vysledok = + pomocny;


    }


  printf("vysledok: %d\n", vysledok);


    return 0;
}
 
Odpovědět
9.12.2021 22:59
Avatar
Jozef Vendel
Člen
Avatar
Odpovídá na Jozef Vendel
Jozef Vendel:9.12.2021 23:02

zaujimave

Editováno 9.12.2021 23:04
 
Odpovědět
9.12.2021 23:02
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Jozef Vendel
DarkCoder:10.12.2021 3:08

Dříve, než zde ukáži řešení, tak pár rad k tvému kódu:

  • V C, pokud funkce nepřebírá argumenty, používá se klíčové slovo void.
  • Nepáruješ makro vyjadřující velikost pole s polem.

Buď použij makro jako velikost pole, např:

#define SIZE 7
int numbers[SIZE] = {5, 16, 34, 60, 61, 52, 32};

nebo si velikost pole zjisti pomocí operátoru preprocesoru sizeof

int numbers[] = {5, 16, 34, 60, 61, 52, 32};
int len = sizeof(numbers) / sizeof(numbers[0]);
  • Funkce pow() přebírá dva argumenty typu double, kde první představuje základ, druhý exponent a vrací typ double. Je dobré přetypovávat na typ, který funkce očekává a na typ na který převádíme.
  • pro navyšování hodnoty proměnné se používá operátor +=. Překladač při zpracování příkazu
vysledok = + pomocny;

nezahlásil chybu, neboť si nevědomky použil unární +. Což mělo za následek přiřazení proměnné pomocny proměnné vysledok.

Zde je řešení:

#include <stdio.h>
#include <math.h>

int main(void){
        const int nums[] = { 5, 16, 34, 60, 61, 52, 32 };
        int len = sizeof(nums) / sizeof(nums[0]);
        int sum = 0;

        for (int i = 0, offset = len - 1; i < len; i++) {
                sum += (nums[i] * (int)pow(10.0, offset - (double)i));
        }

        printf("Vysledek: %d\n", sum);
        return 0;
}

Velikost pole je určena pomocí operátoru preprocesoru sizeof, což umožňuje snazší testování přidáváním nebo ubíráním počtu čísel v poli. Výraz len - 1 je konstanta, jejíž hodnota je uložena do proměnné offset. Důvodem je optimalizace, je zbytečné provádět vyhodnocování aritmetického výrazu, který je konstantou v každé iteraci cyklu.

Odpovědět
10.12.2021 3:08
"Chceš-li předávat své znalosti, měj kvalitní podklady."
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 35. Zobrazit vše