1 ELEMENTARZ http hermes umcs lublin plczmpf Kompilator
1. ELEMENTARZ http: \hermes. umcs. lublin. pl~czmpf • Kompilator: a) gcc [cc, g++] gcc [-opcje] nazwa_pliku. c -lm [-o nazwa_programu] b) ifc [-opcje] nazwa_pliku. c -lm [-o nazwa_programu] STANDARDOWA NAWZW PROGRAMU: a. out Informacje o opcjach kompilatora: man gcc ifc --help /opt/intel/compilers/docs/ • Głowny blok programu
INSTRUKCJE WYJŚCIA printf(``control’’, agr 1, arg 2, . . . ) Funkcja printf pod nadzorem argumentu tekstowego control przekształca, formatuje i wypisuje argumenty (agr 1, agr 2, . . . ) do standardowego wyjscia (ekran). UWAGA: control w cudzyslowie. Tekst sterujący zawiera obiekty dwojakiego rodzaju: zwykłe znaki (kopiowane do strumienia wyjściowego) specyfikacje przekształceń (podające sposób przekształcanie i wypisywania kolejnego argumentu) Wszystkie specyfikacje rozpoczynają się znakiem % i kończą znakiem przekształcenia. Miedzy % a znakiem przekształcenia mogą się znajdować: • - (znak minus) oznacza żądanie dosunięcia wyprowadzonego argumentu do prawego marginesu pola • ciąg cyfr określający minimalny rozmiar pola. Jeśli wyprowadzany argument jest mniejszy niż rozmiar pola, pozostałe „miejsce” jest uzupełniane znakami odstępu; jeśli argument jest większy - pole zostanie rozszerzone • . (znak kropki) oddziela jedną specyfikacje wielkości pola od drugiej • l (liketa „el”) wskazuje, że odpowiedni argument jest typu „long”
LISTA ZNAKÓW PRZEKSZTAŁCEŃ: d - argument drukowany w postaci dziesiętnej o - argument drukowany w postaci ósemkowej (bez znaku +, -!) x - w postaci szestnastkowej (bez znaku!) u - dziesiętna bez znaku c - argument jako jeden znak („character”) s - argument jest tekstem znakowym, znaki tekstu będą wypisywane do napotkania znaku zerowego e - agrument w postaci wykładniczej x. xxxxx. E xx, liczba znaków po kropce zależna od precyzji f - liczba zmiennoprzecinkowa, ale nie w postaci wykładniczej g - to e albo f, zależnie od wielkości liczby
PRZYKŁADY: : %20 s: jest zajęta : %-20 s: przesunięcie na lewo) : %-20. 3 s: 3 znaki tekstu) : %. 5 s: dopasowywane : ala ma kota: (pole 20 znaków, część : ala ma kota : (minus powoduje : ala : (pole 20, wyprowadzamy : ala m: (pole „nieokreślone”, automatycznie, 5 znaków) : %6 d% : 123456: ; : 3456: , itd. JAK DZIAŁA: printf(“%4 d %6. 1 f”, a, b)? printf(“%. 0 f”, a)? printf jest odpowiednikiem write w PASCALU, odpowiednikiem writeln jest umieszczenie n w argumencie kontrolnym
przykład: printf((“ala ma kota”) ; printf(“i psa”); -> ala ma kota i psa printf((“ala ma kotan”) ; printf(“i psan”); ala ma kota i psa tutaj będzie kursor po wypisaniu Najprostszy program: main() { printf(“ A KUKU/n”); }
INSTRUKCJA WEJŚCIA: Formatowane wejście - funkcja scanf(control, arg 1, arg 2, . . . ) UWAGA 1: wprowadzenie zmiennych liczbowych WYMAGA poprzedzenia argumentu znakiem &. Jak dowiemy się później, znak & oznacza wskazanie. argumenty liczbowe funkcji MUSZĄ BYĆ WSKAŹNIKAMI!! UWAGA 2: w funkcji scanf znak f jest synonimem e ! PRZYKŁADY: 1) scanf(“%d %f %s”, &i, &x, nazwisko) instrukcja ta dla danych wejściowych: 25 54. 32 E-1 Kowalski powoduje przypisanie zmiennej i (stałoprzecinkowa) wartości 25 zmiennej x (zmiennoprzecinkowa) wartości 5. 432 zmiennej nazwisko - wartości Kowalski
2) scanf(“%2 d %f %*d %2 s”, &i, &x, nazwisko) instrukcja ta dla danych wejsciowych 56789 0123 45 a 72 spowoduje przypisanie i wartości 56 (2 d!); zmiennej x - wartości 789. 0 (czyta do znaku zerowego - spacji!), pole *d (co oznacza *? ) spowoduje „przeskoczenie” 0123 (do kolejnego znaku spacji), a zmienna nazwisko będzie miala wartośc 45, ale nie jako liczba, ale jako ciag znaków!
ZMIENNE 1. nazwy zmniennych - podobnie jak w PASCALU. UWAGA: w zależności od kompilatora jedynie kilka pierwszych znaków w nazwie zmiennej jest wazne. W standardzie ANSI jest to 8 znaków. Dlatego w STANDARDZIE nazwy alamakot oraz alamakota nie byłyby rozrózniane. 2. Typy i rozmiary zmiennych Zmienne proste, dalsze typy później char - jeden bajt, jeden znak int - typ calkowity (w PASCALU integer) float - typ rzeczywisty (real) double - rzeczywisty długi (extended) short int - „krótkie” integer long int long float = double unsigned int - bez znaku 3) deklaracja zmiennych int arg 1, arg 2, . . . float arg 11, arg 12, . .
Arytmetyka: operatory +, -, *, / , % (reszta z dzielenia, modulo) operator przypisania = ( w PASCALU : =) Komentarz: /* tutaj wpisujemy komentarz*/ Grupowanie: {. . . } (w pascalu begin. . end) Koniec instrukcji - znak ; PRZEYKŁAD: /*ten program przeliczy temperatury Fahrenheita na Celsjusz*/ main() { int dolna, gorna, krok; float fahr, cels; dolna=0; /*najnizsza temp Fahr. */ gorna=300; /*najwysza temp Fahrr. */ krok=10; /*krok tablicowania */ fahr=dolna; while(fahr <= gorna) { cels=(5. 0/9. 0)*(fahr-32. 0); /*uwaga NIE 5/9 DLACZEGO? */ printf(``%4. 0 f %6. 1 fn”, fahr, cels); fahr=fahr+krok; }
ZADANIE DO WYKONANIA: Zadanie 1. Napisac program, który czyta dwie liczby rzeczywiste i oblicza ich sumę, różnicę oraz iloczyn. Wyniki wypisuje a) w jednej linii; b) każdy wynik w odrębnej linii.
KAŻDY JEST ZOBOWIĄZANY WYKONAĆ ZADANIA. WYKONANE ZADANIA NALEŻY WYSŁAĆ NA ADRES: sokol@hermes. umcs. lublin. pl W nagłówku poczty należy podać: NAZWISKO, IMIE, NUMER ZADANIA termin wykonania - 1 tydzień, przekroczenie terminu jest równoważne niewykonaniu zadania. Brak odpowiedzi na więcej niż połowa zadań oznacza brak zaliczenia wykładu. Odpowiedzi przyjmuję jedynie poprzez e-mail. Za błędy w przesłaniu poczty odpowiedzialność ponosi wysyłający
Pliki z zadaniami mogą być również automatycznie sprawdzane w celu eliminacji przesłania przez dwie lub więcej osób tych samych rozwiązań. Program sprawdzający eliminować będzie wszystkie pliki, w których stwierdzona wzajemna zgodność będzie większa niż 75% (kryteria zgodności to kryteria systemu PLAGIAT, stosowanego w UMCS do sprawdzania prac magisterskich i dyplomowych). Eliminacja - usuwanie zbiorów oznacza, że nie ma możliwości „odwołania się”. Stosować więc należy długie nazwy zmiennych, np. zamiast suma - suma_a_i_b, suma_ab;
w ostatnim programie zamiast nadawania wartości: dolna=0 możemy wartość dolna (podobnie: gorna, krok) zdefiniować jako STAŁE SYMBOLICZNE #define dolna 0 #define gorna 300 #define krok 10 main() {. . } INSTRUKCJE #DEFINE NA POCZĄTKU PROGRAMU! Podobnie jak w PASCALU pewne stałe są PRE-DEFINIOWANE np. EOF - znak końca zbioru
WEJŚCIE I WYJŚCIE ZNAKOWE Funkcje: getchar() i putchar() (funkcja getchar() to analog readkey w PASCALU) INSTRUKCJA „FOR” SKŁADNIA: int i, krok; scanf(“%d”, &krok); for (i=0; i<=100; i=i+krok) { instrukcje wykonywane „wewnatrz” for} OPERATORY RELACJI: < - mniejszy, <= - mniejszy lub równy, >- większy, >= - większy lub równy OPERATORY PRZYRÓWNANIA == - równy, != - różny (! jest zaprzeczeniem), ILOCZYN LOGICZNY („AND”) i SUMA LOGICZNA („OR”) || - lub, && - i UWAGA: OPERATORY LOGICZNE != OPERATORY BITOWE: & - koniunkcja, | -alternatywa, ^ - różnica symetryczna („XOR”)
PRZYKŁADY PROSTYCH PROGRAMÓW: Program 1. Zlicza ilość znaków wejściowych, do momentu pojawienia się znaku końca zbioru (EOF) main() { long liczba_znakow; liczba_znakow=0; while{getchar()!=EOF) /* 1 */ ++liczba_znakow; /*w petli jedna instrukcja, nie trzeba {}, ale mozna 2 */ printf(“%ldn”, liczba_znakow); /* 3 */ } KOMENTARZE: 1. jaki znak jest znakiem końca zbioru w Linuxie (Unixie): stty -a 3. liczba_znakow zadeklarowana jako „long”, stąd formad wydruku %ld; n powoduje przeskok kursora do następnego wiersza po wykonaniu instrukcji. Jeśli znaków jest duzo należy deklarować double! (c. f. PASCAL!). wówczas format wydruku trzeba zmienić (jak? - np. %. 0 f) 2. ++n jest „skrótem” dla n=n+1; podobnie --n to skrót n=n-1 ALE: istnieje też n++ oraz n--. W przypadku ++n wartość LEWEJ STRONY jest wyznaczana PO wykonaniu operacji NA PRAWEJ STRONIE, zaś dla n++ PRZED wykonaniem operacji (podobnie --n oraz n--
UWAGA: najprostsze wprowadzanie danych z pliku (znak EOF jest automatycznie generowany przez edytor: nazwa_programu < nazwa_pliku_danych a. out < nazwa_pliku_danych
Program 2. Zlicznie linii a) Wersja „jak w pascalu” main() { int c, numer_linii; c=getchar(); /* C, ZNAK ALE TYP INTEGER!!*/ while(c!=EPF) { if( c==‘n’) /* n to znak konca linii */ ++ numer_linii; c=getchar(); } printf((“%dn”, numer_linii); } b) wersja „typu c” main() { int c, numer_linii; while((c=getchar())!=EOF) /*PRZYPISANIE I WARUNEK*/ if(c==‘n’) ++numer_linii; printf (“%dn”, numer_linii); }
Program 3. Zliczanie słów, wierszy, znaków (słowo kończy się albo znakiem nowej linii, albo odstępem. Odstęp może być spacją, lub znakiem tabulacji!) #define tak 1 #define nie 0 main() { int c, n_l, n_s, n_z, i_s; /*n_l-linia, n_s-slowo, n_z-znak*/ { i_s=nie; n_l=n_w=n_z=0; /* wielokrotne przypisanie! */ while((c=getchar())!=EOF) { ++n_z; if(c==‘n’) ++n_l; if(c==‘ ‘||c==‘n’||c==‘t’) i_s=nie; /* else if(i_s==nie) { i_s=tak; ++ n_s; }} printf(``%d %d %d/n”, n_l, n_s, n_z); }
TABLICE JEDNOWYMIAROWE int tablica[10]; float tablica[10]; itp. - tablica[0], tablica[1], . . . , tablica[9] w deklaracji 10 elementow, elementy liczymy od 0 ! PRZYKŁAD: program sprawdzający ile jest cyfr poszczególnego rodzaju w wyedytowanym zbiorze.
UWAGA 1: Czytamy stosując funkcje getchar() wprowadzania ZNAKÓW. Nie możemy stosować scanf, bo nie wiemy, czy mamy do czynienia z cyfra, czy tez z innym znakiem (np. . a, n, k, . . ). Ale w C MOŻEMY deklarować czytane znaki jako int; w istocie w komputerze znaki pamiętane są jako kody ASCI Znaki (kody) są uporządkowane w kolejności 0, 1, 2, 3, . . . 9 a więc stosowanie relacji porządku <, >, itd. jest uzasadnione. Podobnie litery są uporządkowane: a, b, c, . . . z. Podobnie pisaliśmy w PASCALU. UWAGA 2: Zadeklarowaliśmy tablice ile[10] o elementach ile[0], ile[1], ile[2], . . . , ile[9]. Element ile[i] (i=0, 1, . . , 9) zawierać będzie ilośc zer, jedynek, . . dziewiątek. c jest „character”, tj. kodem znaku (kodem 0, 1, 2, . . 9). ‘ 0’ jest kodem zera. Ponieważ kody 0, 1, 2, . . 9 są KOLEJNYMI liczbami całkowitymi różnica c-’ 0’ jest liczbą całkowita z przedziału [0, 9], a więc INDEKSEM tablicy.
ZADANIE 2 DO SAMODZIELNEGO ROZWIĄZANIA: napisać analogiczny program wyznaczający liczbę wystąpień kolejnych liter a-z, A-Z ZADANIE 3: Napisać program wyznaczający HISTOGRAM długości słów w dokumencie. Przjąć, że wszystkie słowa o długości > 15 należą do jednej kategorii. Słowa oddziela n, ‘ ‘(spacje) lub ‘t’
FUNKCJE - wstęp napisz funkcję, która oblicza potęgi całkowite liczby całkowitej /* program główny*/ main() { int i; for(i=0; i<=10; ++i) printf(“%d %d %dn”, i, potega(2, i), potega(-2, i)) } /* funkcja */ potega(x, n) int(x, n); /*deklaracja typow argumentow funkcji*/ { int i, p; p=1; for(i=1; i<=n; ++i) p=p*x return(p); /*to jest podstawienie potega=p !! */ }
Wszystkie funkcje maja postać: nazwa(lista argumentów - jeśli występują) deklaracja argumentów { deklaracje instrukcje } Deklaracje argumentów umieszcza się po nazwie funkcji, między nazwą funkcji a otwierającym nawiasem klamrowym. Po nawiasie klamrowym mogą wystąpić nazwy zmiennych używanych w funkcji. Są to nazwy lokalne i niedostępne dla wszystkich innych funkcji. Wartość obliczana zwracana jest to programu głównego (main()) poprzez instrukcję return. Nie wszystkie funkcje muszą zwracać wartość. Instrukcja return bez nawiasu i zmiennej (wyrażenia) oznacza, że od tego momentu następuje powrót do programu głównego.
ZADANIE 4. Funkcja lower(c ) zwraca c, jeśli c nie jest literą, lub wartość małej litery, jeśli c jest dużą literą. Np. dla c=‘A’, lower(c )=a; dla c=‘ 9’ - wartość lower(c )=9. Napisz funkcję lower(c ). Wskazówki: Pamietaj, że znaki ASCI mogą być podstawiane pod zmienne typu int Pamietaj, że w kodzie ASCI litery są uporządkowane. Najpierw wystepują duże litery (alfabetycznie), później małe (alfabetycznie) Jeśli c jest dużą litera, to c>=‘A’ && c<=‘Z’ Pamiętaj, że jeśli c jest dużą literą, to c+’a’-’A’ jest odpowiadającą jej małą literą
Uzupełnienie: kod ASCI. Każdy znak kodowany jest na 2 bajtach (8 bitach): 0 1 2 3 4 5 6 7 kolejne bity, każdy z nich ma wartość 0 lub 1 Bit 7 w standardowym kodzie ASCI nie jest stosowany, stosowany jest w rozszerzeniach (np. polskich). Jeśli znak jest litera, bit 6 ma wartość 1, w przeciwnym wypadku 0. Bit 5 ma wartość 0 - jest to duża litera; wartość 1 - mała litera lub inny znak; bit 4 ma wartość zero - litera od a-o (A-O, zależnie od bitu 5), wartość 1 -> p-z lub nie jest literą. Kod litery p to q Ile wynosi p&q ? p|q ? 01101001 10111010 00101000 ? ? ? ? ?
Zauważ, że reprezentacja binarna liczby 223 to 11011111 =1*2**0+1*2**1+1*2**2+. . 0*2**5+1*2**6+ 1*2**7 co będzie wynikiem działania c&223 ? ? jeśli c jest mała litera? Może duża litera? Reprezentacja binarna liczby 32 to 00100000 = 2**5 co będzie wynikiem c|32, jeśli c jest dużą literą? Może mała litera? Czy potrafisz więc rozwiązać zadanie 4, wykorzystując powyższe informacje?
ARGUMETY FUNKCJI SĄ PRZEKAZYWANIE PRZEZ WARTOŚĆ. Oznacza to, że jeśli w funkcji fun(x), wywoływanej z argumentem x, wartość argumentu będzie zmieniona, to w programie głównym pozostanie ona niezmieniona. Podczas wywołania funkcji tworzona jest „kopia” argumentu i na niej wykonywane są działania. Jeśli potrzeba, to można spowodować, aby funkcja zmieniała wartość argumentu. W tym celu podczas wywołania musimy przekazać adres zmiennej (WSKAŹNIK DO ZMIENNEJ), funkcja wywoływana musi zadeklarować odpowiedni argument jako adres (WSKAŹNIK). Będziemy o tym mówić poźniej
ZASIĘG ZMIENNYCH: Zmienne zadeklarowane wewnątrz funkcji są zmiennymi lokalnymi („prywatnymi” danej funkcji). Każda zmienna lokalna funkcji „zaczyna istnieć” w momencie wywołania funkcji i znika po zakończeniu jej działania. Zmienne lokalne określane są także jako „automatyczne” Przeciwieństwem do zmiennych lokalnych są zmienne zewnętrzne globalne. Są to zmienne dostępne przez nazwę w dowolnej funkcji. Ze względu na to, że zmienne globalne są ogólnie dostepne, mogą być stosowane zamiast list argumentów funkcji. Do definiowania zmiennych globalnych stosuje się definicję extern (deklaracja w sposób jawny), albo deklarację niejawną, poprzez kontekst (por. PASCAL) Stałe definiowane instrukcja #define są globalne Przykład programu: w czytanym zbiorze wierszy znajdujemy wiersz najdłuższy i wypisujemy go
#define maxlinia 1000 char linia[maxline]; char pamieta[maxline]; int max; main() /* glowny */ { int dlugosc; exctern int max; extern char pamieta[]; max=0; while ((dlugosc=getline())>0) if(dlugosc>max) { max=dlugosc; copy(); } if(max>0) printf(``%s”, pamieta); } getline() /* funkcja */ { int c, i; extern char linia[]; for(i=0; i<maxlinia-1 && (c=getchar()) !=EOF &&c!=‘n’; ++i) linia[i]=c; if(c==‘n’) { linia[i]=c; ++i; } linia[i]=‘ ’; return(i); }