Menu

Składnia C: struktura programu w C wyjaśniona krok po kroku

Każdy program w C ma ten sam szkielet: dyrektywy include, funkcję main, instrukcje zakończone średnikiem i bloki w nawiasach klamrowych. Oto, co robi każda część i jakie reguły kompilator naprawdę egzekwuje.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

C ma bardzo mało składni do nauczenia: około 32 słów kluczowych i garść reguł interpunkcji. Prawie każdy program, jaki kiedykolwiek napiszesz, ma ten sam zewnętrzny kształt, więc warto raz, starannie rozebrać go na części.

Najmniejszy kompletny program

To się kompiluje, uruchamia i nic nie robi:

Bez include, bez wyjścia, bez szablonowej klasy czy modułu. main to punkt wejścia: gdy system operacyjny uruchamia twój program, wywołuje main. Gdy main zwraca wartość, program się kończy, a zwrócona wartość jest kodem wyjścia.

Dodaj wypisywanie, a będziesz potrzebować jednego include:

Dyrektywy preprocesora

Linie zaczynające się od # są obsługiwane przed właściwą kompilacją, przez preprocesor. Nie są instrukcjami C i nie mają średnika.

#include <stdio.h>    /* nagłówek biblioteki standardowej: nawiasy ostre */
#include "myutils.h"  /* twój własny nagłówek: cudzysłowy, szukany najpierw lokalnie */
#define MAX 100       /* makro: MAX jest zastępowane przez 100 wszędzie poniżej */

#include to dosłowne wklejenie tekstu: cała zawartość wskazanego pliku trafia w to miejsce. stdio.h zawiera deklarację printf, dzięki której kompilator wie, jakie argumenty przyjmuje printf. Pomiń include, a dostaniesz implicit declaration of function 'printf'.

Różnica między nawiasami ostrymi a cudzysłowami dotyczy miejsca, w którym kompilator szuka: <...> oznacza systemowe katalogi nagłówków, a "..." każe najpierw szukać obok bieżącego pliku.

Funkcja main

int main(void) {
    return 0;
}

Cztery części, każda coś znaczy:

  • int: typ zwracany przez main. Wartość trafia do systemu operacyjnego jako kod wyjścia, gdzie 0 oznacza sukces.
  • main: zarezerwowana nazwa, którą wywołuje środowisko uruchomieniowe. Każdy program C działający pod systemem operacyjnym ma dokładnie jedną taką funkcję.
  • (void): lista parametrów. void oznacza tu "nie przyjmuje argumentów". Zapis main() jest dozwolony, ale słabszy: puste nawiasy w C oznaczają "nieokreślone parametry", co wyłącza sprawdzanie argumentów.
  • { ... }: ciało funkcji.

Druga standardowa forma przyjmuje argumenty wiersza poleceń:

int main(int argc, char *argv[]) { ... }

Używaj int main(void), dopóki ich nie potrzebujesz.

Instrukcje i średniki

Instrukcja to pojedyncze polecenie i kończy się średnikiem.

Cztery instrukcje, cztery średniki. Średnik jest terminatorem, a nie separatorem: ostatnia instrukcja w bloku też go potrzebuje.

Co nie ma średnika:

#include <stdio.h>        /* linia preprocesora: bez średnika */

int add(int a, int b) {   /* nagłówek definicji funkcji: bez średnika */
    return a + b;
}                         /* nawias zamykający funkcji: bez średnika */

if (x > 0) {
    ...
}                         /* nawias zamykający bloku sterującego: bez średnika */

Przypadek, który gryzie każdego, to średnik tam, gdzie powinno być ciało:

if (score > 90);              /* BUG: ten ; to całe ciało if */
    printf("Doskonale!\n");   /* wykonuje się zawsze, niezależnie od score */

To całkowicie poprawny C. if steruje pustą instrukcją, a printf to po prostu kolejna linia w sekwencji. -Wall ostrzega przed tym; kompilator cię nie zatrzyma.

Bloki i nawiasy klamrowe

Nawiasy klamrowe grupują instrukcje w blok, który liczy się jako jedna instrukcja wszędzie tam, gdzie oczekiwana jest instrukcja.

Nawiasy są opcjonalne, gdy ciało to jedna instrukcja, ale ich pomijanie to przepis na słynne błędy: dodasz później drugą linię, a ona po cichu wypadnie z if. Zawsze używaj nawiasów.

