Programowanie w języku C
Kurs początkowy
Dr inż. Lucjan Miękina
upel.agh.edu.pl/wimir/login/
Katedra Robotyki i Mechatroniki
November 26, 2012
1/1
Programowanie w języku C
Instrukcje
Instrukcja jest najmniejszą niezależną częścią wykonywalnego kodu; określa ona
działanie do wykonania przez program. Typowo instrukcje są wykonywane kolejno,
choć nie jest to regułą. Instrukcje są wykonywane w celu wywołania pewnego efektu,
ale nie posiadają samoistnej wartości.
W języku C istnieją następujące kategorie instrukcji:
Instrukcje z etykietami Instrukcje iteracyjne
Etykiety instrukcji while
Etykiety case do-while
Etykiety default for
Instrukcje deklaracji Instrukcje skoku
Instrukcje wyrażeniowe break
continue
Instrukcje blokowe (złożone)
return
Instrukcje wyboru
goto
if-else
switch
2/1
Programowanie w języku C
Instrukcja blokowa
Instrukcja blokowa lub złożona pozwala zgrupować dowolną ilość zmiennych i instrukcji
w instrukcji wyższego rzędu. Wszystkie definicje, deklaracje i instrukcje zawarte w
nawiasach ograniczających blok są traktowane jako elementy pojedynczej instrukcji.
Blok może być zdefiniowany wszędzie tam, gdzie jest dopuszczalne wystąpienie
pojedynczej instrukcji. W konsekwencji każdą pojedynczą instrukcję można zastąpić
instrukcją blokową, np. przy rozbudowie funkcjonalności programu.
Instrukcja blokowa ma następującą postać:
Zgodnie ze standardem języka z r. 89 (C89), definicje i deklaracje muszą poprzedzać
instrukcje. Natomiast zgodnie ze standardem języka z r. 99 i standardem C++,
definicje i deklaracje mogą być umieszczone w dowolnym miejscu bloku i być
przemieszane z kodem (instrukcjami).
3/1
Programowanie w języku C
Instrukcja blokowa
Blok definiuje lokalny zakres zmiennych. Jeśli pewien element danych (zmienna) jest
zdefiniowany wewnątrz bloku i nie jest przedefiniowany (czyli powtórnie zdefiniowany)
wewnątrz zagnieżdżonych bloków, to jest on w nich widoczny i dostępny.
Przykład instrukcji blokowej, ilustrujący zastosowanie bloków zagnieżdżonych.
#include
int main() {
int x = 1, y = 3; // inicjalizacja x na 1, y na 3
{ // start bloku zagniezdzonego
int x = 2; // inicjalizacja x na 2
printf("wewnetrzne x = %4d, y = %4d\n", x, y);
} // koniec bloku zagniezdzonego
printf("zewnetrzne x = %4d, y = %4d\n", x, y);
return(0);
}
Rezultat wykonania:
wewnetrzne x = 2, y = 3
zewnetrzne x = 1, y = 3
4/1
Programowanie w języku C
Instrukcje pętli programowych
Instrukcje pętli programowych są używane do powtarzanego wykonywania wybranych
instrukcji.
Pętla while
Pętla while powtarza wykonywanie instrukcji zawartych w jej ciele, dopóki wyrażenie
sterujące ma wartość różną od zera.
Pętla while ma postać, określoną poniższym grafem:
Wyrażenie sterujące musi być typu arytmetycznego lub wskaznikowego. Wartość tego
wyrażenia jest obliczana przed przystąpieniem do ewentualnego wykonania instrukcji
ciała pętli. Jeśli wartość tego wyrażenia jest równa zeru, instrukcje zawarte w ciele
pętli w ogóle nie są wykonywane. Jeśli wartość tego wyrażenia jest różna od zera,
wykonuje się instrukcje zawarte w ciele pętli, a następnie ponownie oblicza się wartość
wyrażenia sterującego, co warunkuje dalsze działanie pętli.
Nawet gdy wartość wyrażenia sterującego jest różna od zera, można zakończyć
wykonywanie pętli umieszczając w jej ciele instrukcję break, return lub goto.
5/1
Programowanie w języku C
Przykład pętli while
Przykład prostej pętli while, w której ciele wypisywana jest wartość zmiennej
(kontrolnej) cnt, po czym dokonuje się zwiększenia wartości cnt o jeden:
// zmienna kontrolna petli, musi byc zainicjalizowana !
int cnt = 0;
printf("Petla WHILE:\n");
while(cnt < 3) {
printf("\t cnt = %1d\n", cnt);
cnt = cnt + 1; // inkrementacja zmiennej cnt
}
Rezultat wykonania:
Petla WHILE:
cnt = 0
cnt = 1
cnt = 2
6/1
Programowanie w języku C
Instrukcje pętli programowych - pętla do-while
Pętla do-while powtarza wykonywanie instrukcji zawartych w jej ciele, dopóki
wyrażenie sterujące ma wartość różną od zera. Ze względu na kolejność przetwarzania,
instrukcje ciała tej pętli wykonują się co najmniej jeden raz.
Pętla do-while ma postać, określoną poniższym grafem:
Wyrażenie sterujące musi być typu arytmetycznego lub wskaznikowego. Instrukcje
ciała tej pętli wykonują się po raz pierwszy zanim obliczana jest wartość wyrażenia
sterującego. Dalsze przetwarzanie zależy od wartości wyrażenia sterującego: jeśli jest
różna od zera to ciało pętli wykonuje się, po czym ponownie oblicza się wartość
wyrażenia sterującego. Jeśli wartość ta jest równa zeru to pętla kończy się.
Nawet gdy wartość wyrażenia sterującego jest różna od zera, można zakończyć
wykonywanie pętli umieszczając w jej ciele instrukcję break, return lub goto.
7/1
Programowanie w języku C
Przykład pętli do-while
Przykład prostej pętli do-while, w której ciele wypisywana jest wartość zmiennej
(kontrolnej) cnt, po czym dokonuje się zwiększenia wartości cnt o jeden:
// zmienna kontrolna petli, musi byc zainicjalizowana !
int cnt = 0;
printf("Petla DO-WHILE:\n");
do {
printf("\t cnt = %1d\n", cnt);
cnt = cnt + 1; // inkrementacja zmiennej cnt
}
while(cnt < -5);
Rezultat wykonania:
Pętla DO-WHILE:
cnt = 0
Pomimo tego, że wartość wyrażenia sterującego jest równa zeru od początku pętli,
wykonuje się jeden jej obieg.
8/1
Programowanie w języku C
Instrukcje pętli programowych - pętla for
Pętla for wykonuje następujące działania:
Oblicza wartość wyrażenia inicjalizującego przed pierwszym obiegiem pętli
W każdym obiegu pętli:
oblicza wartość wyrażenia warunkowego pętli i jeśli nie jest ono równe zeru
wykonuje ciało pętli
wykonuje wyrażenie końcowe po każdym obiegu pętli (zwykle używane do
inkrementacji)
Pętla for ma postać, określoną poniższym grafem:
Analogiczne działanie ma poniższy ciąg instrukcji, zbudowany z użyciem pętli while:
wyrazenie1;
while(wyrazenie2) {
instrukcja
wyrazenie3;
}
9/1
Programowanie w języku C
Przykład pętli for
Wewnątrz nawiasów () mogą się znalezć 3 wyrażenia, oddzielone średnikami:
wyrażenie1 - inicjalizujące; jest wykonywane tylko przed pierwszym obiegiem pętli. Można
w nim zadeklarować i ewentualnie zainicjować zmienną. Jeśli nie ma takiej potrzeby, można
to wyrażenie opuścić
wyrażenie2 - warunkowe; jest wykonywane przed każdym obiegiem pętli. Musi ono być typu
arytmetycznego lub wskaznikowego. Jeśli ma wartość zero, pętla kończy się i sterowanie jest
przekazane do następnej instrukcji po pętli for. Jeśli wyrażenie2 ma wartość różną od zera,
wykonuje się instrukcje ciała pętli. Jeśli wyrażenie2 nie występuje, przyjmuje się, że warunek
kontynuacji pętli jest spełniony
wyrażenie3 końcowe; jest wykonywane po każdym obiegu pętli. Zwykle jest używane do
inkrementacji, dekrementacji.
Dyskutowany wcześniej przykład, ilustrujący działanie pętli while, może być teraz
zapisany jako:
1 #include
2
3 int main(int argc, char** argv) {
4 int cnt;
5 printf("Petla FOR:\n");
6 for(cnt = 0; cnt < 3; cnt++)
7 printf("\t cnt = %1d\n", cnt);
8 return 0;
9 }
10/1
Programowanie w języku C
Przykład pętli for
Można zauważyć większą zwartość kodu realizującego to same zadanie, niż przy użyciu
omówionych wcześniej pętli, przy zachowaniu zbliżonego poziomu czytelności
programu. Należy jedynie pamiętać o rzeczywistym usytuowaniu trzech części
sterujących instrukcji for, czyli wyrazenie1, wyrazenie2 i wyrazenie3 w ciągu
wykonywanych instrukcji.
Nawet gdy wartość wyrażenia sterującego jest różna od zera, można zakończyć
wykonywanie pętli umieszczając w jej ciele instrukcję break, return lub goto. Jeśli nie
występuje wyrażenie2, staje się to konieczne, by zakończyć pętlę.
Jeśli w wyrażeniu1 została zadeklarowana zmienna (co jest możliwe w C99), to
standardowo wychodzi ona z zasięgu po zakończeniu pętli.
Pętla for bez wyrażenia inicjalizującego:
int index=99, var1, var2, list[100];
for (; index > 10; --index) {
list[index] = var1 + var2;
printf("list[%d] = %d\n", index, list[index]);
}
11/1
Programowanie w języku C
Przykłady pętli for
Pętla for bez wyrażenia inicjalizującego, warunkowego i końcowego. Pętla będzie się
wykonywać do momentu wczytania ze strumienia znaku e :
char znak;
for (;;) {
scanf("%c", &znak);
if(znak == \n )
continue;
if (znak == e )
break;
printf("Wczytano znak %c\n", znak);
}
Przykład ilustrujący możliwość umieszczenia wielu inicjalizacji w wyrażeniu1 i wielu
inkrementacji w wyrażeniu3. Należy wtedy użyć operatora przecinek. Pierwszy
przecinek jest użyty do rozdzielenia dwu deklaracji zmiennych całkowitych i, j. Drugi
przecinek rozdziela dwa wyrażenia inkrementacji zmiennych i, j po każdym obiegu
pętli.
for (int i = 0, j = 50; i < 10; ++i, j += 10)
printf("\ni=%d and j = %d", i, j);
12/1
Programowanie w języku C
Przykłady pętli for
Przykład zagnieżdżonej pętli for, wykonującej się dla wszystkich elementów
2-wymiarowej tablicy o rozmiarach [3][2]. W pętli drukuje się wartości kolejnych
wierszy i kolumn.
1 #include
2
3 #define KOL 3 // il. kolumn
4 #define WIE 2 // il. wierszy
5
6 int main() {
7 int wie, kol;
8 float war;
9 float a2d [WIE] [KOL]; // 2-wymiarowa tablica GLOBALNA
10
11 // pętla do inicjalizacji elementow zerami
12 for(wie = 0; wie < WIE; wie++)
13 for (kol = 0; kol < KOL; kol++)
14 a2d[wie][kol] = 0.;
15 printf("Wprowadz wartosc numeru wiersza, kolumny i elementu\n");
16 scanf("%d %d %f", &wie, &kol, &war);
17 a2d[wie][kol] = war;
18 // pętla do drukowania elementow, powtornie uzywa zmiennych wie, kol
19 for (wie = 0; wie < WIE; wie++) {
20 printf("\n"); // przejscie do nowej linii na poczatku wiersza
21 for (kol = 0; kol < KOL; kol++)
22 printf("%5.2f\t", a2d[wie][kol]);
23 }
24 return 0;
25 }
13/1
Programowanie w języku C
Funkcje o zmiennej liczbie argumentów
Niekiedy zachodzi potrzeba użycia funkcji o zmiennej liczbie argumentów. Takimi są
np. funkcje printf i scanf.
Aby uzyskać dostęp do argumentów wewnątrz tego rodzaju funkcji, należy użyć funkcji
zadeklarowanych w pliku . Wprowadza on nowy typ o nazwie va_list i 3
funkcje, które operują na obiektach tego typu: va_start, va_arg i va_end.
Przed pierwszą operacją dostępu do listy argumentów, należy wywołać va_start. Jej
deklaracja jest następująca:
void va_start(va_list ap, parmN);
Funkcja va_start inicjalizuje ap w celu następujących potem operacji realizowanych
przez funkcje va_arg i va_end. Drugi argument do va_start, nazwany parmN jest
identyfikatorem ostatniego "zwykłego" parametru funkcji (bezpośrednio przed , ...).
Po takiej inicjalizacji, argumenty dostarczone do funkcji mogą być kolejno
udostępnione za pomocą funkcji va_arg. Jej deklaracja jest następująca:
type va_arg(va_list ap, type);
Każde jej wywołanie pobiera następny argument jako wartość typu zdefiniowanego
przez parametr type.
Po odczytaniu wszystkich argumentów należy wywołać funkcję va_end, z parametrem
wskazującym na listę ap.
14/1
Programowanie w języku C
Funkcje o zmiennej liczbie argumentów
1 #include
2 #include
3
4 int maxof(int n_args, ...) {
5 int i;
6 int max, a;
7 va_list ap;
8
9 va_start(ap, n_args);
10 max = a = va_arg(ap, int);
11 printf("%d ", a);
12 for(i = 1; i < n_args; i++) {
13 a = va_arg(ap, int);
14 printf("%d ", a);
15 if(a > max)
16 max = a;
17 }
18 va_end(ap);
19 return max;
20 }
21
22 int main() {
23 int i = -1, j[] = {1, 2, 3, 4}, mx;
24 printf("Wartosci wejsciowe: ");
25 mx = maxof(3, i, j[3], 0);
26 printf("\nWartosc max.: %d\n", mx);
27 return 0;
28 }
Rezultat wykonania:
15/1
Programowanie w języku C
Instrukcja wyboru if-else
Instrukcja if-else jest instrukcją wyboru, która umożliwia przejście do jednej z
dostępnych gałęzi wykonania programu. Instrukcja if-else pozwala warunkowo
wykonać instrukcję, wtedy gdy wyrażenie testowe przyjmuje wartość różną od zera.
Wyrażenie to musi być typu arytmetycznego lub wskaznikowego.
Opcjonalnie można umieścić frazę else w instrukcji if . W tym przypadku, jeśli
wyrażenie testowe ma wartość zero, wykonana zostanie instrukcja występująca po
słowie else. Natomiast jeśli wyrażenie testowe ma wartość różną od zera, wykonana
zostanie instrukcja występująca po słowie if, a reszta jest ignorowana.
Instrukcja if-else ma postać, określoną poniższym grafem:
Jeśli instrukcje if są zagnieżdżone i występuje fraza else, dana fraza else jest związana
z najbliższym wcześniejszym wystąpieniem frazy if w tym samym bloku.
Pojedyncza instrukcja występująca w opisanej postaci if-else jest rozumiana jako
instrukcja złożona. W rezultacie, zmienne zadeklarowane w bloku tej instrukcji
złożonej wyjdą z zasięgu (zostaną usunięte ze stosu) w momencie zakończenia
instrukcji if-else.
16/1
Programowanie w języku C
Instrukcja wyboru if-else - przykłady
Na przykład:
if(x)
int i;
jest traktowane jako:
if(x)
{ int i; }
Zmienna i jest widoczna tylko wewnątrz instrukcji if. Takie same zasady stosuje się w
odniesieniu do części else instrukcji if-else.
Przykład
Instrukcja która spowoduje wyświetlenie napisu Dodatnie , jeśli wartość zm. numer
jest większa lub równa zeru.
if(numer >= 0)
printf("Dodatnie\n");
Przykład
Instrukcja, w której fraza else jest użyta w celu wyświetlenia napisu Ujemne jeśli
wartość zm. numer jest mniejsza od zera.
if(numer >= 0)
printf("Dodatnie\n");
else
printf("Ujemne\n");
17/1
Programowanie w języku C
Instrukcja wyboru if-else - przykłady
Przykład
Zagnieżdżona instrukcja if-else:
if(numer >= 0)
if (numer > 0)
printf("Dodatnie\n");
else
printf("Zero\n");
else printf("Ujemne\n");
Przykład
Zagnieżdżona instrukcja if, która nie zawiera frazy else. Nawiasy klamrowe są
stosowane w celu związania frazy else z właściwą frazą if.
if(numer >= 0) {
if (numer > 0)
printf("Dodatnie\n");
}
else printf("Ujemne\n");
18/1
Programowanie w języku C
Instrukcja wyboru if-else - przykłady
Przykład
Zagnieżdżona instrukcja if-else wewnątrz frazy else. Ta forma może być stosowana do
instrukcji wyboru w oparciu o wiele warunków. Testy wykonuje się w kolejności ich
występowania w ciągu instrukcji if-else. Jeśli dany warunek jest spełniony, to wykonuje
się odpowiadającą mu instrukcję i kończy całą instrukcję wyboru.
if(ocena > 4.75)
printf("bdb\n");
else if (ocena > 4.25)
printf("db+\n");
else if (ocena > 3.75)
printf("db\n");
else if (ocena > 3.25)
printf("dst+\n");
else if (ocena > 2.75)
printf("dst\n");
else printf("ndst\n");
19/1
Programowanie w języku C
Instrukcja wyboru switch
Instrukcja switch jest instrukcją wyboru, która umożliwia przejście do jednej z (wielu)
instrukcji zawartych w jej ciele w zależności od wartości wyrażenia sterującego.
Wyrażenie sterującego musi być typu całkowitego lub wyliczeniowego. Ciało instrukcji
switch zawiera przypadki, które zawierają:
etykietę case lub etykietę default (jednokrotnie)
wyrażenie stałe identyfikujące przypadek
ciąg instrukcji realizujących operacje związane z danym przypadkiem.
Jeśli wartość wyrażenia sterującego jest równa wartości pewnego wyrażenia
identyfikującego przypadek, wykonuje się ciąg instrukcji po nim następujących. W
przeciwnym wypadku, wykonuje się instrukcje następujące po etykiecie default, o ile
ona występuje.
Instrukcja switch ma postać, określoną poniższym grafem:
Ciało instrukcji switch jest zawarte w nawiasach klamrowych i może zawierać definicje
typu, deklaracje zmiennych, przypadki typu case i przypadek default. Każdy przypadek
typu case i default może zawierać instrukcje.
20/1
Programowanie w języku C
Instrukcja wyboru switch - ciało
Ciało instrukcji switch ma postać, określoną poniższym grafem:
Ciało instrukcji switch jest zawarte w nawiasach klamrowych i może zawierać definicje
typu, deklaracje zmiennych, przypadki typu case i przypadek default. Każdy przypadek
typu case i default może zawierać instrukcje.
Część case zawiera etykietę case i dowolną ilość instrukcji:
W miejscu, w którym dopuszczalne jest wystąpienie etykiety case, może występować
dowolna ilość takich etykiet.
Część default zawiera etykietę default i dowolną ilość instrukcji:
21/1
Programowanie w języku C
Instrukcja wyboru switch - przykład
enum Oceny { switch(ocena) {
ndst=20, dst=30, pdst=35, case bdb:
db=40, pdb=45, bdb=50 }; printf("bdb\n");
float srednia= ...; break;
enum Oceny ocena; case pdb:
if(srednia > 4.75) printf("db+\n");
ocena=bdb; break;
else if (srednia > 4.25) case db:
ocena=pdb; printf("db\n");
else if (srednia > 3.75) break;
ocena=db; case pdst:
else if (srednia > 3.25) printf("dst+\n");
ocena=pdst; break;
else if (srednia > 2.75) case dst:
ocena=dst; printf("dst\n");
else ocena=ndst; break;
default:
printf("ndst\n");
}
22/1
Programowanie w języku C
Instrukcja break
Instrukcja break umożliwia opuszczenie ciała pętli for, while i do, podobnie jak dla
instrukcji switch.
Często jest pożądana możliwość zakończenia tych pętli w dowolnym miejscu ich ciała,
a nie tylko na początku lub końcu każdego obiegu pętli. Instrukcja break powoduje
natychmiastowe zakończenie wykonywania najgłębiej zagnieżdżonego ciała tych pętli
lub ciała instrukcji switch.
1 #include
2 #include
3
4 int main() {
5 char s[256]; int i;
6 strcpy(s, "Napis ...");
7 i = strlen(s)-1;
8 printf(" %s ma %lu znakow\n",
9 s, strlen(s));
10 while(i >= 0) {
11 if(s[i] != && s[i] != . )
12 break;
13 i--;
14 }
15 s[i+1] = \0 ;
16 printf(" %s ma %lu znakow\n",
Rezultat wykonania:
17 s, strlen(s));
18 return 0;
Napis ... ma 9 znakow
19 }
Napis ma 5 znakow
23/1
Programowanie w języku C
Instrukcja continue
Instrukcja continue powoduje natychmiastowe rozpoczęcie następnego obiegu pętli for,
while lub do, w ciele której została napotkana. Instrukcja continue nie ma
zastosowania w instrukcji switch. W przypadku pętli while i do oznacza to przejście do
opracowania wyrażenia sterującego; natomiast dla pętli for oznacza to przejście do
opracowania wyrażenia końcowego.
1 #include
2 #include
3 #include
4
5 int main() {
6 char s[256]; int i;
7 strcpy(s, "* DUZE male *");
8 printf("Oryginal: %s \n", s);
9 for(i = 0; i < strlen(s); i++) {
Instrukcja continue jest często
10 if(s[i]== ||
używana, kiedy warunkowo ma być
11 s[i]== \n || s[i]== \t )
12 continue; wykonywana ostatnia część pętli,
13 if(islower(s[i]))
która jest tak skomplikowana, że
14 s[i] = toupper(s[i]);
uzyskuje się prostszą postać kodu
15 else
przez zanegowanie warunku
16 if(isupper(s[i]))
17 s[i] = tolower(s[i]); wykonywania tej ostatniej części.
18 }
Rezultat wykonania:
19 printf("Zamiana: %s \n", s);
20 return 0;
Oryginal: * DUZE male *
21 }
Zamiana: * duze MALE *
24/1
Programowanie w języku C
Instrukcja goto
Formalnie instrukcja goto nie jest w ogóle potrzebna, a w praktyce prawie zawsze
można się bez niej obejść. Tym niemniej, są znane sytuacje, kiedy instrukcja goto
może znalezć zastosowanie. Najczęściej dotyczy to konieczności przerwania obliczeń w
głęboko zagnieżdżonym bloku, na przykład wewnątrz dwu lub więcej pętli. Nie
wystarczy wtedy zastosować instrukcję break, ponieważ zapewnia ona tylko
opuszczenie najbardziej wewnętrznej pętli.
1 #include
2 #include
3 void znajdzTakiSamString() {
4 char* s1[] = { "s11", "s12"};
Inną kategorię potencjalnych
5 char* s2[] = { "s12", "s22"};
zastosowań stanowi potrzeba
6 int i, j;
przerwania obliczeń w wielu
7 for(i=0; i < sizeof(s1)/sizeof(char*); i++)
8 for(j=0; j < sizeof(s2)/sizeof(char*); j++) blokach i przejścia do tego
9 if(strcmp(*(s1+i), *(s2+j)) == 0)
samego wspólnego fragmentu
10 goto JEST; // identyczne !
kodu.
11 else
Rezultat wykonania:
12 printf("s1[%1d]= %s != s2[%1d]= %s \n",
13 i, *(s1+i), j, *(s2+j));
14 return; // opuszczenie funkcji
s1[0]= 11 != s2[0]= 12
15 JEST: printf("s1[%1d]= %s == s2[%1d]= %s \n",
s1[0]= 11 != s2[1]= 22
16 i, *(s1+i), j, *(s2+j));
s1[1]= 12 == s2[0]= 12
17 }
18 int main() {
19 znajdzTakiSamString(); return 0;
20 }
25/1
Programowanie w języku C
Struktury
Struktura jest kolekcją zmiennych, potencjalnie różnych typów (odmiennie niż tablice),
zgrupowanych pod wspólną nazwą dla ułatwienia przetwarzania lub bardziej logicznej
reprezentacji. Każdy element struktury nazywa się składnikiem (ang. member) lub
polem (ang. field).
Pole struktury może mieć dowolny typ (standardowy lub zdefiniowany przez
programistę). Każde pole poza ostatnim musi mieć typ zdefiniowany kompletnie.
UWAGA: Typy zdefiniowane nie-kompletnie są to: void; tablice o nieznanym rozmiarze; tablice
zawierające elementy zdefiniowane nie-kompletnie; struktury, unie lub typy wyliczeniowe mające
tylko deklarację (nie mające definicji).
Struktur używa się, aby zgrupować w programie zmienne, które są logicznie (np.
znaczeniowo) powiązane. Na przykład aby zdefiniować dane osobowe, można:
1) zadeklarować zmienne: 2) uczynić je polami struktury osoba:
char* imie; struct osoba {
char* nazwisko; char* imie;
int wiek; char* nazwisko;
int wiek; };
Struktury umożliwiają lepszą organizację złożonych danych, ponieważ pozwalają traktować grupy
powiązanych danych jako całość, a nie jako oddzielne jednostki.
26/1
Programowanie w języku C
Struktury - deklarowanie a definiowanie
Definicja typu strukturowego opisuje składniki struktury. Składa się ona ze słowa
kluczowego struct, za którym opcjonalnie występuje nazwa (identyfikator struktury), a
następnie w nawiasach klamrowych lista pól.
Deklaracja typu strukturowego ma taką samą formę jak definicja, ale brak w niej
nawiasów klamrowych zawierających listę pól.
Oba aspekty ilustruje poniższy graf, w którym deklaracji odpowiada górna gałąz, a
definicji - dolna.
Słowo kluczowe struct wraz z identyfikatorem stanowi nazwę unikalnego typu danych.
Jeśli w definicji nie podaje się nazwy struktury, należy tuż za nawiasami klamrowymi
zawierającymi definicje pól zadeklarować wszystkie zmienne reprezentujące ten typ
struktury.
27/1
Programowanie w języku C
Struktury - definiowanie pól
Lista pól struktury definiuje wszystkie typy danych, jakie można w niej przechowywać.
Pole może mieć dowolny typ poza funkcją, typem nie-kompletnym, typem
modyfikowanym i void. Ponieważ typy nie-kompletne nie mogą być użyte, struktura
nie może zawierać pola swojego typu (rekurencja!), ale może zawierać wskaznik do
swojego typu.
Struktura może zawierać inną strukturę jako pole.
Definicja pola ma postać zgodną z deklaracją zmiennej. Nazwy pól muszą być
unikalne wewnątrz struktury, ale ta sama nazwa może być użyta w innej strukturze, a
nawet może być identyczna z zewnętrzną (w stosunku do struktury) zmienną, funkcją
lub typem.
Dla umożliwienia poprawnego rozmieszczenia elementów w pamięci, mogą być
wtrącone (przez kompilator) przerwy (nie zajęte bajty) między kolejnymi polami.
28/1
Programowanie w języku C
Struktury - inicjalizacja
Inicjalizator struktury ma postać listy wartości jej pól, zawartej wewnątrz nawiasów
klamrowych. Inicjalizator występuje po znaku równości =.
Jeśli nie występują desygnacje (ang. designations), pamięć dla pól struktury jest
przydzielana w kolejności ich deklaracji, a pierwsze pole ma adres początku całej
struktury. Nie trzeba inicjalizować wszystkich pól struktury.
Domyślny inicjalizator (ang. default initializer), który jest stosowany gdy nie ma
jawnego inicjalizatora, dla struktury o statycznym wiązaniu (globalnej) jest rozumiany
jako ciąg domyślnych inicjalizatorów pól struktury. Natomiast dla struktury o wiązaniu
automatycznym (lokalnej) domyślny inicjalizator nie jest zdefiniowany.
Przykład definicji struktury łącznie z inicjalizacją pól jej obiektu, który został
zadeklarowany tuż za listą pól:
struct osoba {
char* imie;
char* nazwisko;
int wiek;
} p1 = { "Miles", "Davis", 63 };
Dzięki tej deklaracji obiekt p1 typu strukturowego osoba będzie miał określone
wartości pól.
29/1
Programowanie w języku C
Struktury - inicjalizacja
Inny sposób inicjalizacji
Nazwane pola struktury mogą być inicjalizowane w dowolnej kolejności dzięki użyciu
desygnatorów. Desygnator określa pole struktury, które ma być zainicjalizowane.
Desygnator dla pola struktury składa się z kropki i nazwy tego pola.
Lista desygnatorów jest ciągiem desygnatorów dowolnych typów złożonych (np.
tablic). Desygnacja składa się z listy desygnatorów, która występuje po znaku
równości =.
Przykład deklaracji struktur łącznie z inicjalizacją przy użyciu desygnatorów:
struct osoba p2 = {
.wiek = 70,
.imie = "Gil",
.nazwisko = "Evans"
};
printf("p2 %p: %s %s ma %d lat\n",
&p2, p2.imie, p2.nazwisko, p2.wiek);
Rezultat wykonania:
p2 8047254: Gil Evans ma 70 lat
30/1
Programowanie w języku C
Struktury - dozwolone operacje
Jedyne dozwolone operacje na strukturach to:
kopiowanie
przypisanie całej struktury do innej
pobranie adresu operatorem &
dostęp do poszczególnych pól
Kopiowanie i przypisanie obejmuje również przekazywanie argumentów będących
strukturami do funkcji i zwracanie wartości przez funkcje.
Nie można porównywać struktur za pomocą operatorów porównania.
Ponadto struktury mogą być inicjalizowane za pomocą listy stałych wartości dla pól i
za pomocą przypisania (w przypadku zmiennych lokalnych typu strukturowego).
31/1
Programowanie w języku C
Struktury - dozwolone operacje
Przykłady deklaracji struktury jako pojedyncze zmienne:
1 #include
2 struct osoba {
3 char* imie;
4 char* nazwisko;
5 int wiek;
6 };
7 int main() {
8 struct osoba p1, p2;
9 struct osoba* p = &p1; // wsk. do struktury
10 // ustawienie wartosci pol przez przypisania
11 p1.imie = "John";
12 p1.nazwisko = "Scofield";
13 p1.wiek = 55;
14 // dostep do pol
15 printf("p1 %p: %s %s ma %d\n", &p1, p1.imie, p1.nazwisko, p1.wiek);
16 printf("p %p: %s %s ma %d\n", p, p->imie, p->nazwisko, p->wiek);
17 // przypisanie str. p1 do p2
18 p2=p1; // kopiuje pole po polu
19 printf("p2 %p: %s %s ma %d\n", &p2, p2.imie, p2.nazwisko, p2.wiek);
20 return 0;
21 }
Rezultat wykonania:
p1 0x7fffeb8834a0: John Scofield ma 55
p 0x7fffeb8834a0: John Scofield ma 55
p2 0x7fffeb883480: John Scofield ma 55
32/1
Programowanie w języku C
Struktury - struktury jako elementy tablic
Struktury mogą być elementami tablic, jak poniżej:
1 #include
2 struct osoba {
3 char* imie;
4 char* nazwisko;
5 int wiek;
6 };
7 int main() {
8 struct osoba violinists[] = { {"Jean-Luc", "Ponty"},
9 { "Michal", "Urbaniak"}, { "Stephane", "Grapelli"} };
10 // ustawienie wartości niezainicjowanyh pól przez podstawienie
11 violinists[0].wiek = 55;
12 violinists[1].wiek = 60;
13 violinists[2].wiek = 70;
14 int i, ile = sizeof(violinists) / sizeof(struct osoba);
15 printf("Tablica violinists ma %d struktury, a w nich:\n", ile);
16 for(i = 0; i < ile; i++)
17 printf("- %s %s, %d lat\n", violinists[i].imie, violinists[i].nazwisko, violinists[i].wiek);
18 return 0;
19 }
Rezultat wykonania:
Tablica violinists ma 3 struktury, a w nich:
- Jean-Luc Ponty, 55 lat
- Michal Urbaniak, 60 lat
- Stephane Grapelli, 70 lat
33/1
Wyszukiwarka
Podobne podstrony:
Wyklad PI 5
Wyklad PI 1 cz 2
Wyklad PI
Wyklad PI 9
Wyklad PI 3
Wyklad PI 2 cz 2
Wyklad PI 4
Wyklad PI 2 cz 1
Wyklad PI
Sieci komputerowe wyklady dr Furtak
Wykład 05 Opadanie i fluidyzacja
WYKŁAD 1 Wprowadzenie do biotechnologii farmaceutycznej
mo3 wykladyJJ
więcej podobnych podstron