sem. II i III
Dr inż. M. Czyżak
Katedra Elektrotechniki Teoretycznej i
Informatyki
Literatura:
1. A.R. Neubauer, Języki C i C++, Twój pierwszy program, Help,
W-wa, 1995.
2. C. Sexton, Język C to proste, RM, W-wa, 2001.
3. G. Perry, Język C w przykładach, Que, W-wa, 2000.
4. Brian W. Kernighan, Dennis M. Ritchie, Język ANSI C, WNT,
Warszawa, 1994.
5. Andrzej Zalewski, Programowanie w językach C i C++ z
wykorzystaniem pakietu Borland C++, Nakom, Poznań, 1999.
Język ANSI C - historia
1972 – definicja języka C– Dennis M. Ritchie
Pierwowzór – beztypowy język B ( Ken Thompson (1970))
będący adaptacją języka BCPL( Basic Combined Programming
Language, Martin Richards(1967) ) dla PDP-7.
1974- opis języka C – D.M. Ritchie, B.W. Kernighan, The C
programming language, Prentice-Hall. Standard K&R.
1988- unowocześniony standard języka C- język ANSI C. Opis
standardu : American National Standard for Information Systems-
Programming Language C, X3.159-1989). Później standard ISO
9899:1990.
Język ANSI C - wstęp
Zastosowanie: początkowo systemy operacyjne,
oprogramowanie narzędziowe ( kompilatory, edytory) i
oprogramowanie sieciowe, później oprogramowanie użytkowe.
Kompilatory dostępne w praktycznie każdym systemie
operacyjnym. Język C jest podstawowym językiem tworzenia
oprogramowania dla procesorów sygnałowych i sterujących
różnego typu urządzeniami (przykład- kompilator Keil C dla
8051).
Język ANSI C - wstęp
Cechy języka C cz I:
Typy:
- typy podstawowe : typy znakowe, całkowite i rzeczywiste
- typy pochodne : wskaźnikowe, tablice, struktury, unie i
inne.
Wyrażenia : budowane z operatorów i ich argumentów
Wskaźniki : operacje na adresach niezależnie od maszyny
Język ANSI C - wstęp
Cechy języka C cz. II:
Konstrukcje sterujące:
- grupowanie instrukcji (instrukcja złożona)
- podejmowanie decyzji ( if, if-else, switch)
- realizacja powtarzania ze sprawdzaniem warunku na
początku ( for, while), na końcu ( do-while)
- przerwanie (break) i kontynuacja pętli (continue)
Język ANSI C - wstęp
Cechy języka C cz III:
Ogólna budowa programu
- program składa z pewnych jednostek programowych
( fragmentów kodu ) zwanych funkcjami z dobrze
określonymi mechanizmami komunikacji z otoczeniem;
- program w C posiada tzw. płaską strukturę tzn. funkcje
są niezależne i nie można definiować jednych funkcji w
drugich.
Język ANSI C - wstęp
Cechy języka C cz IV:
Funkcje:
- mogą zwracać wartości typów podstawowych, struktury,
unie i wskaźniki;
- zmienne w funkcjach mogą być zmiennymi lokalnymi
(automatyczne i statyczne) lub zewnętrznymi;
- mogą być wywoływane rekurencyjnie;
- mogą być rozmieszczone w jednym lub większej liczbie
plików.
Język ANSI C - wstęp
Przykład 1. Prosty program w języku C- wersja 1
#include <stdio.h>
main()
{
printf("Pierwszy program w języku C");
}
Język ANSI C - wstęp
Przykład 2. Prosty program w języku C- wersja 2
#include <stdio.h>
#include <conio.h>
main()
{
printf(”Pierwszy program w języku C”);
getch();
}
Język ANSI C - wstęp
Przykład 3. Prosty program w języku C- wersja 3
/* program ten jest uzupełniony o wybrane elementy*/
#include <stdio.h>
#include <conio.h>
main()
{
clrscr();
printf("Pierwszy program w języku C");
printf("\n napisany przez J. Kowalskiego");
getch();
return 0;
}
Język ANSI C - przykład
Przykład 4. Prosty program z użyciem zmiennych
#include <stdio.h>
#include <conio.h>
main()
{ int a;
int b;
int c;
a=1;
b=2;
c=a+b;
printf("\n Suma a+b =%d",c);
getch();
return 0;
}
Język ANSI C – pojęcie zmiennej
Zmienna w języku C
Zmienna w języku C z punktu widzenia programisty oznacza
pewien obszar pamięci komputera, który może być używany przez
programistę w określony sposób. Np. dla zmiennej a, rozmiar tego
obszaru określa typ int ( skrót od integer-całkowity). Typ ten oznacza, że
w zmiennych tego typu można przechowywać wartości całkowite ( dla
kompilatora Borland Builder C++ typ int zajmuje 32 bity i można
przechowywać wartości z zakresu . Liczby całkowite są
przechowywane w kodzie U2.
]
1
2
,
2
[
31
31
−
−
Język ANSI C – operatory
Operatory w języku C
Operatory to znaki lub kombinacje znaków symbolizujące pewne
operacje w programie np. =, +, -.
Operatory służą wraz i innymi elementami do tworzenia tzw. wyrażeń.
Wyrażenie jest pewną kombinacją operatorów i innych elementów takich
jak zmienne i stałe.
Przykładami wyrażeń mogą być:
-a - jest to wyrażenie składające się z operatora
minus (-) i argumentu ( zmiennej a )
-b+c – wyrażenie to składa się z operatora plus(+) i
dwóch argumentów (zmienne a i b)
Język ANSI C – operatory
Operator minus(-) w pierwszym wyrażeniu jest operatorem
jednoargumentowym, a operator plus(+) w drugim wyrażeniu jest
operatorem dwuargumentowym.
Ogólnie w języku C operator jednoargumentowy może być użyty w
sposób następujący:
op argument lub argument op,
a operator dwuargumentowy
argument1 op argument 2
Język ANSI C – operatory
Operatory w C można podzielić na następujące grupy:
-operatory arytmetyczne ( np. +,-,*,/, %, ++, --)
-operatory relacyjne (<,<=, ==, >, >=, !=)
-operatory logiczne (&&, ||, !)
-operatory bitowe ( ~, &, |, ^)
-operator funkcyjny ()
-operator indeksowania [ ]
- operatory adresowy ( &) i dereferencji (*)
Język ANSI C – operatory
-operator sizeof
-operator warunkowy(?)
-operatory przypisania ( np. =)
-operator rzutowania (typ)
-operator przecinkowy
-operatory bezpośredniego( . ) i pośredniego odwołania do pola
struktury(->)
Język ANSI C – typy całkowite
Zakresy i rozmiary typów całkowitych
Typ Rozmiar(bity) Zakres liczbowy
unsigned char
8 0 do 255
char
8 -128 do 127
short int
16 -32768 do 32767
unsigned short int
16 0 do 65536
int
32 -2147483648 do 2147483647
unsigned int
32 0 do 4294967295
long int
32 zakres int
unsigned long int
32 zakres unsigned int
( typ wyliczeniowy enum zostanie omówiony w dalszej części)
unsigned oznacza typ bez znaku (kod NKB), pozostałe
są przechowywane w kodzie U2.
Język ANSI C – operatory
Operatory arytmetyki na liczbach całkowitych
(ang. integer arithmetic)
- operatory jednoargumentowe ‘+’ i ‘ –’
- operator dodawania ‘ + ’
- operator odejmowania ‘-’
- operator mnożenia ‘*’
- operator dzielenia całkowitego ‘/’
- operator obliczania reszty z dzielenia całkowitego
Operatory te są stosowane, gdy argument lub argumenty operatora są
typu całkowitego.
Język ANSI C – operatory
/*Przykład 5. Program ilustrujący użycie operatorów arytmetyki całkowitej
dla liczb ze znakiem*>
#include <stdio.h>
#include <conio.h>
main()
{ int a,b,c;
printf("Podaj a:");
scanf("%d", &a);
printf("\nPodaj b:”);
scanf("%d", &b);
c=a+b;
printf("\n Suma %d + %d =%d", a,b,c);
c=a-b;
printf("\n Roznica %d - %d =%d", a,b,c);
c=a*b;
printf("\n Iloczyn %d * %d =%d", a,b,c);
c=a/b;
printf("\n Iloraz calkowity %d przez %d =%d", a,b,c);
c=a%b;
printf("\n Reszta z dzielenia całkowitego %d przez %d =%d", a,b,c);
getch();
return 0; }
Język ANSI C – typy całkowite
Uwaga: ani argumenty ani też rezultaty poszczególnych
działań nie mogą przekraczać zakresów liczbowych dla
poszczególnych typów podanych w tabeli. Przykładowo, mnożenie liczb
65000*40000 da liczbę ujemną.
Reprezentacja tego iloczynu jest 32-bitowa, stąd najwyższy jej bit
wchodzi na pozycję znaku, co powoduje, że otrzymany ciąg bitów jest
traktowany jako liczba ujemna w kodzie U2.
Język ANSI C – typy całkowite
/*Przykład 6. Program ilustrujący użycie operatorów arytmetyki całkowitej
dla liczb bez znaku*/
#include <stdio.h>
#include <conio.h>
main()
{ unsigned int a,b,c;
printf("Podaj a:");
scanf("%u", &a);
printf("\nPodaj b:");
scanf("%u", &b);
c=a+b;
printf("\n Suma %u + %u =%u", a,b,c);
c=a-b;
printf("\n Roznica %u - %u =%u", a,b,c);
c=a*b;
printf("\n Iloczyn %u * %u =%u", a,b,c);
c=a/b;
printf("\n Iloraz calkowity %u przez %u =%u", a,b,c);
c=a%b;
printf("\n Reszta z dzielenia całkowitego %u przez %u =%u", a,b,c);
getch();
return 0;}
Język ANSI C – typy całkowite
Przykład 7. Program ilustrujący użycie operatorów arytmetyki całkowitej
do obliczania wyrażenia
#include <stdio.h>
#include <conio.h>
#include <math.h>
main()
{ int k,l, licznik, mianownik, wynik;
printf("Podaj k:");
scanf(”%d”, &k);
printf(”\n Podaj l:”);
scanf("%d", &l);
licznik=k*k*k+ k%5 +abs(l);
mianownik=k+ k/(k+l);
wynik=licznik/mianownik;
printf("\n Wartosc wyrazenia=%d", wynik);
getch();
return 0;
}
l
k
k
k
l
k
k
y
+
+
+
+
=
5
3
Język ANSI C – operatory cz. V
Wartości logiczne w języku C
-Wartość logiczna prawda jest reprezentowana przez każdą
liczbę różną od zera, np. 1,2, -5.
-Wartość logiczna fałsz jest reprezentowana przez 0.
Język ANSI C – operatory cz. VI
Operatory relacji w języku C
Operatory te to:
‘ < ‘ - mniejsze
‘ < =‘ - mniejszy lub równe
‘ >‘ - większe
‘ >= ‘ - większe lub równe
‘==‘ - równe
‘!=‘ - różne
Język ANSI C – operatory cz. IV
Wyrażenie relacyjne
Wyrażenie relacyjne to wyrażenie składające się z operandów
połączonych pewnym operatorem relacji
op1 operator_relacyjny op2,
np. a>b, a!=b, a==b.
Wartością wyrażenia relacyjnego jest 1, jeżeli wyrażenie jest prawdziwe
albo też 0, gdy wyrażenie jest fałszywe.
Język ANSI C -operatory
Przykład. Prosty program ilustrujący zastosowanie operatorów relacyjnych
#include <stdio.h>
#include <conio.h.>
int main(int argc, char * argv{})
{ int a,b,c;
printf(” Podaj a=:”);
scanf (”%d”, &a);
printf(” Podaj b=:”);
scanf (”%d”, &b);
c=a<b;
printf (”\n Wartosc wyrazenia %d < %d=%d”,a,b,c);
c=a<=b;
printf (”\n Wartosc wyrazenia %d <= %d=%d”,a,b,c);
c=a==b;
prinf (”\n Wartosc wyrazenia %d ==%d=%d”,a,b,c);
c=a>b;
printf (”\n Wartosc wyrazenia %d > %d=%d”,a,b,c);
c=a>=b;
printf (”\n Wartosc wyrazenia %d > =%d=%d”,a,b,c);
c=a!=b;
printf (”\n Wartosc wyrazenia %d != %d=%d”,a,b,c);
getch(); return 0; }
Przykład. Program uzupełniony o możliwość wielokrotnego wykonania ( nieskończona
pętla while)
#include <stdio.h>
#include <conio.h.>
int main(int argc, char * argv{})
{ int a,b,c;
while (1) // początek pętli while
{
printf(” Podaj a=:”);
scanf (”%d”, &a);
printf(” Podaj b=:”);
scanf (”%d”, &b);
c=a<b;
printf (”\n Wartosc wyrazenia %d < %d=%d”,a,b,c);
c=a<=b;
printf (”\n Wartosc wyrazenia %d <= %d=%d”,a,b,c);
c=a==b;
prinf (”\n Wartosc wyrazenia %d ==%d=%d”,a,b,c);
c=a>b;
printf (”\n Wartosc wyrazenia %d > %d=%d”,a,b,c);
c=a>=b;
printf (”\n Wartosc wyrazenia %d > =%d=%d”,a,b,c);
c=a!=b;
printf (”\n Wartosc wyrazenia %d != %d=%d”,a,b,c);
getch();
} // koniec pętli do while
return 0; }
Przykład. Program uzupełniony o możliwość wielokrotnego wykonania ( pętla while z określoną
liczbą wykonań )
#include <stdio.h>
#include <conio.h.>
int main(int argc, char * argv{})
{ int a,b,c, n, licznik=0;
printf(” Podaj liczbe wykonan petli”);
scanf(”%d”,&n);
while (licznik <n) {
printf(” Podaj a=:”);
scanf (”%d”, &a);
printf(” Podaj b=:”);
scanf (”%d”, &b);
c=a<b;
printf (”\n Wartosc wyrazenia %d < %d=%d”,a,b,c);
c=a<=b;
printf (”\n Wartosc wyrazenia %d <= %d=%d”,a,b,c);
c=a==b;
prinf (”\n Wartosc wyrazenia %d ==%d=%d”,a,b,c);
c=a>b;
printf (”\n Wartosc wyrazenia %d > %d=%d”,a,b,c);
c=a>=b;
printf (”\n Wartosc wyrazenia %d > =%d=%d”,a,b,c);
c=a!=b;
printf (”\n Wartosc wyrazenia %d != %d=%d”,a,b,c); licznik=licznik+1;
getch(); }
return 0; }
Język ANSI C – operatory cz. VII
Operatory logiczne w języku C
Operatory te to:
‘ ! ‘ - operator negacji
‘&&‘ - operator koniunkcji( iloczynu logicznego)
‘||‘ - operator alternatywy (sumy logicznej)
Język ANSI C – operatory
Tabela wartości dla operatorów logicznych
x
y
x&&y
x||y
!x
0 (fałsz)
0 (fałsz)
0
0
1
0 (fałsz)
1 (prawda)
0
1
1
1 (prawda)
0 (fałsz)
0
1
0
1 (prawda)
1 (prawda)
1
1
0
Przykład. Program ilustrujący najprostsze użycie operatorów logicznych.
#include <stdio.h>
#include <conio.h.>
int main(int argc, char * argv{})
{ int a,b,c, n, licznik=0;
printf(” Podaj liczbe wykonan petli”);
scanf(”%d”,&n);
while (licznik <n) {
printf(” Podaj a=:”);
scanf (”%d”, &a);
printf(” Podaj b=:”);
scanf (”%d”, &b);
c=a&&b;
printf (”\n Wartosc wyrazenia %d &&%d=%d”,a,b,c);
c=a||b;
printf (”\n Wartosc wyrazenia %d ||%d=%d”,a,b,c);
c=!a;
prinf (”\n Wartosc wyrazenia !%d=%d”,a,c);
licznik=licznik+1;
getch(); }
return 0; }
Przykład. Wyrażenia logiczne. Dla obliczenia wartości w poniższych wyrażeniach
przyjęto x=1, y=4, z=1.
Wyrażenie
Wartość wyrażenia
x<=1 && y==3
0
x<=1||y==3
1
!(x>1)
1
!x>1
0
!(x<=1||y==3)
0
x>=1&&y==3||z<14
1
Priorytety operatorów cz. I
O kolejności stosowania operatorów w wyrażeniu decyduje ich
priorytet ( pierwszeństwo). Priorytet operatora decyduje o tym czy
będzie on użyty przed innymi operatorami czy też po nich. Przykładowo,
w wyrażeniu
a+b*c
stosowany jest najpierw operator * , a dopiero później operator +.
Podobnie w wyrażeniu
a>b && c<d || e>f
stosowane są najpierw operatory relacyjne, później operator && i
następnie operator ||.
Język ANSI C -operatory
Język ANSI C
Hierarchia operatorów ( dotychczas stosowanych)
Poziom 1 (najwyższy) ‘ –’ , ‘+’ (jednoargumentowy), ‘!’
Poziom 2 ‘ *’, ‘/’, ‘%’
Poziom 3 ‘+’, ‘-’
Poziom 4 ‘<‘, ‘<=‘, ‘>’,’>=‘,
Poziom 5 ‘==‘, ‘!=‘
Poziom 6 ‘&&’
Poziom 7 ‘ ||’
Poziom 8 ‘=‘
Język ANSI C – identyfikator
Identyfikatory
Pisząc program musimy wybrać nazwy dla zmiennych, funkcji i
innych obiektów.
-Identyfikator(nazwa) jest sekwencją liter i cyfr o dowolnej
długości (niektóre kompilatory wprowadzają tu pewne ograniczenia).
-Pierwszy znak identyfikatora musi być literą, przy czym znak
podkreślenia '_' jest traktowany jako litera.
-Litery duże i małe są rozróżniane.
Język ANSI C – identyfikatory
-Służą one do zapisu konstrukcji, jakie są dopuszczalne w C.
-Identyfikator nie może być słowem kluczowym(niektóre
identyfikatory zostały zastrzeżone przez twórców języka).
Budowa identyfikatora
Identyfikator w C musi spełniać następujące wymagania:
a) zaczynać od litery (A do Z, a do z) lub też od znaku
podkreślenia _ ;
b) składać z liter (A do Z, a do z), cyfr lub też znaków
podkreślenia _ ;
c) nie może być słowem kluczowym (słowo kluczowe to takie
słowo jak for czy while ).
Język ANSI C – identyfikatory
Przykład. Legalne (dopuszczalne) identyfikatory
ilosc
ilosc_calkowita
_suma
kolumna3
ILOSC
Z wyjątkiem identyfikatorów zewnętrznych (nazw zewnętrznych),
pierwsze 31 znaków każdego identyfikatora to tzw. znaki znaczące.
Jeżeli dwa identyfikatory różnią się od 32 znaku, mogą być uznane za
ten sam identyfikator. Ze względu na to , że rozróżniane są litery małe i
wielkie identyfikatory ilosc i ILOSC są różnymi identyfikatorami.
Język ANSI C – identyfikatory
Przykład. Identyfikatory nielegalne (niepoprawne).
ilosc$
(niedopuszczalny znak $)
2_suma
(rozpoczyna się cyfrą)
long
(słowo kluczowe)
druga suma
(w identyfikatorze nie może być
spacji)
ILOSC-CALKOWITA (niedopuszczalny znak -)
Język ANSI C – komentarze
Komentarze
- Komentarze są ciągami znaków ujętych w znaki /* */.
- Komentarze są ignorowane przez kompilator.
Przykład.
/* Komentarz w języku C */
- Komentarze takie mogą obejmować wiele wierszy.
- W komentarzach można używać polskie znaki.
- Jeśli stosuje się kompilator C++, można też stosować komentarz
jednowierszowy rozpoczynający się od znaków //.
Język ANSI C
W języku ANSI C istnieją następujące słowa kluczowe:
auto
double
int
struct
break
else
long
switch
case
enum
register
typedef
char
extern
return
union
const
float
short
unsigned
continue
for
signed
void
default
goto
sizeof
volatile
do
if
static
while
Język ANSI C – typ znakowy
Typ znakowy
-W językach programowania istnieje konieczność
reprezentowania, oprócz liczb, także znaków, np. liter.
-Znaki są reprezentowane wewnętrznie w postaci pewnych
całkowitych nieujemnych liczb zwanych kodami znaków.
-Sposób przyporządkowania poszczególnym znakom
odpowiednich liczb zwany jest kodem. Przykłady kodów to np.
ASCII, EBDIC, Unicode, 8859-2.
Język ANSI C – typ znakowy
Kod ASCII
- Kod ASCII (ang. American Standard Code for Information
Interchange) jest standardowym sposobem kodowania znaków.
- Standardowy oznacza, że jest powszechnie przyjęty przez wytwórców
różnych urządzeń, aby mogły się ze sobą komunikować.
- Kodowanie oznacza, że każdemu znakowi odpowiada w tym kodzie
pewna liczba będąca jej tzw. kodem ASCII.
Język ANSI C – typ znakowy
Kod ASCII
- W kodzie ASCII znaki o kodach z zakresu [0,127] należą do
tzw. standardowego zestawu znaków. Kodom z tego zakresu
odpowiadają te same znaki we wszystkich urządzeniach
wykorzystujących kod ASCII.
Ogólna budowa kodu ASCII
- Kody z zakresu [0,31] reprezentują tzw. znaki sterujące
np. kod 8 znak BS (ang. backspace), kod 10 znak LF
(ang. Line Feed- nowa linia), kod 13 znak CR (ang. Carriage
Return- powrót karetki, terminologia pochodzi z maszyn do
pisania). Cyfry są reprezentowane przez kody z przedziału
[48,57], duże litery z [65,90], a małe litery [97,122].
( kody pozostałych znaków w dostarczonym materiale).
Język ANSI C – typ znakowy
Typ znakowy
- W języku C istnieje specjalny typ char o zakresie [-128,127]
przeznaczony do operacji na znakach. Zmienne i stałe tego typu
zajmują 1 bajt. Zmienne są definiowane w sposób następujący:
char ch;
- W języku C istnieje szereg funkcji istnieje umożliwiających
wykonywanie operacji na znakach takich jak wprowadzanie znaków z
klawiatury, wyprowadzanie znaków na ekran i klasyfikacja znaków.
Język ANSI C – typ znakowy
Wejście znakowe(1)
- Znaki mogą być wczytywane z klawiatury przy zastosowaniu
funkcji pochodzących ze standardowej biblioteki języka C lub też
funkcji dostarczanych przez producentów kompilatorów.
1. Funkcja scanf.
Przy wczytywaniu znaków konieczne jest zastosowanie deskryptora
format %c.
printf(” Podaj znak :”);
scanf (”%c”,&ch);
2. Funkcja getchar().
printf(” Podaj znak :”);
ch=getchar();
Język ANSI C – typ znakowy
Wejście znakowe (2)
- Funkcja getch();
printf(” Podaj znak :”);
ch=getch();
Wczytywanie znaku przy użyciu scanf i getchar wymaga Enter po
wprowadzeniu znaku.
Język ANSI C – typ znakowy
Wyjście znakowe
- Wyprowadzenie znaku na ekran może być zrealizowane w sposób
następujący
printf(” Znak=%c”, ch);
lub
putchar(ch);
lub
putch (ch);
Język ANSI C – typ znakowy
Przykład. Drukowanie wybranych znaków i ich kodów ASCII.
#include <stdio.h>
#include <conio.h>
main()
{ int i ;
i=32;
clrscr();
while (i<256)
{
printf(”\n \n Znak =%c kod dec=%3d hex =%x oct=%o”, i ,
i, i, i );
getch();
i++;
}
return 0;
}
Język ANSI C – typ znakowy
Stałe znakowe
Stała znakowa – ciąg złożony z jednego lub wiekszej liczby
znaków ujęty w pojedyncze apostrofy np. ‘x’.
Stałe jednoznakowe są typu char, a wieloznakowe typu int.
Stałe znakowe mogą być używane w operacjach arytmetycznych.
W operacjach stosowany jest kod ASCII liczby np..
int cyfra;
cyfra= ‘5’-’0’;
Faktycznie jest to odejmowanie 53-48, czyli w zmiennej cyfra
będzie wartość 5.
Język ANSI C – typ znakowy
Stałe znakowe
Stałe znakowe mogą być zapisywane również przy zastosowaniu
kodów heksalnych i oktalnych, np. stałą znakową
‘A’ można zapisać także jako ‘\x41’ albo też ‘\101’ .
Mechanizm ten ma szczególne znaczenie jeżeli chce się
drukować znaki, które nie występują na klawiaturze.
Język ANSI C – typ znakowy
Stałe znakowe
Przykładowo, napis ” Róża bez kolców” można
wydrukować w sposób następujący:
printf("\n R\242\276a bez kolc\242w"); //wersja oktalna
printf("\n R\xa2\xbe a bez kolc\xa2w");// wersja heksalna
W powyższych instrukcjach zastosowano kody oktalne i heksalne
liter ó i ż. 242 i a2 są kodami ó, a 276 i be litery ż.
Język ANSI C – typ znakowy
Sekwencje ucieczki ( ang. escape sequences)
Znaki, które nie mają reprezentacji graficznej na
ekranie monitora lub też mają specjalne znaczenia w
łańcuchach znaków, mogą być wygenerowane przy użyciu
tzw. sekwencji ucieczki złożonych z ukośnika \ i
odpowiedniego znaku.
Język ANSI C – typ znakowy
Tabela sekwencji ucieczki cz. I
Nazwa sekwencji
Symbol
Zapis znakowy
Wartość liczbowa
Nowy wiersz
NL(LF)
\n
10 (dec)
Tabulacja
pozioma
HT
\t
9(dec)
Tabulacja
pionowa
VT
\v
11(dec)
Kasowanie znaku
(backspace)
BS
\b
8(dec)
Powrót karetki
CR
\r
13(dec)
Język ANSI C – typ znakowy
Tabela sekwencji ucieczki cz. II
Nazwa sekwencji
Symbol
Zapis znakowy
Wartość liczbowa
Nowa strona
( form feed)
FF
\f
12 (dec)
Dzwonek
(alert)
BEL
\a
7(dec)
Lewy ukośnik
\
\\
92(dec)
Znak zapytania
?
\?
63(dec)
Pojedynczy
apostrof
‘
\’
39(dec)
Podwójny
apostrof
”
\”
34(dec)
Znak zerowy
NUL
\0
0
Język ANSI C – typy rzeczywiste
Zakresy i rozmiary typów rzeczywistych
Typ Rozmiar(bity) Zakres liczbowy Liczba cyfr znaczących
float
32 6-7
double
64 15-16
long double
80 19-20
308
308
10
4
.
3
do
10
7
.
0
⋅
⋅
−
38
38
10
4
.
3
do
10
4
.
3
⋅
⋅
−
4932
4932
10
1
.
0
do
10
4
.
3
⋅
⋅
−
Język ANSI C – typy rzeczywiste
Przykład. Program ilustrujący wczytywanie i drukowanie zmiennych rzeczywistych typu
float, double i long double.
#include <stdio.h>
#include <conio.h>
main()
{ float x; double y; long double z;
printf(”Podaj x:”);
scanf(”%f”, &x); // %f jest deskryptorem formatu stosowanym przy wczytywaniu
// i drukowaniu zmiennych typu float
printf(”\n Podaj y:”);
scanf(”%lf”, &y);// %lf deskryptor formatu dla zmiennych typu double
printf(”\nPodaj z:”);
scanf(”%Lf”, &z);// %Lf deskryptor formatu dla zmiennych typu long double
printf(”\n x=%f”, x);
printf(”\n y=%f”, y);
printf(”\n z=%Lf”, z);
getch();
return 0; }
Język ANSI C – typy rzeczywiste
/*Przykład. Program ilustrujący użycie operatorów arytmetyki rzeczywistej*/
#include <stdio.h>
#include <conio.h>
main()
{ double a,b,c;
printf(”Podaj a:”);
scanf(”%lf”, &a);
printf(”Podaj b:”);
scanf(”%lf”, &b);
c=a+b;
printf(”\n Suma %f + %f =%f”, a,b,c);
c=a-b;
printf(”\n Roznica %f - %f =%10.2f”, a,b,c);
c=a*b;
printf(”\n Iloczyn %f * %f =%.4f”, a,b,c);
c=a/b;
printf(”\n Iloraz %e przez %e =%f”, a,b,c);
getch();
return 0;}
Język ANSI C – typy rzeczywiste
Formatowanie wydruku liczb rzeczywistych
Formatowanie wydruku to kształtowanie zewnętrznej postaci liczb (na ekranie monitora lub
na drukarce). Zakres takiego kształtowania zależy od formatu liczby rzeczywistej czyli sposobu
jej przechowywania w pamięci komputera. Powszechnie przyjmuje się tzw. formaty standardowe
zgodne z pewną normą. Normą tą jest tzw. standard IEEE 754. Standard ten określa cztery
podstawowe formaty binarne liczb rzeczywistych:
- zwykły o o pojedynczej precyzji (SINGLE)
- rozszerzony o pojedynczej precyzji (SINGLE EXTENDED)
- zwykły o podwójnej precyzji (DOUBLE)
- rozszerzony podwójnej precyzji (DOUBLE EXTENDED)
s
...........................
...............
E- wykładnik w e-bitowym
kodzie z obciążeniem +N
f- ułamek ( m-bitowy kod
modułu mantysy bez bitu
ukrytego)
Język ANSI C – typy rzeczywiste
W standardzie IEEE 754 wymaga się, aby reprezentacje liczb były znormalizowane( nie dotyczy
to liczb bardzo bliskich 0). Moduł mantysy ma być liczbą z przedziału
i obowiązuje konwencja ukrytej jedynki, co oznacza, że najstarszy bit mantysy jest równy 1,
jednak nie jest pamiętany. Każdy moduł ma postać 1.bbb.....b. Wartość liczby znormalizowanej
można wyrazić następującą zależnością:
M
2
1
<
≤ M
( )
E
s
f
F
2
)
1
(
1
⋅
+
⋅
−
=
Język ANSI C – typy rzeczywiste
Wybrane formaty IEEE 754
Parametr
Symbol
SINGLE
DOUBLE
DOUBLE
EXTENDED
Rozmiar formatu
n
32
64
>=79
Rozmiar mantysy
m
23(+1)
52(+1)
>=64
Rozmiar wykładnika
e
8
11
>=15
Obciążenie wykladnika
N
127
1023
>=16383
Zakres wykładnika
E
[-126,127] [-1022,1023]
[-(N-1),N]
Dokładność
ulp
Zakres formatu
R
7
23
10
2
−
−
≈
15
52
10
2
−
−
≈
1
2
+
−m
38
128
10
2
≈
308
1024
10
2
≈
4932
16384
10
2
≈
Język ANSI C – typy rzeczywiste
Maksymalna ilość znaczących cyfr dziesiętnych, które można uzyskać w wydruku wynika z
wielkości liczb dziesiętnych, która z kolei wynika z przeliczenia maksymalnych wartości
mantysy na postać dziesiętną. Dla typu SINGLE ( w języku C odpowiada mu typ float) mantysa
może reprezentować liczbę dziesiętną o wartości
co umożliwia uzyskanie 6-7 cyfr dziesiętnych. Podobnie
dla typu double mamy
co daje 15-16 cyfr dziesiętnych.
7
23
10
2
≈
15
52
10
2
≈
Język ANSI C – typy rzeczywiste
Dla typu long double mamy
czyli 19-20 cyfr dziesiętnych.
Podstawowe formaty wydruku liczb rzeczywistych w języku C to
- format stałoprzecinkowy
- m.dd..ddd
- format zmiennoprzecinkowy ( notacja inżynierska)
m.d....d e xx lub m.d....d e xxxx
( zamiast e może też być stosowane E).
19
64
10
2
≈
±
±
Język ANSI C – typy rzeczywiste
Wybrane zasady tworzenia opisu formatu w łańcuchu formatującym
(pełny opis w B.W. Kernighan, D.M. Ritchie, Język ANSI C, Dodatek B,
Pkt. B1.2 Formatowanie wyjście)
Przykład.
double x=12.348;
printf(”\n x=%10.2lf”, x);
Opis formatu rozpoczyna się znakiem %, liczba 10 oznacza minimalną szerokość pola wydruku,
liczba 2 ilość drukowanych miejsc po kropce dziesiętnej, a lf oznacza wydruk wartości typu
double.
W ogólnym przypadku pomiędzy znakiem % a znakiem przekształcenia mogą wystąpić
- modyfikatory( umieszczane w dowolnej kolejności), które wpływają na postać wydruku:
Język ANSI C – typy rzeczywiste
Modyfikatory te to:
-znak minus (-) powodujący dosunięcie wydruku do lewego krańca pola
- znak plus (+) wypisanie liczby zawsze ze znakiem
- odstęp poprzedzenie wyniku znakiem odstępu, jeżeli pierwszym drukowanym znakiem nie jest
plus lub minus
-znak zero (0) uzupełnienie liczby wiodącymi zerami do pełnego rozmiaru pola
Następnym znakiem jest liczba określająca minimalny rozmiar pola. Przekształcony
argument zostanie wydrukowany w polu o ilości znaków nie mniejszej niż ta liczba. Jeżeli
argument wymaga szerszego pola, to pole wydruku jest rozszerzane. Jeżeli argument jest krótszy,
dopełniany jest spacjami z lewej strony (ew. w zależności od modyfikatora z prawej lub zerami).
Kolejnym znakiem jest kropka, której następuje liczba oznaczająca precyzję czyli ilość cyfr po
kropce dziesiętnej w specyfikacjach f, e i E.
Język ANSI C – typy rzeczywiste
Uwagi dodatkowe o formatach f, e i E
Dla formatu f domyślną precyzją jest 6, przy precyzji zero opuszcza się kropkę dziesiętną. Dla
formatu m.dddddde xx lub formatu m.ddddddE xx domyślną precyzją jest 6 i przy precyzji
zero również opuszcza się kropkę dziesiętną.
Przykład. Formaty z zastosowaniem modyfikatorów.
x=25.3485;
printf(”\n x=% 020.4f”,x);// uzupełnienie zerami
printf(”\n x=% +20.4f”,x);// drukowanie znaku liczby
printf(”\n x=% -20.4f”,x);//dosunięcie do lewego krańca pola
Otrzymane wydruki:
x= 000000000000025.3485
x= +25.3485
x= 25.3485
± ±
±
Język ANSI C – typy rzeczywiste
Standard ANSI/ISO C definiuje zawartość i postać standardowej biblioteki języka ANSI
C. Standard określa zestaw funkcji, w który muszą być wyposażone kompilatory zgodne
ze standardem. Kompilatory mogą też zawierać funkcje, które nie są określone w
standardzie. Każda funkcja zdefiniowana w standardowej bibliotece języka C ma
odpowiadający jej nagłówek, nagłówki te są zawarte w plikach nagłówkowych
włączanych dyrektywą #include.
Standard C89 zawiera następujące 22 standardowe funkcje arytmetyczne:
acos
cos
fmod
modf
tan
asin
cosh
frexp
pow
tanh
atan
exp
ldexp
sin
atan2
fabs
log
sinh
ceil
floor
log10
sqrt
Arytmetyczne funkcje standardowe ANSI C
Język ANSI C – typy rzeczywiste
acos
double acos (double arg);
long double acosl (long double arg);
Funkcje te obliczają arcus cosinus arg. Argument musi należeć do przedziału [-1,1].
Jeżeli argument nie należy do tego przedziału, pojawi się błąd dziedziny (ang. domain
error).
asin
double asin (double arg);
long double asinl (long double arg);
Funkcje te obliczają arcus sinus arg . Argument musi należeć do przedziału [-1,1].
Jeżeli argument nie należy do tego przedziału, pojawi się błąd dziedziny (ang. domain
error).
Język ANSI C – typy rzeczywiste
atan
double atan (double arg);
long double atanl (long double arg);
Funkcje atan and atanl dla argumentu rzeczywistego obliczają wartość arcusa
tangensa (wynik w zakresie -pi/2 do pi/2).
double atan2 (double y, double x);
long double atan2l (long double y, long double x);
Funkcje atan2 and atan2l dla argumentu rzeczywistego obliczają wartość arcusa
tangensa y/x (wynik w zakresie -pi/2 do pi/2).
Język ANSI C – typy rzeczywiste
double ceil (double num);
long double ceill (long double num);
Funkcje zwracają (obliczają) najmniejszą liczbę całkowitą typu double nie mniejszą niż
num.
Np. Dla num 1.05 funkcja zwraca wartość 2.0, a dla -1.05, zwraca -1.0.
double cos (double arg);
double cosl (long double arg);
Funkcja ta zwraca cosinus arg. Kąt jest podawany w radianach. Zwracana wartość w
zakresie [-1,1].
double cosh (double arg);
long double coshl (long double arg);
Funkcja ta zwraca cosinus hiperboliczny arg.
Język ANSI C – typy rzeczywiste
double exp (double num);
long double expl (long double num);
Funkcja oblicza .
W pewnych sytuacjach argumenty przekazane do tych funkcji powodują nadmiar
arytmetyczny lub wynik nie może zostać obliczony. Gdy powstaje nadmiar
arytmetyczny, funkcja exp zwraca HUGE_VAL a expl zwraca _LHUGE_VAL.
Rezultaty o bardzo dużej wartości powodują ustawienie zmiennej globalnej errno
na
ERANGE
Result out of range.
Przy niedomiarze arytmetycznym funkcje te zwracają 0.0, errno nie jest zmieniana.
Traktowanie błędu dla tych funkcji może być zmienione poprzez funkcje _matherr and
_matherrl.
x
e
Język ANSI C – typy rzeczywiste
/* _matherr example biblioteka standardowa C++ Builder 6.0*/
// przykład dla zaawansowanych – przechwytywanie i korekcja błędu
// dziedziny
#include <math.h>
#include <string.h>
#include <stdio.h>
int _matherr (struct _exception *a)
{
if (a->type == DOMAIN)
if (!strcmp(a->name,"sqrt")) {
a->retval = sqrt (-(a->arg1));
return 1;
}
return 0;
}
int main(void)
{
double x = -2.0, y;
y = sqrt(x);
printf("_Matherr corrected value: %lf\n",y);
return 0;
}
Język ANSI C – typy rzeczywiste
double fabs (double num);
long double fabsl (long double num);
Funkcje obliczają wartość bezwzględną argumentu num.
double floor (double num);
long double floorl (long double num);
Funkcje te zwracają (obliczają) największą liczbę całkowitą nie większą niż num.
Np. dla 1.05 funkcja zwraca wartość 1.0, a dla -1.05, zwraca -2.0.
double fmod (double a, double b);
long double fmodl (long double a, long double b);
Funkcje obliczają resztę z dzielenia a/b.
Język ANSI C – typy rzeczywiste
double frexp (double num, int *pexp);
long double frexpl (long double num, int *pexp);
Funkcje te rozkładają liczbę num na mantysę z przedziału [0.5,1.0] oraz wykładnik
całkowity exp, takie że num=mantysa .
Przykład.
int exp, mantysa;
double num=0.5;
mantysa=frexp(num,&exp);
double ldexp (double num, int exp);
long double ldexpl (long double num, int exp);
Funkcje obliczają wartość wyrażenia num .
exp
2
⋅
exp
2
⋅
exp
2
⋅
Język ANSI C – typy rzeczywiste
double log (double num);
long double logl (long double num);
Funkcje obliczają logarytm naturalny z num. Jeżeli num<0, występuje błąd dziedziny,
dla num=0 błąd zakresu.
double log10 (double num);
long double log10l (long double num);
Funkcje obliczają logarytm dziesiętny z num. Jeżeli num<0, występuje błąd
dziedziny, dla num=0 błąd zakresu.
Język ANSI C – typy rzeczywiste
double modf (double num, int *pi);
long double modfl (long double num, int *pi);
Funkcje te rozkładają liczbę num na część całkowitą i część ułamkową.
Funkcja zwraca część ułamkową, a część całkowitą wstawia do zmiennej wskazywanej
przez wskaźnik pi.
Przykład.
int cz_calkowita,cz_ulamkowa;
double num=0.5;
cz_ulamkowa=modf(num,&cz_calkowita);
double pow(double base, double exp);
long double powl (long double base, long double exp );
Funkcje obliczają wartość base podniesioną do potęgi exp. Reguły obliczania takie jak
dla funkcji exp.
Jeżeli argument odpowiadający base przekazany do pow lub powl jest rzeczywisty i
mniejszy od 0, a argument odpowiadający exp nie jest całkowity lub jeśli argument
odpowiadający base jest równy 0 a argument odpowiadający exp jest mniejszy od 0, lub
stosuje się wywołanie pow(0,0), zmienna globalna errno jest ustawiana na wartość
EDOM Domain error. .
Język ANSI C – typy rzeczywiste
double sin (double arg);
long double sinl (long double arg);
Funkcje te zwracają sinus arg. Kąt jest podawany w radianach. Zwracana wartość w
zakresie [-1,1].
double sinh (double arg);
long double sinhl (long double arg);
Funkcje te zwracają sinus hiperboliczny arg.
double sqrt (double arg);
long double sqrtl (long double arg);
Funkcja ta zwraca dodatni pierwiastek kwadratowy z arg. Jeżeli arg
mniejszy od 0, zmienna globalna errno jest ustawiana na wartość EDOM Domain error.
Język ANSI C – typy rzeczywiste
double tan (double arg);
long double tanl (long double arg);
Funkcje te zwracają tangens arg. Wartość arg jest podawana w radianach.
double tanh (double arg);
long double tanhl (long double arg);
Funkcje te zwracają tangens hiperboliczny arg.
Język ANSI C – typy rzeczywiste
⎣ ⎦
x
x
x
ctgz
x
e
tgx
x
y
π
+
+
−
+
+
+
=
3
2
)
1
(
log
3
sin
log
5
Przykład. Napisać program obliczający dane wyrażenie dla zmiennych x i z typu double
wprowadzanych z klawiatury. Przy wprowadzaniu danych sprawdzać czy dane
reprezentują liczby, czy należą do dziedziny oraz czy nie nastąpi przekroczenie zakresu
typu double.
Język ANSI C – typy rzeczywiste
#include <stdio.h>
#include <conio.h>
#include <math.h>
int main(int argc, char* argv[])
{ double x,z,p1,p2,p3,p4,p5,p6,q1,q2,q3,licznik,mianownik,wynik;
int k;
printf("\n Podaj x:");
scanf("%lf",&x);
printf("\n Podaj z:");
scanf("%lf",&z);
p1=fabs(sin(x));
p2=log10(p1);
p3=fabs(tan(x));
p3=sqrt(p3);
p4=fabs(pow(x,5));
p5=exp(p4);
p6=floor(pow(3,x));
q1=log10(x-1)/log10(2);
q2=pow(1/tan(z),1/3.0);
q3=pow(M_PI,x);
Przykład. Obliczanie wyrażenia ( wersja bez sprawdzania danych)
Język ANSI C – typy rzeczywiste
// cz.2 programu obliczającego wyrażenie
licznik=p2+p3+p5+p6;
mianownik=q1+q2+q3;
if (mianownik) {
wynik=licznik/mianownik;
printf("\n Wartosc wyrazenia wynosi=%f",wynik);
getch(); }
else {
printf("\n Dzielenie przez zero");
getch(); }
return 0;
}
Język ANSI C – typy rzeczywiste
Dziedzina:
a) ze względu na funkcję logarytm w liczniku x musi być różny od wielokrotności pi.
b) ze względu na funkcję logarytm w mianowniku, musi być x>1.
Ograniczenie na x wynika też z wartości przybieranych przez człon
Musi być spełniona zależność
Graniczną wartość x możemy określić jako
5
x
e
308
10
5
≤
x
e
71
.
3
10
ln
308
5
≅
⋅
=
x
Język ANSI C – typy rzeczywiste
// Fragment programu związany ze sprawdzaniem danych wejściowych
#include <stdio.h>
#include <conio.h>
#include <math.h>
int main(int argc, char* argv[])
{ double x,z,p1,p2,p3,p4,p5,p6,q1,q2,q3,licznik,mianownik,wynik;
int k;
do
{
printf("\n Podaj x:");
k= scanf("%lf”,&x);
fflush(stdin);
if (k==0) printf(”\n Niewlasciwy format liczby”);
else
if (x<=1 || x==M_PI||x>3.7) printf(”\n x nie należy do dziedziny”);
}
while (k==0 || x<=1|| x==M_PI ||x>3.7 );
do {
printf("\n Podaj z:");
k=scanf("%lf",&z);
} while(!k||fmod(z,M_PI)==0);
Język ANSI C – typy rzeczywiste
Z obliczaniem wyrażeń w języku C wiążą się trzy zagadnienia:
a) problem kolejności obliczania podwyrażeń
b) konwersja typów w wyrażeniach
c) rzutowanie (zmiana typu wyrażenia)
Ad a.
Język C nie określa kolejności w jakiej są obliczane podwyrażenia danego
wyrażenia. Kompilator ma więc swobodę w zmianie kolejności obliczania tak aby
uzyskać zoptymalizowany kod. Przykładowo w wyrażeniu
x=f1() +f2();
nie można określić czy funkcja f1 będzie wywołana jako pierwsza.
Język ANSI C – typy rzeczywiste
Ad.b.
Jeżeli w wyrażeniu występują zmienne i stałe różnych typów, są one wszystkie
przekształcane do jednego wspólnego typu. Kompilator przekształca wszystkie
operandy do największego typu występującego w wyrażeniu. W pierwszym rzędzie
wartości typu char i short int przekształcane są do typu int.
Przekształcenia typów przebiegają zgodnie z powyższymi regułami:
- jeżeli operand jest typu long double, to drugi operand jest przekształcany do typu
long double,
-jeżeli operand jest typu double, to drugi operand jest przekształcany do typu double,
-jeżeli operand jest typu unsigned long, to drugi operand jest przekształcany do typu
unsigned long,
-jeżeli operand jest typu float, to drugi operand jest przekształcany do typu float,
-jeżeli operand jest typu long int, to drugi operand jest przekształcany do typu long
int,
Język ANSI C – typy rzeczywiste
Ad. b (ciąg dalszy-przekształcenia typów)
-jeżeli operand jest typu unsigned int , to drugi operand jest przekształcany do typu
unsigned int,
Istnieje jednak pewien specjalny przypadek: jeżeli jeden operand jest typu long a
drugi typu unsigned int, i wartości typu unsigned int nie można przedstawić przy
użyciu typu long, wtedy oba operandy są przekształcane do typu unsigned int.
Język ANSI C – typy rzeczywiste
Ad. b (ciąg dalszy-przekształcenia typów)
Po zastosowaniu powyższych reguł każda para operandów ma ten sam typ oraz wynik
operacji jest tego samego typu, co typ obu operandów.
Przykład.
char ch=3; int i=5; float f=1.5; double d=2.5,wynik;
wynik=(ch / i) + (f * d) -
(f + i);
int double float
int double float
double
double
Język ANSI C – typy rzeczywiste
Ad.c. (rzutowanie)
Typ wyrażenia można narzucić lub zmienić przy pomocy tzw. rzutowania. Ogólna
postać rzutowania to:
(typ) wyrażenie,
lub
typ ( wyrażenie)
Rzutowanie jest operatorem o priorytecie takim jak pozostałe operatory
jednoargumentowe.
Język ANSI C – typy rzeczywiste
Przykład. Napisać fragment programu określający procentową ilość udanych prób w
stosunku do ogólnej ilości prób.
// Przykład. Zmiana typu poprzez rzutowanie
#include <stdio.h>
#include <conio.h>
#include <math.h>
int main(int argc, char* argv[])
{
int ilosc_prob, ilosc_udanych_prob;
double udzial_procentowy;
printf("\n Podaj ilosc prob :");
scanf("%d",&ilosc_prob);
printf("\n Podaj ilosc udanych prob:");
scanf("%d",&ilosc_udanych_prob);
udzial_procentowy=
double (ilosc_udanych_prob
)/ilosc_prob*100;
printf("\n Udzial procentowy udanych prob=%6.2f%", udzial_procentowy);
getch();
return 0;
}
Język ANSI C – instrukcje
Instrukcja złożona (grupująca)
Instrukcja złożona składa się z nawiasu klamrowego otwierającego, dowolnych
instrukcji (mogą być również kolejne instrukcje złożone) i nawiasu klamrowego
zamykającego:
Przykład. Instrukcja złożona.
{
printf("Instrukcja 1" );
printf("Instrukcja 2\n");
}
Wszystkie instrukcje w języku C z wyjątkiem instrukcji złożonej kończą się średnikiem
Instrukcja złożona jest stosowana wtedy, gdy istnieje konieczność zgrupowania kilku
instrukcji, tak aby były traktowane jako jedna instrukcja.
Język ANSI C – instrukcje
Instrukcja while
Instrukcja while jest instrukcją iteracyjną, umożliwiającą powtarzanie pewnego ciągu
operacji. Instrukcja while ma następującą postać:
while (wyrażenie)
akcja
W instrukcji while najpierw określa się czy wyrażenie jest prawdziwe czy też
fałszywe. C wymaga by wyrażenie było zawarte w nawiasach.. Jeżeli wyrażenie jest
prawdziwe, wykonywana jest akcja i następuje powrót do obliczania wyrażenia.
wyrażenie jest ponownie testowane i jeżeli jest prawdziwe znowu wykonywana jest
akcja i następuje kolejny powrót do obliczania wyrażenia. Jeżeli jednak przy którymś
obliczaniu wyrażenia, stwierdzone zostanie, że wyrażenie jest fałszywe, następuje
natychmiastowe przejście do instrukcji znajdującej się po instrukcji while.
Język ANSI C – instrukcje
Akcja może się składać z jednej instrukcji lub też szeregu instrukcji zawartych
w nawiasach {
}. Użycie tych nawiasów jest konieczne jeśli akcja
obejmuje więcej niż jedną instrukcję.
Przykład. Instrukcja while.
int x=0;
while (x != 2)
x = x + 1;
printf (“\n x = %d”, x);
Język ANSI C – instrukcje
Fragment ten wydrukuje
x = 2
Zmienna x jest inicjalizowana wartością 0 przy definicji. Ponieważ != jest operatorem
relacyjnym „różne” (nierówne), wyrażenie
x != 2
ma wartość prawda i wykonywane jest instrukcja
x = x + 1,
która dodaje 1 do x, i wynik umieszcza w x. Następuje powrót do obliczania wyrażenia
po while. Wyrażenie x != 2 jest prawdziwe (gdyż x równa się 1), więc znowu dodawane
jest 1 do x i następuje powrót do obliczania wyrażenia po while. Wyrażenie x != 2 jest
teraz fałszywe (bo x równa się 2) więc zostanie wykonana instrukcja
printf (“\n x = %d”, x); która pisze x = 2
Język ANSI C – instrukcje
Instrukcja do while
Instrukcja do while jest podobna do instrukcji while, z tą różnicą, że wyrażenie
kontrolujące pętlę jest na końcu pętli. Cała pętla wykonywana jest przynajmniej raz.
do
akcja
while (wyrażenie);
Przy wykonywaniu pętli do while wykonywana jest najpierw akcja, a następnie
wykonywane jest sprawdzenie, czy wyrażenie jest prawdziwe czy też nie. Jeżeli jest
prawdziwe, następuje powrót do początku pętli. Jeżeli w którymś momencie wyrażenie
staje się fałszywe, wykonywana jest pierwsza instrukcja występująca po pętli. Część
pętli oznaczona jako akcja może być jedną instrukcją lub też grupą instrukcji zamkniętą
w nawiasy { }.
Język ANSI C – instrukcje
Instrukcja do while jest użyteczna wtedy, gdy test w sposób naturalny znajduje się
na końcu pętli. Przykładem takiej sytuacji może być weryfikacja wartości wprowadzanej
przez użytkownika z klawiatury. Po wprowadzeniu wartości, jest ona sprawdzana.
Jeżeli wartość jest niedopuszczalna przy danym formacie, użytkownik zachęcany jest do
wprowadzenia innej wartości.
Przykład. Użycie instrukcji do while do wprowadzenia liczby dodatniej.
int wartosc, k;
do {
printf (“\nPodaj liczbe calkowita:”);
k = scanf (“%d”, &wartosc);
fflush(stdin); //Czyszczenie strumienia wejściowego
} while (!k || wartosc <=0);
Język ANSI C – instrukcje
Instrukcja warunkowa if
Instrukcja warunkowa if umożliwia uzależnienie wykonania pewnej instrukcji od
spełnienia pewnego warunku. Warunek ten jest reprezentowany przez wyrażenie
umieszczone po słowie if. Wyrażenie to przybiera wartość prawda lub wartość fałsz
(wszystkie wartości różne od 0 są w języku C traktowane jako prawda, wartość 0 jako
fałsz). Instrukcja ta ma następującą postać
if (wyrażenie)
akcja;
Język ANSI C – instrukcje
Wyrażenie musi być zawarte w nawiasach. Aby wykonać if najpierw oblicza się
wyrażenie i określa się czy jest prawdziwe czy też fałszywe. Jeżeli wyrażenie jest
prawdziwe, zostaje wykonana akcja i sterowanie przechodzi do instrukcji programu
umieszczonej po akcji.
Jeżeli wyrażenie jest fałszywe, akcja zostaje pominięta i następuje przejście do
instrukcji umieszczonej po akcji. Część if określona jako akcja składa się z pojedynczej
instrukcji lub instrukcji złożonej (pewnej liczby instrukcji umieszczonych w nawiasach
{}).
Język ANSI C – instrukcje
Przykład. Instrukcja if
int kod;
printf(”\n Podaj kod:”);
scanf(”%d”,&kod);
if (kod= =1)
printf ("\n warunek jest spełniony");
Jeżeli z klawiatury podano wartość 1, fragment programu drukuje napis
warunek jest spełniony
Nie należy mylić znaku = z parą znaków = =. Można wprawdzie napisać if (x=1),
jednak wyrażenie po if jest tutaj równe 1 niezależnie od wartości x, więc instrukcja if
nie będzie pełnić swojej roli.
Język ANSI C – instrukcje
Instrukcja if else
Instrukcja ta ma następującą postać:
if (wyrażenie)
akcja1
else
akcja2
Podobnie jak dla instrukcji if, najpierw obliczane jest wyrażenie po if. Jeżeli wyrażenie
ma wartość logiczną prawda, wykonywana jest akcja1,
natomiast jeżeli wyrażenie ma wartość fałsz, jest wykonywana akcja2.
Język ANSI C – instrukcje
Przykład. Instrukcja if else
int kod;
printf(”\n Podaj kod”);
scanf(” %d”,&kod);
if (kod==3245)
printf(”\n Podano prawidłowy kod”);
else
printf(”\n Kod nie jest poprawny”);
Język ANSI C – instrukcje
Przykład. Instrukcja if else ze złożonymi instrukcjami po if i po else.
int kod;
printf(”\n Podaj kod”);
scanf(” %d”,&kod);
if (kod!=2)
{
printf(”\n Instrukcje te wykonują się gdy ”);
printf(”\n zmienna kod ma wartość rozna od 2”);
}
else
{
printf(”\n Instrukcje te się wykonuja”);
printf(”\n gdy zmienna kod ma wartosc 2 ”);
}
Język ANSI C – instrukcje
Przykład. Określić napisy drukowane przez poniższy fragment programu dla zmiennej
kod=1 i 2.
int kod;
printf(”\n Podaj kod”);
scanf(” %d”,&kod);
if (kod==2)
{
printf(”\n Matematyk”);
if (kod==2)
printf(” artysta”);
else
printf(” programista”);
}
else
printf(”\n Specjalista programista”);
Język ANSI C – instrukcje
Instrukcje if zagnieżdżone
W instrukcji takiej po if lub po else występuje kolejna instrukcja warunkowa if lub if
else.
Instrukcja taka ma budowę następującą:
if (wyrażenie1)
akcja1;
else if (wyrażenie2)
akcja2;
else if (wyrażenie3)
.
.
.
else if (wyrażenie n)
akcja n;
Język ANSI C – instrukcje
Działanie instrukcji if zagnieżdżone
Instrukcja taka funkcjonuje w sposób następujący:
jeżeli prawdziwy jest warunek pierwszy (wyrażenie1) to wykonywana jest akcja1 i
następuje przejście do instrukcji umieszczonej po akcji n-tej.
Ogólnie, jeżeli jest prawdziwe wyrażenie i-te, to jest wykonywana i-ta akcja i
następuje przejście do instrukcji po wyrażeniu n-tym.
Jest wykonywana tylko jedna akcja (grupa akcji w nawiasie klamrowym), pozostałe
akcje są odrzucane.
Język ANSI C – instrukcje
Przykład. Instrukcja if zagnieżdżone.
int kod;
printf(”\n Podaj kod”);
scanf(” %d”,&kod);
if (kod= =1)
printf("Akcja ta jest wykonywana gdy kod jest równy 1");/*instrukcja 1*/
else if (kod= =2)
printf("Akcja ta jest wykonywana gdy kod jest równy 2");/*instrukcja 2*/
else if (kod<=3)
printf("Akcja ta jest wykonywana gdy kod jest mniejszy równy 3");/*instrukcja 3*/
Gdy zmienna kod ma wartość 1, wykonywana jest instrukcja 1, pomimo że
wyrażenie kod<=3 jest prawdziwe, jednak sterowanie do niego w tym przypadku nie
dochodzi.
Język ANSI C – instrukcje
Instrukcja if else z akcją domyślną
if (wyrażenie1)
akcja1;
else if (wyrażenie2)
akcja2;
else if (wyrażenie3)
.
.
.
else if (wyrażenie n)
akcja n;
else
akcja;
Akcja jest tutaj działaniem domyślnym, które jest wykonywane, gdy
żadna z akcji od 1 do n nie zostanie wykonana.
Język ANSI C – instrukcje
Przykład. Instrukcja if else z akcją domyślną.
int kod;
printf(”\n Podaj kod”);
scanf(” %d”,&kod);
if (kod= =1)
printf(”Akcja ta jest wykonywana, gdy kod jest rowny 1");
else if (kod= =2)
printf("Akcja ta jest wykonywana, gdy kod jest rowny 2");
else if (kod<=3)
printf("Akcja ta jest wykonywana gdy kod jest mniejszy lub
rowny 3");
else
printf("Akcja ta jest wykonywana, gdy "
"żadna z akcji 1, 2, 3 nie wykona się");
Język ANSI C – operator ? (wyrażenie warunkowe)
Operator ? pozwala na zastąpienie niektórych instrukcji if-else. Operator ten ma postać:
wyrażenie1 ? wyrażenie2 :wyrażenie3
Operator ten działa w sposób następujący: najpierw jest obliczane wyrażenie1, jeśli ma
ono wartość logiczną prawda, wtedy jest obliczane wyrażenie2 i staje się ono wartością
całego wyrażenia, jeśli zaś wyrażenie1 ma wartość logiczną fałsz, obliczane jest
wyrażenie3 i ono staje się wartością całego wyrażenia.
Przykład.
int x, y;
x=5;
y=x>10? 50 : 100;
Język ANSI C – operator ? (wyrażenie warunkowe)
Przykład.
z=a>b? a: b; // max(a,b)
Powyższa instrukcja wyznacza większą z wartości a i b.
Wyrażenie warunkowe może być stosowane wszędzie tam, gdzie w języku C może
wystąpić wyrażenie. Priorytet operatora ? jest względnie niski ( tuż nad operatorem
przypisania) stąd nie jest konieczne stosowanie nawiasów, aby wymusić odpowiednią
kolejność wykonywania operacji.
Język ANSI C – operator przecinkowy
Użycie operator przecinkowego jest stosowany przedstawić w sposób następujący:
wyr1, wyr2,…,wyrN
Wyrażenia oddzielone przecinkami oblicza się od lewej do przy czym typem i wartością
całego wyrażenia są typ i wartość wyrażenia wyrN.
Przykład.
int x, y;
x= (y=15;y+1);
Wartość x jest równa 16.
Język ANSI C – operatory inkrementacji i dekrementacji
.
Dla operatorów tych stosowane są następujące symbole
++ - dla operatora inkrementacji (zwiększania),
oraz
-- - dla operatora dekrementacji ( zmniejszania).
Operatory te zwiększają wartość swego argumentu o 1 (operator ++), lub też
zmniejszają o 1 ( operator --). Operatory te mogą być używane w następujących
formach:
++ operand -
++ - operator preinkrementacji,
operand++ -
++ - operator postinkrementacji,
-- operand -
-- operator predekrementacji,
operand -- -
-- operator postdekrementacji,
Język ANSI C – operatory inkrementacji i dekrementacji
Operand w powyższych wyrażeniach z operatorami ++ lub -- może być typu
arytmetycznego lub wskaźnikowego, musi być jednak tzw. Lwartością (ang. Lvalue), tzn.
musi reprezentować pewną lokację pamięci.
Użycie powyższych operatorów powoduje dwa efekty:
- wartość operandu jest modyfikowana ( zwiększana lub zmniejszana
o 1),
- wyrażeniu z operandem jest przypisywana pewna wartość.
Język ANSI C – operatory inkrementacji i dekrementacji
Działanie operatora postinkrementacji (operand ++).
- wartość operandu jest zwiększana o 1,
- wartość wyrażenia operand ++ jest równa początkowej
wartości operandu.
Przykład.
x=3;
y=x++;
y=x++;
x jest zwiększany o1 wartość wyrażenia jest równa
(x=4) początkowej wartości x ( y=3)
Język ANSI C – operatory inkrementacji i dekrementacji
Działanie operatora preinkrementacji (++operand).
- wartość operandu jest zwiększana o 1,
- wartość wyrażenia ++operand jest równa zwiększonej o 1
wartości operandu.
Przykład.
x=3;
y=++x;
y=++x;
x jest zwiększany o1 wartość wyrażenia jest równa
(x=4) zwiększonej wartości x ( y=4)
Język ANSI C – operatory inkrementacji i dekrementacji
Działanie operatora postdekrementacji (operand - -).
- wartość operandu jest zmniejszana o 1,
- wartość wyrażenia operand -- jest równa początkowej
wartości operandu.
Przykład.
x=3;
y=x--;
y=x--;
x jest zmniejszany o1 wartość wyrażenia jest równa
(x=2) początkowej wartości x ( y=3)
Język ANSI C – operatory inkrementacji i dekrementacji
Działanie operatora predekrementacji (- - operand).
- wartość operandu jest zmniejszana o 1,
- wartość wyrażenia operand -- jest zmniejszonej o 1
wartości operandu.
Przykład.
x=3;
y=--x;
y=--x;
x jest zmniejszany o1 wartość wyrażenia jest równa
(x=2) zmniejszonej wartości x ( y=2)
Język ANSI C – instrukcje
Przykład. Użycie operatorów preinkrementacji i postinkrementacji.
#include <stdio.h>
#include <conio.h>
int main(int argc, char* argv[])
{
int x,y;
x= (y=15,y=y+1,y=y+1,++y);
printf("\n x=%d",x);
x= (y=15,y=y+1,y=y+1,y++);
printf("\n x=%d",x);
getch();
return 0;
}
Język ANSI C – instrukcje
Instrukcja for
Instrukcja for, zwana też pętlą for, jest instrukcją iteracyjną podobnie jak instrukcje while
i do while. Stosowana jest ona do wielokrotnego powtarzania pewnego segmentu kodu.
Pętla for w języku C jest podobna do pętli for w innych językach programowania,
posiada jednak znacznie większe możliwości.
Pętla for ma następującą postać:
for (wyr1; wyr2; wyr3)
akcja
Język ANSI C – instrukcje
Wyrażenie wyr1 jest stosowane do inicjalizacji pętli, wyrażenie wyr2 jest używane do
testowania warunku kontynuacji pętli, wyrażenie wyr3 służy do uaktualniania pętli. Akcja
stanowi treść (ciało) pętli. Działanie:
Krok1. Obliczenie wyrażenia wyr1 (jest ono obliczane jeden raz i tylko jeden raz
na początku działania pętli).
Krok 2a. Obliczenie wyr2 i sprawdzenie czy wyrażenie wyr2 jest prawdziwe czy
też fałszywe.
Krok 2b. Jeżeli wyr2 jest fałszywe, zakończenie pętli i przejście do instrukcji
umieszczonej bezpośrednio po pętli. Jeżeli wyr2 jest prawdziwe,
wykonanie akcji.
Krok 3. Obliczenie wyrażenia wyr3, następnie przejście do Kroku 2.
Język ANSI C – instrukcje
Ciało pętli (akcja) może być pojedynczą instrukcją albo też instrukcją złożoną
(grupującą), jeśli jest konieczne wykonanie w pętli więcej niż jednej instrukcji
Przykład. Użycie pętli for.
int sum=0;
int i;
for (i=1; i<=4;i=i+1)
sum=sum+i;
W powyższym przykładzie w pętli for najpierw jest wykonywana instrukcja i=1 ,
następnie sprawdzany jest warunek i<=4, dla i=1 jest on prawdziwy, więc wykonywana
jest instrukcja sum=sum+i; i następuje przejście do instrukcji i=i+1, i przyjmuje wartość
2, i wykonywane jest sprawdzenie i<=4, warunek jest prawdziwy, więc ponownie
wykonywana jest instrukcja sum=sum+i. Gdy i przybierze wartość 5, warunek i<=4 nie
spełniony i pętla kończy się.
Język ANSI C – instrukcje
Przykład. Użycie pętli for ( typowy zapis)
#include <stdio.h>
#include <conio.h>
int main(int argc, char* argv[])
{
int i,sum;
for( i=0,sum=0; i<=4;i++)
sum=sum+i;
printf("\n sum=%d",sum);
getch();
return 0;
}
W wyrażeniu wyr1 użyto operator przecinkowy.
Język ANSI C – instrukcje
#include <stdio.h>
#include <conio.h>
int main(int argc, char* argv[])
{
int x, y;
for( x=0,y=0; x+y<10 ;x++)
{
y=getch(); // wczytywanie y jako znaku
putchar(y); // drukowanie wczytanego znaku
y=y -'0'; // wyznaczanie cyfry reprezentowanej przez wczytany znak
}
printf("\n x=%d y=%d", x,y);
getch();
return 0;
}
Język ANSI C – instrukcje
Odmiany pętli for
1. Pętla nieskończona
for ( ; ; )
printf (” Pętla ta będzie działać w nieskończoność”);
Brak wyr2 uważany jest za wyrażenie prawdziwe.
2. Pętla bez treści(ciała)
for (i=0;i<100000;i++) ; // pętla taka może realizować opóźnienie w programie
Ogólnie w pętli for może nie być któregoś z wyrażeń albo też wszystkich, jednak
zawsze muszą być dwa średniki.
Przykład. Pętla bez wyrażenia wyr3.
for( i=0,sum=0; i<=4;)
{
sum=sum+i;
i++;
}
Język ANSI C – instrukcje
Instrukcja break
Instrukcja break powoduje natychmiastowe przerwanie wykonywania pętli, w
której została umieszczona.
Przykład . Użycie instrukcji break w pętli.
for (i=0;i<5;i++)
{
printf("\n i=%d ",i);
if (i==3) break;
printf("\n Koncowa instrukcja petli");
}
printf("\n Poza petla");
W przykładzie powyższym, gdy zmienna i osiągnie wartość 3, warunek po if ma wartość
logiczną prawda, co powoduje wykonanie jest instrukcja break, która daje
natychmiastowe przerwanie wykonywania pętli.
Język ANSI C – instrukcje
Instrukcja continue
Instrukcja continue jest podobna do instrukcji break w tym sensie, że również
przerywa działanie pętli, jednak pętla nie ulega zakończeniu, lecz następuje przeskok do
wykonania wyrażeń sterujących pętlą. Dla pętli for mamy
for (wyr1;wyr2;wyr3)
{
blok instrukcji (1)
if (warunek) continue;
blok instrukcji (2)
}
Jeżeli warunek po if jest prawdziwy, to wykonanie continue powoduje
natychmiastowe przejście, bez wykonania bloku instrukcji2 do obliczenia wyrażenia
wyr3 i następnie do obliczenia wyrażenia wyr2. Jeżeli wyrażenie wyr2 ma wartość
prawda, wykonanie pętli jest kontynuowane.
.
Język ANSI C – instrukcje
Dla pętli while i pętli do while następuje natychmiastowe przejście do obliczenia
wyrażenia sterującego pętlą, czyli dla pętli while na początek pętli, a dla pętli do while
na koniec pętli.
Przykład . Program oblicza średnią liczb dodatnich podawanych na wejscie, liczby
ujemne są odrzucane przy użyciu instrukcji continue.
#include <stdio.h>
#include <conio.h>
main()
{
double x, suma=0;
int ilosc=0;
while ( printf ("\n Podaj liczbe :"), scanf("%lf" ,&x)!=0)
{
if (x<0.0) continue;
suma=suma+x;
ilosc++;
}
if (ilosc>0)
printf("\n Srednia=%f", suma/ilosc);
else
printf("\n Nie podano zadnych liczb dodatnich");
getch();
t
0
Język ANSI C – instrukcje
Instrukcja switch
switch( wyrazenie_calkowite)
{
case etykieta_1: instrukcja 1;
case etykieta_2: instrukcja 1;
.
.
.
case etykieta_n: instrukcja_n;
default: instrukcje;
}
Wyrażenie po słowie switch, zwane wyrażeniem wyboru lub selektorem, musi
przyjmować wartości całkowite. Etykiety są całkowitymi wartościami stałymi lub
wyrażeniami stałymi. Jeśli podczas wykonywania instrukcji switch jedna z etykiet ma
wartość równą wartości selektora (oznaczonego jako wyrazenie_calkowite), to
wykonanie instrukcji switch rozpoczyna się od wykonania instrukcji znajdującej się przy
tej etykiecie.
Język ANSI C – instrukcje
Jeżeli w instrukcji switch występuje słowo default (ang. domyślny), instrukcje
umieszczone po słowie default są wykonywane, gdy żadna z etykiet nie ma wartości
równej selektorowi. Etykieta default jest opcjonalna, i jeżeli nie występuje, to następuje
przejście do pierwszej instrukcji po instrukcji switch.
Jeżeli chce się uzyskać wykonanie tylko jednej konkretnej instrukcji, należy po
każdym wariancie umieścić słowo break wraz ze średnikiem. Spowoduje to
natychmiastowe przerwanie wykonywania instrukcji switch po zrealizowaniu instrukcji
związane z danym wariantem.
Język ANSI C – instrukcje
Przykład. W przykładzie wczytywana jest liczba całkowita i jeżeli jest to liczba 0,1,2 lub
3, drukowany jest komunikat informujący o wartości liczby. Jeżeli jest podaną liczbą jest
inna liczba, drukowany jest komunikat Inna liczba.
#include <stdio.h>
#include <conio.h>
main()
{
int liczba;
printf("\n Podaj liczbe:");
scanf("%d", &liczba);
switch( liczba)
{
case 0: printf("\n Liczba 0");
break;
case 1: printf("\n Liczba 1");
break;
case 2:case 3: printf("\n Liczba 2 lub 3");
break;
default : printf("\n Inna liczba");
}
getch();
return 0; }
Język ANSI C – instrukcje
Instrukcja goto (cz.1)
Instrukcja goto to tzw. instrukcja skoku powodująca bezwarunkowe sterowania
do pewnego punktu w programie opatrzonego etykietą.
Etykieta jest identyfikatorem i zakończona jest dwukropkiem. Etykietę można
umieścić przed każdą instrukcją w funkcji, w której występuje instrukcja goto.
Przykład.
int j=1;
E1: j++;
if (j<=100) goto E1;
printf(”\n j=%d”, j);
Język ANSI C – instrukcje
Instrukcja goto (cz.2)
Stosowanie instrukcji goto nie jest zalecane, gdyż zwykle jej wielokrotne użycie
powoduje, iż program staje się mniej czytelny jak również trudniejszy do modyfikacji.
Istnieją jednak sytuacje, gdzie instrukcja goto jest wygodnym rozwiązaniem.
Przykład.
int i,j,k;
for ( i=0;i<100;i++)
for (j=0;j<100;j++)
for (k=0;k<50;k++)
if (i+j+k>10000) goto E2;
E2: printf (”\n Instrukcja poza petlami”);
Język ANSI C – tablice
Tablice w języku C są pewnymi strukturami danych stanowiącymi zbiory
zmiennych tego samego typu, do których odwołujemy się przy użyciu wspólnej nazwy.
Tablice jednowymiarowe mają strukturę w pewnym sensie zbliżoną do struktur
matematycznych takich jak wektory, a tablice dwuwymiarowe do macierzy.
W języku C tablice umieszczane są w ciągłych obszarach pamięci. Najniższy adres
odpowiada pierwszemu elementowi tablicy, a najwyższy ostatniemu.
Definicja tablicy jednowymiarowej ma następującą postać:
typ nazwa_tablicy [rozmiar];
typ określa typ każdego elementu tablicy, rozmiar musi być określony w standardzie
C89 przy użyciu wyrażenia stałego. Tak więc rozmiar tablicy jest ustalany w trakcie
kompilacji.
Dostęp do elementów tablicy uzyskuje się poprzez tzw. indeksowanie.
Język ANSI C – tablice
Indeksowanie realizuje się umieszczając indeks ( numer elementu tablicy ) w nawiasach
kwadratowych za nazwą tablicy. W języku C elementy indeksowane są od zera.
Przykład.
int a[20];
a[0]=1; // wpisanie do pierwszego elementu tablicy wartości 1,
// po lewej stronie zastosowano operator indeksowania i indeks 0
a[3]=2;
a[5]=2*a[0]-5*a[3]+10; // do elementu a[5] wstawiana jest wartość 2.
Elementy tablicy mogą być traktowane w ten sam sposób jak zmienne danego
typu.
Język ANSI C – tablice
Poza zastosowaniem instrukcji podstawienia, elementom tablicy można nadać
wartości przy użyciu tzw. inicjalizacji lub instrukcji wejścia.
Przykład. Inicjalizacja tablicy.
int a[5]={ 1, 3, -1, 4, 5};
Ilość elementów inicjalizujących może być równa lub mniejsza od ilości elementów
tablicy.
Jeżeli nie stosuje się inicjalizacji przy definicji tablicy, jej elementy mogą mieć wartości
przypadkowe, gdy tablica jest definiowana wewnątrz funkcji. Tablice definiowane poza
funkcjami bez inicjalizacji (tablice zewnętrzne) są zerowane.
Język ANSI C – tablice
Przykład. Wczytywanie i drukowanie tablicy
#include <stdio.h>
#include <conio.h>
int main()
{ double x[10]; int i;
for (i=0;i<10;i++)
{ printf(”\n Podaj element x[%d]=”,i);
scanf(”%lf”,&x[i]);
fflush(stdin); }
for (i=0;i<10;i++)
printf(”\n x[%d]=%f”,i, x[i]);
getch();
return 0; }
Język ANSI C – tablice
Przykład. Wczytywanie i drukowanie tablicy ze sprawdzaniem formatu
#include <stdio.h>
#include <conio.h>
int main()
{ double x[10]; int i;
for (i=0;i<10;i++)
{
do
{
printf(”\n Podaj element x[%d]=”,i);
k=scanf(”%lf”,&x[i]);
fflush(stdin);
} while (k==0);
}
for (i=0;i<10;i++)
printf(”\n x[%d]=%f”,i, x[i]);
getch();
return 0;
Język ANSI C – tablice
Przykład. Sumowanie różnych kategorii elementów tablicy.
int a[10]={ 1, 3, -1, 4, 5,6,9,2,15,12};
int i, suma=0, suma_p=0, suma_ind=0, ind1=2, ind2=6;
for (i=0;i<10;i++) suma = suma + a[i];
for (i=0;i<10;i++) if (a[i] %2==0) suma_p = suma_p+a[i];
for (i=ind1;i<=ind2 ;i++) suma_ind = suma_ind + a[i];
Język ANSI C – tablice
Przykład. Wyszukiwanie w tablicy elementu minimalnego i maksymalnego
int a[10]={ 1, 3, -1, 4, 5,6,9,2,15,12};
int i, amin, amax;
amin=a[0];
for (i=1;i<10;i++)
if ( a[i] < amin) amin = a[i];
amax=a[0];
for (i=1;i<10;i++)
if ( a[i] > amax) amax= a[i];
printf(”\n element minimalny =%d ”,amin);
printf(”\n element maksymalny =%d ”,amax);
Język ANSI C – tablice
Przykład. Wyszukiwanie w tablicy zadanej wartości i zapis wartości indeksów elementów
równych tej wartości
#include <stdio.h>
#include <conio.h>
int main(int argc, char* argv[])
{ int a[10]={ 1, 2, -1, 4, 5,6,9,2,15,12};
int i, k=0,element, poz[10];
printf("\n Podaj poszukiwany element :");
scanf("%d",&element);
for (i=0;i<10;i++)
if ( a[i] ==element ) poz[k++]=i;
if (k)
{ printf("\n Pozycje tablicy na ktorych wystepuje element=%d", element);
for (i=0;i<k;i++)
printf(" %d ", poz[i]);
}
else printf("\n Zadany element nie wystepuje w tablicy");
getch();
return 0; }
Język ANSI C – tablice
Sortowanie jest procesem ustawiania zbioru obiektów w określonym porządku.
Sortowanie stosuje się w celu ułatwienia późniejszego wyszukiwania elementów
sortowanego zbioru.
Problem sortowania można sformułować następująco:
Dane są obiekty
Sortowanie (niemalejąco) polega na przestawianiu tych obiektów aż do chwili
osiągnięcia uporządkowania
takiego, że dla danej funkcji porządkującej f zachodzi związek:
n
a
a
a
,...,
,
2
1
3
2
1
,...,
,
k
k
k
a
a
a
)
(
...
)
(
)
(
3
2
1
k
k
k
a
f
a
f
a
f
≤
≤
≤
Język ANSI C – tablice
Zwykle nie oblicza się wartości funkcji porządkującej, lecz przechowuje się je w jawnej
postaci jako składowe każdego obiektu. Wartość tej funkcji nazywana jest kluczem
obiektu. Dla tablic kluczem obiektu jest wartość elementu.
Metody sortowania obiektów w miejscu można podzielić na trzy zasadnicze grupy:
- sortowanie przez zamianę (ang. exchange sort),
- sortowanie przez wybieranie (selekcję, ang. selection sort),
- sortowanie przez wstawianie (ang. insertion sort),
Przykłady metod:
- sortowanie przez prostą zamianę ( sortowanie bąbelkowe)
- sortowanie przez proste wybieranie,
- sortowanie przez proste wstawianie,
Język ANSI C – tablice
Sortowanie przez prostą zamianę( sortowanie bąbelkowe)
Metoda ta polega na porównywaniu w kolejnych przebiegach kluczy kolejnych
sąsiadujących elementów (dla tablic wartości elementów tablicy) i ewentualnej zamianie
miejscami tych elementów, jeżeli nie spełniają zadanej relacji. Po zakończeniu danego
przebiegu następuje sprawdzenie czy nastąpiły w nim zamiany. Jeśli tak, realizowany
jest kolejny przebieg, jeśli nie, to sortowanie zostało zakończone.
Język ANSI C – tablice
Sortowanie przez prostą zamianę( sortowanie bąbelkowe)
Przykład. Posortować niemalejąco tablicę 5-elementową zawierającą elementy
8,6,10,2,1. Pokazane zostaną poniżej stany tablicy w kolejnych przebiegach.
I. przebieg II. przebieg III. przebieg IV. przebieg V. przebieg
8,6,10,2,1 6,8,2,1,10
6,2,1,8,10 2,1,6,8,10 1,2,6,8,10
6,8,10,2,1 6,8,2,1,10
2,6,1,8,10 1,2,6,8,10 1,2,6,8,10
6,8,10,2,1 6,2,8,1,10
2,1,6,8,10 1,2,6,8,10 1,2,6,8,10
6,8,2,10,1 6,2,1,8,10
2,1,6,8,10 1,2,6,8,10 1,2,6,8,10
6,8,2,1,10 6,2,1,8,10
2,1,6,8,10 1,2,6,8,10 1,2,6,8,10
// Sortowanie przez prostą zamianę (bąbelkowe)
#define n 5 // sortowanie niemalejąco
#include <stdio.h>
#include <conio.h>
int main(int argc, char **argv)
{ int i, nr=1,p, zam;
int a[5]={8,6,10,2,1};
do
{ zam=0;
printf("\n przebieg nr=%d",nr++);
for (i=0;i<n -1;i++)
if (a[i+1]<a[i]) {
p=a[i];
a[i]=a[i+1];
a[i+1]=p;
zam=1; }
}
while (zam);
printf("\n Stan wektora po sortowaniu");
for (i=0;i<n;i++) printf(" % d ",a[i]);getch(); }
Język ANSI C – tablice
Język ANSI C – tablice
Sortowanie przez proste wybieranie
Metodę tę można opisać następująco:( sortowanie niemalejąco)
- wybrać element o najmniejszym kluczu ( dla tablic element o
najmniejszej wartości)
- wymienić go z pierwszym elementem.
Operacje te powtarza się z pozostałymi n-1 obiektami, następnie z n-2 obiektami, aż
pozostanie jeden obiekt - największy.
Język ANSI C – tablice
// Sortowanie przez proste wybieranie
#define n 8
#include <stdio.h>
#include <conio.h>
int main(int argc, char **argv)
{ int i,i1,j,k,p,amin; int a[8]={9,5,-2,7,-4,15,-20,100};
for (i=0;i<n;i++)
{ amin=a[i];
k=i;
for (j=i+1;j<n;j++)
if (a[j]<amin)
{ amin=a[j];
k=j; }
if (k!=i)
{ p=a[i];
a[i]=a[k];
a[k]=p;
}
} printf("\n Stan wektora po sortowaniu");
for (i=0;i<n;i++) printf(" % d ",a[i]); getch();}
Język ANSI C – tablice
Sortowanie przez proste wstawianie
Metoda ta jest stosowana przez grających w karty. Zaczynamy od „ pustej” lewej
ręki, po czym bierzemy ze stołu kolejne karty i wstawiamy w odpowiednie miejsca w
zbiorze kart trzymanych w lewej ręce. Dla danej karty znajdujemy właściwe miejsce,
porównując ją kolejno z kartami w lewej ręce.
9
5
2
7
1
5
9
2
5
9
2
5
7
9
1
2
5
7
9
Język ANSI C – tablice
#define n 5 // Sortowanie przez wstawianie
#include <stdio.h>
#include <conio.h>
int main(int argc, char **argv)
int i,j,x; int a[5]={9,5,2,7,1};
j=0;
while (j<n)
{
x=a[j];
i=j-1;
while (i>=0 && a[i]>x)
{
a[i+1]=a[i];
i=i-1;
}
a[i+1]=x;
j=j+1;
}
printf("\n Stan wektora po sortowaniu");
for (i=0;i<n;i++)
printf(" % d ",a[i]);getch(); }
Język ANSI C – funkcje
W języku ANSI C program składa się z jednego lub większej liczby segmentów
kodu zwanych funkcjami, z których jedna musi nazywać się main().
Wykonanie programu zaczyna się od funkcji main() i program powinien kończyć się
wraz z zakończeniem działania funkcji main()( program również może się zakończyć,
gdy pojawi się sytuacja nienormalna-wyjątek, np. dzielenie przez zero, albo też gdy
zostanie zakończony w sposób jawny- ctrl-break, powodem zakończenia może być też
wywołanie funkcji exit().
Język ANSI C – funkcje
Powody stosowania funkcji w programach
1. Program jest zbyt duży by pisać go jako jedną funkcję main().
2. Podział zadania programistycznego na mniejsze, które mogą być opracowywane
niezależnie( np. w różnym czasie lub równocześnie przez różnych programistów).
3. Modularyzacja programu- podział programu na jednostki realizujące wyodrębnione
logicznie zadania.
4. Ułatwienia w uruchamianiu dużych programów ( można niezależnie uruchamiać i
testować poszczególne funkcje).
5. Korzystanie z bibliotek lub funkcji stworzonych przez innych programistów.
6. Unikanie powtarzania w programie tego samego kodu, gdy pewne zadania trzeba
wykonywać wielokrotnie.
Język ANSI C – funkcje
Funkcje a struktura programu w jezyku C (cz. I)
-Program w języku C może być programem jednoplikowym lub wieloplikowym.
W programie jednoplikowym wszystkie funkcje znajdują się w jednym pliku lub są do
niego dołączane przy zastosowaniu dyrektywy #include. W programie wieloplikowym
pliki są łączone w sposób zależny od środowiska ( np. w C++ Builder opcja Project -
>Add to Project).
- Funkcje nie muszą występować w pliku w określonym porządku ( pewne
sposoby uporządkowania mogą wymagać dodatkowych deklaracji), jednak
umieszczenie main() jako pierwszej funkcji w pliku ułatwia analizę programu).
Język ANSI C – funkcje
Funkcje a struktura programu w języku C (cz. II)
- Każda funkcja może wywoływać dowolną inną funkcję.
- Nie jest dopuszczalne zagnieżdżanie funkcji, tzn. nie można jednej funkcji
definiować wewnątrz innej funkcji.
- W programie występuje tylko jedna funkcja main() i musi ona wystąpić niezależnie
od liczby plików źródłowych.
Język ANSI C – funkcje
Przykład. Prosty program stosujący funkcję do obliczania kwadratu pewnej wartości.
#include <stdio.h>
#include <conio.h>
int kwadrat (int num) {
int pom; // zmienna lokalna funkcji
pom=num*num;
return pom; } // zmienna pom nie jest konieczna, może być
// return num*num;
main() {
int liczba, wartosc;
printf(”\n Podaj wartosc :”);
scanf(”%d”,&wartosc);
liczba=kwadrat(wartosc);/* zmienna wartosc jest tzw. argumentem funkcji,
po prawej stronie znaku podstawienia umieszczono tzw. wywołanie funkcji czyli
uruchomienie jej kodu. Zmienna wartość zawiera liczbę, która ma być podniesiona
do kwadratu */
Język ANSI C – funkcje
printf (”\n Kwadrat liczby %d wynosi :%d”, wartosc, liczba);
getch();
return 0;
}
Język ANSI C – funkcje
#include <stdio.h>
#include <conio.h>
int kwadrat (int); // deklaracja funkcji
main() {
int liczba, wartosc;
printf(”\n Podaj wartosc :”);
scanf(”%d”,&wartosc);
liczba=kwadrat(wartosc);
printf (”\n Kwadrat liczby %d wynosi :%d”, wartosc, liczba);
getch();
return 0; }
int kwadrat (int num)
{
int pom;
pom=num*num;
return pom;
}
Język ANSI C – funkcje
Zadanie. Napisać i wywołać w main() dla dwóch par argumentów następujące funkcje:
a) funkcję obliczającą sumę swoich argumentów typu int
b) funkcję obliczającą różnicę swoich argumentów typu int
c) funkcję obliczającą iloczyn swoich argumentów typu int
Język ANSI C – funkcje
Przykład. Napisać i zastosować w programie funkcję silnia.
#include <stdio.h>
#include <conio.h>
int silnia (int n )
{
int i, sil=1;
if (n>0)
for (i=1;i<=n;i++)
sil=sil*i;
return sil;
}
main() {
int l1=5, l2=6;
sil1=silnia (l1);
sil2=silnia (l2);
printf(”\n % d ! wynosi %d”, l1,sil1);
printf(”\n % d ! wynosi %d”, l2,sil2);
getch();
return 0;
}
Język ANSI C – funkcje
Przykład. Napisać i zastosować w programie funkcję wczytajd wczytującą zmienną
typu double.
#include <stdio.h>
#include <conio.h>
double wczytajd (void )
{ int k;
double x;
do {
printf(”\n Podaj zmienna :”);
k=scanf(”%lf”,&x);
if (k==0) printf(”\n Niepoprawny format liczby !”);
fflush(stdin);
} while (k==0); // można też while (!k);
return x; }
main() {
double x1,x2;
x1=wczytajd ();
x2=wczytajd();
printf(”\n x1 wynosi %f”, x1);
printf(”\n x2 wynosi %f”, x2);
getch();
return 0; }
Język ANSI C – funkcje
Ogólna budowa funkcji
Definicja funkcji
Typ_zwracanej_wartości nazwa_funkcji (deklaracja parametrów formalnych, jeśli
występują)
{
deklaracje
instrukcje
}
Definicje poszczególnych funkcji mogą się pojawić w jednym pliku lub większej liczbie
plików źródłowych, przy czym żadna funkcja nie może być rozdzielona między plikami
(definicja funkcji musi być umieszczona w jednym pliku).
Język ANSI C – funkcje
Deklaracja funkcji ( cz. I)
Deklaracja funkcji stanowi informację dla innych funkcji stosujących daną funkcję o
typie zwracanej wartości, liczbie i typach parametrów funkcji.
Deklaracja ma postać skróconego nagłówka funkcji zakończonego średnikiem.
Przykład. Deklaracje funkcji
int kwadrat (int, int);
int echo_line (void);
void print_hist ( int size);
void print_prompt( void);
Nazwy po typach parametrów są opcjonalne i są ignorowane przez kompilator.
Nazwy parametrów stosować można dla celów dokumentacji, pozwalają one
zorientowąć się co do roli poszczególnych parametrów bez sięgania do definicji
funkcji.
Język ANSI C – funkcje
Definicja a deklaracja funkcji
Definicja funkcji występować jednokrotnie.
1. Deklaracja funkcji f może występować wewnątrz funkcji g , która
wywołuje daną funkcję f lub też na zewnątrz wszystkich funkcji.
2. Deklaracja funkcji f wewnątrz funkcji g służy tylko funkcji g.
3. Deklaracja funkcji f na zewnątrz wszystkich funkcji służy wszystkim
tym funkcjom, których definicje umieszczono po deklaracji funkcji f .
Język ANSI C – funkcje
Instrukcja return (cz. I)
Instrukcja return ( ang. powróć, zwróć) pełni dwie zasadnicze funkcje:
1. Zwraca sterowanie programem do miejsca wywołania funkcji
( do funkcji wywołującej).
2. Umożliwia przekazanie wartości obliczonej przez funkcję do funkcji
wywołującej.
Język ANSI C – funkcje
Instrukcja return cz. II
Funkcja, która zwraca wartość, powinna mieć przynajmniej jedną instrukcję return w
formie
return (wyrażenie);
lub
return wyrażenie;
gdzie wyrażenie jest jakimkolwiek legalnym wyrażeniem języka C.
Obie formy mają to samo znaczenie.
Do funkcji wywołującej zwracana (przekazywana) jest wartość
wyrażenia.
Funkcja przy wywołaniu może zwrócić co najwyżej jedną wartość.
Język ANSI C – funkcje
Instrukcja return cz. III
Przykład. Instrukcja return.
a) return ( 25*5 + fun2(x);
b) return (25*5+ fun2(x));
c)
double modul ( double x)
{
return x>0 ? x : -x;
}
Niezależnie od tego czy wyrażenie po return jest skomplikowane, czy też nie, zwracana
jest jedna wartość.
Język ANSI C – funkcje
Instrukcja return IV
Funkcja może posiadać kilka instrukcji return, jednak w czasie danego
wywołania funkcji może zostać wykonana tylko jedna instrukcja return.
Nie powinno się stosować w funkcji kilku instrukcji return, gdyż funkcja staje się
mniej zrozumiała oraz trudniejsza do testowania i modyfikacji.
Instrukcja return nie jest konieczna w funkcji, która nie zwraca żadnej wartości,
ale jeśli jest używana to w postaci
return;
Jeśli nie ma instrukcji return, wykonywane są kolejne instrukcje w treści funkcji,
aż do momentu dojścia do nawiasu zamykającego funkcję.
Język ANSI C – wskaźniki
Wskaźniki cz. I
Wskaźniki to typ obiektów, przechowujących adresy innych obiektów np. zmiennych.
Adres to konkretna lokalizacja pewnego obiektu w pamięci.
Jeżeli pewien obiekt typu wskaźnikowego (np. zmienna) przechowuje adres innego
obiektu, to mówimy, że wskazuje na ten obiekt.
Język ANSI C – wskaźniki
1000
1008
1004
20
1008
0
1012
160
1016
1
Adres pamięci
Zawartość
Zmienna umieszczona pod adresem 1000 wskazuje na zmienną umieszczoną pod
adresem 1008.
Język ANSI C – wskaźniki
Definicja prostej zmiennej wskaźnikowej
Jeżeli zmienna ma przechować adresy innych obiektów, należy ją odpowiednio
zdefiniować. Definicja zmiennej wskaźnikowej składa się z nazwy typu
wskazywanych obiektów, gwiazdki oraz nazwy zmiennej
typ_wskazywanych_obiektów * nazwa_zmiennej ;
typ_wskazywanych_obiektów zwany jest zwykle typem wskaźnika.
Przykład. Definicja zmiennej wskazującej na obiekty typu int.
int * px;
Język ANSI C – wskaźniki
Operatory wskaźnikowe
W języku C istnieją dwa operatory wskaźnikowe:
- operator adresowy &
- operator adresowania pośredniego * ( dereferencji)
Jednoargumentowy operator & przyłożony do operandu zwraca adres operandu w
pamięci ( dokładniej - wyrażenie &operand reprezentuje adres operandu).
Jednoargumentowy operator * przyłożony do operandu wskaźnikowego, zwraca
wartość znajdującą się pod adresem zawartym w obiekcie (zmiennej) występującym po
operatorze.
Język ANSI C – funkcje
Przykład. Proste działania przy użyciu wskaźników.
int *px, *py; // definicja zmiennej wskaźnikowej px
int i=5, j,k=10;
px=&i; // przypisanie adresu zmiennej i wskaźnikowi px;
j=*px; // podstawienie i do j przy użyciu wskaźnika
*px= i+k; // podstawienie sumy i+k do i
py=px;
*py=20; // podstawienie do i wartości 20
printf(”\n i=%d”, *py); // drukowanie i przy użyciu wskaźnika py
*py=*py+5;
printf(”\n i=%d”, *py);
Język ANSI C – funkcje
Przykład. Wczytywanie i drukowanie zmiennej przy użyciu wskaźnika
#include <stdio.h>
#include <conio.h>
main()
{
double *p;
double x;
p=&x;
printf(”\n Podaj x:”);
scanf(”%lf ”, p);
printf(”\n x=%f”,*p);
getch();
return 0;
}
Język ANSI C – funkcje
Wskaźniki i tablice
Nazwa tablicy w C jest stałym wskaźnikiem do pierwszego elementu tablicy. Np.
jeżeli stworzymy definicje
int a[5];
int *pa;
i zastosujemy instrukcję
pa=a;
to wskaźnik pa będzie wskazywał na a[0], czyli pierwszy element tablicy a.
Stosując wskaźniki można wykonać te same operacje na tablicach, co przy użyciu
indeksowania.
Język ANSI C – funkcje
Przykład. Proste działania na tablicach przy użyciu wskaźników
#include <stdio.h>
#include <conio.h>
main() {
int a[10];
int *pa,i;
pa=a; // przypisanie wskaźnikowi pa adresu a[0]
*pa=10; // zapis 1 do a[0]
pa++; // zwiększenie wskaźnika, wskazuje on teraz na a[1]
*pa=20; // zapis 2 do a[1];
pa=pa+1; // wskaźnik wskazuje na element a[2]
for (i=2; i<10; i++)
{
printf("\n Podaj a[%d]=",i);
scanf("%d",pa);
pa++;
}
pa=a; // ustawienie wskaźnika na początek tablicy
// alternatywnie pa= pa -10
for (i=0;i<10;i++)
printf("\n a[%d]=%d", i,*pa++);
getch();}
Język ANSI C – funkcje
Komunikacja funkcji z otoczeniem
Każda funkcja w C może dysponować mechanizmami komunikacji z otoczeniem.
Funkcja może pobierać wartości lub adresy od funkcji wywołującej, może zwracać
wartość do funkcji wywołującej, jak również modyfikować argumenty, których adresy
zostały do niej przekazane.
Istnieją dwa główne sposoby przekazywania argumentów:
- przekazywanie przez wartość
- przekazywanie przez zmienną( przekazywanie przez referencję, przez
wskaźnik)
Język ANSI C – funkcje
Przekazywanie przez wartość
Przy przekazywaniu przez wartość, wartości argumentów są kopiowane do
parametrów formalnych, zmiany parametrów formalnych nie mają wpływu na wartości
argumentów ( potocznie mówi się, że funkcja działa na kopiach argumentów). Przy
takim sposobie przekazywania parametrów funkcja wywoływana nie może zmienić
argumentów zastosowanych przy wywołaniu.
Argument może być wyrażeniem, którego wartość jest najpierw obliczana i
następnie przekazywana do funkcji wywołującej.
Język ANSI C – funkcje
Przykład. Przekazywanie przez wartość.
#include <stdio.h>
#include <conio.h>
int sqr (int); // deklaracja funkcji
main() {
int t=10, kw;
kw=sqr(t); // argument wywołania – zmienna t nie jest modyfikowana, pomimo że
// parametr formalny odpowiadający t, jest modyfikowany.
printf (”\n Kwadrat liczby %d wynosi :%d”,t, kw);
getch();
return 0;
}
int sqr (int k)
{
k=k*k;
return k;
}
// Przypisanie k=k*k modyfikuje tylko lokalną zmienną k.
Język ANSI C – funkcje
Przekazywanie przez zmienną
Przy przekazywaniu przez zmienną, do funkcji przekazuje się wskaźnik do
argumentu ( adres argumentu), a nie jego wartość. Funkcja wywoływana dysponując
tym wskaźnikiem może zmienić argument znajdujący się poza funkcją.
Mechanizm przekazywania przez zmienną umożliwia przekazanie na zewnątrz
funkcji więcej niż jedną wartość.
Język ANSI C – funkcje
Przykład. Funkcja zwracająca dwie wartości
#include <stdio.h>
#include <conio.h>
int dodaj_mnoz ( int , int, int *);
main() {
int x=10, y=20, suma, iloczyn;
suma=dodaj_mnoz(x,y,&iloczyn);
printf(”\n Suma= %d iloczyn=%d ”, suma, iloczyn);
getch();
return 0;
}
int dodaj_mnoz ( int a, int b, int pc*)
{
int sum, ilo;
sum=a+b;
ilo=a*b;
*pc=ilo;
return sum;
}
Język ANSI C – funkcje
Przykład. Funkcja zamieniająca swe argumenty.
#include <stdio.h>
#include <conio.h>
void swap ( int *, int *);
main() {
int i=10, j=20;
printf(”\n Wartości i oraz j przed zamianą i=%d j=%d:”, i,j);
swap(&i, &j);
printf(”\n Wartości i oraz j po zamianie i=%d j=%d:”, i,j);
getch();
return 0;
}
void swap ( int *px, int *py)
{ temp=*px;// zapisz do temp wartość znajdującą się pod
// adresem px
*px=*py; // umieść w komórce wskazywanej przez px,
// wartość znajdującą się pod adresem
// wskazywanym przez py
*py=temp; // umieść w komórce wskazywanej przez py,
// wartość z komórki temp
}
Język ANSI C – funkcje
Przekazywanie tablic jako argumentów
Gdy argumentem funkcji wywoływanej jest tablica, do funkcji przekazywany jest
jej adres ( adres pierwszego elementu). W związku z tym funkcja operuje na
przekazanej jej tablicy, a nie na kopii. Funkcja ma możliwość zmiany tej zawartości.
Język ANSI C – funkcje
Przykład. Funkcja oblicza sumę elementów tablicy i umieszcza tę sumę w pierwszym
elemencie tablicy ,
#include <stdio.h>
#include <conio.h>
void suma_tab( int [ ], int );
main() {
int sum, a[5]= { 0,1,2, -1,3};
suma_tab(a,5);
printf(”\n Suma elementów tablicy a=%d”, a[0]);
getch();
return 0; }
void suma_tab( int b[ ], int n)
{ int i,suma;
for (i=0;i<n; i++)
suma=suma+b[i];
b[0]=suma;
}
Język ANSI C – funkcje
Przykład. Funkcje wczytujące i drukujące tablicę jednowymiarową.
#include <stdio.h>
#include <conio.h>
void wczyt_tab( int [ ], int );
void druk_tab( int [ ], int );
main() {
int a[5],b[10];
wczyt_tab(a,5);
wczyt_tab(b,10);
druk_tab(a,5);
druk_tab(b,10);
getch();
return 0; }
void wczyt _tab( int x[ ], int n)
{ int i;
for (i=0;i<n; i++)
{ printf(”\n Podaj element %d=”,i);
scanf(”%d”,&x[i]);}
}
Język ANSI C – funkcje
Przykład cd. Funkcje wczytujące i drukujące tablicę jednowymiarową.
void druk _tab( int x[ ], int n)
{
int i;
for (i=0;i<n; i++)
printf(”\n Element %d=%d ”,i, x[i]);
}
Język ANSI C – funkcje
Przykład. Funkcja obliczająca w tablicy sumy liczb parzystych, nieparzystych,
dodatnich i ujemnych. #include <stdio.h>
#include <conio.h>
void wczyt_tab( int [ ], int );
int oblicz_sumy(int [ ], int n,int *pnp,int *pd, int *pu);
main() {
int a[10], suma_p, suma_np, suma_d, suma_u;
wczyt_tab(a,10);
suma_p=oblicz_sumy(a,10,&suma_np, &suma_d, &suma_u);
printf("\n suma_p=%d suma_np=%d suma_d=%d suma_u=%d",\
suma_p, suma_np, suma_d, suma_u);
getch();
return 0;
}
void wczyt_tab(int x[ ], int n)
{ int i;
for (i=0;i<n; i++)
{ printf("\n Podaj element %d=",i);
scanf("%d",&x[i]);}
}
Język ANSI C – funkcje
Przykład cd. Funkcja obliczająca w tablicy sumy liczb parzystych,
nieparzystych, dodatnich i ujemnych ( wersja 1)
int oblicz_sumy(int x[ ], int n, int *pnp, int *pd, int *pu)
{
int i, suma_p=0, suma_np=0, suma_d=0, suma_u=0;
for (i=0;i<n; i++)
{
if (x[i]%2==0) suma_p+=x[i];
else suma_np+=x[i];
if (x[i]>0) suma_d+=x[i];
else suma_u+=x[i];
*pnp=suma_np;
*pd=suma_d;
*pu=suma_u;
}
return suma_p;
}
Język ANSI C – funkcje
Przykład cd. Funkcja obliczająca w tablicy ilości liczb parzystych, nieparzystych,
dodatnich i ujemnych ( wersja 2- krótsza)
int oblicz_sumy(int x[ ], int n, int *pnp, int *pd, int *pu)
{ int i,suma_p=0;
*pnp=*pd=*pu=0;
for (i=0;i<n; i++)
{
if (x[i]%2==0) suma_p+=x[i];
else *pnp+=x[i];
if (x[i]>0) *pd+=x[i];
else *pu+=x[i];
}
return suma_p;
}
Język ANSI C – tablice wielowymiarowe
W języku C poza tablicami jednowymiarowymi można stosować tablice
wielowymiarowe. Tablice dwuwymiarowe odpowiadają macierzom. Możliwość
definiowania tablic wielowymiarowych w C wynika stąd, że elementy tablicy mogą być
tablicami.
Zapis
int a[3][3];
definiuje tablicę o trzech wierszach i trzech kolumnach, lub też jedno-wymiarową tablicę
o trzech elementach, z których każdy jest tablicą składającą się z trzech elementów.
Elementy tablicy a zapisujemy jako a[i] [j].
Język ANSI C – tablice wielowymiarowe
Inicjalizacja tablic dwuwymiarowych
Przykład. Zainicjować tablicę b[3] [3].
int b[3][3]= { {2,1,1}, {3,4,2}, {2,3,4}};
W wyniku takiej inicjalizacji otrzymujemy następujące wartości elementów :
b[0][0] :2 b[0][1] : 1 b[0][2] :1
b[1][0] :3 b[1][1] : 4 b[1][2] :2
b[2][0] :2 b[2][1] : 3 b[2][2] :3
Tablicę b [3][3] można też zainicjować w sposób następujący:
int b[3][3]= {2,1,1,3,4,2,2,3,3};
Tablice wielowymiarowe są zapamiętywane w C wierszami ( ostatni indeks z prawej
strony zmienia się najszybciej ). Przykładowo dla tablicy b
mamy następujące rozmieszczenie tablicy w pamięci
b[0][0], b[0][1], b[0][2], b[1][0], b[1][1], b[1][2], b[2][0], b[2][1], b[2][2].
Język ANSI C – tablice wielowymiarowe i funkcje
Gdy tablica wielowymiarowa jest parametrem funkcji, konieczne jest podanie
wszystkich wymiarów poza pierwszym.
Przykład. Napisać program wczytujący i drukujący dwie tablice o wymiarze 3x3.
#include <stdio.h>
#include <conio.h>
void wczyt2D( int x[ ][3], int n)
{ int i,j,k;
for (i=0; i<n;i++)
for (j=0;j<3;j++)
do {
printf (”\n Podaj element [%d][%d]=”,i, j);
k=scanf(”%d”, &x[i][j]);
fflush(stdin);
} while (k==0);
return; }
Język ANSI C – tablice wielowymiarowe i funkcje
Przykład c.d.
void druk2D( int x[ ][3], int n)
{ int i,j,k;
for (i=0; i<n;i++)
{ for (j=0;j<3;j++)
printf (”element [%d][%d]=%d”,i, j, x[i][j]);
printf(”\n”);
}
return;
}
int main()
{ int a[3][3], b[3][3];
wczyt2D(a,3);
wczyt2D(b,3);
druk2D(a,3);
druk2D(b,3);
getch();
return 0;
}
Język ANSI C – funkcje
#include <stdio.h>
#include <conio.h>
void kopiuj2D( int x[ ][3], int n);
int main()
{
int b[3][3]= { {2,1,1}, {3,4,2}, {2,3,4}};
int a[3][3];
kopiuj2D( a,b);
getch();
}
void kopiuj2D( int x[ ][3],y[ ][3], int n)
{ int i,j,k;
for (i=0; i<n;i++)
for (j=0;j<3;j++)
x[i][y]=y[i][j];
}
Język ANSI C – funkcje
Przykład. Przepisywanie tablicy dwuwymiarowej do tablicy jednowymiarowej.
#include <stdio.h>
#include <conio.h>
void kopiuj1D_2D( int b[ ][2],int n1, int d[ ])
{ int i,j,k=0;
for (i=0;i<n1;i++)
for (j=0;j<2;j++)
d[k++]=b[i][j];
}
int main ()
{ int tab2D[2][2]={ {1,2},{2,3}};
int tab1D[4];
int i;
kopiuj1D_2D(tab2D, 2, tab1D);
for (i=0;i<4; i++)
printf(" %d ", tab1D[i]);
getch();
}
Język ANSI C – funkcje
Przykład. Mnożenie macierzy.
#include <stdio.h>
#include <conio.h>
#define m 3
void mnoz_mac( int a[ ][m],int b[][m], int c[ ][m], int n)
{ int i,j,k,s;
for (i=0;i<n;i++)
for (k=0;k<n;k++)
{ s=0;
for (j=0;j<n;j++)
s=s+a[i][j]* b[j][k];
c[i][k]=s; }
}
int main ()
{ int u[m][m]={ {1,2,1},{1,1,1}, {2,1,1}};
int v[m][m]={ {2,1,0},{1,2,0}, {3,2,1}};
mnoz_mac( u,v, z,3);
for (i=0; i<n;i++)
{ for (j=0;j<3;j++)
printf (”element [%d][%d]=%d”,i, j, x[i][j]);
printf(”\n”);
getch(); }
Język ANSI C – dynamiczna alokacja pamięci cz. I
W języku ANSI C istnieją zasadniczo dwa rodzaje zmiennych:
- zmienne zwykłe definiowane w funkcji main() lub na zewnątrz wszystkich funkcji,
lub w pewnym bloku. Każda zmienna tego rodzaju posiada swoją nazwę oraz
określony typ.
- zmienne dynamiczne tworzone i usuwane w trakcie działania programu; taki
sposób przydzielania pamięci zwany jest alokacją w trakcie działania programu
(ang. run-time allocation). Zmienne te nie posiadają nazw, znane są wyłącznie
adresy przydzielonej im pamięci ( wskaźniki do tej pamięci).
Do przydzielania pamięci zmiennym dynamicznym służą w ANSI C funkcje malloc i
calloc. Do usuwania zmiennych dynamicznych stosuje się funkcję free.
Język ANSI C – dynamiczna alokacja pamięci cz. I
Funkcje malloc i calloc (stdlib.h)
Każda z tych funkcji alokuje przydziela pamięć i zwraca adres tej pamięci (wskaźnik do
tej pamięci). Rozmiar przydzielanej pamięci nie musi być znany podczas kompilacji.
Funkcja malloc
Nagłówek funkcji tej ma postać następującą:
void * malloc (int);
Funkcja malloc oczekuje, jako swojego argumentu liczby bajtów, które mają być
przydzielone w danym wywołaniu funkcji. Jeżeli przydzielenie pamięci jest możliwe,
funkcja zwraca wskaźnik do tej pamięci, jeśli nie, funkcja zwraca NULL (zerowy
wskaźnik).
Zwracany wskaźnik jest typu void*, czyli jest to wskaźnik do void.
Wskaźnik ten musi być przekształcony (przez rzutowanie) na wskaźnik do żądanego
typu. Język C gwarantuje, że wskaźnik do void może być przekształcony na wskaźnik
do każdego innego typu.
Język ANSI C – dynamiczna alokacja pamięci
Przykład. Zastosowanie funkcji malloc do alokacji pamięci dla zmiennej dynamicznej
typu int.
#include <stdio.h>
#include <conio.h>
int main() {
int *ptr;
ptr=(int*) malloc( sizeof(int));
if (ptr==NULL){
printf(”\n Przydzielenie pamięci nie było możliwe”);
getch();return 1;}
printf(” Podaj wartosc :”);
scanf(”%d”, ptr);
printf(”\n Wartosc to :”, *ptr);
free(ptr);
getch();
return 0; }
Język ANSI C – dynamiczna alokacja pamięci cz. I
Funkcja calloc
Nagłówek funkcji tej ma postać następującą:
void * calloc (int,int);
Funkcja calloc oczekuje dwóch argumentów typu int. Pierwszy
argument oznacza liczbę bloków pamięci, które mają zostać
przydzielone, a drugi rozmiar pojedynczego bloku. Funkcja zwraca
wskaźnik do pierwszego bloku. Wskaźnik ten jest typu void* i musi być
rzutowany na wskaźnik do wymaganego typu.
Język ANSI C – funkcje
Przykład. Zastosowanie funkcji calloc do alokacji pamięci dla tablicy liczb typu int.
#include <stdio.h>
#include <conio.h>
int main() {
int *ptr;
ptr=(int *) calloc(5, sizeof(int));
for (i=0;i<5;i++) {
printf(”\n Podaj element %d”, i);
scanf(”%d”, ptr++); }
ptr=ptr-5;
for (i=0;i<5;i++) {
printf(”\n Element [%d]=%d”, *ptr++);
ptr-=5;
free(ptr);
getch();
Język ANSI C – dynamiczna alokacja pamięci cz. I
Przykład. Dynamiczna alokacja tablicy z użyciem funkcji zwracającej wskaźnik.
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
int * wczyt_tab(int n);
int main(int argc, char **argv)
{
int *pa,i,n=5;
pa=wczyt_tab(5);
for (i=0;i<n;i++)
printf("\n Element[%d]=%d",i, *pa++);
pa-=5;
free(pa);
getch();}
Język ANSI C – funkcje
Przykład cz. II ( ciąg dalszy programu)
// definicja funkcji zwracającej wskaźnik do wczytanej tablicy
int * wczyt_tab(int n)
{
int i,*px;
px=(int*) malloc(n*sizeof(int));
for (i=0;i<n;i++)
{ printf("\n Podaj element[%d]=",i);
scanf("%d",px++);
}
px=px-n;
return px;
}
Język ANSI C – funkcje
Przykład. Program wczytujący tablicę dwuwymiarową przy użyciu wskaźnika, do
funkcji przekazywany jest wskaźnik do pierwszego elementu tablicy dwuwymiarowej.
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
//Do funkcji przekazywany jest wskaźnik do pierwszego elementu tablicy
//dwuwymiarowej oraz liczba wierszy i liczba kolumn.
void wczyt(int *px, int w, int k)
{
int i,j;
for (i=0;i<w;i++)
for (j=0;j<k;j++)
{
printf("\n Podaj element [%d][%d]=",i,j);
scanf("%d",px++);
}
}
Język ANSI C – funkcje
// Przykład c.d. zastosowanie funkcji wczyt do wczytania
// tablicy dwuwymiarowej 3x3.
int main()
{
int x[3][3];
int *px;
int i,j;
clrscr();
px=&x[0][0];
wczyt(px,3,3);
for (i=0;i<3;i++)
for (j=0;j<3;j++)
printf("\n element [%d][%d]=%d",i ,j, x[i][j]);
getch();
return 0; }
Język ANSI C – funkcje
Przykład. Funkcja wczyt_D alokuje pamięć dla tablicy dwuwymiarowej o zadanej
liczbie kolumn i zadanej liczbie wierszy, wczytuje tablicę i zwraca wskaźnik do
jej pierwszego elementu.
int *wczyt_D(int w, int k)
{
int *px;
int i,j;
px=(int*)calloc(w*k,sizeof(int));
for (i=0;i<w;i++)
for (j=0;j<k;j++)
{
printf("\n Podaj element [%d][%d]=",i,j);
scanf("%d",px++);
}
px=px-w*k;
return px;
}
Język ANSI C – funkcje
// Przykład c.d. zastosowanie funkcji wczyt_D do wczytania
// tablicy dwuwymiarowej 3x3.
int main()
{
int *py,i,j;
clrscr();
py=wczyt_D(3,3);
for (i=0;i<3;i++)
for (j=0;j<3;j++)
printf("\n element [%d][%d]=%d",i,j,*py++);
py-=9;
free(py);
getch();
return 0;}
Język ANSI C – operatory bitowe
Język C pozwala programiście na bezpośrednie współdziałanie ze sprzętem (
hardware’m) poprzez użycie operatorów bitowych i wyrażeń bitowych. Operatory bitowe
umożliwiają działanie na pojedynczych bitach. Operatory te działają wyłącznie z typami
całkowitymi np. takimi jak char czy też int.
Aby stosować operatory bitowe w danym systemie powinno się zgromadzić następujące
informacje:
- liczba bitów, które tworzą bajt,
- liczba bajtów dla typów całkowitych,
- system kodowania znaków (np. ASCII)
- typ stosowanej reprezentacji liczb ujemnych( np. kod U2)
Poniżej założymy 8-bitowy bajt i 16-bitową komórkę dla przechowywania
liczb całkowitych oraz kod U2.
Język ANSI C – operatory bitowe
Operatory bitowe to:
- ‘ ~ ‘ - bitowy operator uzupełnienia do 1,
-’&’ - bitowy operator koniunkcji (iloczynu logicznego),
-’ | ‘ - bitowy operator alternatywy (sumy logicznej),
- ’^’ - bitowy operator różnicy symetrycznej (XOR),
- ‘<<‘ - bitowy operator przesunięcia w lewo,
- ‘>>’ - bitowy operator przesunięcia w prawo.
Język ANSI C – operatory bitowe
Bitowy operator uzupełnienia do 1, ‘ ~ ‘ (zwany tyldą), neguje poszczególne bity
swojego argumentu (zamienia zera na jedynki a jedynki na zera).
Przykład.
short int x,y;
x=6;
y=~x;
printf(„\n Wartosc y=%d”, y);
Wartość ~x wynosi 7. Wynika to ze stosowania kodu U2 reprezentowania liczb
ujemnych. Liczba 6 ma następującą reprezentację binarną
0000 0000 0000 0110
Po negacji otrzymujemy
1111 1111 1111 1001 czyli -7 w U2.
( Można to łatwo sprawdzić:
+7 0000 0000 0000 0111 -> -7 w U1 1111 1111 1111 1000 , czyli po dodaniu
1, otrzymujemy 1111 1111 1111 1001)
Język ANSI C – operatory bitowe
Rozszerzenie znakowe ( ang. sign extension)
W operacjach wykonywanych na bitach występuje problem konwersji pomiędzy różnymi
formatami liczb całkowitych (np. char i short int).
Przy konwersjach takich istnieje konieczność zachowania wartości konwertowanej
liczby. Dla liczb ujemnych przy przechodzeniu z formatu krótszego na dłuższy,
wszystkie bity starsze, które nie występowały w formacie krótszym zamieniane są na 1.
Działanie takie nie powoduje zmiany wartości liczby ujemnej.
Przykład. Dana jest liczba -6 w kodzie U2 umieszczona w komórce 8-bitowej
0000 0110 +6 w U2,
1111 1001 -6 w U1
1111 1010 -6 w U2
Po rozszerzeniu do 16 bitów mamy
1111 1111 1111 1010
Można sprawdzić, że kod ten reprezentuje -6 w U2.
+16 0000 0000 0000 0110, - 6 w U1 1111 1111 1111 1001 ,
-6 w U2
1111 1111 1111 1010
Bitowe operatory logiczne
-’&’ - bitowy operator koniunkcji (iloczynu logicznego),
-’ | ‘ - bitowy operator alternatywy (sumy logicznej),
- ’^’ - bitowy operator różnicy symetrycznej (XOR).
Operatory te działają niezależnie na parach bitów o tej samej wadze obydwu swoich
argumentów.
Wyniki działania poszczególnych operatorów pokazano w tabeli.
Dla dwóch danych bitów b1 i b2 otrzymujemy:
Język ANSI C – operatory bitowe
b1
b2
b1&b2
b1|b2
b1^b2
0
0
0
0
0
0
1
0
1
1
1
0
0
1
1
1
1
1
1
0
Język ANSI C – operatory bitowe
Przykład. Dane są następujące definicje
short int lanbit1=12;
short int lanbit2=-35
lanbit1 000 000 000 1100
lanbit2 1111 1111 1101 1101
Wykonać podane poniżej działania w programie i poprzez obliczenia na liczbach
binarnych
1. ~lanbit1
-13
9. lanbit1^lanbit2
-47
2. ~lanbit2
34
10. ~(lanbit1^lanbit2)
46
3. lanbit1&lanbit2
12
4. ~lanbit1&lanbit2
-47
5. ~(lanbit1&lanbit2)
-13
6. lanbit1| lanbit2
-35
7. ~(lanbit1|lanbit2)
34
8. (~lanbit1|lanbit2)
Język ANSI C – operatory bitowe
Przykład. Maskowanie w słowie 8-go bitu.
#include <stdio.h>
#include <conio.h>
int main()
{ int c;
int maska=127;
while ((c=getchar())!=EOF)
putchar( c&maska);
getch();
}
Język ANSI C – operatory bitowe
Przykład. Wyznaczanie reprezentacji binarnej liczby 8-bitowej.
#include <stdio.h>
#include <conio.h>
int main()
{ char x=12;
int i,k=1, bit[8];
for (i=0;i<8;i++)
{ if (x&k) bit[i]=1; else bit[i]=0;
k*=2; }
for (i=0;i<8;i++) printf(” %d ”,bit[i]);
getch();
return 0;
}
Język ANSI C – operatory bitowe
Operatory przesunięć bitowych (ang. bitshift operators)
Operatory bitowe przesuwają bity swego argumentu znajdującego się po lewej
stronie operatora o zadaną liczbę bitów w lewo lub w prawo. Wyrażenia z użyciem tych
operatorów można zapisać następująco:
E1<< E2 lub E1>>E2,
gdzie E1 reprezentuje przed wykonaniem operacji wzorzec bitowy, który ma zostać
przesunięty, dla operatora<< w lewo, a dla operatora >> w prawo.
Jeśli nie ma nadmiaru arytmetycznego, dla operatora << przesunięcie jest
równoważne mnożeniu przez a na najmłodsze pozycje pierwszego argumentu
wchodzą zera. Działanie operatora >> odpowiada dzieleniu całkowitemu przez
dla typów bez znaku ( unsigned), wtedy na skrajne pozycje z lewej strony
wchodzą zera. Dla typów ze znakiem, jeżeli wchodzą zera dla liczb nieujemnych, a
jedynki dla liczb ujemnych mówimy o przesunięciu arytmetycznym, a jeżeli zera
niezależnie od znaku liczby, to jest to tzw. przesunięcie logiczne.
2
2
E
2
2
E
Język ANSI C – operatory bitowe
Przykład. Użycie operatorów bitowych przesunięcia w lewo i w prawo.
#include <stdio.h>
#include <conio.h>
int main() {
int x1=‘A’, x2=‘0’;
int y1=3,y2=2;
printf(”\n %d”, x1<<y1);// kod ASCII znaku ‘A’ jest równy 65 stąd
// w wyniku przesunięcia otrzymujemy 520
printf(”\n %d ”, x2>>y2); // przesunięcie prawo o 2 odpowiada dzieleniu
// całkowitemu, otrzymujemy
getch();
}
Język ANSI C – operatory bitowe
Przykład. Ustawianie określonego bitu w słowie.
Ustawianie bitu o numerze nr_bitu na 1
x= x | 1<< nr_bitu;
Najpierw realizowane jest przesunięcie 1 o nr_bitu w lewo,
czyli wstawienie 1 na określoną, następnie wykonywana jest suma logiczna, co
powoduje ustawienie bitu na 1, jeśli był równy 0.
Ustawianie bitu o numerze nr_bitu na 0
x= x& ~(1<<nr_bitu);
Na miejsce bitu o numerze nr_bitu wstawiane jest 0, i następnie wykonywany jest
iloczyn logiczny, co powoduje ustawienie bitu na 0, jeżeli był równy 1.
Język ANSI C – operatory bitowe
Przykład. Dane jest słowo 8-bitowe. Napisać funkcję wyznaczającą wartość
dziesiętną grupy n bitów począwszy od pozycji p.
int obl_wart_bitow (char x, int n, int p)
// n – liczba bitów, p –pozycja ( pozycje numerowane od 0)
{
return x>>(p+1-n)& ~( ~0<<n);
}
Zasada działania funkcji tej jest następująca:
- przesunięcie bloku n-bitowego na najmłodsze pozycje ( pozycje
o wagach od 1 do ( działanie x>> (p+1-n) )
- utworzenie maski wcinającej n najmłodszych bitów ze słowa 8-bitowego
( maska ta ma 1 na n najmłodszych bitach i zero na pozostałych)
- obliczenie iloczynu bitowego przesuniętego bloku n-bitowego i maski.
1
2
−
n
Język ANSI C – operatory bitowe
Przykład. Operatory bitowe (ciąg dalszy).
Tworzenie maski
- ~0 - oznacza utworzenie słowa składającego się z samych jedynek,
- ~0<<n – przesunięcie maski w lewo o n pozycji , powoduje, że na
najmłodszych n pozycjach pojawiają się zera,
- ~( ~0<<n) – po zanegowaniu na najmłodszych n pozycjach pojawiają się
jedynki, a na pozostałych zera, czyli utworzona została
potrzebna maska.
Język ANSI C – operatory bitowe
Zadania z operatorów do realizacji na laboratorium.
1. Dla zadanej liczby dodatniej typu char zanegować jej bity przy użyciu operatora ~, i
obliczyć przy użyciu kodu U2 wartość bezwzględną otrzymanej liczby, porównać z
wynikiem na ekranie.
2. Dla zadanej liczby ujemnej typu char zanegować jej bity przy użyciu operatora ~, i
obliczyć przy użyciu kodu U2 wartość bezwzględną otrzymanej liczby, porównać z
wynikiem na ekranie.
3. Wyznaczyć wzorzec bitowy danej liczby typu short int i zapisać w tablicy,
wydrukować tablicę.
4. Utworzyć maskę bitową zawierającą same zera poza wybranym bitem równym 1
stosując operatory przesunięć bitowych.
5. Wyznaczyć dla wartości typu char wartość dziesiętną wybranej grupy n bitów
począwszy od pozycji o indeksie p.
6. Sprawdzić czy n-ty bit ma wartość 1.
7. Zmienić wartość n-tego bitu liczby stosując operatory bitowe.
8. Wstawić do słowa kodowego typu char na pozycję najstarszą wartość 1, jeśli
liczba jedynek jest nieparzysta, lub zero jeżeli jest parzysta.
Język ANSI C – zasięgi, klasy pamięci i kwalifikatory
Zasięg
Jeżeli pewien obiekt (np. zmienna) zostanie zdefiniowany w programie, to można
go użyć w odpowiedniej części programu, której rozmiar jest określany przez tzw.
zasięg identyfikatora tego obiektu (zmiennej). W języku C wyróżniamy cztery zasięgi:
-zasięg bloku
-zasięg funkcji
-zasięg prototypu
-zasięg pliku
Język ANSI C – zasięgi, klasy pamięci i kwalifikatory
Zasięg bloku cz. 1
Blok to lista instrukcji umieszczona w klamrach { }. Wszystkie identyfikatory
zadeklarowane na początku bloku mają zasięg ograniczony do bloku, w którym zostały
zdefiniowane.
{
int i,j;
i+=1;
j*=2;......
}
Ciało funkcji stanowi blok, stąd parametry formalne mają zasięg ograniczony do ciała
funkcji.
Język ANSI C – zasięgi, klasy pamięci i kwalifikatory
Zasięg bloku cz. 2
Gdy bloki są zagnieżdżane ( jeden blok znajduje się wewnątrz drugiego bloku)
definicja identyfikatora w bloku zewnętrznym rozciąga się również na blok wewnęrzny.
Jeżeli w bloku wewnętrznym zdefiniowano identyfikator o tej samej nazwie co
identyfikator zdefiniowany w bloku zewnętrznym, to identyfikator z bloku zewnętrznego
nie będzie dostępny. Mówimy wtedy, że identyfikator wewnętrzny przesłania
identyfikator zewnętrzny.
{
double x=20;
{
int i, x[10];
....
}
x+=10;
}
Język ANSI C – zasięgi, klasy pamięci i kwalifikatory cz. 3
Zasięg prototypu
Zasięg ten odnosi się do nazw zdefiniowanych w prototypach funkcji. W prototypach
nie muszą występować nazwy parametrów, jeżeli jednak występują, to nie muszą być
zgodne z nazwami parametrów formalnych, ani też ich nazwy nie powodują konfliktu z
jakimikolwiek innymi nazwami.
Przykład.
double * f2 (int *pd, int n);
Prototyp funkcji zwracającej wskaźnik do double. Nazwy pd i n nie muszą występować.
Język ANSI C – zasięgi, klasy pamięci i kwalifikatory
Zasięg funkcji
Odnosi się on do etykiet stosowanych w instrukcjach skoku goto. Etykiety wewnątrz
funkcji nie mogą się powtarzać.
Zasięg pliku
Identyfikatory zdefiniowane na zewnątrz wszystkich bloków mają zasięg ograniczony
do pliku. Oznacza to, że są one widoczne od miejsca, w którym zostały zdefiniowane do
końca pliku. Definicje umieszczone w pliku nagłówkowym, który został włączony
dyrektywą #include, obowiązują do końca pliku, w którym została umieszczona ta
dyrektywa.
Język ANSI C – zasięgi, klasy pamięci i kwalifikatory
Klasy pamięci dla zmiennych
Klasa pamięci określa typ pamięci, w której przechowywana jest zmienna. Klasa
pamięci zmiennej określa moment utworzenia zmiennej, czas przechowywania jej
wartości, jak również moment usunięcia danej zmiennej. Wyróżnia się następujące klasy
pamięci
- klasa pamięci auto
- klasa pamięci static
- klasa pamięci register
- klasa pamięci external
Język ANSI C – zasięgi, klasy pamięci i kwalifikatory
Klasa pamięci auto ( zmienne automatyczne)
Zmienna zdefiniowana wewnątrz funkcji otrzymuje domyślną klasę auto ( zwana jest
zmienną automatyczną). Definicję zmiennej automatycznej można zapisać następująco
auto int liczba;
jednak zwykle słowo auto jest pomijane. Pamięć dla zmiennej jest alokowana
(przydzielana), gdy sterowanie programu wchodzi do bloku zawierającego definicję
danej zmiennej i jest dealokowana, gdy sterowanie opuszcza ten blok. Termin auto
wywodzi się stąd, iż proces ten odbywa się automatycznie bez udziału programisty.
Zmienna typu auto jest widoczna tylko w bloku, w którym znajduje się jej definicja.
Jeżeli zmienna typu auto jest jednocześnie definiowana i inicjalizowana, to jej
inicjalizacja jest powtarzana za każdym razem, gdy sterowanie programu wchodzi do
bloku ją zawierającego.
Język ANSI C – zasięgi, klasy pamięci i kwalifikatory
Klasa pamięci static
Zmienna o klasie pamięci static może być zdefiniowana wewnątrz bloku np.
wewnątrz funkcji albo też na zewnątrz wszystkich bloków. Zmienne statyczne są
tworzone przed rozpoczęciem wykonywania programu i istnieją przez cały czas jego
wykonywania.
Definicja zmiennej statycznej typu int ma postać
static int liczba;
Zmienne statyczne zdefiniowane wewnątrz bloku mają ten sam zasięg co inne
zmienne zdefiniowane w bloku. Jednak zachowują one swą wartość po opuszczeniu
bloku przez sterowanie programu. Powoduje to na przykład w przypadku funkcji, że
wartość statycznej zmiennej lokalnej może być przechowywana pomiędzy kolejnymi
wywołaniami funkcji.
Język ANSI C – zasięgi, klasy pamięci i kwalifikatory
Przykład. Funkcja zliczająca i zwracająca ilość swoich wywołań.
int uchwyt_bledu (void)
{
static int liczba;
liczba++;
return liczba;
}
Zmienna liczba jest inicjalizowana tylko jeden raz przy pierwszym wywołaniu funkcji.
Przy każdym kolejnym wywołaniu, wartość zmiennej liczba jest zwiększana o 1 z
przechowywana między wywołaniami funkcji, gdy sterowanie programu opuszcza blok
funkcji.
Język ANSI C – zasięgi, klasy pamięci i kwalifikatory
Zmienna statyczna c.d.
W przypadku zmiennej statycznej, która została zdefiniowana poza wszystkimi
blokami ( na zewnątrz wszystkich funkcji), definicja taka ogranicza widoczność zmiennej
do pliku, w którym definicja ta wystąpiła.
Przykład. Zasięg zmiennej statycznej.
W skład projektu wchodzą dwa pliki : plik1.c i plik2.c
// plik1.c
static double x;
int f1 (void)
{ ….}
double f2( double x)
{……..}
// plik2.c
static int x;
char * f3( char *s)
{ …}
W obu plikach występują zmienne o nazwie x, jednak są one dostępne tylko tam,
gdzie występują ich definicje.
Język ANSI C – zasięgi, klasy pamięci i kwalifikatory
Klasa pamięci register
Definiując zmienną typu register tworzy się zalecenie dla kompilatora, aby
umieścił daną zmienną w rejestrze procesora, traktowanym jako komórka pamięci.
Powodem stosowania takiego zalecenia jest czas dostępu, który jest zwykle dla
rejestrów znacznie krótszy niż dla pamięci zewnętrznej. Kompilatory mogą
uwzględniać to zalecenie lub nie, z drugiej strony jednak sam kompilator stara się
umieszczać w rejestrach częściej używane zmienne np. liczniki pętli. Jeżeli
zmienna nie stanie się zmienną register, to będzie zmienną automatyczną.
#include <stdio.h>
#include <conio.h>
int main() {
register int i;
for (i=1;i<1000;i++) sum+=i;
printf(”\n Suma=%d”,suma); getch(); }
Język ANSI C – zasięgi, klasy pamięci i kwalifikatory
Klasa pamięci extern ( program z jednym plikiem źródłowym)
Język ANSI C – pliki
Wprowadzenie cz. 1
Plik jest podstawową jednostką służącą do przechowywania informacji w każdym
systemie operacyjnym. Każdy plik ma swoją nazwę, długość w bajtach, atrybuty
określające sposób korzystania z pliku oraz nadane uprawnienia dla poszczególnych
użytkowników określające sposób korzystania z pliku.
W systemach komputerowych występują różnego rodzaju urządzenia, do których
przesyłane są dane czy też są z nich pobierane. System operacyjny izoluje jednak
programy użytkowe od szczegółów pracy poszczególnych urządzeń. Jest to
realizowane przy użyciu tzw. strumieni. Strumienie stanowią element pośredniczący
między programem a systemem operacyjnym. Wyróżniamy strumienie binarne, które
stanowią ciągi bajtów bez żadnej specjalnej struktury. Plik związany ze takim
strumieniem jest to tzw. plik binarny. Strumień może też posiadać pewną strukturę –
składać się z linii tekstu zakończonych znakiem końca linii. Plik związany z takim
strumieniem to tzw. plik tekstowy).
Język ANSI C – pliki
Wprowadzenie cz. 2
Strumienie są zwykle buforowane, oznacza to, że np. zapis w programie do
pliku jest tylko zapisem do pewnego obszaru pamięci. Zawartość bufora jest
zapisywana na nośniku, gdy bufor zostanie napełniony, lub też program zażąda
tego w sposób jawny. Długość pliku może być ograniczona wielkością nośnika lub
też ograniczenie może wynikać z pewnych własności systemowych (zakres typu
całkowitego).
Elementy pliku są zwykle dostępne sekwencyjnie, co oznacza, że w danym
momencie istnieje dostęp tylko do jednego elementu pliku. Liczba elementów pliku
może się zmieniać w trakcie przetwarzania pliku. Koniec pliku jest zaznaczany z
punktu widzenia języka C znakiem EOF( ang. end-of-file). W pliku jest to znak ctrl-Z
(ASCII 26).
Język ANSI C – pliki
Z każdym plikiem jest związana pewna zmienna, tzw. wskaźnik pliku
określająca aktualnie dostępny element pliku.
Numeracja elementów pliku zaczyna się od zera.
Identyfikacja pliku w systemie operacyjnym może się odbywać poprzez
wskaźnik do pliku (ang. file pointer) lub też uchwyt pliku (ang. handle) bedący
pewną liczbą identyfikującą plik w ramach systemu operacyjnego.
Język C nie ma wbudowanych operacji wejścia-wyjścia związanych z
realizacją funkcji plikowych, stosowane są dla ich realizacji funkcje biblioteczne z
pliku stdio.h.
Aby rozpocząć realizację operacji plikowych na istniejącym pliku lub też
utworzyć nowy plik, należy zdefiniować wskaźnik do pewnej struktury zawierającej
konieczne informacje dla uzyskania dostępu do pliku.
Język ANSI C – pliki
Definicja wskaźnika do pliku może mieć następującą postać:
FILE *fp;
FILE jest typem strukturowym zdefiniowanym w pliku stdio.h.
Przetwarzanie pliku w trakcie działania programu może polegać na wykonywaniu
różnego rodzaju operacji na pliku np. utworzeniu lub otwarciu pliku, zapisie elementów,
odczycie elementów, usuwaniu elementów czy też porządkowaniu (np. sortowaniu).
Rozpoczęcie operacji na pliku wymaga jego utworzenia lub otwarcia.
W języku C plik jest tworzony lub otwierany przy użyciu funkcji fopen (istnieje też
funkcja open do tzw. operacji niskopoziomowych).
Po zakończeniu operacji na pliku, plik jest zamykany przy użyciu funkcji fclose.
Zamknięcie pliku powoduje zarejestrowanie zmian dokonanych w pliku w trakcie jego
przetwarzania.
Język ANSI C – pliki
Funkcja fopen i parametry otwarcia pliku cz.1
Funkcja fopen posiada dwa parametry. Pierwszy jest parametrem typu tablica znaków
określający nazwę pliku, drugi parametr też będący tablicą znaków, określa tzw. tryb
utworzenia lub otwarcia pliku.
Przykład.
FILE *fp;
fp=fopen("Plik1.dat", "w");
Nazwa pliku podana bez ścieżki dostępu oznacza, że plik będzie się znajdował w tym
katalogu, w którym zapisano projekt. Można też podać ścieżkę dostępu do pliku w
sposób następujący:
fp=fopen("C:\\moje dokumenty\\Plik2.dat", "w");
(należy stosować podwójny ukośnik dla uzyskania pojedyńczego znaku \, dla tego znaku
wymgana jest tzw. sekwencja ucieczki).
Język ANSI C – pliki
Funkcja fopen i parametry otwarcia pliku cz.2
Funkcja fopen zwraca wskaźnik do pliku, jeśli jego otwarcie lub utworzenie było
możliwe. Jeżeli nie było to możliwe, funkcja fopen zwraca zerowy wskaźnik NULL.
Wskazanym jest sprawdzanie uzyskanej wartości wskaźnika przed rozpoczęciem
operacji plikowych w następujący sposób
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
main() {
FILE *fp;
fp=fopen("Plik1.dat", "w");
if (fp!=NULL) { // wystarczy if (fp)
printf(" Plik został utworzony"); getch();}
else printf("\n Plik nie zostal utworzony"); getch(); exit(1);}
Język ANSI C – pliki
Funkcja fopen i parametry otwarcia pliku cz.3
Tryb
Jeśli plik istnieje
Jeśli plik nie
istnieje
"r"
Otwiera plik do czytania
Błąd
"w"
Otwiera nowy plik, jeśli
istniał plik o danej nazwie
jego zawartość jest
kasowana
Tworzy nowy plik
"a"
Otwiera plik do
dopisywania
Tworzy nowy plik
Tryby otwarcia plików cz. 1
Język ANSI C – pliki
Tryby otwarcia plików cz. 2
Funkcja fopen i parametry otwarcia pliku cz.4
Tryb
Jeśli plik istnieje
Jeśli plik nie
istnieje
"r+"
Otwiera plik do odczytu i
zapisu
Błąd
"w+"
Otwiera nowy plik do
zapisu i odczytu, jeśli istniał
plik o danej nazwie jego
zawartość jest kasowana
Tworzy nowy plik
"a+"
Otwiera plik do
dopisywania i odczytu
Tworzy nowy plik
Język ANSI C – pliki
Funkcja fopen i parametry otwarcia pliku cz.4
Powyższe tryby dotyczą zasadniczo plików tekstowych ( zależy to od ustawienia
zmiennej systemowej _fmode). Dla plików binarnych należy dodać do nazwy trybu
literę b, np. "rb", "wb", "r+b", "w+b". Dla trybów tekstowych należy dodać literę t, czyli
"rt", "wt", "r+t", "w+t".
Język ANSI C – pliki
Standardowe funkcje plikowe /ANSI C i BB/
fopen
putc
feof
fflush
fclose
getc
ferror
setbuf
ftell fgetc
fgetpos
setvbuf
fwrite
fprintf
fsetpos
fread
fscanf
remove
fseek
fputs
rewind
fputc
fgets
clearerror
Pewnych funkcji ze standardu nie ma w BB, natomiast w BB występuje cały szereg
dodatkowych funkcji plikowych(np. do operacji niskopoziomowych czy też do działań na
katalogach, które są specyficzne dla danej grupy systemów operacyjnych).
Język ANSI C – pliki
Funkcja fopen
FILE *fopen( const char *file_name, const char *access_mode);
Argument pierwszy wskazuje plik do otwarcia, argument drugi access_mode określa czy
plik (strumień) zostanie otwarty do zapisu, odczytu czy obu tych operacji. Określa on też
tryb (binarny czy tekstowy). Funkcja zwraca wskaźnik do pliku (wskaźnik do struktury
FILE wykorzystywanej przy dostępie do strumienia) albo też NULL.
FILE *fp;
fp=fopen (”Plik3.dat”, ”r+b”);
Maksymalną liczbę otwartych plików określa stała FOPEN_MAX, maksymalną długość
nazwy stałą FILENAME_MAX.
Język ANSI C – pliki
Funkcja fclose
int fclose (FILE *fp);
Funkcja ta zamyka plik (strumień) związany ze strukturą FILE wskazywaną przez fp.
Funkcja zwraca 0, jeśli działanie się powiodło lub też EOF. W przypadku strumieni
wyjściowych, strumień jest opróżniany przed zamknięciem pliku.
FILE *fp;
fclose (fp);
Język ANSI C – pliki
Funkcja ftell
long int ftell(FILE *fp);
Zwraca pozycję wskaźnika pliku wskazywanego prze fp. Dla plików binarnych
pozycja jest mierzona w bajtach od początku pliku. Jeżeli powstał błąd, zwraca -1L i
nadaje zmiennej globalnej errno wartość dodatnią. errno jest ustawiana na jedną z
dwóch wartości :
EBADF Niewłaściwy wskaźnik do pliku
ESPIPE Niedopuszczalna operacja seek na urządzeniu
Język ANSI C – pliki
Funkcja fwrite
size_t fwrite(void *buffer, size_t size, size_t count, FILE *fp );
Funkcja zapisuje do pliku wskazywanego przez fp, z miejsca pamięci
wskazywanego przez buffer, count bloków danych, każdy o rozmiarze size. Funkcja
zwraca liczbę zapisanych bloków.
Przykład.
int i=5;
FILE *fplik;
fplik=fopen(”Plik4.dat”, ”w+b”);
fwrite(&i, sizeof(int),1,fplik);
fclose(fplik);
Język ANSI C – pliki
Funkcja fwrite
size_t fread(void *buffer, size_t size, size_t count, FILE *fp );
Funkcja wczytuje z pliku wskazywanego przez fp, do miejsca pamięci
wskazywanego przez buffer, count bloków danych, każdy o rozmiarze size. Funkcja
zwraca liczbę odczytanych bloków.
Przykład.
int i;
FILE *fplik;
fplik=fopen(”Plik4.dat”, ”r+b”);
fread(&i, sizeof(int),1,fplik);
printf(”\n Element=%d”, i);
fclose(fplik);
Język ANSI C – pliki
Funkcja fseek
int fseek(FILE *file_pointer, long int offset, int whence );
Funkcja ustawia nową pozycję bieżącą pliku wskazywanego przez fp. Następna
operacja plikowa rozpocznie się od tej pozycji. Nowa pozycja jest oddalona o offset
bajtów od punktu odniesienia określonego przez trzeci parametr whence. Parametr ten
może przyjmować następujące wartości:
SEEK_SET – przesunięcie jest realizowane względem początku pliku,
SEEK_CUR – przesunięcie jest realizowane względem bieżącej pozycji,
SEEK_END – przesunięcie jest realizowane względem końca pliku
Funkcja zwraca wartość różną od zera w przypadku wystąpienia błędu.
Język ANSI C – pliki
Przykład. Zapis 5 liczb typu int i odczyt pliku.
#include <stdio.h>
#include <conio.h>
int main()
{ int i, buf, tab[5]={ 1,-1,2,3,5};
FILE *fp;
fp=fopen("Pliktest1.dat","w+b");
for (i=0;i<5;i++) // Zapis 5 liczb do pliku
fwrite(&tab[i],sizeof(int),1,fp);
fclose(fp); // zamiast zamykania i ponownego otwierania
// można użyć fseek(fp,0,0) lub rewind.
fp=fopen("Pliktest1.dat","r+b");
for (i=0;i<5;i++) // Odczyt 5 liczb z pliku
{ fread(&buf,sizeof(int),1,fp);
printf("\n Element pliku nr %d =%d",i,buf); }
fclose(fp); getch(); return 0; }
Język ANSI C – pliki
Przykład. Dany jest plik test1.dat liczb typu int, dopisać zadaną ilość liczb n=5 do pliku
( na końcu pliku) i odczytać plik.
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
int main()
{ int i, buf, ilosc_elementow_typu_int, n=5;
FILE *fp;
fp=fopen("Pliktest1.dat","r+b");
fseek(fp,0,SEEK_END);
for (i=0;i<n;i++)
{ printf("\n Podaj liczbe :");
scanf("%d",&buf):
fwrite(&buf,sizeof(int),1,fp); }
// Wyznaczenie ilości elementów w pliku po dopisaniu
ilosc_elementow_typu_int= ftell(fp)/sizeof(int);
Język ANSI C – pliki
Przykład. cd.
for (i=0;i< ilosc_elementow_typu_int;i++)
{
fread(&buf,sizeof(int),1,fp);
printf("\n Element pliku nr %d =%d",i,buf);
}
fclose(fp);
getch();
}
Język ANSI C – pliki
Przykład. Dany jest plik test2.dat liczb typu double, zsumować liczby dodatnie w pliku,
a następnie wyznaczyć wartość minimalną w pliku.
#include <stdio.h>
#include <conio.h>
int main()
{ int i, ilosc_elementow_typu_double;
double buf, suma_d=0, amin;
FILE *fp;
fp=fopen("Pliktest2.dat","r+b");
fseek(fp,0,SEEK_END);
ilosc_elementow_typu_double= ftell(fp)/sizeof(double);
// Wyznaczanie sumy liczb dodatnich
for (i=0;i< ilosc_elementow_typu_double;i++)
{ fread(&buf,sizeof(double),1,fp);
if (buf>0) suma_d+=buf;
}
Język ANSI C – pliki
Przykład. cd.
fseek(fp, 0, SEEK_SET);
fread(&amin,sizeof(double),1,fp);
for (i=1;i< ilosc_elementow_typu_double;i++)
{
fread(&buf,sizeof(double),1,fp);
if (buf<amin) amin=buf;
}
printf("\n Element minimalny =%f",amin);
fclose(fp);
getch();
}
Język ANSI C – pliki
Przykład. Dany jest plik test1.dat liczb typu int , zamienić miejscami element drugi i
elementem czwartym.
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
int main()
{ int i, buf1,buf2, buf, ilosc_elementow_typu_int;
FILE *fp;
fp=fopen("Pliktest1.dat","r+b");
fseek(fp,0,SEEK_END);
ilosc_elementow_typu_int= ftell(fp)/sizeof(int);
if (ilosc_elementow_typu_int<4)
{ printf("\n Nie ma wystarczajacej liczby elementow");
getch();
fclose(fp);
exit(1); }
Język ANSI C – pliki
Przykład. c.d.
fseek (fp,1*sizeof(int),SEEK_SET);
fread(&buf1,sizeof(int), 1,fp);
fseek (fp,3*sizeof(int),SEEK_SET);
fread(&buf2,sizeof(int), 1,fp);
fseek (fp,1*sizeof(int),SEEK_SET);
fwrite(&buf2,sizeof(int), 1,fp);
fseek (fp,3*sizeof(int),SEEK_SET);
fwrite(&buf1,sizeof(int), 1,fp);
fseek(fp,0,0);
for (i=0;i< ilosc_elementow_typu_int;i++)
{ fread(&buf,sizeof(int),1,fp);
printf("\n Element pliku nr %d =%d",i,buf); }
fclose(fp); getch(); }
Język ANSI C – pliki
Przykład. W przykladzie przedstawiono dwie metody odczytu pliku.
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{ FILE *fp;
double x[8]={1.5,2,3.5,4.5,5.5,6.8,7.5,8}, buf;
int i,k,ilosc_bajtow_w_pliku,ilosc_elementow_typu_double_w_pliku;
fp=fopen("pliktest.dat","w+b");
if (fp) { printf("\n Plik zostal utworzony"); getch(); }
else { printf("\n Plik nie daje utworzyc"); getch(); exit(1);}
for (i=0;i<8;i++)
fwrite(&x[i],sizeof(double),1,fp);
fclose(fp);
Język ANSI C – pliki
fp=fopen("pliktest.dat","r+b");
// Metody odczytu pliku
// Metoda 1 - z użyciem wyznaczania liczby elementów pliku
fseek(fp,0,2);
ilosc_bajtow_w_pliku=ftell(fp);
ilosc_elementow_typu_double_w_pliku=\
ilosc_bajtow_w_pliku/sizeof(double);
printf("\n Metoda 1");
fseek(fp,0,0);
for (i=0;i< ilosc_elementow_typu_double_w_pliku;i++)
{
fread(&buf,sizeof(double),1,fp);
printf("\n Element %d = %lf",i,buf);
}
getch();
Język ANSI C – pliki
printf("\n\n\n");
i=1;
// Metoda 2 - użycie sprawdzania wartości zwracanej przez funkcję fread
clrscr();
fseek(fp,0,0);
printf("\n Metoda 3");
while (fread(&buf,sizeof(double),1,fp))
printf("\n Element %d = %lf",i++,buf);
getch();
fclose(fp);
return 0;
}
Język ANSI C – pliki
Przykład. Tworzenie kopii pliku, należy utworzyć kopię pliku pliktest.dat
o nazwie plikcopy.dat w bieżącym katalogu.
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{ FILE *fp,*fp1; char bufc;
double x[8]={1.5,2,3.5,4.5,5.5,6.8,7.5,8}, buf;
int i,k,ilosc_bajtow_w_pliku,ilosc_elementow_typu_double_w_pliku;
fp=fopen("pliktest.dat","w+b");
if (fp) { printf("\n Plik zostal utworzony"); getch(); }
else { printf("\n Plik nie daje utworzyc"); getch(); exit(1);}
for (i=0;i<8;i++)
fwrite(&x[i],sizeof(double),1,fp);
Język ANSI C – pliki
Przykład. c.d. (tworzenie kopii pliku)
fp1=fopen("plikcopy.dat","w+b");// utworzenie nowego pustego pliku
fseek(fp,0,0);
while ( fread(&bufc,sizeof(char),1,fp)) // kopiowanie bajt po bajcie
fwrite(&bufc,sizeof(char),1,fp1);
printf("\n Kopia pliku");
i=1;
fseek(fp1,0,0);
while (fread(&buf,sizeof(double),1,fp1))
printf("\n Element %d = %lf",i++,buf);
getch();
return 0;
}
Język ANSI C – tablice znaków
Tablice znaków (łańcuchy)
Tablice znaków stanowią specjalny rodzaj tablic o budowie ułatwiającej
przetwarzanie tekstów. Przetwarzanie obejmuje szereg operacji takich jak tworzenie,
modyfikacją i przeszukiwanie.
Tablice znakowe mogą być definiowane w sposób następujący:
char s1[5];
char s2[5 ]=”ABCD”;
char s3[ ]=”abcd”;
Definicje tablic s2 i s3 zawierają też inicjalizację.
Tablice znaków zakończone są znakiem ‘\0’. Znak ten umożliwia wykrycie końca
tablicy, a tym samym umożliwia traktowanie tablic znaków w nieco inny sposób niż
zwykłych tablic.
Język ANSI C – tablice znaków
Przykładowo, tablica s2 ma następującą budowę:
'A'
'B'
'C'
'D'
'\0'
Tak więc definiując tablicę należy przewidzieć jedną komórkę na znak
końcowy ‘\0’.
Budowa tablicy znaków
Język ANSI C – tablice znaków
Stałe łańcuchowe i wskaźniki do znaków cz. 1
Stałe łańcuchowe ( stałe typu tablica znaków), np. ”Tekst” , są przechowywane w
pamięci jako tablice znaków z ostatnim elementem równym ‘\0’.
”Tekst” jest typu char *, czyli wskaźnik do znaku. Wskaźnik do znaku może więc
zostać zainicjowany stałą łańcuchową
char *ps=”Tekst”; // sposób 1
Inicjalizacja taka jest równoważna parze instrukcji
char *ps; // sposób 2
ps=”Tekst”;
W przypadku sposobu 1 do wskaźnika ps jest przypisywany wskaźnik do tablicy
znaków, a nie do *ps ( czyli nie do miejsca wskazywanego przez ps).
Język ANSI C – tablice znaków
Stałe łańcuchowe i wskaźniki do znaków cz. 2
Warto też zauważyć, że przy definicji tablicy znakowej
char s2[5];
nie jest możliwa realizacja przypisania w programie
s2=”ABCD” ;// przypisanie błędne
Wynika to z faktu, że s2 jako nazwa tablicy jest typu stały wskaźnik do znaku, który to
wskaźnik nie może być zmieniony poprzez przypisanie.
Język ANSI C – tablice znaków
Wczytywanie i drukowanie tablic znakowych cz.1
W języku C istnieje specjalny deskryptor formatu %s umożliwiający wczytywanie i
drukowanie tablic znakowych przy użyciu funkcji scanf i printf, istnieją też funkcje
biblioteczne realizujące te operacje.
Jeśli zdefiniowano tablicę znakową
char s1[5];
można ją wczytać i wydrukować w poniższy sposób:
printf(”\ Podaj lancuch :”);
scanf(”%s”,s1); /// nie stosuje się znaku & przed s2, gdyż s2 jest
//wskaźnikiem.
printf(”\n Wczytany lancuch to :%s ”, s1);
Język ANSI C – tablice znaków
Wczytywanie i drukowanie tablic znakowych cz.1
Jednak wczytywanie łańcuchów przy użyciu funkcji printf nie pozwala na wczytanie
łańcuchów zawierających spacje, gdyż wczytywanie łańcucha jest przerywane po
napotkaniu spacji. Dla takich łańcuchów należy zastosować funkcję gets lub też funkcję
fgets. Funkcja gets te ma następujący prototyp:
char *gets(char *s);
Opis działania funkcji gets:
Funkcja wczytuje znaki ze standardowego wejścia ( stdin) aż do momentu
napotkania znaku nowej linii (Enter). Wczytywane znaki są wyświetlane na ekranie i
zapamiętywane począwszy od miejsca wskazywanego przez s. Znak nowej linii jest
zastępowany w łańcuchu znakiem końca łańcucha '\0'. Ciąg wejściowy może zawierać
pewne białe znaki (np. spacje i znaki tabulacji poziomej). Funkcja zwraca s, gdy
operacja się powiodła, lub NULL w przypadku wystąpienia błędu.
Język ANSI C – tablice znaków
Wczytywanie i drukowanie tablic znakowych cz.2
Długość wczytywanego ciągu znaków nie jest ograniczana, co przy ciągach
dłuższych niż to wynika z argumentu funkcji gets, może powstać uszkodzenie
sasiednich obszarów pamięci.
Przykład.
char lan [20];
printf ("\n Podaj lancuch:");
gets(lan);
Bardziej uniwersalną funkcją służącą do wczytywania łańcuchów jest fgets.
Język ANSI C – tablice znaków
Wczytywanie i drukowanie tablic znakowych cz.3
Funkcja fgets ma nastepujący prototyp:
char *fgets(char *s, int n, FILE *stream);
Funkcja ta czyta do łańcucha s znaki ze strumienia wejściowego (pliku) określonego
przez wskaźnik stream. Funkcja kończy wczytywanie znaków po przeczytaniu n - 1
znaków lub też po pojawieniu się znaku nowej linii. Funkcja wpisuje znak nowej linii do
do łańcucha. Funkcja zwraca łańcuch lub NULL w przypadku pojawienia się końca pliku
lub błedu.
Przykład. Wczytywanie ze standardowego strumienia wejściowego
char lan [20];
printf ("\n Podaj lancuch:");
fgets(lan,15,stdin);
Język ANSI C – tablice znaków
Wczytywanie drukowanie tablic znakowych cz.4
Do drukowania tablic znakowych można zastosować funkcje puts i fputs.
Prototyp funkcji puts ma postać
int puts(const char *s);
Funkcja wyprowadza łańcuch na wyjście standardowe (stdout) i dołącza znak nowej
linii. W przypadku pomyślnej realizacji funkcja zwraca wartość nieujemną, w
przeciwnym przypadku EOF.
int fputs(const char *s, FILE *stream);
Funkcja zapisuje łańcuch s do do strumienia wyjściowego określonego przez
wskaźnik stream. Funkcja nie zapisuje do pliku znaku '\0'.
W przypadku powodzenia operacji funkcja zwraca wartość nieujemną, w przypadku
błędu wartość EOF.
Język ANSI C – tablice znaków
Przykład. Zapis do pliku dwóch łańcuchów i odczyt.
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv) {
char s1[10]="ABCDE";
char s2[10]="abcde", s3[10], s4[10];
FILE *fp;
fp=fopen("Plik1.txt","w+");
fputs(s1,fp);
fputc('\n',fp);
fputs(s2,fp);
fputc('\n',fp); // dopisanie znaku nowej linii, aby funkcja
// fgets czytała tylko pierwszy łańcuch z pliku
Język ANSI C – tablice znaków
Przykład. c.d. Odczyt pliku i wydruk.
fseek(fp,0,0);
fgets(s3,10,fp);
printf("%s",s3);
fgets(s4,10,fp);
printf("%s",s4);
getch();
fclose(fp);
return 0;
}
Język ANSI C – tablice znaków
Standardowe funkcje łańcuchowe cz. 1
Poniżej omówione zostaną wybrane najczęściej spotykane funkcje związane z
przetwarzaniem łańcuchów (pełny zestaw w <string.h> i <stdlib.h>.
Funkcje te to:
strlen, strcpy, strcat, strcmp, strlwr, strupr, atoi, itoa, strchr, strstr.
Funkcja strlen
size_t strlen(const char *s);
Funkcja oblicza długość łańcucha s bez końcowego znaku '/0'.
Przykład.
char s[20]="12345678";
int dl;
dl=strlen(s);// dl będzie równe 8
Język ANSI C – tablice znaków
Standardowe funkcje łańcuchowe cz. 2
Funkcja strcpy
char *strcpy(char *dest, const char *src);
Kopiuje łańcuch src do łańcucha dest. Kopiowanie ulega zakończeniu po
skopiowaniu znaku '\0' kończącego łańcuch src.
Funkcja zwraca wskaźnik dest .
Przykład.
#include <stdio.h>
#include <string.h>
int main(void) {
char lan1[10="ABC";
char lan2[ ]= "12345";
strcat(lan1, lan2);
printf("%s", lan1);
return 0; }
Język ANSI C – tablice znaków
Funkcja strcat
char *strcat(char *dest, const char *src);
Dołącza łańcuch src do końca łańcucha dest. Funkcja zwraca wskaźnik dest .
Długość połączonego łańcucha jest równa strlen(dest)+strlen(src).
Przykład.
#include <stdio.h>
#include <string.h>
int main(void) {
char lan1[20]="abcde";
char lan2[ ]= "123456789";
strcat(lan1, lan2);
printf("%s", lan1);
return 0; }
Standardowe funkcje łańcuchowe cz. 3
Język ANSI C – tablice znaków
Standardowe funkcje łańcuchowe cz. 4
Funkcja strcmp
int strcmp(const char *s1, const char *s2);
Porównuje łańcuch s1 z łańcuchem s2, porównując kody znaków (np. kody ASCII)
obu łańcuchów. Porównanie kończy się, gdy w jednym z łańcuchów zostanie
napotkany znak o większym kodzie lub też zostanie osiągnięty koniec jednego z
łańcuchów ( wtedy dłuższy łańcuch uważany jest za większy).
Funkcja zwraca
- wartość <0, gdy s1<s2,
-wartość 0, gdy s1==s2,
-wartość >0, gdy s1>s2.
Język ANSI C – tablice znaków
Standardowe funkcje łańcuchowe cz. 5
Przykład. Zastosowanie funkcji strcmp.
#include <stdio.h>
#include <string.h>
#include <conio.h>
int main(void) {
char lan1[10]="abcde",lan2[10 ]; int p;
printf(" Podaj lancuch:");
scanf("%s", lan2);
p= strcmp(lan1,lan2);
if (p<0) printf(" lan1<lan2"); else if ( p==0) printf("\n lan1=lan2");
else printf("\n lan1>lan2");
getch(); return 0; }
Język ANSI C – tablice znaków
Przykład. Wczytywanie dwuwymiarowej tablicy znaków (tablicy łańcuchów)
oraz sortowanie niemalejąco. (cz.1)
// cz. 1 programu
#include <stdio.h>
#include <conio.h>
#include <string.h>
int main(int argc, char* argv[])
{
char stab[5][10];
char spom[10];
int i,zam;
for(i=0;i<5;i++)
{
printf("\n lan%d :",i);
scanf("%s",stab[i]); // wczytywanie tablicy znaków będącej wierszem
} // tablicy dwuwymiarowej
for(i=0;i<5;i++) printf("\n lan %s",stab[i]);
Język ANSI C – tablice znaków
Cz. 2 programu
do
{
zam=0;
for (i=0;i<4;i++)
if (strcmp(stab[i],stab[i+1])>0)
{ strcpy(spom, stab[i]);
strcpy(stab[i], stab[i+1]);
strcpy( stab[i+1],spom );
zam=1;
}
}
while (zam);
printf("\n\n Tablica po sortowaniu");
for(i=0;i<5;i++)
printf("\n lan %s",stab[i]);
getch();
return 0;}
Język ANSI C - struktury
Język ANSI C - struktury
Struktury
Struktury ( zwane w innych językach programowania rekordami) stanowią typ
służący do przetwarzania informacji powiązanych ze sobą. Definicja typu
strukturowego ma następującą postać
struct nazwa_typu
{ typ_pola_1 nazwa_pola_1;
typ_pola_2 nazwa_pola_2;
.
.
typ_pola_n nazwa_pola_n;
} ;
Tak więc definicja typu strukturowego składa się ze słowa kluczowego struct, po
którym następuje nazwa danego typu strukturowego ( czasami określana jako
etykieta), po czym po nawiasie otwierającym występują typy poszczególnych
składowych struktury oraz ich nazwy. Składowe typu strukturowego zwane są polami
struktury.
Język ANSI C - struktury
Definicja typu strukturowego kończy się nawiasem zamykajacym.
W typie strukturowym mogą wystąpić pola, które same mogą być typu strukturowego,
mówimy wtedy o tzw. typie strukturowym zagnieżdżonym.
Nazwy pól muszą być różne w ramach jednego typu strukturowego, jednak
można stosować te same nazwy w ramach innych typów strukturowych.
Nazwa pola struktury może być taka sama jak nazwa danego typu
strukturowego czy też zmiennej strukturowej.
Język ANSI C - struktury
Przykład. W ramach jednego typu danych chcemy przechowywać pewne informacje o
pracownikach. Zdefiniujemy uproszczony typ strukturowy pozwalający na
przechowywanie takich informacji ( w rzeczywistych sytuacjach może być konieczne
stosowanie nawet kilkudziesięciu pól).
struct pracownik
{ char nazwisko [20];
char imie [20];
int wiek;
double dochod;
} rek1, rek2;
rek1, rek2 są zmiennymi typu pracownik. Zmienne strukturowe można też zdefiniować
w sposób następujący:
struct pracownik rek3, rek4, rek5;
Język ANSI C - struktury
Można też zdefiniować tablicę struktur
struct pracownik pracownicy [20];
Zmienna pracownicy jest tablicą struktur składającą się z 20 struktur typu
pracownik.
Dla realizacji dostępu do pól typu strukturowego, w języku C wprowadzono
specjalny operator dostępu do pól struktury – operator „.”( kropka). Operator ten jest
stosowany w sposób następujący: jeśli mamy zmienną strukturową rek1 typu pracownik,
to możemy wprowadzić wartość do jej pola dochod w sposób następujący:
rek1. dochod=1500;
W ogólnym przypadku, polami zmiennych strukturowych możemy posługiwać się jak
zmiennymi takiego typu, jak typ danego pola struktury.
Język ANSI C - struktury
Przykład. W ramach jednego typu danych chcemy przechowywać pewne informacje o
pracownikach. Zdefiniujemy uproszczony typ strukturowy pozwalający na
przechowywanie takich informacji ( w rzeczywistych sytuacjach może być konieczne
stosowanie nawet kilkudziesięciu pól).
struct pracownik
{ char nazwisko [20];
char imie [20];
int wiek;
double dochod;
} rek1, rek2;
rek1, rek2 są zmiennymi typu pracownik. Zmienne strukturowe można też zdefiniować
w sposób następujący:
struct pracownik rek3, rek4, rek5;
Język ANSI C - struktury
Można też zdefiniować tablicę struktur
struct pracownik pracownicy [20];
Zmienna pracownicy jest tablicą struktur składającą się z 20 struktur typu
pracownik.
Dla celów typem strukturowym, w języku C wprowadzono specjalny operator
dostępu do pól struktury – operator „.”( kropka). Operator ten jest stosowany w sposób
następujący: jeśli mamy zmienną strukturową rek1 typu pracownik, to możemy
wprowadzić wartość do jej pola dochod jak następuje:
rek1. dochod=1500;
W ogólnym przypadku polami zmiennych strukturowych możemy posługiwać się jak
zmiennymi takiego typu, jak typ danego pola struktury.
Język ANSI C - struktury
1. Pola typu numerycznego ( typy całkowite i typy rzeczywiste)
Jak zaznaczono powyżej, pola takie można stosować, jako zmienne danego typu
rek2. dochod=1000;
rek2. wiek=25;
pracownicy[0].dochod=1200;
pracownicy [0].wiek=24;
scanf(”%d”,&rek3.dochod);
scanf(”%d”,&rek3.wiek);
scanf (”%lf”, &pracownicy[1].dochod);
scanf (”%d”, &pracownicy[1].wiek);
Wprowadzanie/wyprowadzanie informacji z /do pól zmiennych strukturowych cz. 1
Język ANSI C - struktury
2. Pola typu tablica znaków
strcpy (rek1.nazwisko, ” Kowalski”);
scanf(”%s”, rek2.nazwisko);
gets( rek3.nazwisko);
Wyprowadzanie informacji odbywa się podobnie jak dla innych zmiennych.
printf (”\n %d ”, rek1.dochod);
printf(”\n %s ”, rek1.nazwisko);
Wprowadzanie/wyprowadzanie informacji z /do pól zmiennych strukturowych cz. 2
Język ANSI C - struktury
Inicjalizacja struktur
Zmienne typu strukturowego, podobnie jak tablice, mogą być inicjalizowane przy
definicji.
Przykład. Inicjalizacja pól zmiennej typu student.
struct student
{ char nazwisko[20];
char imie [20];
int rok studiow;
char wydzial[20];
};
struct student student1={ "Kowalski", "Marcin", 2, "EiA"};
struct student student2={ "Iksiński", "Andrzej", 3, "EiA"};
Język ANSI C - struktury
Inicjalizacja tablic struktur
Przykład. Inicjalizacja tablicy struktur typu student
struct student
{ char nazwisko[20];
char imie [20];
int rok studiow;
char wydzial[20];
};
struct student studenci[3]={ {”Kowalski”, ”Marcin”, 2, ”EiA”},
{ ”Iksiński”, ”Andrzej”, 2, ”EiA”},
{ ”Malinowski”, ”Dariusz”, 2, ”EiA”} };
Przykład. Program rekordy1 wczytujący i drukujący pojedyncze struktury.
#include <condefs.h>
#include <stdio.h>
#include <conio.h>
#include <string.h>
// program rekordy1 wczytuje dane do struktur
// i następnie drukuje
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char **argv)
{ struct student
{ char nazwisko[20];
char imie [20];
int rok_studiow;
char wydzial[20];
};
Język ANSI C - struktury
Język ANSI C – struktury
struct student student1, student2;
/* Bezpośrednie nadawanie wartości polom struktur */
strcpy(student1.nazwisko,"Kowalski");
strcpy(student1.imie,"Jan");
student1.rok_studiow=2;
strcpy(student1.wydzial,"EiA");
Język ANSI C – struktury
// Program rekordy1 cz. II
/* Do wczytywania pól struktury student 2 z klawiatury zastosowano trzy różne
funkcje wczytywania pól typu tablica znaków, by pokazać różne
sposoby wczytywania takich pól */
printf ("\n Podaj dane 2-go studenta ");
printf ("\n Nazwisko: ");
scanf("%s",student2.nazwisko);
printf ("\n Imie: ");
fflush(stdin);
fgets(student2.imie,15,stdin);
printf("\n Rok studiow :");
scanf("%d",&student2.rok_studiow);
printf ("\n Wydział: ");
scanf("%s",student2.wydzial);
Język ANSI C – struktury
// program rekordy1 cz. III
/* Drukowanie struktur student1 i student2*/
printf("\n\n Dane studenta 1 ");
printf("\n Nazwisko :%s", student1.nazwisko);
printf("\n Imie :%s", student1.imie);
printf("\n Rok studiow :%d", student1.rok_studiow);
printf("\n Wydzial :%s", student1.wydzial);
printf("\n\n\n Dane studenta 2 ");
printf("\n Nazwisko :%s", student2.nazwisko);
printf("\n Imie :%s", student2.imie);
printf(" Rok studiow :%d", student2.rok_studiow);
printf("\n Wydzial :%s", student2.wydzial);
getch();
return 0;}
Język ANSI C – struktury
Struktury zagnieżdżone
Struktury zagnieżdżone to takie struktury w których
przynajmniej jedno z pól jest typu strukturowego.
struct nazwa_typu
{ typ_pola_1 nazwa_pola_1;
struct nazwa_typu_strukturowego nazwa_pola_2;
.
.
typ_pola_n nazwa_pola_n;
} ;
Język ANSI C – struktury
struct data
{
int dzien;
int miesiac;
int rok;
}
struct dane_studenta
{ char nazwisko[20];
char imie [20];
struct data data_ur ;
int rok studiow;
char wydzial[20];
};
struct dane_studenta dane_studenta1, dane_studenta2;
Język ANSI C – struktury
Przykład . Program rekordy2 wczytuje dane do tablicy struktur i następnie drukuje
int main(int argc, char **argv)
{ struct data {
int dzien;
int miesiac;
int rok; };
struct dane_studenta
{ char nazwisko[20];
char imie [20];
struct data data_ur;
int rok_studiow;
char wydzial[20]; };
struct dane_studenta studenci[4];
Język ANSI C – operatory
// Program rekordy2 cz. II
int i;
/* Bezpośrednie nadawanie wartości polom
tablicy struktur */
strcpy(studenci[0].nazwisko,"Kowalski");
strcpy(studenci[0].imie,"Jan");
studenci[0].rok_studiow=2;
studenci[0].data_ur.dzien=2;
studenci[0].data_ur.miesiac=5;
studenci[0].data_ur.rok=1980;
strcpy(studenci[0].wydzial,"EiA");
strcpy(studenci[1].nazwisko,"Nowak");
strcpy(studenci[1].imie,"Andrzej");
studenci[1].rok_studiow=2;
studenci[1].data_ur.dzien=2;
studenci[1].data_ur.miesiac=6;
studenci[1].data_ur.rok=1981;
strcpy(studenci[1].wydzial,"EiA");
Język ANSI C – struktury
// program rekordy2 cz. III
for (i=2;i<4;i++)
{ printf ("\n Podaj dane studenta %i",i+1);
printf ("\n Nazwisko: "); scanf("%s",studenci[i].nazwisko);
fflush(stdin);
printf ("\n Imie: "); scanf("%s",studenci[i].imie);
fflush(stdin);
printf("\n Podaj date urodzenia ");
printf("\n dzien :"); scanf ("%d",&studenci[i].data_ur.dzien);
printf("\n miesiac :"); scanf ("%d",&studenci[i].data_ur.miesiac);
printf("\n rok :"); scanf ("%d",&studenci[i].data_ur.rok);
printf("\n Rok studiow :"); scanf("%d",&studenci[i].rok_studiow);
printf ("\n Wydział: "); scanf("%s",studenci[i].wydzial);
fflush(stdin); }
Język ANSI C – struktury
// Program rekordy2 cz. IV
/* Drukowanie tablicy struktur */
for (i=0;i<4;i++)
{
printf("\n\n Dane studenta %d ", i+1);
printf("\n Nazwisko :%s", studenci[i].nazwisko);
printf("\n Imie :%s", studenci[i].imie);
printf(" data urodzenia :%d.%d.%d ", studenci[i].data_ur.dzien,\
studenci[i].data_ur.miesiac,studenci[i].data_ur.rok);
printf("\n Rok studiow :%d", studenci[i].rok_studiow);
printf("\n Wydzial :%s", studenci[i].wydzial);
}
getch();
return 0;}
Język ANSI C – struktury
Przykład. Zapis struktur do pliku i odczyt.
#include <condefs.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
struct student
{ char nazwisko[20];
char imie[20]; };
FILE *fp;
char s[20]="pliktest.dat";
Język ANSI C – struktury
Przykład. c.d. Zapis i odczyt struktur
int main(int argc, char **argv)
{ char ch; int i;
struct student tab[4]={ {"iksinski","jan"},{"ygrekowski","andrzej "},
{"wojcik","marcin"},{"kowalski","marek"}}; //inicjalizacja tablicy struktur
struct student tab1[4],st;
fp=fopen(s,"w+b");
fwrite(&tab,sizeof(student),4,fp);// zapis tablicy struktur do pliku,
// można zapisać 4 bloki pętla nie jest konieczna,
fseek(fp,0,SEEK_SET);
i=1;
while (fread(&st,sizeof(student),1,fp))
{ printf("\n Dane studenta %d",i++);
printf("\n Nazwisko:%s", st.nazwisko);
printf("\n Imie:%s", st.imie); }
getch(); return 0; }
Język ANSI C – struktury