Podstawy języka C
Język C i inne języki programowania
Pierwszy standard (faktyczny)
rozprowadzany z systemem Unix System V
Brian W. Kernighan, Denis M. Ritchie: The C Programming Language (Prentice-Hall 1978, polskie wydanie: Język C, WNT 1987)
często używany skrót: standard K&R
Aktualny standard (formalny)
opracowany przez Amerykański Narodowy Instytut Standaryzacji (ANSI)
przyjęty w grudniu 1989
Brian W. Kernighan, Denis M. Ritchie: The C Programming Language, Second Edition (Prentice-Hall 1988, polskie wydanie: Język ANSI C, WNT 1994)
Lokalizacja języka C wśród języków programowania
najwyższy poziom - Ada, Modula-2, Pascal, COBOL, FORTRAN, BASIC
średni poziom - C++, C, FORTH
najniższy poziom - asembler
Charakterystyka języka C
stanowi połączenie elementów języka programowania wysokiego poziomu z funkcjonalnością asemblera
umożliwia działania na pojedynczych bitach, bajtach i adresach - podstawowych obiektach funkcjonowania komputera
jest przenośny (ang. portable) - łatwo jest przystosować tekst źródłowy do różnych typów komputerów
jest czytelny (ang. readable) - łatwo można stwierdzić, co program robi
W języku C |
W asemblerze |
a = b+c-2 ; |
LOAD b, %r0 |
|
LOAD c, %r1 |
|
ADD %r0, %r1 |
|
SUB &2, %r1 |
|
STORE %r1, a |
1.2. Program w języku C
1.2.1. Przykład programu w języku C
/* mój pierwszy program w C */ komentarz
#include <stdio.h> dyrektywa preprocesora
int main() nagłówek funkcji
{
printf("Witam\n"); treść funkcji
return 0;
}
Każdy program w języku C jest zbudowany z pewnej liczby funkcji, czyli samodzielnych podprogramów. Każdy program ma co najmniej jedną funkcję.
Funkcja jest to zestaw instrukcji, które realizują określone zadanie.
W każdym programie musi istnieć funkcja o nazwie main - jest ona wywoływana jako pierwsza po rozpoczęciu wykonywania programu.
Funkcja main() zawiera plan działań programu, składający się z wywołań innych funkcji.
Elementy składowe programu
/* ... */ |
Komentarz języka C; komentarzem jest wszystko wewnątrz znaków /* i */; może to być kilka wierszy. W kompilatorze Borlanda można również stosować komentarze z języka C++. Taki komentarz jest poprzedzony znakami //; może to być tylko jeden wiersz. |
#include |
Dyrektywa preprocesora - określa dołączany do programu plik z informacjami potrzebnymi do prawidłowej kompilacji i wykonania programu. #include <stdio.h> dołącza plik potrzebny dla funkcji printf(). stdio.h jest skrótem od: standard input-output header file - plik nagłówkowy standardowego wejścia-wyjścia. |
int main(){ } |
Definicja funkcji; funkcja ma nagłówek i treść (instrukcje) zawartą między nawiasami klamrowymi. Typ funkcji określa rodzaj wartości, który funkcja zwraca po wykonaniu; int oznacza, że funkcja zwraca wartość całkowitą. |
printf("Witam\n"); |
Wywołanie funkcji bibliotecznej printf() w celu wydrukowania tekstu. Symbol \n oznacza przejście do nowego wiersza. |
return 0; |
Funkcja main zwraca wartość 0 (liczba całkowita) do systemu operacyjnego - oznacza to, że program wykonał się prawidłowo i do końca. |
1.2.2. Struktura programu w języku C
1.2.3. Kompilacja programu
Program źródłowy (ang. source code): dający się odczytać tekst programu.
Kod wynikowy (ang. object code): przekład tekstu źródłowego programu na język komputerowy.
Program wykonywalny (ang. executable program): program binarny gotowy do wykonania
Kompilator (ang. compiler): program, który wczytuje cały tekst źródłowego i przekłada go na język komputerowy
Konsolidator (ang. linker): program, który łączy oddzielnie skompilowane funkcje w jeden program; wiąże on kod wynikowy z funkcjami biblioteki C
Biblioteka (ang. library): plik zawierający funkcje standardowe, z których można korzystać w programie. Podczas wywołania takiej funkcji kompilator zapamiętuje jej nazwę, zaś konsolidator łączy kod wynikowy tekstu źródłowego z kodem istniejącym w bibliotece.
1.3. Przegląd konstrukcji języka C
1.3.1. Zmienne i stałe
Dane programu zapisywane są w postaci zmiennych (ang. variable) lub stałych (ang. constant).
Zmienna to pewien obszar pamięci o nadanej symbolicznej nazwie, w którym można przechowywać dane i z którego można te dane odczytać.
Stała (literał, ang. literal constant) to dana zapisana w sposób dosłowny (liczba, znak, tekst), nie zmienia się podczas wykonywania programu.
Przykład:
1.3.2. Identyfikatory
Identyfikator (ang. identifier) to nazwa służąca do oznaczania zmiennych, funkcji i innych obiektów zdefiniowanych przez użytkownika.
Nazwa może zawierać litery, cyfry, znak podkreślenia.
Nazwa może rozpoczynać się od litery lub znaku podkreślenia.
Rozróżniane są małe i wielkie litery.
Nazwa nie może być słowem kluczowym języka C.
Standard ANSI ogranicza rozmiar nazw do 31 znaków.
Przykłady:
Poprawne nazwy |
Niepoprawne nazwy |
licznik |
1licznik |
test12 |
test-12 |
test_12 |
test..12 |
1.3.3. Podstawowe typy danych
Dane (zmienne i stałe) przechowywane są w pamięci jako ciąg bitów.
Typ danych - nadaje znaczenie ciągowi bitów o określonym adresie i długości:
określa ile pamięci potrzeba do przechowania danej,
jakie operacje mogą być wykonane na danej,
jak te operacje są interpretowane.
W C istnieje pięć podstawowych typów danych:
char (znakowy) - do przechowywania znaków ASCII i małych liczb całkowitych
int (całkowity) - do przechowywania liczb całkowitych
float (zmiennoprzecinkowy) - do przechowywania liczb rzeczywistych
double (zmiennoprzecinkowy podwójnej długości) - do przechowywania liczb rzeczywistych
void (pusty) - do zastosowań specjalnych, np. dla funkcji nie zwracających wartości
Typ i nazwę zmiennej nadaje użytkownik za pomocą odpowiedniej deklaracji, biorąc pod uwagę dane, które mają być w zmiennej przechowywane.
Przykład:
int licznik; /* zmienna typu int o nazwie licznik
( może przechowywać liczby całkowite
z zakresu określonego typem int) */
double suma; /* zmienna typu double o nazwie suma
(może przechowywać liczby rzeczywiste) */
char c; /* zmienna typu char o nazwie c
(może przechowywać znaki lub małe liczby całkowite)*/
Typ stałej określa użytkownik odpowiednio zapisując daną w instrukcji.
1.3.4. Słowa kluczowe
W języku C słowa o zastrzeżonym znaczeniu nazywane są słowami kluczowymi (ang. key words). Jest ich 32.
Tych słów nie można używać jako nazwy zmiennych i innych obiektów.
Przykłady słów kluczowych:
int - używane jest do określenia typu całkowitego
if - instrukcja wyboru
sizeof - operator
1.3.5. Wyrażenia
Wyrażenie (ang. expression) to kombinacja stałych, zmiennych i operatorów stosowanych do zapisu wykonywanych obliczeń.
Wyrażenie ma wartość i jest określonego typu.
Przykłady wyrażeń:
2 * 3 /* mnożenie dwóch stałych:
wartość 6, typ int */
i + 1 /* dodawania stałej i zmiennej typu int:
wartość zależy od i, typ int */
5 + h*6 /* h jest typu int; wartość zalezy od h,
typ int */
0.5 * sqrt(2.) /* sqrt - pierwiastek;
wartość 0.5*1.41, typ double */
1.3.6. Operatory arytmetyczne
Symbol |
Znaczenie |
* |
Mnożenie |
/ |
Dzielenie |
% |
Reszta z dzielenia (dzielenie modulo) |
+ |
Dodawanie |
- |
Odejmowanie |
Operatory arytmetyczne można stosować do wszystkich podstawowych typów.
Ograniczenia:
operator dzielenia modulo może być stosowany tylko do typów całkowitych
Operatorom nadany jest priorytet, aby operacje arytmetyczne były realizowane w sposób jednoznaczny.
W tabeli linią poziomą oddzielono operatory o różnych priorytetach.
Operatory *, / i % mają wyższy priorytet niż operatory + i - .
Do zmiany kolejności wykonywania działań można używać nawiasów.
Przykład:
2 + 3 * 5 daje w wyniku 17
(2 + 3) *5 daje w wyniku 25
Dwie arytmetyki:
arytmetyka liczb całkowitych: wynik działania na liczbach całkowitych jest liczbą całkowitą
arytmetyka liczb rzeczywistych: wynik działania na liczbach rzeczywistych jest liczbą rzeczywistą
w przypadku mieszanym (liczba całkowita i liczba rzeczywista) wynik jest liczbą rzeczywistą.
Przykład:
1 / 2 daje w wyniku 0
4 / 3 daje w wyniku 1
1./ 2 daje w wyniku 0.5
1./2. daje w wyniku 0.5
1.3.7. Operatory relacji
Symbol |
Znaczenie |
|
< |
mniejsze |
|
<= |
mniejsze lub równe |
|
> |
większe |
|
>= |
większe lub równe |
|
== |
równe |
|
!= |
nierówne |
Pomiędzy dwoma wyrażeniami może występować 6 relacji.
W tabeli linią poziomą oddzielono operatory o różnych priorytetach.
Wszystkie operatory relacji mają niższy priorytet od operatorów arytmetycznych.
Każda operacja porównania generuje wynik 1, jeżeli warunek jest spełniony lub 0 jeżeli warunek nie jest spełniony.
Przykład 1:
załóżmy, że x ma wartość 2, zaś y wartość 5
x < y daje w wyniku 1
Przykład 2:
wyrażenie x + 1 < y * 2 jest interpretowane jako (x+1) < (y*2)
1.3.8. Instrukcje
Instrukcja (ang. statement) opisuje czynności wykonywane w programie.
Instrukcja pojedyncza jest zakończona średnikiem.
Najprostszą instrukcją jest instrukcja pusta. Ma ona postać:
;
Nie powoduje ona wykonania żadnej czynności i jest wprowadzona przede wszystkim do ujednolicenia opisu pewnych konstrukcji.
Inny przykład instrukcji pojedynczej to:
i=2; /* przypisanie wartości 2 zmiennej i */
printf("Witamy\n"); /* wywołanie_funkcji */
Ciąg instrukcji umieszczony w nawiasach klamrowych tworzy instrukcję złożoną (ang. compound statement). Nazywana jest ona również blokiem.
Instrukcji złożonej nie trzeba kończyć średnikiem.
Przykład instrukcji złożonej:
{
printf("zwiększ i o 1\n");
i=i+1;
}
Instrukcję złożoną traktuje się tak, jak pojedynczą instrukcję. Można ją umieścić wszędzie tam, gdzie może pojawić się pojedyncza instrukcja.
1.3.8.1. Instrukcja przypisania
Ogólna postać instrukcji przypisania (ang. assignment statement):
nazwa_zmiennej = wyrażenie;
Przykłady:
i=1;
i=(2+3)*5;
i=2+3*5;
k=i+j;
1.3.8.2. Instrukcja wywołania funkcji
Ogólna postać instrukcji wywołania funkcji (ang. function call):
nazwa_funkcji(parametr1, parametr2,...,parametrN);
Przykłady:
printf("Witamy\n");
a=sqrt(2.); /* pierwiastek kwadratowy */
b=pow(12.0,5.); /* 12 do potęgi 5 */
1.3.8.3. Instrukcja wyboru
Instrukcja wyboru (warunkowa, ang. selection) w zależności od wyniku testu warunkowego pozwala przejść do określonego fragmentu programu.
Wynikiem testu może być wartość prawda lub nieprawda.
W języku C:
prawda jest dowolną liczbą różną od zera
nieprawda jest liczbą 0.
W C istnieją dwa typy instrukcji wyboru: if i switch.
Przykład 1: pojedynczy wybór if
if (wyrażenie) instr_1; // Wykonaj, gdy prawda: // wartość wyrażenia // jest różna od zera
|
if (punkty >= 15 ) printf("Zaliczone\n)";
|
Wykonanie:
Oblicz wartość wyrażenia.
Jeśli wartość to prawda, wykonaj instrukcję. W przeciwnym wypadku przejdź do instrukcji następującej po instrukcji wyboru.
Przykład 2: Podwójny wybór if -else
if (wyrażenie)
instr_1 // Wykonaj, gdy prawda
else
instr_2 // Wykonaj, gdy fałsz:
// wartość wyrażenia równa zeru
1.3.8.4. Instrukcja iteracyjna
Instrukcja iteracyjna (ang. iteration) powoduje wielokrotne wykonanie pewnej grupy instrukcji.
Jest nazywana również instrukcją pętli (ang. loop).
Do instrukcji iteracyjnych należą: while, for i do/while.
Przykład - instrukcja while: powtarzaj instrukcje, dopóki wyrażenie jest prawdą.
while (wyrażenie) while (x<y)
instrukcja x=x+1;
Oblicz wyrażenie.
Jeśli jego wartość jest różna od zera (prawda), wykonaj instrukcje.
Wróć na początek while i ponownie oblicz wyrażenie.
Powtarzaj ten cykl, aż do chwili, w której wartość wyrażenia stanie się zerem (fałsz). Wtedy przejdź do instrukcji następującej po pętli.
1.4. Instrukcje wejścia - wyjścia
1.4.1. Wyświetlanie danych na ekranie monitora - printf()
#include <stdio.h>
int main()
{
int suma;
suma=2+5;
printf("Wynik dodawania 2+5 wynosi %d\n",suma);
return 0;
}
printf("Witamy\n");
printf("Pole kola o promieniu %f=%f \n",r,pow);
printf("Pierwiastek %lf wynosi %lf\n",liczba, sqrt(liczba));
printf("Kwadrat liczby %d to %d\n", liczba, liczba*liczba);
Argumenty funkcji printf()
Pierwszy argument (łańcuch formatu): określa sposób wyświetlania wszystkich następnych argumentów.
Składa się z dwóch rodzajów elementów:
znaków, które mają być wyświetlone w nie zmienionej postaci ("Wynik dodawania 2+5 wynosi ")
specyfikatorów przekształceń, które określają sposób wyświetlania wartości kolejnych argumentów; specyfikator przekształcenia rozpoczyna się od znaku %,
za którym występuje kod formatu (%d)
Kolejne argumenty określają co ma być wyświetlone. Mogą to być zmienne, funkcje zwracające wartość, wyrażenia.
Liczba argumentów znajdujących się za łańcuchem formatu musi być dokładnie taka sama, jak liczba specyfikatorów formatu.
Specyfikatory przekształceń dla podstawowych typów danych:
%d - typ int: liczba całkowita ze znakiem w systemie dziesiętnym
%f - typ float: liczba zmiennoprzecinkowa w systemie dziesiętnym
%e - typ float: liczba zmiennoprzecinkowa w zapisie wykładniczym
%lf - typ double: liczba zmiennoprzecinkowa w systemie dziesiętnym
%le - typ double: liczba zmiennoprzecinkowa w zapisie wykładniczym
%c - typ char: pojedynczy znak
%s - tablica znakowa zakończona znakiem NULL: napisy
Ze specyfikatorami przekształceń mogą wystąpić modyfikatory formatu określające:
minimalną szerokość pola
dokładność - czyli liczbę wyświetlanych pozycji dziesiętnych
wyrównanie wyświetlanych danych - dosunięcie do lewej lub prawej strony pola
1.4.2. Wczytywanie danych z klawiatury - scanf()
#include <stdio.h>
int main()
{
int liczba, kwadrat;
printf("Wpisz liczbe calkowita: ");
scanf("%d", &liczba);
kwadrat=liczba*liczba;
printf("Kwadrat %d to: %d\n",liczba, kwadrat);
return 0;
}
Argumenty funkcji scanf()
Pierwszy argument (łańcuch formatu) określa sposób wczytywania wartości do zmiennych wskazywanych przez zmienne występujące na liście argumentów.
Pozostałe argumenty wskazują zmienne, do których są wczytywane wartości.
Funkcja buforuje wiersze danych wejściowych, czyli czeka na naciśnięcie klawisza Enter.
Specyfikatory formatu dla podstawowych typów danych:
%d - typ int: liczba całkowita ze znakiem w systemie dziesiętnym
%ld - typ long int: liczba całkowita ze znakiem w systemie dziesiętnym
%f - typ float: liczba zmiennoprzecinkowa w systemie dziesiętnym
%e - typ float: liczba zmiennoprzecinkowa w zapisie wykładniczym
%lf - typ double: liczba zmiennoprzecinkowa w systemie dziesiętnym
%le - typ double: liczba zmiennoprzecinkowa w zapisie wykładniczym
%c - typ char: pojedynczy znak
1.4.3. Wczytywanie i wyświetlanie pojedynczych znaków - getchar() i putchar()
Każdy wiersz wczytywanych danych składa się z zera lub więcej znaków, po których następuje znak nowego wiersza.
Cały tekst to strumień znaków podzielony na wiersze.
Funkcja getchar() pobiera ze strumienia znaków następny znak i zwraca jego wartość.
Przykład:
c=getchar(); /* wartość c to następny znak z wejścia */
Funkcja putchar(c) wypisuje znak c na ekranie.
Przykład:
c='*';
putchar(c); /* wyświetla gwiazdkę na ekranie */
Przykład programu:
#include <stdio.h>
/* Zlicz znaki w tekście zakończonym kropką */
int main() {
char c;
int licznik;
licznik=0;
c=getchar();
while(c!='.') {
licznik=licznik+1;
c=getchar();
}
printf("%d\n",licznik);
return 0;
}
1.5. Dyrektywy preprocesora
Tekst źródłowy programu może zawierać instrukcje dla kompilatora. Są to dyrektywy preprocesora (ang. preprocessor directives).
Wszystkie dyrektywy rozpoczynają się od znaku #.
Każda dyrektywa musi się znajdować w oddzielnym wierszu.
1.5.1. Dyrektywa #include
Poleca kompilatorowi włączenie w miejscu jej występowania innego pliku źródłowego.
Składnia:
#include <nazwa_pliku>
#include "nazwa_pliku"
Znaki < > używane są do włączania standardowych plików nagłówkowych; poszukiwane są one w katalogach określonych w konfiguracji kompilatora.
Znaki " " oznaczają, że najpierw plik jest poszukiwany w bieżącym katalogu, gdy nie zostanie znaleziony przeszukiwane są katalogi standardowe implementacji.
1.5.2. Dyrektywa #define
Definiuje nazwę i ciąg znaków, który będzie zamiast niego wstawiany w każdym miejscu pliku źródłowego.
Składania:
#define nazwa ciąg_znaków
Przykład:
#define PI 3.14159
main() {
....
obwod=2*PI*r;
}
1.6. Przykłady programów
/* Program oblicza powierzchnie koła - wersja 1 */
#include <stdio.h>
#define PI 3.14
int main()
{
float r,pow;
r=1;
pow=PI*r*r;
printf("Pole kola o promieniu %f=%f \n",r,pow);
return 0;
}
/* Program oblicza powierzchnie koła - wersja 2 */
#include <stdio.h>
#define PI 3.14
int main()
{
double r,pow;
printf("Wpisz promien kola: ");
scanf("%lf",&r);
pow=PI*r*r;
printf("Pole kola o promieniu %lf=%lf \n",r,pow);
return 0;
}
/* Program oblicza pierwiastek kwadratowy liczby */
#include <stdio.h>
#include <math.h>
int main()
{
double liczba;
printf("Wpisz liczbe dodatnia: ");
scanf("%lf",&liczba);
if (liczba > 0)
printf("Pierwiastek z liczby %lf wynosi %lf\n",
liczba, sqrt(liczba));
else
printf("Wpisana liczba %lf nie jest dodatnia\n",liczba);
return 0;
}
/* Liczba spacji w zdaniu */
#include <stdio.h>
int main() {
int c, spacje=0;
printf("Wpisz zdanie:\n");
c=getchar();
while (c != '\n') {
if (c == ' ')
spacje=spacje+1;
c=getchar();
}
printf("Spacje: %d.\n", spacje);
return 0;
17
D. Rybarczyk, Studia zaoczne - wykłady
w1pwsz, 2005-02-17
program źródłowy
w języku C
(source file)
pliki nagłówkowe
(header files)
funkcje
biblioteka funkcji
(library)
Program w języku C
składa się z jednego lub wielu plików
w pliku znajduje się jedna lub wiele funkcji
zawsze musi zawierać funkcję o nazwie main(), od której rozpoczyna się wykonywanie programu
może zawierać odwołania do plików nagłówkowych i funkcji bibliotecznych
nazwy potrzebnych plików nagłówkowych wskazywane są za pomocą dyrektywy #include
nazwy bibliotek wskazywane są za pomocą parametrów kompilacji
Pliki nagłówkowe
zawierają wspólne deklaracje i definicje dla wszystkich funkcji, z których korzysta program
są to pliki tekstowe
nazwa pliku ma rozszerzenie .h
przykład: stdio.h
Biblioteki funkcji
zawierają funkcje włączane do programu podczas konsolidowania (linkowania)
każda biblioteka ma swój plik nagłówkowy (jeden lub wiele)
są dostarczane przez producenta kompilatora (np. biblioteka run-time - czasu wykonania) lub tworzone przez użytkownika
są to pliki binarne
mogą mieć różne rozszerzenia, na przykład .lib
funkcje
#include
main()
{
printf();
}
Program źródłowy
(Preprocesor)
Kompilator
Program wynikowy
Program wynikowy
Konsolidator
Program wykonywalny
program.c
Biblioteki
program.exe
i = 5;
stała
zmienna o nazwie i
int licznik;
licznik = 0;
zmienna typu int
stała typu int (liczba całkowita)
Przykład 1.
double suma;
suma = 0.;
zmienna typu
double stała typu double (liczba z kropką dziesiętną)
Przykład 2.
char c;
c='*';
zmienna
typu char stała typu char (znak w apostrofach)
Przykład 3.
punkty > 15
wyświetl "zaliczone"
prawda
fałsz
wyrażenie
instrukcja_1
prawda
fałsz
if (punkty >= 15)
printf("Zaliczone\n");
else
printf("Nie zaliczone");
wyrażenie
instrukcja_1
fałsz
instrukcja_2
prawda
fałsz
(wartość równa zeru)
oblicz wartość wyrażenia
wykonaj instrukcje
prawda
(wartość różna od zera)
fałsz
x<y
zwiększ x o 1
prawda
Każdej zmiennej odpowiada specyfikator formatu;
zmiennej typu int odpowiada specyfikator %d