Programowanie w języku C
Kurs początkowy
Dr inż. Lucjan Miękina
upel.agh.edu.pl/wimir/login/
Katedra Robotyki i Mechatroniki
December 10, 2012
1/1
Programowanie w języku C
Pamięciowe operacje wejścia/wyjścia - zapis do pamięci za pomocą funkcji sprintf
Funkcja sprintf jest identyczna jak printf, z wyjątkiem dodatkowego pierwszego
parametru, który jest wskaznikiem do bloku pamięci. Aańcuch formatujący jest drugim
parametrem. Funkcja jest zadeklarowana jako:
int sprintf(char* buf, char* format, ...);
Wielokropek (...) oznacza, że za łańcuchem formatującym może wystąpić dowolna
ilość dodatkowych argumentów, których wartości są wyprowadzane.
1 #include
2 #include
3 int MemOut(char* buffer) {
4 if(buffer) {
5 float tab[] = { 1.1, 2.2, 3.3};
6 int i, cnt = 0, len = sizeof(tab)/ sizeof(tab[0]);
7 printf("MemOut(): len=%2d\n", len);
8 cnt += sprintf(buffer, "len=%2d\n", len);
Rezultat wykonania MemOut():
9 for(i = 0; i < len; i++) {
10 int pop = cnt;
MemOut(): len= 3
11 cnt += sprintf(buffer + cnt,
Zapis 23 zn.: tab[0]= 1.1e+00
12 "tab[%1d]=%8.1e\n", i, tab[i]);
13 printf("Zapis %d zn.: %s\n", cnt, buffer + pop); Zapis 39 zn.: tab[1]= 2.2e+00
14 }
Zapis 55 zn.: tab[2]= 3.3e+00
15 printf("BUFOR:\n%s", buffer);
BUFOR:
16 return 0;
len= 3
17 }
tab[0]= 1.1e+00
18 return -1;
tab[1]= 2.2e+00
19 }
tab[2]= 3.3e+00
2/1
Programowanie w języku C
Pamięciowe operacje wejścia/wyjścia - odczyt z pamięci za pomocą funkcji sscanf
Funkcja sscanf jest identyczna jak scanf, z wyjątkiem dodatkowego pierwszego
parametru, który jest wskaznikiem do bloku pamięci z którego czytane są dane.
Aańcuch formatujący jest drugim parametrem. Funkcja jest zadeklarowana jako:
int sscanf(char* buf, char* format, ...);
Wielokropek (...) oznacza, że za łańcuchem formatującym może wystąpić dowolna
ilość dodatkowych argumentów, będących adresami zmiennych do których są
wprowadzane kolejne wartości.
20 int MemIn(char* buffer) {
21 if(buffer) {
22 printf("BUFOR w MemIn():\n%s", buffer);
23 int len, i, j, cnt = 0;
24 cnt += sscanf(buffer, "len=%d\n", &len);
Rezultat wykonania
25 printf("Czytanie %d elem:\n", len);
MemIn():
26 float tab[len];
27 for(i = 0; i < len; i++) {
BUFOR w MemIn():
28 buffer = strchr(buffer, \n ); buffer++;
len= 3
29 cnt += sscanf(buffer, "tab[%d]=%e\n",
30 &j, &tab[i]); tab[0]= 1.1e+00
31 printf("tab[%d]= %8.1e\n", j, tab[j]);
tab[1]= 2.2e+00
32 }
tab[2]= 3.3e+00
33 return 0;
Czytanie 3 elem:
34 }
tab[0]= 1.1e+00
35 return -1;
tab[1]= 2.2e+00
36 }
tab[2]= 3.3e+00
3/1
Programowanie w języku C
Plikowe operacje wejścia/wyjścia - obsługa plików binarnych
Operacje realizowane w trybie binarnym polegają na kopiowaniu wybranych obszarów
pamięci operacyjnej do pliku, lub odczycie z pliku zadanej liczby bajtów i przesłaniu ich
do pamięci operacyjnej. Odbywa się to bez jakiejkolwiek konwersji (przekształcenia), a
więc jest maksymalnie szybkie i dokładne, a także maksymalnie oszczędne jeśli chodzi
o rozmiar pliku. Otrzymuje się jednak postać zapisu nieczytelną dla operatora.
Aby zapewnić współpracę z plikami binarnymi należy:
otworzyć je w trybie binarnym; do odczytu (używając trybu "rb") lub do zapisu
(używając trybu "wb")
do odczytu danych wykorzystać funkcję:
size_t fread(void* b, size_t s, size_t c, FILE* fp);
do zapisu danych użyć funkcji:
size_t fwrite(const void* b, size_t s, size_t c, FILE* fp);
Funkcje fread i fwrite zwracają rezultat typu size_t, o wartości równej ilości poprawnie
przesłanych danych (w przypadku pełnego sukcesu równy wartości parametru c).
4/1
Programowanie w języku C
Plikowe operacje wejścia/wyjścia - obsługa plików binarnych: zapis
Poniżej podano fragmenty kodu realizujące operacje zapisu i odczytu danych z
przykładu dotyczącego funkcji fscanf i fprintf, ale w trybie binarnym.
1 #include
2
3 int BinOut(char* fname) {
4 FILE* fp = fopen(fname, "wb");
5 if (fp) {
6 float tab[] = { 1.1, 2.2, 3.3 };
7 int i, len = sizeof(tab) / sizeof(tab[0]);
8 fwrite(&len, sizeof(int), 1, fp);
9 for (i = 0; i < len; i++) // L1
10 fwrite(&tab[i], sizeof(float), 1, fp); // L2
11 fclose(fp);
12 return 0;
13 } else {
14 perror("fopen");
15 return -1;
16 }
17 }
Zamiast linii L1 i L2 można użyć bardziej zwartego zapisu:
fwrite(tab, sizeof(float), len, fp);
co spowoduje zapis bloku danych o adresie początku tablicy tab i o rozmiarze
podanym w len.
5/1
Programowanie w języku C
Plikowe operacje wejścia/wyjścia - obsługa plików binarnych: odczyt
19 int BinIn(char* fname) {
20 FILE* fp = fopen(fname, "rb");
21 if (fp) {
22 int len, ok = fread(&len, sizeof(int), 1, fp);
23 printf("%d pole: len=%d", ok, len);
24 if (ok > 0) {
25 float tab[len]; // zmienna jako ilosc el.!
26 int i;
27 for (i = 0; i < len; i++) { // L1
28 ok = fread(&tab[i], sizeof(float), 1, fp); // L2
29 if (ok != 1)
30 break;
31 printf("\ntab[%d]=%g", i, tab[i]);
32 }
33 }
34 fclose(fp);
35 return 0;
36 } else {
37 perror("fopen");
38 return -1;
39 }
40 }
Zamiast linii L1 i L2 można użyć bardziej zwartego zapisu:
fread(tab, sizeof(float), len, fp);
co wprowadzi z pliku do pamięci począwszy od adresu początkowego tablicy tab blok
danych o rozmiarze podanym w len.
6/1
Programowanie w języku C
Plikowe operacje wejścia/wyjścia - obsługa plików binarnych: program główny i wyniki
42 int main() {
43 if (BinOut("F.bin") == 0)
44 BinIn("F.bin");
45 return 0;
46 }
Rezultat wykonania:
1 pole: len=3
tab[0]=1.1
tab[1]=2.2
tab[2]=3.3
W przypadku użycia niepoprawnej nazwy pliku (np. nieistniejąca ścieżka do katalogu),
funkcja perror wyświetli następujący opis błędu:
fopen: No such file or directory
7/1
Programowanie w języku C
Plikowe operacje wejścia/wyjścia - swobodny dostęp do pliku
Omawiane dotąd funkcje wejścia/wyjścia działają w sposób sekwencyjny, tzn.
wykonują operacje na kolejnych bajtach strumienia; o ile programista nie podejmie
działań zmieniających bieżącą pozycję w pliku (ang. file position indicator). W
sekwencji: odczyt-zapis-odczyt (jeśli plik był otwarty w odpowiednim trybie) druga
operacja odczytu zacznie się tuż po ostatnio zapisanych danych. Należy pamiętać, że
biblioteka stdio wymaga, by programista wymusił opróżnienie bufora po każdej z
takich naprzemiennych operacji.
Funkcje swobodnego dostępu do pliku pozwalają sterować bieżącą pozycją kursora
pliku. Kursor jest przez nie przesuwany bez konieczności wykonywania zapisu lub
odczytu, tak by odzwierciedlał bajt, który będzie podlegał następnej operacji plikowej.
Istnieją 3 rodzaje funkcji do odczytu lub zmiany pozycji kursora w pliku:
Odczyt pozycji kursora może być realizowany za pomocą ftell i fgetpos.
Ustawienie bieżącej pozycji kursora pliku na zero (co odpowiada początkowi
pliku), jest realizowane przez funkcję:
void rewind(FILE *fp);
Ustawienie bieżącej pozycji kursora pliku na dowolną. Można tu zastosować
funkcje fseek i fsetpos.
8/1
Programowanie w języku C
Plikowe operacje wejścia/wyjścia - swobodny dostęp do pliku
Funkcja ftell, zadeklarowana:
long ftell(FILE *fp);
zwraca aktualną wartość (mierzoną w znakach) kursora dla pliku binarnego. Dla pliku
tekstowego jest zwracana pewna wartość umowna (ang. magic number); może ona
być użyta tylko do zmiany bieżącej pozycji za pomocą wywołania fseek. W przypadku
błędu zwracana jest wartość -1L i ustawiana jest odpowiednia wartość wyrażenia errno.
Funkcja fgetpos, zadeklarowana:
int fgetpos(FILE *fp, fpos_t *pos);
zapisuje aktualną wartość bieżącej pozycji pliku fp w argumencie *pos, w celu użycia
przez funkcję fsetpos. Typ fpos_t jest specjalnie zdefiniowany do przechowywania
takich wartości. fgetpos zwraca nie-zero w przypadku błędu.
Funkcja fseek, zadeklarowana:
int fseek(FILE *fp, long pozycja, int baza);
pozwala ustawić bieżącą pozycję kursora pliku fp na dowolną wartość dla plików
binarnych, a dla plików tekstowych na wartość odczytaną za pomocą funkcji ftell.
Funkcja fseek zeruje flagę końca pliku i usuwa pamięć związaną z wykonaniem funkcji
ungetc zarówno dla wejścia jak i wyjścia.
Funkcja fseek zwraca zero po poprawnym wykonaniu, a wartość różną od zera dla
niepoprawnego żądania.
9/1
Programowanie w języku C
Plikowe operacje wejścia/wyjścia - swobodny dostęp do pliku
W ogólnym przypadku, za pomocą fseek można ustawić pozycję na bajcie oddalonym
o wartość przekazaną za pomocą parametru pozycja (w bajtach) od miejsca w pliku
określonego za pomocą parametru baza. Wartość parametru pozycja może być
ujemna. Wartości parametru baza mogą być ustalone jako:
SEEK_SET, co definiuje bazę związaną z początkiem pliku,
SEEK_CUR, co definiuje bazę związaną z bieżącym położeniem w pliku,
SEEK_END, co definiuje bazę związaną z końcem pliku. Nie gwarantuje się
poprawnego działania funkcji fseek dla plików binarnych w tym trybie.
Dla plików tekstowych, wartość parametru pozycja musi być równa zeru lub wartości
zwróconej przez ostatnie wywołanie funkcji ftell dla tego samego strumienia, a wartość
parametru baza musi być SEEK_SET.
Funkcja fsetpos, zadeklarowana:
int fsetpos(FILE *fp, const fpos_t *pos);
ustawia kursor dla pliku fp na wartości zapisanej przez funkcję fgetpos w argumencie
*pos, a następnie zwraca wartość świadczącą o sukcesie lub błędzie (różną od zera dla
niepoprawnego żądania).
10/1
Programowanie w języku C
Plikowe operacje wejścia/wyjścia - swobodny dostęp do pliku - przykład
Pokazano zapis tablicy danych typu float, po którym następuje przesunięcie kursora
pliku wstecz o rozmiar tablicy i ponowny zapis elementów tablicy ze zmienionym
znakiem.
3 int RandOut(char* fname) {
4 FILE* fp = fopen(fname, "wb");
5 if(fp) {
6 float tab[] = { 1.1, 2.2, 3.3 };
7 int len = sizeof(tab) / sizeof(tab[0]);
8 fwrite(&len, sizeof(int), 1, fp);
9 int i;
10 for(i = 0; i < len; i++)
11 fwrite(&tab[i], sizeof(float), 1, fp);
12 // powrót do elementu tab[0]
13 if(fseek(fp, - sizeof(tab), SEEK_CUR) == 0) // OK
14 for(i = 0; i < len; i++) {
15 tab[i] *= -1.; // zmiana znaku
16 fwrite(&tab[i], sizeof(float), 1, fp);
17 }
18 fclose(fp);
19 return 0;
20 }
21 else {
22 perror("fopen");
23 return -1;
24 }
25 }
11/1
Programowanie w języku C
Plikowe operacje wejścia/wyjścia - swobodny dostęp do pliku - przykład
W programie głównym wywołuje się funkcję realizującą zapis w konwencji swobodnego
dostępu do pliku i odczyt kontrolny z użyciem wcześniej dyskutowanej funkcji BinIn.
50 int main() {
51 if(RandOut("F.bin") == 0)
52 BinIn("F.bin");
53 return 0;
54 }
Rezultat wykonania:
1 pole: len=3
tab[0]=-1.1
tab[1]=-2.2
tab[2]=-3.3
12/1
Programowanie w języku C
Wyrażenia
Wyrażenia zbudowane są z obiektów programu w postaci stałych, zmiennych i
wywołań funkcji, połączonych za pomocą odpowiednich operatorów. Opracowanie
wyrażenia ma na celu określenie jego wartości i składa się z wykonania operacji,
realizowanych przez operatory w nim występujące.
Kolejność wykonania operacji zawartych w wyrażeniu jest określona przez:
nawiasy (operacje w najbardziej wewnętrznych nawiasach wykonuje się przed
innymi operacjami)
priorytety (pierwsze są wykonywane operacje o wyższym priorytecie)
wiązania operatorów, które stosuje się gdy obok siebie występują operatory o
takich samych priorytetach. Rozróżnia się wiązanie lewe i prawe. Operator
mający wiązanie lewe wiąże się z argumentem występującym po jego lewej
stronie, a operator mający wiązanie prawe wiąże się z argumentem występującym
po jego prawej stronie. Większość operatorów ma wiązanie lewe (tzn.
wykonywane są od lewej do prawej).
13/1
Programowanie w języku C
Wyrażenia
W poniższym przykładzie wartość 5 jest podstawiona do zmiennych a i b ponieważ
operator = ma wiązanie prawe. Zgodnie z tym, wartość zmiennej c jest najpierw
podstawiana do b, a potem zmienna b jest podstawiana do a.
int a, b = 9, c = 5;
a = b = c;
Ponieważ kolejność obliczania części wyrażenia nie jest ogólnie określona, można
jawnie to określić przez wprowadzenie nawiasów grupujących elementy w nich zawarte.
W wyrażeniu:
a + b * c / d
operacje * i / są wykonywane przed + zgodnie z priorytetami. b jest mnożone przez c
zanim c jest dzielone przez d zgodnie z wiązaniami.
14/1
Programowanie w języku C
Wyrażenia - priorytety i wiązania operatorów
Klasa Wiązanie Operatory
Nawiasy W głąb, lewe ( wyrażenie nazwa_funkcji(parametry
Dostępu, post- lewe [] -> . expr++ expr--
1-argumentowe prawe ! ~ + - * & (typ sizeof ++expr --expr
Multiplikatywne lewe * / %
Addytywne lewe + -
Przesunięcia lewe << >>
Relacyjne lewe < <= > >=
Równości lewe == !=
Bitowe AND lewe &
Bitowe XOR lewe ^
Bitowe OR lewe |
Logiczne AND lewe &&
Logiczne OR lewe ||
Warunkowe prawe ? :
Przypisania prawe = += -= *= /= &= |= ^= <<= >>=
Sekwencji lewe ,
15/1
Programowanie w języku C
Wyrażenia - używanie operatorów
Operatory arytmetyczne
+ - * / % ++ --
Dwuargumentowe operatory + i mają takie same priorytety, niższe niż operatory *, /
i %, które z kolei są niższe od jedno-argumentowych operatorów + i -. Operatory
arytmetyczne mają wiązanie lewe. Operatory relacyjne
> >= < <=
mają ten sam priorytet, który jest wyższy niż operatorów równości
== !=
Operatory relacyjne mają priorytet niższy niż operatory arytmetyczne, więc wyrażenie:
i < cnt-1
jest traktowane zgodnie z oczekiwaniami, czyli:
i < (cnt - 1)
Operacje wykonywane z użyciem tych operatorów mają ogólną postać: Exp1 # Exp2
gdzie # może być jednym z operatorów: > >= < <= == !=, natomiast Exp1 i
Exp2 są wyrażeniami. Rezultatem operacji porównania jest stała o wartości 1 jeśli
relacja jest spełniona, albo stała o wartości 0.
16/1
Programowanie w języku C
Wyrażenia - używanie operatorów
Operatory logiczne
! // negacja
&& // koniunkcja
|| // alternatywa
użyte w wyrażeniu, powodują obliczanie jego wartości, które jest kontynuowane tylko
do momentu gdy jego prawdziwość (lub nie) daje się jednoznacznie określić często
przed końcem całego wyrażenia. Priorytet && jest wyższy niż || i priorytety obu są
niższe niż priorytety operatorów relacyjnych, więc wyrażenie:
i < cnt-1 && (c=getchar()) != \n
wymaga tylko jednej pary nawiasów (bo priorytet != jest wyższy niż priorytet
przypisania).
Operacje przypisania
Podstawowa operacja przypisania ma postać:
Var = Exp
gdzie Var jest nazwą zmiennej, a Exp jest wyrażeniem o typie zgodnym z typem Var.
Wykonanie tej operacji polega na opracowaniu wyrażenia Exp i następnie
zainicjowaniu wartości zmiennej Var.
17/1
Programowanie w języku C
Wyrażenia - używanie operatorów
Istnieją skrócone sposoby zapisu wyrażenia o postaci ogólnej: Var = Var # Exp
gdzie # może być jednym z operatorów: +, -, *, /, % i innych.
Przykłady:
x += 3; // to samo co: x = x + 3;
x /= 2; // to samo co: x = x / 2;
Operacje bitowe
Służą do wykonania operacji niezależnie na poszczególnych bitach słowa.
1 #include
2 int main() {
3 int i = 0xff;
4 printf("~0xff = %#x \n", ~i); // negacja
5 // koniunkcja
6 printf("0xff & 0xf = %#x \n", i & 0xf);
7 // alternatywa
8 printf("0xff | 0x100 = %#x \n", i | 0x100); Rezultat wykonania:
9 // różnica symetryczna
10 printf("0xff ^ 0xf = %#x \n", i ^ 0xf);
~0xff = 0xffffff00
11 // przesunięcie bitowe w lewo
0xff & 0xf = 0xf
12 printf("0xff << 4 = %#x \n", i << 4);
13 // przesunięcie bitowe w prawo 0xff | 0x100 = 0x1ff
14 printf("0xff >> 4 = %#x \n", i >> 4);
0xff ^ 0xf = 0xf0
15 return 0;
0xff << 4 = 0xff0
16 }
0xff >> 4 = 0xf
18/1
Programowanie w języku C
Wyrażenia - operacja warunkowa
Ma ona postać:
warunek ? wyr1 : wyr2
gdzie :
warunek jest wyrażeniem warunkowym, domyślnie typu int
wyr1 jest wyrażeniem, które będzie opracowane jeśli warunek ma wartość różną
od zera
wyr2 jest wyrażeniem, które będzie opracowane jeśli warunek ma wartość równą
zeru
wyr2 może być złożone z prostszych; jego składowe są wtedy oddzielone przecinkami.
Wyrażenie warunkowe musi być typu skalarnego, natomiast wyr1 i wyr2 mogą być
typu arytmetycznego, wskaznikowego, strukturowego, unijnego lub void i muszą mieć
typy wzajemnie zgodne.
Sposób wykonywania całości:
Opracowanie wyrażenia warunkowego
Jeśli jego wartość jest różna od zera opracowanie wyrażenia wyr1
W przeciwnym przypadku - opracowanie wyrażenia wyr2
Operacja warunkowa ma wiązanie prawe.
19/1
Programowanie w języku C
Wyrażenia - operacja warunkowa - przykłady
Przykład
Poniższe wyrażenie określa, która zmienna (y czy z) ma większą wartość i podstawia
ją do zmiennej x:
x = (y > z) ? y : z;
co mogłoby być zrealizowane bardziej rozbudowaną instrukcją:
if(y > z) x = y;
else x = z;
Przykład
Poniższa instrukcja wywołuje funkcję printf, której drugi argument jest określony
wyrażeniem warunkowym. Jeśli zmienna c reprezentuje cyfrę, to wartość tej zmiennej
staje się drugim argumentem, w przeciwnym razie jest nim znak x .
printf(" c = %c\n", isdigit(c) ? c : x );
20/1
Programowanie w języku C
Wyrażenia - operacja warunkowa - przykłady
UWAGA: Jeśli ostatnie wyrażenie w operacji warunkowej jest podstawieniem, należy
użyć nawiasów, ponieważ operator = ma niższy priorytet niż operator ? : . Na
przykład:
int i, j, k;
(i == 7) ? j++ : k = j;
Bez nawiasów, kompilator traktuje to wyrażenie tak jak poniżej:
int i, j, k;
((i == 7) ? j++ : k) = j;
To znaczy że zmienna k jest traktowana jako ostatnie wyrażenie, a nie całe wyrażenie
k = j. Aby podstawić wartość zmiennej j do k kiedy warunek i == 7 jest
nieprawdziwy, należy umieścić podstawienie w nawiasach:
int i,j,k;
(i == 7) ? j++ : (k = j);
21/1
Wyszukiwarka
Podobne podstrony:
Wyklad PI 5
Wyklad PI 1 cz 2
Wyklad PI 9
Wyklad PI 3
Wyklad PI 2 cz 2
Wyklad PI 4
Wyklad PI 8
Wyklad PI 2 cz 1
Wyklad PI
Sieci komputerowe wyklady dr Furtak
Wykład 05 Opadanie i fluidyzacja
WYKŁAD 1 Wprowadzenie do biotechnologii farmaceutycznej
mo3 wykladyJJ
więcej podobnych podstron