Laboratorium Podstaw Informatyki
Kierunek Elektrotechnika
Ćwiczenie 1.2
Podstawy
Wprowadzenie do programowania w języku C
Zakład Metrologii AGH
Kraków 2000
Twój pierwszy program w C
Program w języku C, jak i w wielu innych językach składa się ze zmiennych, stałych oraz procedur. Zmienne służą do przechowywania danych na, których program operuje przy pomocy procedur, które w języku C nazywane są funkcjami. Oczywiście w jakiś sposób musimy zaznaczyć gdzie program się rozpoczyna, a gdzie kończy. W języku C program zawsze rozpoczyna się od głównej funkcji zwanej main. Oprócz funkcji zdefiniowanych przez programistę, program wykorzystuje funkcje biblioteczne. Funkcje biblioteczne to takie, które ktoś kiedyś napisał, skompilował, udokumentował i udostępnił innym do użytkowania. Najczęściej programiści korzystają z funkcji bibliotecznych zapewniających komunikację z systemem operacyjnym i obsługującym wejście/wyjście (klawiatura, monitor, dyski, drukarka). Aby móc korzystać z takich funkcji bibliotecznych trzeba o tym powiadomić kompilator. Robi się to poprzez włączenie odpowiedniego pliku nagłówkowego przez #include <nazwa pliku nagłówkowego>, plik ten zawiera deklaracje funkcji, zmiennych i typów danych.
Najczęściej włączanym plikiem nagłówkowym jest stdio.h, jak się łatwo domyślić zawiera on deklaracje standardowych (std) funkcji do obsługi wejścia/wyjścia (io). Tak więc jesteśmy już gotowi do napisania prostego programu.
#include <stdio.h>
main( ) /* nazwa funkcji, za którą są nawiasy w których określone są parametry
przekazywane do funkcji */
{ /*nawias otwierający
/* to jest komentarz - kompilator go ignoruje, można go pominąć przy przepisywaniu */
printf("ahoj, przygodo\n"); /* to jest wywołanie funkcje printf z jednym
tekstowym argumentem */
} /* to już koniec funkcji main i koniec programu */
Program ten zawiera tylko jedną funkcję (główną), wypisuje na ekranie tekst: ahoj, przygodo i powoduje przejście kursora do nowej linii. W nawiasach klamrowych { i } umieszcza się instrukcje wykonywane przez daną funkcję. Program ten wywołuje bardzo często używaną funkcję biblioteczną printf. Argumentem tej funkcji, w naszym przypadku, jest stała tekstowa ahoj, przygodo\n. Stała tekstowa zawsze jest zawarta pomiędzy dwoma znakami ". Sekwencja \n jest znakiem nowej linii, to ona powoduje, że kursor przechodzi do nowej linii.
Zadanie 1: Spróbuj coś zmienić, np.: dopisz nowe wywołanie funkcji printf, zmień stała tekstową (tekst, który ma być wyświetlony). Zrób eksperyment z innymi znakami specjalnymi: \t - znak tabulacji, \0 - null (znak oznaczający koniec tekstu), \b - backspace (znak cofnięcia), \\ - znak \, \" - znak ".
Typy i rozmiary danych
Teraz poznamy podstawowe typy danych obecne w jezyku C. Aby program mógł działać poprawnie i efektywnie musi wiedzieć jakiego typu są dane na których wykonuje operacje. W języku C mamy do dyspozycji takie podstawowe typy danych jak:
char jeden bajt, mieści jeden znak ze zbioru znaków. Ponieważ jezyk C dostępny jest na różne maszyny, to bezpiecznym założeniem jest, że ten typ może poprawnie reprezentować liczby z zakresu 0..127;
int typ całkowity, na platformach 32 bitowych zakres liczb reprezentowanych przez ten typ to -2^31 do +2^31-1;
float typ zmiennoprzecinkowy pojedynczej precyzji, służy do przechowywania liczb rzeczywistych;
double typ zmiennoprzecinkowy podwójnej precyzji, służy do przechowywania liczb rzeczywistych, ale z większą precyzją.
Dodatkowo dostępne kwalifikatory do stosowania razem z typem int:
short int któtki całkowity
long int długi całkowity
unsigned int całkowity bez znaku (tylko dodatnie)
Słowo int może być opuszczone, a więc równoważny jest zapis:
short któtki całkowity
long długi całkowity
unsigned całkowity bez znaku (tylko dodatnie)
Oto co gwarantuje się w sprawie rozmiarów typów podstawowych:
1=sizeof(char)<=sizeof(short)<=sizeof(int)<=sizeof(long)
sizeof(float)<=sizeof(double)
Ponadto gwarantuje się, że typ char zajmuje co najmniej 8 bitów, short co najmniej 16, a long co najmniej 32.
Jeśli chcesz się dowiedzieć jaki jest rozmiar poszczególnych typów na twojej maszynie, pod kompilatorem, którego używasz to skorzystaj z operatora sizeof. Operator sizeof umożliwia określenie rozmiaru (ile bajtów zajmuje w pamięci) danego typu (również typy złożone jak tablice i struktury), lub zmiennej danego typu. Rozmiar ten jest obliczany na etapie kompilacji, a wartość zwracana jest typu int.
Przykładowe użycie to:
1) dla danego typu:
sizeof(int);
sizeof(long int); /* ile miejsca zajmuje w pamięci obiekt typu long int */
2) dla zmiennej danego typu:
float x; /*definicja zmiennej x typu float */
int a,b; /*definicja dwóch zmiennych a i b typu int */
sizeof(x); /*ile miejsca zajmuje w pamięci zmienna x*/
sizeof(a); /*ile miejsca zajmuje w pamięci zmienna a*/
W języku C wszystkie zmienne muszą być zadeklarowane przed wcześniejszym użyciem. Deklaracja składa się z typu i listy zmiennych tego typu. W naszym przypadku deklaracjami są:
float x;
int a, b;
Deklaracje, te są także definicjami - definicja powoduje przydział pamięci dla definiowanej zmiennej. Mówią one że x jest zmienną typu float (zmiennoprzecinkowa), oraz a i b są typu int (całkowite). Każda deklaracja, definicja i instrukcja musi być zakończona średnikiem.
Zadanie 2: Napisz program, który wypisze rozmiar wszystkich znanych Ci typów danych. Zrealizuj to na dwa sposoby: poprzez użycie operatora sizeof z argumentem będącym typem danych, oraz z argumentem będącym zmienną danego typu.
Do rozwiązania powyższego zadania potrzebne będzie nam rozszerzenie wiadomości o funkcji printf.
Deklaracja funkcji (zawarta w zbiorze stdio.h) jest następująca:
int printf(char *format, [, argument, ...]);
Deklaracja ta mówi, że funkcja printf zwraca wartość typu int, ale na razie nie będzie nas to interesować. Dalej widać, że funkcja printf może posiadać wiele argumentów oddzielonych przecinkami. Pierwszym argumentem funkcji printf jest ciąg znaków (tekst). Ten tekst jest wyświetlany, ale mogą w nim wystąpić specjalne znaki sterujące, które nie są wyświetlane, ale są interpretowane. Znaki sterujące poprzedzone są znakiem %. Znak ten symbolicznie wskazuje miejsce, gdzie ma być wyświetlona wartość kolejnego argumentu (tzn. drugiego, trzeciego, itd) oraz określa format, w jakim ta wartość będzie wypisana, a także typ argumentu. Najlepiej zobaczmy to na przykładzie. Wypiszemy wartość zmiennej x, która jest typu float oraz zmiennej b, która jest typu int. Dodatkowo wypiszemy tekst:
zmienna x = <wartość x> ,zmienna = <wartość b>.
printf("zmienna x = %f, zmienna b = %d", x, b);
Symbole %f i %d informują funkcję printf, że drugi jej argument (pierwszym jest stała tekstowa "zmienna x = %f, zmienna b = %d" ) jest typu float i ma być wypisany jako float, a trzeci jest typu int i ma być wypisany jako int. Wszelkie próby oszukania funkcji printf np. próba wypisania zmiennej typu float jako int mogą zakończyć się katastrofą.
Instrukcje
Do wykonywania operacji na danych w jezyku C służą instrukcje. Teraz poznamy niektóre z nich.
Instrukcja złożona:
Instrukcja złożona jest ciągiem instrukcji prostych zamkniętych w nawiasy klamrowe { i }.
Instrukcja warunkowa
Instrukcja warunkowa ma postać:
if( wyrażenie ) instrukcja /*jeśli wyrażenie jest prawdziwe, tzn. ma wartość niezerową to wykonaj instrukcje. */
if( wyrażenie ) instrukcja1 else instrukcja2 /*jeśli wyrażenie jest prawdziwe, tzn. ma wartość niezerową to wykonaj instrukcja1 w przeciwnym wypadku wykonaj instrukcja2 */
Przykład:
#include <stdio.h>
main()
{
int i = 101;
if(i > 100) { /*nawias otwierający instrukcji złożonej */
printf("wartość i większa od 100");
printf("\n”);
} /*nawias zamykający instrukcji złożonej */
else { /*nawias otwierający instrukcji złożonej */
printf("wartość i mniejsza lub równa 100");
printf("\n”);
} /*nawias zamykający instrukcji złożonej */
}
Zadanie 3: zmodyfikować program tak, aby pozwalał na sprawdzeni podzielności liczby przez 2. Do sprawdzenia podzielności należy zastosować dwuargumentowy operator modulo: arg1 % arg2. Operator ten podaje resztę z dzielenia arg1 przez arg2. Np. 7%2 daje w wyniku 1.
Instrukcja for
Instrukcja for służy do organizacji pętli i ma postać
for( wyrażenie1 ; wyrażenie2 ; wyrażenie3 ) instrukcja
Pierwsze wyrażenie określa stan początkowy pętli, tzn. zazwyczaj służy do inicjalizacji zmiennej sterującej pętli. Jest ono obliczane jako pierwsze wyrażenie i tylko jeden raz. Drugie wyrażenie jest warunkiem, którego wartość sprawdza się przed każdym obrotem pętli - gdy jego wartość będzie zero, wówczas wykonywanie pętli będzie przerwane. Trzecie wyrażenie zwykle określa zmianę stanu pętli i jest wykonywane po każdym obrocie pętli, np. zwiększa wartość zmiennej sterującej o jeden. Dowolne wyrażenie (a nawet wszystkie) można opuścić. Pominięcie warunku wyrażenie2 jest równoważne z zastąpieniem go stałą różną od zera.
Przykład: wypiszemy dziesięć liczb z pewnym krokiem.
#include <stdio.h>
main()
{
int i; /* definicja zmiennej i */
for(i = 10; i < 30; i = i + 2) { /*znów przykład instrukcji złożonej, choć można by się bez
niej obejść */
printf("liczba %d", i); /* instrukcja powtarzana w pętli */
printf("\n"); /* druga instrukcja powtarzana w pętli */
}
}
Zadanie 4: zmodyfikować powyższy przykład tak aby nie występowały w nim stałe liczbowe, a jedynie stałe symboliczne. W tym celu musimy skorzystać z usług preprocesora języka C.
Preprocesor języka C posiada możliwość definiowania stałych symbolicznych. Robi się to przy użyciu dyrektywy
#define identyfikator ciąg_znaków.
Zdefiniujemy np. stała symboliczną początek, która będzie miała wartość 10
#define początek 10
Jeśli teraz gdzieś w programie w wyrażeniu wystąpi słowo początek, to zostanie ono zamienione na liczbę 10, przed właściwą kompilacją.
Zadanie 5: na podstawie programu przykładowego (dla pętli for) napisać program, który będzie wypisywał kolejne liczby w kolejnych liniach, tak aby przed każdą liczbą występowało tyle spacji ile wynosi wypisana liczba. Zobacz przykład:
0
1
2
3
Instrukcja while
Druga instrukcja służąca do organizacji pętli ma postać:
while( wyrażenie ) instrukcja
Wykonanie instrukcji powtarza się tak długo, jak długo wartość wyrażenia wyrażenie jest różna od zera. Sprawdzenia tego dokonuje się przed każdym wykonaniem instrukcji instrukcja.
Zadanie 6:
Rozwiązać zadania podane w opisie instrukcji for, ale z użyciem pętli while.
Instrukcja do
Trzecia instrukcja służąca do organizacji pętli ma postać:
do instrukcja while( wyrażenie ) ;
Wykonanie podinstrukcji instrukcja powtarza się tak długo, aż wartość wyrażenia wyrażenie stanie się zerem. Sprawdzenia tego dokonuje się po każdym wykonaniu podinstrukcji.
Zadanie 7:
Rozwiązać zadania podane w opisie instrukcji for, ale z użyciem pętli do while.
Zakład Metrologii AGH