Bloki tworzą też zasięg: zmienna zadeklarowana wewnątrz { ... } przestaje istnieć przy nawiasie zamykającym.

Wielkość liter i białe znaki

C rozróżnia wielkość liter wszędzie. total, Total i TOTAL to trzy osobne nazwy. Wszystkie słowa kluczowe są pisane małymi literami, więc Int, Return i Printf to błędy, a komunikat o błędzie dla Printf jest mylący, bo kompilator zakłada, że chodziło ci o jakąś funkcję, o której nigdy nie słyszał.

Białe znaki są za to prawie całkowicie dowolne. Kompilator traktuje każdy ciąg spacji, tabulatorów i znaków nowej linii jako jeden separator. To jest poprawne:

int    main ( void )
{
    printf
    ( "Czesc\n" ) ;
    return 0 ;
}

I to też:

int main(void){printf("Czesc\n");return 0;}

Oba kompilują się identycznie. Skoro kompilatorowi to obojętne, formatowanie jest wyłącznie dla ludzi, a konwencjonalny układ (jedna instrukcja na linię, cztery spacje albo jeden tabulator na poziom zagnieżdżenia, nawias otwierający w tej samej linii) warto stosować, bo każdy kod w C, który przeczytasz, będzie używał czegoś bardzo podobnego.

Dwa miejsca, w których białe znaki mają znaczenie: nie możesz rozdzielić słowa kluczowego ani identyfikatora (in t to nie int) i nie możesz wstawić znaku nowej linii do zwykłego literału stringowego.

Identyfikatory: zasady nazewnictwa

Identyfikator to każda nazwa, którą wybierasz: zmienne, funkcje, typy. Zasady:

  • Składa się z liter, cyfr i podkreślników.
  • Nie może zaczynać się od cyfry. total2 jest w porządku, 2total już nie.
  • Nie może być słowem kluczowym: żadnej zmiennej o nazwie int, for czy return.
  • Wielkość liter ma znaczenie.
  • Nazwy zaczynające się od podkreślnika i wszystko, co ma dwa podkreślniki z rzędu, są zarezerwowane dla implementacji: nie wymyślaj takich.
int score;        /* dobrze */
int total_items;  /* dobrze: snake_case to konwencja w C */
int _hidden;      /* dozwolone, ale zarezerwowane: unikaj */
int 2fast;        /* błąd */
int float;        /* błąd: słowo kluczowe */

W pełni opisany program

Wszystko powyższe w jednym miejscu:

Kolejność czytania ma tu znaczenie: with_tax jest zdefiniowana przed tym, jak main jej używa. C czyta plik od góry do dołu, więc funkcja musi być zadeklarowana, zanim zostanie wywołana. Zdefiniuj ją wcześniej albo napisz na górze prototyp funkcji i zdefiniuj ją później.

Najczęściej zadawane pytania

Jaka jest podstawowa struktura programu w C?

Najpierw dyrektywy preprocesora (#include <stdio.h>), potem definicje funkcji, z których jedna musi być main. Wewnątrz funkcji instrukcje kończą się średnikiem, a bloki są otoczone nawiasami klamrowymi. Minimalny program to #include <stdio.h> plus int main(void) { return 0; }.

Dlaczego int main(void), a nie po prostu main()?

int to typ zwracany przez main, czyli kod wyjścia, który program oddaje systemowi operacyjnemu. (void) jawnie mówi, że main nie przyjmuje argumentów. Zapis main() z pustymi nawiasami to starszy styl, który nic nie mówi kompilatorowi o parametrach, więc ten mniej sprawdza.

Czy wszystkie instrukcje w C wymagają średnika?

Każda instrukcja tak, ale nie każda linia. Dyrektywy preprocesora (#include, #define), definicje funkcji i nawias zamykający bloku albo if/for/while go nie mają. Zabłąkany średnik po if (x) to poprawny C, który po cichu sprawia, że ciało wykonuje się bezwarunkowo.

Czy C rozróżnia wielkość liter?

Tak, całkowicie. count, Count i COUNT to trzy różne identyfikatory, a Int to nie słowo kluczowe int. Wszystkie słowa kluczowe C są pisane małymi literami, więc wielka litera w Return albo Printf powoduje błąd.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