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.voidoznacza tu "nie przyjmuje argumentów". Zapismain()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.
total2jest w porządku,2totaljuż nie. - Nie może być słowem kluczowym: żadnej zmiennej o nazwie
int,forczyreturn. - 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.