Język C, C++.
Transkrypt
Język C, C++.
Język C, C++. Wprowadzenie do programowania w języku C/C++: struktura programu, nazwy i słowa zastrzeżone, podstawowe typy danych, struktura funkcji, stałe, zmienne, deklaracje, wyrażenia, instrukcje we/wy, operatory, instrukcje sterujące, preprocesor, tablice, wskaźniki. Wejście, wyjście w c/C++. Język C został zdefiniowany w 1972 r. przez Dennisa M Ritchie z Bell Laboratories w New Jersey. Język C jest językiem ogólnego zastosowania. Język w miarę prostoty, niezbyt obszerny, szerokiego zastosowania. Charakteryzuje się także nowoczesnymi strukturami danych i bogatym zestawem operatorów. C nie jest językiem "bardzo wysokiego poziomu", nie jest nawet "duży", i nie został opracowany dla jakiejś szczególnej dziedziny zastosowao. Brak ograniczeo oraz ogólnośd powodują, że w wielu przypadkach jest wygodniejszy i bardziej sprawny od innych języków oprogramowania o pozornie większych możliwościach. Można zrobid w nim w miarę wszystko. Ścisły związek z UNIX - ci sami twórcy. Tysiące funkcji bibliotecznych. Język C opracował i zrealizował Dennis Ritchie dla systemu operacyjnego UNIX działającego na minikomputerze DEC PDP-11. S System operacyjny, kompilator C i niemal wszystkie programy usługowe systemu UNIX są napisane w C. Kompilatory języka C tworzy się dla różnych maszyn, łącznie z IMB/370, jednak C nie jest związany z żadnym konkretnym systemem czy sprzętem i łatwo w nim pisad programy, które można uruchamiad bez zmian na dowolnej maszynie, na której język C jest zrealizowany. Język C funkcjonuje do dziś jako ANSI C. W latach 80 rozszerzenie - C++ (struktury obiektowe, sprawdzanie wszystkiego). Można w nim tworzyd małe programy jak i stosowad do komercyjnych zastosowao. Najbardziej popularny język na świecie (łącznie z C++). Cechuje go elastycznośd, nie jest rygorystyczny pod względem sprawdzania - można popełnid wiele nadużyd, wskazana ostrożnośd (programy ciężko się uruchamia gdy duża elastycznośd). Pascal jako język dydaktyczny jest bardzo hermetyczny i sztywny. Z punktu widzenia programisty: języki niskiego poziomu języki wyższego poziomu W językach wyższego poziomu abstrahujemy od rozkazów wewnętrznych i komórek pamięci Języki wewnętrzne, maszynowe, algorytmiczne (Pascal, częściowo C), języki czwartej generacji (w tym niektóre języki do tworzenia aplikacji na bazie danych np. SQL) Więcej operacji elementarnych za pomocą jednej konstrukcji języka wyższej generacji. W SQL przełożenie o wysokim współczynniku np. 1:10 Program w języku źródłowym (Pascal, C, 4GL Informix...) Translator program w innym języku wynikowym (niższego poziomu, np. w języku wewnętrznym) Strategie tłumaczenia: 1. Program źródłowy -> Kompilator -> Program wynikowy -> SO (system operacyjny) -> PaO (pamięć) i wykonanie 2. Program źródłowy <--> Interpretator -> Jakieś operacje Cechy języków programowania: Języki niskiego bądź wysokiego poziomu (jak złożone operacje można zakodować za pomocą pojedynczych. instrukcji) Języki dedykowane dla określonych zastosowań: obliczenia inżynierskie (np. Fortrran), symulacja (np. Smaltalk), przetwarzanie danych (bazy danych), zagadnienia sztucznej inteligencji (program może się sam zmieniać w trakcie wykonywania) np. LISP, PROLOG, sterowanie Ułatwienia dla tworzenia programów - programy małe lub duże - jak zapanować nad złożonością, poszczególni ludzie lub firmy tworzą fragmenty programu Modularyzacja, kompilacja oddzielna, scalanie modułów Techniki obiektowe np. C++ Język C Język C pierwotnie miał ułatwiać tworzenie oprogramowania systemowego - UNIX. UNIX z definicji wyposażony w kompilator C. Język C można zakwalifikować jako język wysokiego poziomu (1:10 - źródło wynik). Można również wykonać operacje zastrzeżone dla niskiego poziomu - elementy programowania niskiego poziomu. Możliwość operowania adresami - operacje na adresach (np. wsk, *wsk, *(wsk+7)). Pozwala to wyeliminować wstawki w języku Asemblera. Wersje języka C: Wersja 1 - zgodna ze standardem pierwotnym K & R Wersja 2 - zgodna z ANSI 1989 Borland C oparty na ANSI C, Microsoft C, Watcom C, Unix C, C++ W języku C podprogramami są funkcje. Zmienne lokalne i globalne. Łączy cechy wysokiego z możliwościami języka niskiego poziomu. Język w wysokim stopniu przenośny. Elastyczność - łagodniej kontroluje zgodność typów - kontrowersyjne, niebezpieczne. Zwięzłość - w Pascalu np. 10 linii, w C - kilka linii. Ze zwięzłością nie należy przesadzać - trudniej wykryć błąd. Ogólna struktura programu w języku C Cechą języka C/C+ jest możliwość budowy programu z wielu modułów. Modułem może być każdy zbiór zawierający poprawny kod źródłowy. W pełni poprawny moduł, którego kompilacja zakończy się sukcesem: int n; Program w C zbudowany jest z funkcji. Każda z nich może posiadać parametry oraz określony typ wartości. Aby można było wygenerować kod wynikowy programu (w DOS, Windows plik .EXE), w jednym i tylko w jednym z modułów musi się znaleźć funkcja main, od której rozpocznie się wykonywanie programu. Moduł zawierający funkcję main nazywa się modułem głównym. Najprostszy wykonywalny program C: int main(void) { return 0; } Po uruchomieniu TC.EXE Program ten składa się tylko z bezparametrowej funkcji main, której wartość jest typu całkowitego (int). Ciało funkcji zbudowane jest z instrukcji, które powinny znaleźć się w bloku wyznaczonym nawiasami kwadratowymi. Funkcja ta zwraca za pomocą instrukcji return wartość zero. Program TC.EXE – Turbo C Katalogi Turbo C Katalog: c:\Tc 2011-10-15 15:22 <DIR> BGI 2011-11-12 15:03 <DIR> BIN – tu są program, m.in. TC.EXE – środowisko programistyczne, , TCC.EXE – kompilator 2011-10-15 15:22 <DIR> CLASSLIB 2011-10-15 15:22 <DIR> DOC 2011-10-15 15:22 <DIR> EXAMPLES 2011-10-15 15:22 <DIR> INCLUDE 2011-10-15 15:22 <DIR> LIB - biblioteki 2011-11-08 10:43 <DIR> Programy Menu programu TC.EXE MenuFile – Plik: opcje: New – Nowy, Open – Otwórz, Save – Zapisz, Save as – Zapisz jako, Save All – zapisz wszystko, Change dir – zmień katalog, DOS Shell – okno DOS (exit – wyjście), Quit – wyjście Menu Edit Search – szukaj Run - Uruchom Compile – Kompiluj Compile Alt F9 – kompiluj, Make – utwórz, Link – linkuj, Build All – zbuduj wszystko, Information – informacja, Remove messages – usuń komunikaty (wiadomości) Debug - debugowanie Project – Projekt Options – Opcje Window – Okno Help Ustawienia programu - przykładowe: Options, Directories Kompilacja programu: Po kompilacji programu: Alt C, Compile lub Alt F9 lub F9 utworzy się plik wynikowy P1.EXE w katalogu Output Directory Uruchomienie programu: Alt R lub Ctrl F9 Skompiluje się również program w postaci: main() { }, ewentualnie w postaci void main() { } lub void main(void) { } Przykład z Turbo C // Borland C++ - (C) Copyright 1991 by Borland International /* HELLO.C -- Hello, world */ #include <stdio.h> int main() { printf("Hello, world\n"); return 0; } Po uruchomieniu i naciśnięciu Alt F5 – wynik Pomoc w programie: Help, Index, wpisujemy szukane słowo, np. void i naciskamy Enter Ogólna struktura programu w C/C++ Nagłówek programu #include (włączenia tekstowe) #define stałe makroinstrukcje Zmienne globalne Prototypy funkcji Funkcja main() Funkcje pozostałe W profesjonalnych programach w nagłówku powinna być podana nazwa programu, dane o autorze, prawa autorskie, przeznaczenie programu, data ostatniej aktualizacji programu, nazwa kompilatora, uwagi odnośnie kompilowania, linkowania, wykonania. Sekcja #include zawiera specyfikację włączanych plików bibliotecznych oraz własnych Sekcja #define zawiera definicje stałych i makroinstrukcji Następne sekcje to zmienne globalne oraz prototypy funkcji. Muszą wystąpić przed ciałami funkcji, aby w dalszej części programu nie było odwołań do obiektów nieznanych kompilatorowi. Jeżeli funkcje pozostałe umieszczone byłyby przed funkcją main to specyfikowanie prototypów byłoby zbyteczne. Włączenia tekstowe #include mogą w zasadzie wystąpić w dowolnym miejscu programu. Zaleca się aby dłuższe funkcje lub grupy funkcji były umieszczane w osobnych plikach. Podstawowy fragment (element) programu w języku C main() begin w Pascalu)*/ { /* treść */ } /* klamra otwierająca - początek funkcji głównej (jak /* tu zaczyna się treść programu - w funkcji main() /* klamra zamykająca - jak end w Pascalu*/ /* - rozpoczęcie komentarza, */ - koniec komentarza W pisaniu programów rozróżniane są duże i małe litery - np. w main() Język C/C++ nie ma instrukcji realizujących operacje we/wy. Do tego celu służą funkcje bibliotek standardowych. Użycie ich jest niezbędne, gdy trzeba pobrać dane od użytkownika i wysłać je na ekran. #include <stdio.h> int main(void) // funkcja glowna, brak argumentow, zwraca typ calkowity int { char imie[20]; // deklaracja tablicy znakow int i; // deklaracja zmiennej calkowitej printf("\nPodaj swoje imie "); // wydruk na ekran,\n – nowa linia gets(imie); // pobranie zmiennej imie puts("Ile masz lat? "); // wydruk scanf("%d",&i); // pobranie zmiennej typu calkowitego printf("\n%s ma %d lat.",imie, i); //wydruk napisu i liczby calkow. return 0; // funkcja glowna zwraca 0 – pomyślny koniec } Przykłady prostych programów Przykład prostego programu: prog1.c Wydruk na ekranie napisu: Dzień dobry (z przejściem kursora do nowej linii) /* Prog1.c - Program napisany #include <stdio.h> /* preprocesor - załącz pliku main() { printf("Dzień dobry\n"); /* /* } w pliku żródłowym Prog1.c */ bibliot. standard. stdio.h */ printf - drukuj-fragment bibliot. standard */ \n - znak nowego wiersza */ Komentarz w języku C stanowi tekst ograniczony znakami /* i */ Inne wersje tego programu: #include <stdio.h> void main() { printf("Dzień dobry\n"); } #include <stdio.h> int main() { printf("Dzień dobry\n"); return 0; } # - preprocesor - wstępny przetwarzacz - uwzględnia dodatkowe rzeczy #include <stdio.h> - dołączenie nagłówków z biblioteki standardowej (ścieżka domyślnych przeszukowań) #include "program.h" - dołączenie programu z katalogu aktualnego - podwójne cudzysłowy Język C/C++ wymaga kompilacji, w wyniku czego tworzy sie plik wykonywalny, binarny, z rozszerzeniem EXE. Nie ma interpreterów do języka C. Skompilować wystarczy raz. Nie są ważne odstępy w programie. Muszą być całe słowa. Mogą być znaki spacji, nowego wiersza, tabulacji - nieważne ile. #inlcude musi być w jednej linii. Ważne jest projektowanie. Jedna godzina poświęcona na projektowanie pozwala zaoszczędzić kilka godzin programowania. Prosty przykład obliczeniowy - obliczenie objętości walca /********************************************************/ /* Program p1a.c */ /* Obliczanie objetosci walca (wariant startowy) */ /*------------------------------------------------------*/ #include <stdio.h> void main() { float promien, wysokosc, objetosc; promien = 3.3; wysokosc = 44.4; objetosc = 3.1415926 * promien * promien * wysokosc; printf("Objetosc walca = %f", objetosc); } /********************************************************/ Efektem wykonania będzie wydruk na ekranie: Objętość walca=1519.010254 Następny program zawiera za dużo komentarzy /* poczatek tekstu programu */ /********************************************************/ /* Program p1b.c */ /* Obliczanie objetosci walca (nadmiar komentarzy) */ /*------------------------------------------------------*/ #include <stdio.h> main() { /* wlaczenie biblioteki */ /* poczatek modulu glownego */ /* poczatek bloku */ /* deklaracje zmiennych */ float promien, wysokosc, objetosc; /* nadanie wartosci poczatkowych zmiennym */ promien = 3.3; wysokosc = 44.4; /* obliczenie podstawowe */ objetosc = 3.1415926 * promien * promien * wysokosc; /* wyprowadzenie wyniku */ printf("Objetosc walca = %f", objetosc); } /* koniec bloku */ /********************************************************/ /* koniec tekstu programu */ Następny przykład pozbawiony komentarzy ale czytelny: /* p1c.c */ #include <stdio.h> main() { float promien, wysokosc, objetosc; promien = 3.3; wysokosc = 44.4; objetosc = 3.1415926 * promien * promien * wysokosc; printf("Objetosc walca = %f", objetosc); Następny przykład jest bardzo zwięzły w zapisie ale mało czytelny: /*p1d.c*/#include<stdio.h> main(){float r,h,v;r=3.3;h=44.4;v=3.1415926*r*r*h;printf("V=%f",v);} Wniosek - brak jak i nadmiar komentarzy nie słuzy czytelnosci programu. W praktyce stosowane są 2 sposoby umiejscowiana klamer { }, ograniczających sekwencje instrukcji. 1) main() { /* sekwencja instrukcji */ } 2) main() { /* sekwencja instrukcji */ } Na czytelność programu wpływa stosowanie wcięć. Przykłady. Przeliczenie stopni Fahrenheita na Celsjusza Wersja 1 /* Program sz2.cpp - komentarz Przelicza stopnie Fahrenheita na Celsjusza */ #include <stdio.h> void main() /* Poczatek funkcji glownej main - nic nie zwraca*/ { /* Definicje zmiennych */ int tf=0; /* typ integer - temp. Fahrenheita*/ float tc; /* typ float - temp Celsjusza */ while (tf <=100) /* petla - iteracja przebiegiem petli */ { tc=(5*(tf-32))/9.0; printf("%4d %6.1f \n",tf,tc); tf=tf+10; }; /* while */ } /* main */ tf używana też do sterowania Wersja 2 /* Program sz2a.cpp - bez zmiennej tc Przelicza stopnie Fahrenheita na Celsjusza */ #include <stdio.h> void main() /* Poczatek funkcji glownej main - nic nie zwraca*/ { /* Definicje zmiennych */ int tf=0; /* typ integer - temp. Fahrenheita*/ while (tf <=100) /* petla - iteracja */ { printf("%4d %6.1f \n",tf, 5*(tf-32)/9.0); tf=tf+10; }; /* while */ } /* main */ Uwaga! We wzorze (tf-32)*(5/9) - zaokrąglenie 5/9 do liczb całkowitych!. Bezpieczne mnożenie, niebezpieczne dzielenie. Wersja 3 /* sz2b.c */ #include <stdio.h> #include <conio.h> main() { float fahr, celsius; int lower, upper, step; lower =0; /*dolna granica temp*/ upper=300; step=20; celsius=lower; clrscr(); printf("Zamiana stopni Celsiusza na Fahrenheita\n"); printf(" Celsjusz Fahr\n"); while (celsius<=upper) { fahr=(9.0/5.0*celsius+32.0); printf("%3.0f %20.1f\n",celsius,fahr); celsius=celsius+step; } getch(); return 0; } Formaty wydruku: %d, %i liczba całkowita %x w formacie 16 bez znaku %f, %e, %g zmiennopozycyjny %s string (łańcuch znaków) %c znak %o ósemkowo Deklaracja a definicja Deklaracja - informuje kompilator, że dana nazwa reprezentuje obiekt jakiegoś typu ale nie rezerwuje dla niej miejsca w pamięci. Mówi, że zmienna jest ale nie powołuje jej do życia. Definicja - wprowadza do programu zmienną i przydziela jej pamięć, powołuje obiekt do życia. Przykłady deklaracji, które nie są definicjami: extern int a; int f(int); struct s; typedef int Int; Zmienna - komórka lub grupa komórek Podstawowe elementy języka C (każdego praktycznie języka programowania) zestaw znaków nazwy i słowa zastrzeżone typy danych stałe zmienne i tablice deklaracje wyrażenia instrukcje Zestaw znaków C: litery małe i duże języka łacińskiego (angielskiego) cyfry 0..9 znaki specjalne: ! * + \ " < # ( = | { > % ) ~ ; } / ^ - [ : , ? & _ ] ' . oraz znak odstępu (spacja) Nazwy i słowa zastrzeżone (kluczowe, zarezerwowane) Nazwy służą do identyfikowania elementów programu (stałych, zmiennych, funkcji, typów danych, itd.). Nazwa składa się z ciągu liter i cyfr, z tym, że pierwszym znakiem musi być litera. Znak podkreślenia traktowany jest jako litera. W języku C rozróżniane są duże i małe litery w identyfikatorach. Przykład użycia różnych nazw: /********************************************************/ /* Program p6.c */ /* Obliczanie objetosci walca (rozroznianie nazwy /1) /*------------------------------------------------------*/ */ #include <stdio.h> main() { float promien, wysokosc, objetosc; float PROMIEN, WYSOKOSC, OBJETOSC; promien = 3.3; wysokosc = 44.4; PROMIEN = 10.; WYSOKOSC = 20.; objetosc = 3.1415926 * promien * promien * wysokosc; printf("\nObjetosc walca = %f", objetosc); OBJETOSC = 3.1415926 * PROMIEN * PROMIEN * WYSOKOSC; printf("\nOBJETOSC WALCA = %f", OBJETOSC); } /********************************************************/ Efektem wykonania programu są 2 wydruki: Objetosc walca = 1519.010254 OBJETOSC WALCA = 6283.185059 Użycie odstępu w nazwie jest niedozwolone. Niektóre implementacje rozpoznają w nazwie do 8 znaków, inne więcej (do 32). Słowa zastrzeżone Są to słowa o szczególnym znaczeniu dla języka, których nie wolno używać programiście np. jako nazw zmiennych. Standardowy zestaw znaków zastrzeżonych języka C: auto break case char const goto if long register return unsigned void int continue default do short double else signed sizeof enum extern float static struct switch typedef union volatile while Niektóre kompilatory mają niektóre lub cześć z następujących słów kluczowych ada asm entry far fortran huge near pascal for Podstawowe typy danych i rozmiary danych W języku C występuje tylko kilka podstawowych typów danych: char - jeden bajt, zdolny pomieścić 1 znak int - typ całkowity float - typ zmiennopozycyjne pojedynczej precyzji double - typ zmiennopozycyjny podwójnej precyzji Dodatkowo występuje kilka kwalifikatorów stosowanych z tymi podstawowymi typami. Kwalifikatory short i long odnoszą się do obiektów całkowitych Typ Opis Zakres wartości Reprezentacja char (signed char) pojedynczy znak (np. litera) -128...127 1 bajt unsigned char znak (bez znaku dodatni) 0...255 1 bajt short liczba całkowita krótka -32768...32767 2 bajty unsigned short liczba krótka bez znaku 0...65535 2 bajty int (signed int) liczba całkowita -32768...32767 2 bajty unsigned int całkowita bez znaku 0...65535 2 bajty long (long signed int) liczba całkowita długa -2147483648...2147483647 4 bajty 0...4294967295 4 bajty unsigned long (long j.w. bez znaku unsigned int) float l. rzeczywista -3.4E-38..-3.4E-38,0,3.4E38..3..3.4E38 4 bajty double l. rzeczywista podwójna -1.7E308..-1.7E-308,0,1.7E308..1.7E308 8 bajtów long double l. rzecz. długa podwójna -1E4932..-3.4E-4932,0,3.4E4932..1.1E4932 10 bajtów Szczegóły zależne są od konkretnej implementacji kompilatora języka C. Są jeszcze inne typy danych jak: void (typ funkcji nie zwracającej wartości), enum (typ wyliczeniowy) oraz typ wskaźnikowy. Typ wyliczeniowy (enum) reprezentowany jest na 2 bajtach, wskaźnikowy na 2 lub 4 (w zależności od modelu pamięci), void nie jest reprezentowany. Typy, operatory, wyrażenia Zmienne i stałe są podstawowymi obiektami danych, jakimi posługuje się program. Deklaracje wprowadzają potrzebne zmienne oraz ustalają ich typy i ewentualnie wartości początkowe. Operatory określają co należy z nimi zrobić. Wyrażenia wiążą zmienne i stałe, tworząc nowe wartości. Stałe W C występują 4 rodzaje stałych: stałe całkowitoliczbowe, stałe rzeczywiste, stałe znakowe oraz łańcuchy znaków. Wartość stałej numerycznej nie może wykraczać poza dopuszczalne granice. Stałe całkowitoliczbowe Nazwa Dozwolony zestaw Uwagi znaków Przykłady Stałe dziesiętne 0..9 + - Jeśli więcej niż 1 znak, pierwszym nie może być 0 0 1 876 -122 +909 Stałe ósemkowe 0..7 + - Pierwszą cyfrą musi być 0 0 0111 0777 -0777 +0222 Stałe szesnastkowe Pierwszymi znakami muszą być 0x 0X1234 0x lub 0X 0XAFDEC 0xffff 0..9 a..f A..F + - W celu zainicjowania zmiennych typów int i long po znaku równości podajemy całkowitą stałą liczbową. Przykłady: int l=100; unsigned k=121; int la = 0x2ffa; long i = 25L; /* long */ long unsigned z = 1000lu; /* lub 1000UL */ Stała całkowita, jak np. 1234 jest obiektem typu int. W stałej typu long na końcu występuje litera l lub L, jak 123456789L. Stała całkowita nie mieszcząca się w zakresie int jest traktowana jako stała typu long. W stałych typu unsigned na końcu występuje u lub U, a końcówka ul lub UL oznacza stałą typu unsigned long. Stałe rzeczywiste, zwane zmiennoprzecinkowymi reprezentują liczby dziesiętne. Dozwolony zestaw znaków: 0..9 . + - E e (E lub e reprezentuje podstawę systemu tj. 10) Uwagi: 1.2*10^-3 można zapisać 1.2E-3 lub 1.2e-3. Stałe zmiennopozycyjne zawierają albo kropkę dziesiętną (np. 123.4), albo wykładnik e (np. 1e-2) albo jedno i drugie. Typem stałej zmiennopozycyjnej jest double, chyba, że końcówka stanowi inaczej. Występująca na końcu litera f lub F oznacza obiekt typu float, a litera l lu L - typu long double. Przykłady: 0. 2. 0.2 876.543 13.13E13 2.4e-5 2e8 Deklaracja i inicjalizacja zmiennych rzeczywistych - przykłady:: float s=123.16e10; /* 123.16*10^16 */ double x=10.; long double x=.12398; double xy=-123.45 Stałe znakowe Stała znakowa jest liczbą całkowitą; taką stałą tworzy jeden znak ujęty w apostrofy, np. 'x'. Są to więc pojedyncze znaki zamknięte dwoma apostrofami. Zestaw dowolnych widocznych znaków ASCII. Wartością jest wartość kodu znaku w maszynowym zbiorze znaków. Np. wartością stałej '0' jest liczba 48 - liczba nie mająca nic wspólnego z numeryczną wartością 0. Pewne znaki niegraficzne mogą być reprezentowane w stałych znakowych i napisowych przez sekwencje specjalne, takie jak \n (znak nowego wiersza). Przykłady: 'A' '#' ' ' char a='a'; Znaki z zestawu ASCII o kodach 0 do 31 są znakami sterującymi, niewidocznymi na wydrukach. Znaki o kodach 0...127 są jednakowe dla wszystkich komputerów bazujących na kodzie ASCII. Znaki o kodach 128...255 (kod rozszerzony ASCII) mogą się różnić na różnych komputerach. Escape-sekwencje - sekwencje specjalne Niektóre znaki "niedrukowalne" mogą być przedstawione w postaci tzw. escape-sekwencji, np. znak nowej linii jako sekwencja \n. Pierwszym znakiem tej sekwencji jest backslash (\). Sekwencja specjalna wygląda jak 2 znaki, ale reprezentuje tylko jeden znak Sekwencja znaków Wartość ASCII Znaczenie \a 7 Sygnał dźwiękowy (BEL) \b 8 Cofniecie o 1 znak (BS) \t 9 Tabulacja pozioma (HT) \v 11 Tabulacja pionowa (VT) \n 10 Nowa lina (LF) \f 12 Nowa strona (FF) \r 13 Powrót karetki (CR) \" 34 Cudzysłów \' 39 Apostrof \? 63 Znak zapytania \\ 92 Backslash \0 0 Znak pusty (null) - nie jest równoważne stałej znakowej '0' Stałe napisowe - napisy, łaocuchy znaków (stałe łaocuchowe) Stała napisowa lub napis jest ciągiem złożonym z zera lub wiecej znaków, zawartym między znakami cudzysłowu, np. "Jestem napisem". Stała łańcuchowa składa się z ciągu o dowolnej liczbie znaków. Ciąg ten musi być ograniczony znakami cudzysłowu. Przykłady: "Wynik = " " + 2 mln $" "Linia nr 1\nLinia nr2" "" Łańcuchy mogą zawierać escape-sekwencje. Łańcuchem pustym są same cudzysłowy. Łańcuch w sposób niejawny jest zakończony znakiem null czyli \0. Dlatego np. stała znakowa 'K' nie jest równoważna łańcuchowi "K". Łańcuch znaków (napis) można traktować jako tablicę złożoną ze znaków, uzupełnioną na końcu znakiem '\0' Taka reprezentacja oznacza, że praktycznie nie ma ograniczenia dotyczącego długości tekstów. Programy muszą jednak badać cały tekst, by określić jego długość, np. strlen(s) ze standardowej biblioteki. Przykład: Napis "Katowice" , który może być zadeklarowany jako tablica jednowymiarowa, której elementami są znaki, np. char napis[] = "Katowice" Nr elementu 1 2345 6789 Napis K a t o w i c e \0 Wartość indeksu 0 1 2 3 4 5 6 7 8 Deklaracja i inicjalizacja łańcuchów - przykłady: char s[10]="\n\fAndrzeh\x60"; char str[20]={'\n','\f', 'A', 'n', 'd', 'r', 'z', 'e', 'j', '\x60', '\0'}; "A + B = " Stałe wyliczeniowe (enumeration constant) Stałe wyliczeniowe tworzą zbiór stałych o określonym zakresie wartości. Wyliczenie jest listą wartosci całkowitych, np. enum boolean {NO, YES}; Pierwsza nazwa na liście wyliczenia ma wartość 0, następna 1 itd., chyba że nastąpi jawnie podana wartość. Przykłady: enum KOLOR {CZERWONY, NIEBIESKI, ZIELONY, BIAŁY, CZARNY} KOLOR staje się nazwą wyliczenia, powstaje nowy typ. Do CZERWONY zostaje przypisana wartośc 0, do niebieski 1, zielony 2 itd. Każda stała wyliczeniowa ma wartość całkowitą. Jeśli specjalnie się nie określi, to pierwsza stała przyjmie wartość 0, druga 1 itd. enum KOLOR {red=100, blue, green=500, white, black=700}; red przyjmie wartość 100, blue 101, green 500, white 501, black 700 enum escapes{BELL='\a', BACKSPACE='\b', TAB='\t', NEWLINE='\n', VTAB='\v', RETURN='\r'}; enum months {JAN=1, FEB, MAR, APR , MAY, JUL, AUG, SEP, OCT, NOV, DEC}; (luty jest 2-gi itd.) Stałe symboliczne - makrodefinicje Stała symboliczna jest nazwą przedstawiającą inną stałą - numeryczną, znakową lub tekstową. Definicję stałej symbolicznej umożliwia instrukcja #define: #define NAZWA tekst gdzie NAZWA jest nazwą stałej symbolicznej, a tekst jest związanym z tą nazwą łańcuchem znaków Przykłady: Makrodefinicje proste: #define identyfikator <ciąg-jednostek-leksykalnych> #define PI 3.14159 #define TRUE 1 #define FALSE 0 #define NAPIS1 Siemianowice #define IMIE "Andrzej" (puts(IMIE) rozwija w tekst puts("Andrzej") #define IMIE_I_NAZWISKO IMIE+"Zalewski" rozwinięcie daje tekst "Andrzej + Zaleski" #define WCZYTAJ_IOSTREAM_H #include <iostream.h> Makrodefinicje parametryczne #define identyfikator(idPar1, idPar2,...) ciąg_jedn_leksykalnych #define ILORAZ(a,b) ((a)/(b)) - makrodefinicja ILORAZ - parametry w nawiasach! #define SUMA(a,b) ((a)+(b)) W trakcie kompilacji nazwy stałych symbolicznych są zastąpione przez odpowiadające im łańcuchy znaków. Ułatwia to parametryzację programu, a także umożliwia zastępowanie często niewygodnych w pisaniu sekwencji programu, tworzenie makrodefinicji, tworzenie własnych dialektów języka, czy nawet języków bezkompilatorowych (na bazie kompilatora C). Przykład z walcem, z zastosowaniem pseudoinstrukcji #define /********************************************************/ /* Program p8.c */ /* Obliczanie objetosci walca ( #define ) */ /*------------------------------------------------------*/ #include <stdio.h> #define #define #define #define PI 3.1415926 PROMIEN 3.3 WYSOKOSC 44.4 WYNIK printf("Objetosc walca = %f", objetosc) main() { float promien, wysokosc, objetosc; promien = PROMIEN; wysokosc = WYSOKOSC; objetosc = PI * promien * promien * wysokosc; WYNIK; } /********************************************************/ Wynik programu: Objętość walca = 1519.010254 Dzięki #define program jest bardziej czytelny. Stała PI może być użyta wielokrotnie, wartości danych są widoczne na początku. Użycie dużych liter jako nazwy stałej symbolicznej nie jest obowiązkowe ale zalecane. Zmienne Zmienną nazywamy nazwę (identyfikator) reprezentującą określony typ danych. W chwili rozpoczęcia pracy programu zmienna powinna posiadać nadaną wartość początkową (nie powinna być przypadkowa). W trakcie pracy programu wartości zmiennych ulegają zwykle zmianom. Należy przewidzieć zakres zmienności tych zmiennych. W języku C wszystkie zmienne muszą być zadeklarowane przed ich użyciem, zwykle na początku funkcji przed pierwszą wykonywaną instrukcją. Deklaracja zapowiada właściwości zmiennych. Składa się ona z nazwy typu i listy zmiennych, jak np. int fahr, celsius; W języku C oprócz podstawowych typów: char, short, int, long, float, double występują także tablice, struktury, unie, wskaźniki do tych obiektów oraz funkcje zwracające ich wartości. W przypadku zmiennych nalezy zwrócić uwagę na 2 zasadnicze rzeczy: nadanie wartości początkowej oszacowanie zakresu zmienności Przykład ilustrujacy ten problem /********************************************************/ /* Program p9.c */ /* Obliczanie objetosci walca ( zmienne ) */ /*------------------------------------------------------*/ #include <stdio.h> #define PI #define PROMIEN #define WYNIK 3.1415926 3.3 printf("Objetosc walca = %f", objetosc) main() { float promien, wysokosc, objetosc; int i; promien = PROMIEN; objetosc = PI * promien * promien * wysokosc; /* uwaga */ WYNIK; i=40000; /* uwaga */ printf("\ni = %i ", i); } /********************************************************/ Efekt wykonania: Objetosc walca = 0.000000 i = -25536 Objętość walca jest równa 0, bo nie została zainicjalizowana zmienna 'wysokosc' - przez domniemanie kompilator przyjął 0. Na wydruku i widać, że nastąpiło przekroczenie dopuszczalnego zakresu zmiennej 'i' typu int. Zmienne mogą być automatyczne oraz zmienne zewnętrzne. Zmienne automatyczne pojawiają się i znikają razem z wywołaniem funkcji. Zmienne zewnętrzne to zmienne globalne, dostępne przez nazwę w dowolnej funkcji programu. Zmienna zewnętrzna musi być zdefiniowana dokładnie jeden raz na zewnątrz wszystkich funkcji - definicja przydziela jej pamięć. Taka zmienna musi być też zadeklarowana w każdej funkcji, która chce mieć do niej dostęp. Można to zrobić albo przez jawną deklarację extern, albo niejawnie przez kontekst. Jeśli definicja zmiennej zewnętrznej pojawia się w pliku źródłowym przed użyciem zmiennej w konkretnej funkcji, to nie ma potrzeby umieszczania w tej funkcji deklaracji extern. Deklaracje Deklaracje umożliwiają wyspecyfikowanie grup zmiennych określonego typu. Większość kompilatorów dopuszcza nadanie wartości początkowej zmiennej w deklaracji (inicjalizację). Wszystkie zmienne muszą być zadeklarowane przed użyciem. W deklaracji określa się typ, a następnie wymienia jedną lub kilka zmiennych tego typu, np. int lower, upper; char c, line[1000]; W deklaracjach można nadawać zmiennym wartości początkowe, np. char esc='\'; int i=0; float eps=1.0e-5; int limit=MAXLINE+1; Jeśli zmienna nie jest automatyczna, to jej wartość początkową nadaje się tylko raz - jakby przed rozpoczęciem programu; jej inicjatorem musi być wyrażenie stałe. Zmiennym automatycznym jawnie określone wartości początkowe nadaje się za każdym razem przy wywołaniu funkcji lub przy wejściu do zawierającego je bloku. Zmiennym zewnętrznym i statycznym przez domniemanie nadaje się wartość pocz. zero. Zmienne automat. bez jawnie określonej wartości pocz. mają wartości przypadkowe (śmiecie). Kwalifikator const mówi, że wartość zmiennej będzie stała. const double e=2.71828182; const char mas[]="Uwaga:"; Deklarację const można stosować również do tablicowych paramentów funkcji, by wskazać, że funkcja nie może zmieniać tablicy: int strlen(const char[]); Przykład programu z deklaracjami zmiennych. Niektórym nadano wartości początkowe. Przykład programu z deklaracjami zmiennych. Niektórym nadano wartości początkowe. /********************************************************/ /* Fragment p10.c Turbo C 2.0 */ /* (dozwolone deklaracje elementarne) */ /*------------------------------------------------------*/ main() { /* Komentarz (znaczenie slow kluczowych) typy danych: char int float double - znak (bajt), - liczba calkowita, - liczba rzeczywista, - liczba rzeczywista podwojna, modyfikatory: short - krotki, long - dlugi, signed - ze znakiem, unsigned - bez znaku */ /* --- typy znakowe --------------------------------- */ char c1 ='k'; signed char c2 ='\123'; unsigned char c3 ='\xAB'; /* --- tablice znakow ------------------------------- */ char tekst[] = "Katowice"; unsigned char teKst[30] = "Taki sobie teKst to jest!"; /* --- typy liczb calkowitych ----------------------- */ int i1 = 0; signed int i2 =-32767; unsigned int i3; signed i4 = 32767; unsigned i5 = 32767; short i6 = 3; signed short i7 =-3; unsigned short i8 = 44; short int i9 = 22; signed short int i10 =-555; unsigned short int i11 = 1; long i12 = 11111; signed long i13 =-1; unsigned long i14; long int i15 = 22222; signed long int i16; unsigned long int i17; /* --- typy liczb rzeczywistych --------------------- */ float r1 =-3.4E38; signed float r2 = 3.4E38; unsigned float r3 = 5.5E38; long float r4 = 1.7E308; double r5 = 1.7e308; long double r6 = 1.1e4932; float r7 = 1234.56789; /* dalsza ( robocza ) czesc programu ... */ } /********************************************************/ W deklaracji typu text[]="... " kompilator sam sobie dobiera długość pola tablicy, dbając też, by ostatnim znakiem był null (\0). W przypadku deklaracji explicite, np. text[20]="...", gdy łańcuch będzie dłuższy od 20 to nastąpi jego obcięcie, a gdy będzie krótszy, to niewykorzystane miejsca zostaną wypełnione albo znakami pustymi albo po znaku \0 będą wartości przypadkowe (nieistotne). Operatory arytmetyczne Wyrażenia 2-argumentowe: +, -, *, / oraz operator dzielenia modulo % Dzielenie całkowite obcina cześć ułamkową wyniku. Przykład: int x,y, a=5, b=2; x=a/b; /* w wyniku x otrzyma wartość 2 */ y=a%b; /* y => 1 - reszta z dzielenia */ x % y daje w wyniku resztę dzielenia x przez y. Operatora % nie można stosować do danych typu float i double. Operatory jednoargumentowe: +, -. Dwuargumentowe operatory + i - mają ten sam priorytet, niższy od *, /, %, który z kolei jest niższy od priorytetu jednoargumentowych. operatorów + i -. Operatory arytmetyczne są lewostronnie łączne. Relacje i operatory logiczne Operatory relacji: > >= < <= (mają ten sam priorytet) Operatory przyrównania: == (równe) != (różne) (priorytet niższy) Operatory logiczne: && (and) i || (or) Wyrażenia Wszystko co zwraca wartość jest wyrażeniem. Wyrażeniem może być samodzielny element, np. liczba, stała, zmienna. Może to być też kombinacja w/w elementów połączonych znakami operatorów, np. arytmetycznych lub logicznych. Przykłady: 3.2 PI a=a+b; x=y; x<LAFA; k == m; y = x = a+b; x != y b[i-2] = a[j+1]; Instrukcje Instrukcje są to fragmenty tekstu programu (zwykle linie), które powodują jakąś czynność komputera w trakcie wykonywania programu. Instrukcje można podzielić na grupy: Instrukcje obliczające wartości wyrażeń, np. a=b+c; Każda taka instrukcja musi być zakończona średnikiem; Instrukcje grupujące (złożone) - ograniczone klamrami { }, np. { a=3; b=2.2; p=a*b; printf("Pole=%f",p); } Instrukcje sterujące, np. while, if... Instrukcje wywołania funkcji Przykład instrukcji złożonej (grupującej) /********************************************************/ /* Program p11.c */ /* Obliczanie objetosci walca ( instrukcja bloku ) */ /*------------------------------------------------------*/ #include <stdio.h> #define #define #define #define #define #define PI 3.1415926 PROMIEN 3.3 WYSOKOSC 44.4 KRYTERIUM 1500.0 WSP 2.2 WZOR_OBJETOSC PI * promien * promien * wysokosc main() { float promien, wysokosc, objetosc; promien = PROMIEN; wysokosc = WYSOKOSC; objetosc = WZOR_OBJETOSC; printf("Objetosc walca = %f", objetosc); if (objetosc > KRYTERIUM) { float objetosc, promien = PROMIEN * WSP; objetosc = WZOR_OBJETOSC; printf("\nObjetosc walca = %f (lokalna)", objetosc); } printf("\nObjetosc walca = %f", objetosc); } /********************************************************/ Efekt wykonania programu: Objetosc walca = 1519.010254 Objetosc walca = 7352.010742 Objetosc walca = 1519.010254 (lokalna) Wejście i wyjście programu Do podstawowych funkcji języka C, umożliwiających komunikację z otoczeniem należą: dla operacji wejścia: getchar, gets, scanf; dla operacji wyjścia: putchar, puts, printf; W DOS, wyniki wysyłane na ekran mogą być przy pomocy znaku potoku wysłane do pliku lub na drukarkę. Np. p11 > Wynik.txt (do pliku) p11 > PRN (na drukarkę) Funkcja putchar: int putchar(int) Funkcja wysyła na zewnątrz (do standardowego strumienia wyjściowego stdout, standardowo na ekran0 pojedynczy znak Funkcja (makro) zwraca wartość wypisanego znaku lub EOF (jako sygnał błędu). Przykład: /********************************************************/ /* Program p12.c */ /* ( putchar ) */ /*------------------------------------------------------*/ #include <stdio.h> #define SPACJA 32 main() { char napis[] = "ABCDEFGHIJKLMNOPQRS..."; int znak = 73; /* wyprowadzanie pojedynczych znakow przy pomocy funkcji putchar */ putchar('\n'); putchar(znak); putchar(55); putchar(SPACJA); putchar(SPACJA); putchar('\066'); putchar('\x3A'); putchar('\n'); putchar(SPACJA); putchar(napis[4]); putchar(znak+'\066'-52); putchar(SPACJA); putchar('Z'); putchar(SPACJA); putchar(napis[0]); putchar(SPACJA); putchar('\n'); } /********************************************************/ Wynik: I 7 Z 6 : A E K Funkcja puts: int puts(const char *s); Wysyła łańcuch s do standardowego strumienia wyjściowego (stdout) i dołącza znak końca wiersza. W przypadku powodzenia operacji wartość jest nieujemna, w przeciwnym wypadku EOF. /********************************************************/ /* Program p13.c */ /* ( puts ) */ /*------------------------------------------------------*/ #include <stdio.h> #define NOWA_LINIA putchar('\n') main() { char napis[] = "ABCDEFGHIJKLMNOPQRS..."; /* wyprowadzanie pojedynczych linii tekstu przy pomocy funkcji puts */ NOWA_LINIA; puts(napis); NOWA_LINIA; puts("To jest praktyczna funkcja"); puts("\066\067\x2B\x2A itd."); } /********************************************************/ Wynik: ABCDEFGHIJKLMNOPQRS... To jest praktyczna funkcja 67+* itd. Funkcja printf Wyprowadza wynik przetwarzania w różnych formatach. printf (łańcuch, lista argumentów) int printf(const char *format,...) Przykład: /********************************************************/ /* Program p14.c */ /* ( printf /1/ ) */ /*------------------------------------------------------*/ #include <stdio.h> main() { int k = 21101; /* liczba dziesietna */ printf("\nk(_10) = %i k(_8) = %o k(_16) = %X", k, k, k); } /********************************************************/ Wynik: k(_10) = 21101 k(_8) = 51155 k(_16) = 526D Formaty realizowane przez funkcję printf (znaki typu w łańcuchach formatujących) Typ danych - znak Argument typu w formacie wejściowy Format wyjściowy Liczba %d, %i int liczba całkowita ze znakiem %u unsigned int l. całk. ze bez znaku %o int ósemkowa %x int szestnastkowa bez znaku, małe litery a..f %X int j.w. będą duże litery A..F %f float/double l. zmiennoprzecinkowa: [-]nnnn.mmmmm %e float/double j.w. w postaci [-].nnnne[+-]mmm %E -"- j.w. ze znakiem E %G -"- jak %f lub %E, mniejsza liczba znaków %c char (znak) pojedynczy znak %s char * wskaźnik łańcucha łańcuch znaków, aż do napotkania bajtu zerowego \0 %n int * Liczba dotychczas wysłanych znaków %p pointer wskaźnik argument w postaci wskaźnika, co zależy od modelu pamięci (segm:offs lub offs)liczba 16-wa ZNAK lub ŁAŃCUCH WSKAŹNIK Przykłady: /********************************************************/ /* Program p15.c */ /* ( printf /2/ ) */ /*------------------------------------------------------*/ #include <stdio.h> Przykład main() { float a,b,c; a=153.67789; b=2.33E-2; c = a * b; printf(" %f razy %E wynosi: %f ", a,b,c); } /********************************************************/ Wynik: 153.677887 razy 2.330000E-02 wynosi: 3.580695 /********************************************************/ /* Program p16.c */ /* ( printf /3/ ) */ /*------------------------------------------------------*/ #include <stdio.h> main() { char napis[] = "ABCDEFGHIJKLMNOPQRS..."; int znak = 73; /* wykonanie tego samego co w przykladach p12.c i p13.c przy pomocy funkcji printf */ /* p12.c */ printf("\n%c %c %c %c %c \n%c %c %c\n", znak,55,'Z','\066','\x3A',napis[0],napis[4],znak+'\066'-52); /* p13.c */ printf("\n%s\nTo jest praktyczna funkcja\n%c%c%c%c itd.", napis,'\066','\067','\x2B','\x2A'); } /********************************************************/ Wynik: I 7 Z 6 : A E K ABCDEFGHIJKLMNOPQRS... To jest praktyczna funkcja 67+* itd. /********************************************************/ /* Program p17.c ( Turbo C 2.0 ) */ /* ( printf /4/ ) */ /*------------------------------------------------------*/ #include <stdio.h> main() /* zagadnienie dokladnosci */ { double a=153.67789; int k=22799; int m=-500; int *p; /* wskaznik */ char c='M'; char napis[]="Lepsze C od B lub P p=&k; printf("\n format %%d %d", k); "; printf("\n printf("\n printf("\n printf("\n printf("\n printf("\n printf("\n printf("\n printf("\n printf("\n printf("\n printf("\n printf("\n printf("\n printf("\n format %%i %i", m); format %%u %u", k); format %%o %o", k); format %%x %x", k); format %%X %X", k); format %%f %f", a); format %%e %e", a); format %%E %E", a); format %%g %g", a); format %%G %G", a); format %%c %c", c); format %%s %s", napis); format %%p %p", *p); ------------------------"); "); printf(napis); } /********************************************************/ Wynik: format %d 22799 format %i -500 format %u 22799 format %o 54417 format %x 590f format %X 590F format %f 153.677890 format %e 1.536779e+02 format %E 1.536779E+02 format %g 153.678 format %G 153.678 format %c M format %s Lepsze C od B lub P format %p 654C:590F -----------------------Lepsze C od B lub P Użyty w łańcuchach formatu zapis %% reprezentuje pojedynczy "widzialny" znak procentu. Pełny zapis instrukcji formatu printf: % [Pole znaku] [Szerokość] [.Dokładność] [Modyfikator] Typ danych %[flagi][szerokość][.precyzja][F|N|h\l|L]znak-typu Wszystkie sekwencje formatujące zaczynają się od znaku %. Kolejne elementy określają: Znaki flag - dodatkowe możliwości (np. wyrównanie lewostronne) Szerokość - liczba wysyłanych znaków -całkowita szerokość pola na zapis liczby Precyzja (dokładność) - liczba cyfr znaczących - określa ilość miejsc dziesiętnych po kropce dziesiętnej. Może wystąpić *. Specyfikator precyzji - rozpoczyna się znakiem kropki, który oddziela go od pozostałych elementów sekwencji formatującej. Modyfikator rozmiaru argumentów - zawierają dodatkową informację nt. rozmiaru argumentu i są wykorzystywane w połączeniu ze znakami typu w celu wskazania faktycznego typu argumentu. Znaki typu - określają typ argumentów Zapisy w nawiasach kwadratowych są opcjonalne i nie muszą wystąpić Pole znaku (znaki flag): '+' '-' '#' ' ' (spacja) 0 (zero) - wyprowadzony ciąg znaków będzie wyrównany lewostronnie + znak ma być wydrukowany (- lub +) Flagi w sekwencjach formatujących Flaga Co określa Justuje lewostronnie wartość, umieszczając z prawej strony odpowiednią ilość spacji + Jeśli wyświetlana jest liczba ze znakiem, wówczas zostanie przed nią umieszczony znak + lub -, w zależności od wartości spacja Jeśli wartość jest nieujemna, zamiast plus wyświetlana będzie spacja, w przypadku wartości ujemnych - # Wpływ tego znaku zależy od tego, z jakim znakiem typu jest związany - tabela poniżej Typ danych c, s, d, i, u Reakcja, gdy występuje znak # %o Przy wartościach dodatnich na początku zostanie dopisany znako 0 %x, %X Wszystkie liczby będą przedstawione z 0x lub 0X %e, %E, %f Również w przypadku braku miejsc znaczacych dziesiętnych, po przecinku będzie kropka dzies. %g, %G Odpowiednio jak dla %e i %E, ale będą widoczne nieznaczące zera Nie wpływa Specyfikator precyzji rozpoczyna się znakiem kropki, który oddziela go od pozostałych elementów sekwencji formatującej Specyfikatory precyzji (dokładności) - zagadnienie dokładności obliczeń Specyfikator Precyzja - znaczenie dokładności Domyslne precyzje: - 1 dla znaków typu d, i, o, u, x, X nie podano - 6 dla typu e, E, f - wszystkie znaczące cyfry dla typu g i G .0 Dla znaków typu d, i, o, u, x, X przyjmowana jest precyzja d domysla. Dla e, E, f nie jest drukowana kropka dziesiętna. Liczby całkowite o wartosci zero nie będą drukowane .n Drukowane będzie n znaków lub cyfr dziesiętnych. Może nastąpić obcięcie lub zaokrąglenie * Lista argumentów zawiera wartość określającą precyzję. Specyfikator szerokości - określa minimalną szerokość dla wartości wyjściowej. Specyfikatory szerokości pola Specyfikator szerokości pola Wpływ na formatowane dane n Drukowanych jest przynajmniej n znaków. Jeśli wartość zajmuje mniej niż n znaków, umieszczone będą dodatkowe spacje, z lewej lub prawej strony (jeśli ustawiono odpowiednią flagę) 0n Drukowanych jest przynajmniej n znaków. Jeśli znaków drukowanych jest mniej niż n to nastąpi wypełnienie zerami z lewej strony * Szerokość pola znajdzie się w argumencie poprzedzającym argument, z którym związana jest dana sekwencja Modyfikatory rozmiaru argumentów - zawierają dodatkową informację o typie argumenów wejściowych. Jedna z liter: F, N, h, I Modyfikator Działanie Przekazanie wskaźnika typu far. Argument zostanie potraktowany jako daleki F wskażnik - używany ze znakami typu p, s, n N Przekazanie wskaźnika typu near. Argument będzie traktowany jako wskaźnik bliski. Nie stosować w modelu huge. h Oznacza przekazanie danej typu short int. Argument traktuje się jako short int dla znaków typu d, i, o, u, x, X l Oznacza przekazanie danej typu long int względnie double. L Argument traktowany jako long double dla znaków typu e, E, f, g, G Przykłady: /********************************************************/ /* Program p18.c ( Turbo C 2.0 ) */ /* ( printf /5/ ) */ /*------------------------------------------------------*/ #include <stdio.h> main() /* wybrane formaty */ { double a=153.67789, b=153. ; int k=22799; int m=-500; int *p; /* wskaznik */ char c='M'; char napis[]="Lepsze C od B lub P "; p=&k; printf("\n format %%#-+8d %#-+8d", k); printf("\n format %%#-+8i %#-+8i", m); printf("\n format %%#- 8u %#- 8u", k); printf("\n format %%#-+8o %#-+8o", k); printf("\n format %%#-+8x %#-+8x", k); printf("\n format %%#-+8X %#-+8X", k); printf("\n format %%#020.8f %#020.8f", a); printf("\n format %%# 20.8e %# 20.8e", a); printf("\n format %% +20.8E % +20.8E", b); printf("\n format %% +20.8g % +20.8g", a); printf("\n format %% +20.8G % +20.8G", b); printf("\n format %% +20.8c % +20.8c", c); printf("\n format %%.20s %.20s", napis); printf("\n format %%24p %24p", *p); printf("\n ---------------------------------------"); printf("\n%44.*s",30,napis); m=printf("\n\n123456789 123456789 123456789 123456789 1\n"); printf("\n\"Wynik\" poprzednio wykonanej instrukcji"); printf("\np r i n t f wynosi %i znaki \n", m); } /********************************************************/ Wynik: format %#-+8d +22799 format %#-+8i -500 format %#- 8u 22799 format %#-+8o 054417 format %#-+8x 0x590f format %#-+8X 0X590F format %#020.8f 00000000153.67789000 format %# 20.8e 1.53677890e+02 format % +20.8E +1.53000000E+02 format % +20.8g +153.67789 format % +20.8G +153 format % +20.8c M format %.20s Lepsze C od B lub P format %24p 10B4:590F --------------------------------------Lepsze C od B lub P 123456789 123456789 123456789 123456789 1 "Wynik" poprzednio wykonanej instrukcji p r i n t f wynosi 44 znaki /********************************************************/ /* Program p19.c ( Turbo C 2.0 ) */ /* ( printf /6/ ) */ /*------------------------------------------------------*/ #include <stdio.h> main() /* zapisy rownowazne, dynamiczny format */ { double a=153.22; char napis[]="Wszystko dobre co nie jest niedobre "; int i,j; printf("\n%.9s", napis); printf("\n%.*s", 9, napis); i=9; i=14; i=21; printf("\n%.*s", i, napis); printf("\n%.*s", i, napis); printf("\n%.*s", i, napis); printf("\n printf("\n printf("\n i=9; j=3; printf("\n i=20; j=8; printf("\n a = %#09.3f", a); a = %#0*.3f", 9, a); a = %#0*.*f", 9, 3, a); a = %#0*.*f", i, j, a); a = %#0*.*f", i, j, a); } /********************************************************/ Wynik: Wszystko Wszystko Wszystko Wszystko dobre Wszystko dobre co nie a = 00153.220 a = 00153.220 a = 00153.220 a = 00153.220 a = 00000000153.22000000 /********************************************************/ /* Program p20.c */ /* Obliczanie objetosci walca ( wieksza dokladnosc ) */ /*------------------------------------------------------*/ #include <stdio.h> #define PI #define PROMIEN #define WYSOKOSC 3.1415926 3.3 44.4 main() { { float promien, wysokosc, objetosc; promien = PROMIEN; wysokosc = WYSOKOSC; objetosc = PI * promien * promien * wysokosc; printf("\nObjetosc walca = %f", objetosc); } { double promien, wysokosc, objetosc; promien = PROMIEN; wysokosc = WYSOKOSC; objetosc = PI * promien * promien * wysokosc; printf("\nObjetosc walca = %f", objetosc); } } /********************************************************/ Wynik: Objetosc walca = 1519.010254 Objetosc walca = 1519.010288 /********************************************************/ /* Program p21.c */ /* Obliczanie objetosci walca ( wieksza dokladnosc ) */ /*------------------------------------------------------*/ #include <stdio.h> #define PI #define PROMIEN #define WYSOKOSC 3.1415926 3.3 44.4 main() { double promien, wysokosc, objetosc; promien = PROMIEN; wysokosc = WYSOKOSC; objetosc = PI * promien * promien * wysokosc; printf("\nObjetosc walca = %f", objetosc); printf("\nObjetosc walca = %E", objetosc); printf("\nObjetosc walca = %g", objetosc); printf("\nObjetosc walca = %15.10f", objetosc); printf("\nObjetosc walca = %25.20f", objetosc); } /********************************************************/ Wynik: Objetosc walca = 1519.010288 Objetosc walca = 1.519010E+03 Objetosc walca = 1519.01 Objetosc walca = 1519.0102875816 Objetosc walca = 1519.01028758159987000000 Funkcja getchar int getchar(void) Funkcja odczytuje znak ze standardowego strumienia wejściowego (stdin) i zwraca go po dokonaniu konwersji bez rozszerzenia znakowego. Funckja przy każdym wywołaniu podaje następny znak z wejścia lub EOF, gdy napotkała koniec pliku. W przypadku błędu lub końca zbioru wartością funkcji jest EOF. Stała symboliczna EOF jest zdefiniowana w nagłówku <stdio.h.. Jej wartoscią jest na ogół -1, ale e testach należy używać EOF. Zadaniem funkcji jest wprowadzenie pojedynczego znaku do pamięci komputera. Syntaktycznie postać funkcji jest następująca: c = getchar(); gdzie c jest typu char. Po każdym wywołaniu funkcja getchar pobiera ze strumienia znaków następny znak i wraca z jego zawartością. Zawartością zmiennej jest następny znak z wejścia. Przykłady: #include <stdio.h> /* przepisz wejscie na wyjście, wersja 1 */ main() { int c; c = getchar(); /* przeczytaj znak */ while (c != EOF) /* dopóki znak nie jest znakiem konca pliku (Ctrl Z) */ { putchar(c); /* wypisz przeczytany znak */ c=getchar(); /* przeczytaj nastepny znak */ } } Funkcja scanf int scanf(const char * format, ...) Funkcja scanf jest wejściowym odpowiednikiem funkcji printf . Wczytuje znaki ze standardowego wejścia, interpretuje zgodnie ze specyfikacjami w argumencie format i zapamiętuje wyniki w miejscach określonych przez argumenty, np. int i, j; scanf("%d%d", &i, &h); spowoduje, ze ze standardowego wejścia zostaną pobrane 2 liczby całkowite (sekwencje formatujące %d i %d), których wartość zostanie umieszczona w zmiennych "i" i "j". Syntaktycznie funkcja scanf ma definicję: scanf(łańcuch formatu, lista argumentów) Przykład: Obliczenie objętości walca: /************************************************************/ /* Program p24.c */ /* Obliczanie objetosci walca ( scanf /1/ ) */ /*----------------------------------------------------------*/ #include <stdio.h> #define PI 3.1415926 main() { float promien, wysokosc, objetosc; printf("\n----- Program oblicza objetosc walca -----"); printf("\n----- Podaj dane wejsciowe: \n"); printf("\npromien = "); scanf("%f", &promien); printf("wysokosc = "); scanf("%f", &wysokosc); objetosc = PI * promien * promien * wysokosc ; printf("\nObjetosc walca = %f", objetosc); } /************************************************************/ Wyniki: ----- Program oblicza objetosc wal ----- Podaj dane wejsciowe: promien = 3.3 wysokosc = 44.4 Objetosc walca = 1519.010254 Liczby 3.3 i 44.4 zostały wprowadzone z klawiatury. Każdy łańcuch znaków reprezentujacy liczbę, musi być zakoczony ENTER. Uproszczona wersja w.w. programu - brak zmiennej objętość: /************************************************************/ /* Program p24b.c */ /* Obliczanie objetosci walca ( printf /8/ ) */ /*----------------------------------------------------------*/ #include <stdio.h> #define PI 3.1415926 main() { float promien, wysokosc; printf("\n----- Program oblicza objetosc walca -----"); printf("\n----- Podaj dane wejsciowe: \n"); printf("\npromien = "); scanf("%f", &promien); printf("wysokosc = "); scanf("%f", &wysokosc); printf("\nObjetosc walca = %f",PI*promien*promien*wysokosc); } /************************************************************/ Instrukcja formatu dla funkcji scanf: % [*] [Szerokość] [Modyfikator1] [Modyfikator2] Typ danych Znaczenie opcji: * (gwiazdka) - zignorowanie pola wejściowego szerokość - maks. liczba wczytanych znaków (przerwanie wprowadzania po spacji lub innym nieodpowiednim znaku dla formatu we) Modyfikator1 - F dla wskaźnika far, N dla near Modyfikator2 - h dla short int, l dla long int lub double Znaki typu łańcuchów formatujacych dla funkcji scanf - formaty realizowane przez funkcję scanf Typ danych (znak formatu) Typ argumentu Format wejściowy - dana wprowadzana %d int * liczba całkowita dziesiętna, całkowita ze znakiem %D long * liczba całkowita dzies. ze znakiem %i int * liczba dzies., ósemkowa, 16-wa, całkowita, ze znakiem LICZBA %l long * j.w. %u unsigned * liczba całkowita, dziesiętna, bez znaku %U unsigned long * liczba całk. dziesiętna, bez znaku %o int * liczba ósemkowa ze znakiem %O long * j.w. %x int * liczba 16-wa całkowita %X long * j.w. %f float * liczba zmiennoprzecinkowa %e float * j.w. %E float * j.w. %c char * pojedynczy znak %s char tab[n] łańcuch aż do bajtu zerowego %n brak liczba już wczytanych znaków zapamiętana we wskaźniku typu (int *) %p far * / near * wskaźnik do dowolnego obiektu, jako liczba 16-wa, bliski (ofs) lub daleki (seg:ofs) ZNAKI (znak lub łańcuch znaków) WSKAŹNIK Na liście argumentów funkcji scanf używany jest operator &. Jego wystąpienie przed nazwą zmiennej oznacza adres tej zmiennej. /********************************************************/ /* Program p25.c */ /* ( & ) */ /*------------------------------------------------------*/ #include <stdio.h> main() /* operator & */ { int *p, k=13; printf("\n%i",k); p=k; /* wartosc */ printf("\n%i",p); printf("\n%p",p); p=&k; /* adres k */ printf("\n%p",p); } /********************************************************/ Wynik: 13 (wartość k) 13 (wartość *p) 0000:000D 137F:21E8 (wartość *p w formacie 16-wym) (adres zmiennej k) Przykład na obliczenie objętości walca - wprowadzenie 2 liczb w jednej linii: /************************************************************/ /* Program p26.c ( Turbo C 2.0 ) */ /* Obliczanie objetosci walca ( scanf /2/ ) */ /*----------------------------------------------------------*/ #include <stdio.h> #define PI 3.1415926 main() { float promien, wysokosc, objetosc; printf("\n----- Program oblicza objetosc walca -----"); printf("\nPodaj dane wejsciowe (2 liczby)"); printf("\npromien i wysokosc (format: xxx.xx xxx.xx)\n"); scanf("%6f %6f", &promien, &wysokosc); objetosc = PI * promien * promien * wysokosc ; printf("\nObjetosc walca = %f", objetosc); } /************************************************************/ ----- Program oblicza objetosc walca ----Podaj dane wejsciowe (2 liczby) promien i wysokosc (format: xxx.xx xxx.xx) 3.3 44.4 Objetosc walca = 1519.010254 Znakiem separacji danych może być tu znak spacji, znak nowej linii (ENTER) lub znak tabulacji. W przypadku błędnych formalnie danych (np. litera k zamiast liczby) program nie zawiesza się tylko przyjmowane jest zero jako wartość zmiennej. Dobrym nawykiem jest oddrukowywanie danych wejściowych. /********************************************************/ /* Program p27.c */ /* ( scanf /3/ ) */ /*------------------------------------------------------*/ #include <stdio.h> main() /* to samo co w przyk. p22.c i p23.c { char znak, linia[80]; scanf("%c", &znak); printf("%c\n", znak); scanf("%s", linia); printf("%s", linia); */ /* p22.c */ /* p23.c */ } /********************************************************/ Program poniższy pokazuje możliwość filtrowania znaków: /********************************************************/ /* Program p28.c */ /* ( scanf /4/ ) */ /*------------------------------------------------------*/ #include <stdio.h> main() /* filtrowanie znakow */ { char linia[80]; scanf("%[a-zABC]",linia); printf("%s", linia); } /********************************************************/ Przykładowy wynik: alinaABOLa alinaAB Instrukcja scanf pozwala tu na wprowadzenie wszystkich małych liter a-z oraz wybranych liter A, B, C. Wprowadzony łańcuch zostanie obcięty przed znakiem nie należacym do zbioru podanego. Inne możliwe filtry: %[A-Z] - duże litery dozwolone %[^A-Z] - duże litery wykluczone %[AaBb+-.:K] - wybrane znaki dozwolone %[^XYZxyz] - wybrane znaki wykluczone Operatory i wyrażenia Do wykonania obliczeń zmieniających dane w informacje, niezbędne są operatory. Operator to symbol mówiący komputerowi, jak ma przetwarzać dane. Operatory, z punktu widzenia liczby argumentów dzielimy na dwuargumentowe i jednoargumentowe. a op b - op jest operatorem 2-argumentowym, np. a+b; a*b; a/b; a%b; op a - op jest operatorem jednoargumentowym, np. -a; -(a+b); !a Można je pogrupować wg cech funkcjonalnych na grupy: operatory arytmetyczne operatory porównania - relacyjne operatory logiczne operatory bitowe operatory przypisania operatory unarne operatory rozmiaru operatory konwersji operator warunkowy operator przecinkowy operatory wskazywania Operatory arytmetyczne Operatory arytmetyczne można podzielić na 3 grupy: operatory inkrementacji i dekrementacji: --Op, ++Op, Op--, Op++ operatory addytywne: "+" i "-" operatory multiplikatywne: "*', "/", "%" Operatory te używane są do wykonywania działań matematycznych. Operatory addytywne i multiplikatywne: Operator Funkcja + Dodawanie Wyrażenie Operandy Op1 i Op2 są typu arytmetycznego Op1 typu całk, Op2 Op1+Op2 wskaźnik Op1 wskaźn, Op2 całkowity Przykład Wynik int a=9; int b=2, c; c=a+b; c=11 - Odejmowanie Op1-Op2 Op1 i Op2 są typu arytmet. Op1 i Op2 są int a=9; int wskaźnikami tego c=7 b=2, c; c=a-b; samego typu Op1 jest wskaźnikiem, Op2 typu całkowitego * Mnożenie Op1*Op2 Op1 i Op2 typów arytmet. / Dzielenie Op1 / Op2 -"- % Reszta z dzielenia liczb całkowitych modulo Op1 % Op2 Op1 i Op2 typów całkowitych Brak jest operatora potęgowania (realizuje to funkcja biblioteczna pow) int a=9; int b=2, c; c=a*b; c=18 int a=9; int c=4 b=2, c; c=a/b; int a=9; int b=2, c; c=a%b; c=1 Jeżeli dzielimy zmienne lub liczby całkowite przy pomocy operatora /, to wynik zawsze bedzie liczbą całkowitą. Z operatora % korzystamy do obliczenia reszty z dzielenia liczb całkowitych. Przykład wykorzystujący operatory arytmetyczne: /********************************************************/ /* Program p29.c */ /* ( operatory arytmetyczne ) /*------------------------------------------------------*/ #include <stdio.h> main() { int float k = 20, m = 3, x = 7.5, y = 1.5, i; z; printf("\n k=20, m=3 (int)"); printf("\n---------------------------"); i = k + m; printf("\n k + m = %i ", i); i = k - m; printf("\n k - m = %i ", i); i = k * m; printf("\n k * m = %i ", i); i = k / m; printf("\n k / m = %i ", i); i = k % m; printf("\n k %% m = %i ", i); printf("\n"); printf("\n x=7.5, y=1.5 (float)"); printf("\n---------------------------"); z = x + y; printf("\n x + y = %6.2f ", z); z = x - y; printf("\n x - y = %6.2f ", z); z = x * y; printf("\n x * y = %6.2f ", z); z = x / y; printf("\n x / y = %6.2f ", z); printf("\n---------------------------"); i = k*x + (m+k+1)/y ; printf("\n k*x + (m+k+1)/y = %i (int)", i); z = k*y + (x+k+1.)/m ; printf("\n k*y + (x+k+1.)/m = %6.2f (float)", z); } /********************************************************/ Wynik wykonania: k=20, m=3 (int) --------------------------k + m = 23 k - m = 17 k * m = 60 k / m = 6 k % m = 2 x=7.5, y=1.5 (float) --------------------------x + y = 9.00 */ x - y = 6.00 x * y = 11.25 x / y = 5.00 --------------------------k*x + (m+k+1)/y = 166 (int) k*y + (x+k+1.)/m = 39.50 (float) Operatory porównania - relacyjne Operatory relacyjne pozwalają stwierdzić, czy między operandami zachodzi dana relacja. Jeżeli relacja jest prawdziwa, to jej wartością jest true (prawda, wartość 1), a jeżeli fałszywa, to jej wartością jest false (wartość 0). Operator sprawdzenia róności to "==" (operator przypisania to "="). Operator Znaczenie Relacja Opis Przykład < Mniejszy Op1<Op2 int a,b,wyn; Op1 mniejsze niż a=10; b=3; Op2 wyn = a<b; // zostanie przypisana wartość 0 (false) <= Mniejszy lub równy Op1 <= Op2 Op1 mniejsze równe Op2 wyn = a<=b; // 0 > Większy Op1 > Op2 Op1 większe niż Op2 wyn = a>b; // 1 (true) >= Większy lub równy Op1 >= Op2 == Równy - równe Op1 == Op2 Op1 równe Op2 != Nierówny różne Op1 != Op2 Op1 różne od Op2 wyn = a != b; //1 wyn = a>= b; //1 wyn = a == b; // 0 Operandy Op1 i Op2 w powyższych relacjach muszą spełniać jedną z 2 reguł: Op1 i Op2 są typu arytmetycznego Op1 i Op2 są wskaźnikami zgodnych typów Operandy wyrażeń z operatorem równości == lub różnosci powinny spełnaić w.w. właściwości lub jedną z poniższych: Jeden z operandów jest wskaźnikiem, drugi zaś jest typu void Jeden z operandów jest wskaźnikiem, natomiast drugi stałą oznaczającą adres pusty (NULL) Uwaga! Operator równości jest często mylony z operatorem przypisania = if (a=1) - przypisanie, wartością wyrażenia jest 1, czyli prawda, zamiast if (a==1) - porównanie, wartością wyrażenia jest prawda, jeśli a równa się 1 lub fałsz gdy nie. Kilka przykładów: int k=1; m=2; n=3; Wyrażenie Interpretacja Wartość m<n prawda 1 (k+m)>=n prawda 1 (m-k)>n fałsz 0 n>=3 prawda 1 k != m prawda 1 k == 2 fałsz 0 (m+2) <= k fałsz 0 Operatory logiczne W języku C/C++ wartość logiczna prawda to liczba całkowita różna od zera, zaś fałsz to zero (całkowite) Wyrażenie Operator Znaczenie Opis Przykład && Koniunkcja - logiczne AND Op1 && (i) /iloczyn Op2 int k=1, m=2, n=3; Koniunkcja Op1 i ((k+m)>=n) && Op2 (m==1) // 0 || Alternatywa - logiczne OR (lub) /suma log. Op1 || Op2 Alternatywa Op1 ((m-k)>n) || (m==2) i Op2 //1 ! Negacja - logiczne NOT (nie) !Op1 Negacja Op1 !(k>n) //1 Operandy Op1 i Op2 muszą być skalarami, zaś wartość wyrazenia logicznego jest zawsze typu int. Wartości wyrażeń logicznych (f - fałsz/ false, t - prawda/false) Op1 Op2 Op1 && Op2 Op1 || Op2 !Op1 f f f t t f t f t t t f f t f t t t t f if (x != 0) to samo co if (x) if (y == 0) równoważne if (!y) Przykład (Zalewski, Programowanie w C i C++ ..., str 131): #include <stdio.h> #define TRUE 1 #define FALSE 0 typedef int BOOL; BOOL czy_w_przedziale(double x, double s, double t, BOOL domkniety) { if ((x<t && x>s && !domkniety) || (x<=t && x>=s && domkniety)) return TRUE; else return FALSE; } int main(void) { double x, s=5, t=20; printf("\nPodaj liczbe: "); scanf("%lf",&x); if (czy_w_przedziale(x,s,t,TRUE)) printf("\nLiczba %lf nalezy do przedzialu <%lf, %lf>",x,s,t); else printf("\nLiczba %lf nie nalezy do przedzialu <%lf, %lf>",x,s,t); return 0; } Przykładowy wynik : Podaj liczbe: 3 Liczba 3.000000 nie nalezy do przedzialu <5.000000, 20.000000> Przykład z walcem - promień ma być w przedziale (2, 3.3), a wysokosć w przedziale (4.50, 5.50), dodatkowo H/r ma być w przedziale [2.11,2.42] lub w [2.58, 2.95], objętość walca C <= 100 - walec jest DOBRY /*************************************************************/ /* Program p30.c */ /* Ocena jakosci walca ( operatory logiczne ) */ /*-----------------------------------------------------------*/ #include <stdio.h> #define PI 3.1415926 /* parametry narzucone przez kryterium: P1 - promien minimalny P2 - promien maksymalny H1 - wysokosc minimalna H2 - wysokosc maksymalna hp - stosunek wysokosci do promienia HP1 - dolna granica hp (zakres pierwszy) HP2 - gorna granica hp (zakres pierwszy) HP3 - dolna granica hp (zakres drugi) HP4 - gorna granica hp (zakres drugi) V - objetosc maksymalna #define #define #define #define P1 P2 H1 H2 2.00 3.30 4.50 5.50 */ #define #define #define #define #define HP1 2.11 HP2 2.42 HP3 2.58 HP4 2.95 V 100.00 main() /* kryterium jakosci walca */ { float promien, wysokosc, hp, objetosc; scanf("%f %f", &promien, &wysokosc); hp = wysokosc / promien; objetosc = PI * promien * promien * wysokosc; if (((promien > P1) && (promien < P2)) && ((wysokosc >= H1) && (wysokosc <= H2)) && (((hp>=HP1) && (hp<=HP2)) || ((hp>=HP3) && (hp<=HP4))) && ( objetosc <= V )) { printf("\n------ Walec jest DOBRY dla:"); printf("\npromien= %5.2f, wysokosc=%5.2f",promien,wysokosc); } printf("\nobjetosc=%6.2f, hp= %6.2f",objetosc,hp); } /**************************************************************/ 2.30 5.40 ------ Walec jest DOBRY dla: promien= 2.30, wysokosc= 5.40 objetosc= 89.74, hp= 2.35 Operatory bitowe Bitowe operatory logiczne działają na uporządkowanym ciągu bitów (0,1) i pozwalają na manipulowanie bitami. Za pomocą tych operatorów można realizować funkcje logiczne OR, AND, EXOR, NOT. Operator Znaczenie & Bitowa koniunkcja (AND) Wyrażenia Przykłady Op1 & Op2 0&0=0 0&1=0 1&0=0 1&1=1 Op1 | Op2 0|0=0 0|1=1 1|0=1 1|1=1 | Bitowa alternatywa (OR) ^ Bitowa różnica symetryczna (XOR) Suma modulo 2 Op1 ^ Op2 0^0=0 0^1=1 1^0=0 1^1=1 ~ Bitowa negacja ~Op1 ~0 = 1 ~1 = 0 << Przesunięcie w lewo Op1 << Op2 Przesuń Op1 w lewo o Op2 bitów >> Przesunięcie w prawo Op1 >> Op2 Przesuń Op1 w prawo o Op2 bitów Operandy Op1 i Op2 muszą być typu całkowitego. Użycie operatorów bitowych powoduje wykonanie operacji logicznych na wszystkich parach odpowiadających sobie bitów. Przykład: /********************************************************/ /* Program p31.c */ /* ( operatory bitowe ) */ /*------------------------------------------------------*/ #include <stdio.h> main() { unsigned int k = 0x5555, m = 0x3333, i; printf("\n k = %#x m = %#x ", k, m); printf("\n------------------------------"); i = k & m; printf("\n k & m = %#x ", i); /* wydruk z początkowym )x */ i = k | m; printf("\n k | m = %#x ", i); i = k ^ m; printf("\n k ^ m = %#x ", i); i = ~ m; printf("\n ~ m = %#x ", i); i = k << 3; printf("\n k << 3 = %#x ", i); i = k >> 2; printf("\n k >> 2 = %#x ", i); printf("\n------------------------------"); } /********************************************************/ Wydruk wyników: k = 0x5555 m = 0x3333 -----------------------------k & m = 0x1111 k | m = 0x7777 k ^ m = 0x6666 ~ m = 0xcccc k << 3 = 0xaaa8 k >> 2 = 0x1555 ------------------------------ Operatory przypisania Instrukcją przypisania jest trójka elementów zapisana jako: identyfikator operator_przypisnia wyrażenie Operator Przykład zapisu Zapis równoważny = a=b a=b += a += b a=a+b -= a -= b a=a-b *= a *= b a=a*b /= a /= b a=a/b %= a %= b a=a%b <<= a <<= b a = a << b >>= a >>=b a = a>>b &= a &= b a=a&b ^= a ^= b a=a^b |= a |= b a=a|b Przykłady: double x, y, x; x = y = z = 1.01; c += d + e; // równoważne: c = c + d + e; Przykłady: double x, y, x; x = y = z = 1.01; c += d + e; // równoważne: c = c + d + e; Przykład programu wykorzystującego operatory przypisania: /********************************************************/ /* Program p32.c */ /* ( operatory przypisania ) /*------------------------------------------------------*/ #include <stdio.h> main() { int k = 5, m = 3, i; printf("\n wartosci poczatkowe: k=%i, m=%i, i=?",k,m); printf("\n------------------------------------------"); printf("\n operacja wynik "); printf("\n------------------------------------------"); i = m; printf("\n ( i = m ) i = %i ", i); i += k; printf("\n ( i += k ) i = %i ", i); i -= k; printf("\n ( i -= k ) i = %i ", i); */ i *= k; printf("\n ( i *= k ) i = %i ", i); i /= k; printf("\n ( i /= k ) i = %i ", i); i <<= 3; printf("\n ( i <<= 3 ) i = %i ", i); i >>= 2; printf("\n ( i >>= 2 ) i = %i ", i); i &= k; printf("\n ( i &= k ) i = %i ", i); i ^= k; printf("\n ( i ^= k ) i = %i ", i); i |= k; printf("\n ( i |= k ) i = %i ", i); i %= k; printf("\n ( i %%= k ) i = %i ", i); printf("\n-----------------------------------------"); } /********************************************************/ Wydruk wyników: wartosci poczatkowe: k=5, m=3, i=? -----------------------------------------operacja wynik -----------------------------------------( i = m ) i = 3 ( i += k ) i = 8 ( i -= k ) i = 3 ( i *= k ) i = 15 ( i /= k ) i = 3 ( i <<= 3 ) i = 24 ( i >>= 2 ) i = 6 ( i &= k ) i = 4 ( i ^= k ) i = 1 ( i |= k ) i = 5 ( i %= k ) i = 0 ----------------------------------------- Operatory unarne (jednoargumentowe) W grupie tej wystepują 3 operatory: ++ zwany operatorem inkrementacji (zwiększania) -- zwany operatorem dekrementacji (zmniejszania) - zwany minusem jednoargumentowym oraz + Operatory ++ i -- są szczególnie charakterystyczne dla języka C. Przykładami zapisu mogą być: ++i, --i, i++, i--. Zapisowi i++ lub ++i odpowiada równoważny zapis i = i + 1. Zapisowi i-- lub --i odpowiada i = i-1. Należy pamiętać, że wyrażenia ++i oraz i++ są różne. Operacja: ++i zwiększa wartość zmiennej i o 1 przed jej użyciem, natomiast i++ zwiększa wartość zmiennej i o 1 po uzyciu jej poprzedniej wartości. Operatory zwiększania lub zmniejszania o 1 jest wykonywana przez większość procesoró w jednym rozkazie, dlatego w języku C są oddzielne operatory pozwalajace na wykonanie tych operacji. Operator Dekrementacja Inkrementacja przedrostkowy --Op ++Op przyrostkowy Op-Op++ Operand Op musi być typu arytmetycznego lub wskaźnikowego i jednocześnie musi stanowić l-wartość (zmieniana jest więc wartość zmiennej). Przykład przed- i przyrostkowych operatorów inkrementacji:: int m=3; n=1; r; r=(m++) + (++n) /* r=3+(1+1) = 5; m=m+1=4; */ r = (++m) + (++n) /* m=m+1=4; n=n+1=2; r=(3+1) + (1+1) = 6; */ Istotę różnicy między ++i a i++ oraz --i a i-- ilustruje też poniższy program: /********************************************************/ /* Program p33.c */ /* ( operatory unarne ) */ /*------------------------------------------------------*/ #include <stdio.h> main() { int i=5 ; printf("\n----------------"); printf("\n i = %i ", i ); printf("\n i = %i ", ++i ); printf("\n i = %i ", i ); printf("\n i = %i ", i++); printf("\n i = %i ", i ); printf("\n i = %i ", --i ); printf("\n i = %i ", i ); printf("\n i = %i ", i--); printf("\n i = %i ", i ); printf("\n i = %i ", -i ); printf("\n----------------"); } /********************************************************/ Wydruk wyników: ---------------i=5 i=6 i=6 i=6 i=7 i=6 i=6 i=6 i=5 i = -5 ---------------Instrukcja printf("\n i = %i", ++i) jest równoważna sekwencji instrukcji: i=i+1; printf("\n i = %i",i); natomiast instrukcja printf("\n = %%i", i++); jest równoważna sekwencji instrukcji: printf("\n i =%i",i); i=i+1;. Jeszcze 2 zapisy: a =-b; oraz a -= b; Pierwszy zapis dotyczy minusa unarnego (zmiany znaku liczby: a= (-b)), zapis drugi operacji odejmowania: a = a-b; Operator rozmiaru - sizeof Operator sizeof może być używany w jeden ze sposobów: sizeof wyrażenie (albo sizeof Op) - rozmiar pamięci zajmowany przez operand Op (wyrażenie) sizeof (identyfikator-typu) - rozmiar w bajtach typu określonego przez podany identyfikator Rezultatem jest liczba całkowita, określająca rozmiar argumentu w bajtach. Jeśli Op jest tablicą, to zwracany jest całkowity rozmiar pamięci zajmowany przez wszystkie jej elementy. W związku z tym liczba elementów tablicy równa się sizeof (tab) / sizeof (tab[0]). Jeśli Op jest strukturą lub unią, zwracana jest całkowita wielkość obszaru pamięci przez nią zajmowanego. Typ wartosci pobrania rozmiaru nosi nazwę size_t i jest zdefiniowany m.in. w stdio.h jako unsigned int. Przykład programu z użyciem sizeof: /********************************************************/ /* Program p34.c Turbo C 2.0 */ /* ( operator sizeof ) */ /*------------------------------------------------------*/ #include <stdio.h> main() { char c1; char tekst[] = "Turbo C jak Turbo-Jetta", napis[80]= "Jaki komputer taki pan "; int i1; short int i2; long int i3; float r1; long float r2; double r3; long double int r4; *p; printf("\n Turbo C 2.0 (reprezentacja) "); printf("\n============================= "); printf("\n Typ Liczba bajtow "); printf("\n----------------------------- "); printf("\n char : %2i ", sizeof(char)); printf("\n int : %2i ", sizeof(int)); printf("\n short int : %2i ", sizeof(short int)); printf("\n long int : %2i ", sizeof(long int)); printf("\n float : %2i ", sizeof(float)); printf("\n long float : %2i ", sizeof(long float)); printf("\n double : %2i ", sizeof(double)); printf("\n long double : %2i ", sizeof(long double)); printf("\n pointer : %2i ", sizeof p); printf("\n----------------------------- "); printf("\n tekst : %i ", sizeof tekst); printf("\n napis : %i ", sizeof napis); printf("\n zmienna r4 : %i ", sizeof r4); printf("\n============================= "); } /********************************************************/ Wydruk: Turbo C 2.0 (reprezentacja) ============================= Typ Liczba bajtow ----------------------------char : 1 int : 2 short int : 2 long int : 4 float : 4 long float : 8 double : 8 long double : 10 pointer : 2 ----------------------------tekst : 24 napis : 80 zmienna r4 : 10 ============================= Dla deklaracji tekst[] kompilator zadeklarował tyle miejsca, ile potrzeba so zmieszczenia napisu. Dla deklaracji tab[80] kompilator zarezerwował dokładnie 80 bajtów, mimo, że faktycznie łańcuch jest krótszy. Operator sizeof jest szczególnie pożyteczny przy dynamicznie określanych rozmiarach pamięci dla różnych typach danych. Przykład 2 (Zalewski str. 139): #include <stdio.h> struct PUNKT { double x,y; /* 2 * 8 bajtów = 16 bajtów */ int t[10]; }; /* 10 * 2 bajty = 20 bajtów */ int main(void) { double tab[10]; printf("\nRozmiary:\nTablicy: %d\nTypu float: %d\nStruktury PUNKT: %d", sizeof tab, sizeof (float), sizeof (struct PUNKT)); printf("\nPrzypadek szczególny: rozmiar = %d",sizeof puts("Andrzej")); return 0; } Wynik: Rozmiary: Tablicy: 80 Typu float: 4 Struktury PUNKT: 36 Przypadek szczególny: rozmiar = 2 Rozmiar tablicy tab wynosi 80, co odpowiada 10 elementom po 8 bajtów, rozmiar typu float 4, rozmiar struktury PUNKT - 36. Interesującą ciekawostką jest ostatnie użycie operatora sizeof, które daje wartość 2. Wynika to z faktu, że wartości standardowej funkcji puts są typu int. Ponieważ wyrażenie nie jest obliczane, więc funkcja puts nie zostanie wywołana. Operator konwersji - jednoargumentowy operator rzutowania (cast) Operator konwersji, zwany również operatorem rzutowania pozwala na jawne przekształcenie typów danych. Zapis operatora rzutowania: (nazwa typu) wyrażenie Wyrażenie jest przekształcane wg reguł dla typu określonego przez nazwę typu. Przykład: int a; a=2; (double)a; /* typ operandu zmienia się na typ podany w nawiasie - tu double */ Przykład programu z operatorami konwersji: /********************************************************/ /* Program p35.c */ /* ( operator konwersji ) */ /*------------------------------------------------------*/ #include <stdio.h> #include <math.h> main() { char int float c = 'k'; i = 70; f = 345.6789; printf("\n Wartosci poczatkowe: "); printf("\n c = \'%c\'; i = %i; f = %8.4f;", c ,i, f); printf("\n-------------------------------------"); printf("\n Konwersja Wynik "); printf("\n-------------------------------------"); printf("\n (int) c %i ", (int) c ); printf("\n (float) c %f ", (float) c ); printf("\n (double) i %f ", (double) i ); printf("\n (char) i %c ", (char) i ); printf("\n (double) i+2000 %f ", (double) i+2000 ); printf("\n (int) f %i ", (int) f ); printf("\n sqrt((double) c) %f ", sqrt((double) c)); printf("\n-------------------------------------"); } /********************************************************/ Wydruk wyników: Wartosci poczatkowe: c = 'k'; i = 70; f = 345.6789; ------------------------------------Konwersja Wynik ------------------------------------(int) c 107 (float) c 107.000000 (double) i 70.000000 (char) i F (double) i+2000 2070.000000 (int) f 345 sqrt((double) c) 10.344080 ------------------------------------- Operator konwersji daje możliwośc doraźnego przekształcenia wartości zmiennej określonego typu dla potrzeb bieżących bez naruszania rzeczywistej wartosci tej zmiennej. Argumentem funckcji sqrt jest liczba typu double uzyskana do dokonaniu konwersji kodu całkowitoliczbowego litery k Wyciąg (skrócona wersja) ww. programu: #include <stdio.h> main() { char c='k'; int i=70; printf("k= %d, i= %d\n",c,i); printf("k= %c %%d = %d (int) c = %d\n",c,c,(int) c); printf("i= %d %%c = %c (char) i = %c\n",i,i, (char) i); getchar(); } Wydruk: k= 107, i= 70 k= k %d = 107 (int) c = 107 i= 70 %c = F (char) i = F Operator warunkowy ? Wyrażenie z użyciem operatora warunkowego: Op1 ? Op2: Op3; wyrażenie_warunkowe ? wyrażenie_na_tak: wyrażenie_na_nie; Operator warunkowy (?:) pozwala zapisać w bardziej zwartej formie pewne konstrukcje programowe wymagające użycia instrukcji if. Np. z = (a>b)? a:b; /* z=max(a,b) */ Równoważny zapis: Dla C: if (a>b) z=a; else z=b; Dla Pascala: if a>b then z:=a else z:=b; W operatorze warunkowym operand Op1 musi być skalarem, zaś operatory Op2 i Op3 muszą spełniać jedną z zasad: oba są typu arytmetycznego oba są zgodnymi strukturami lub uniami oba są typu void oba są wskaźnikami zgodnych typów jeden jest wskaźnikiem, a drugi stałą oznaczającą adres pusty (NULL) jeden jest wskaźnikiem obiektu lub niekompletnego typu a drugi typu void. W pierwszej kolejności obliczna jest wartość Op1. Jeśli jest niezerowa (prawda), obliczana jest wartość Op2, a Op3 ignorowane; w przeciwnym razie (Op1 = 0) obliczna jest wartość Op3 a Op2 pomijane. Uzyskana wartość operandu Op2 lub Op3 staje się wartością wyrażenia warunkowego. Przykłady: 1) Typowe zastosowanie - funkcja max /* C++ - Operator warunkowy - funkacja max */ #include <iostream.h> void main() { int max(int, int); int a, b, m; char c; cout << "Program wyznacza max 2 liczb\n"; cout << "Podaj 2 liczby calkowite oddzielone spacja: "; cin >> a >> b; m=max(a,b); cout << "Max liczb " << a << " i " << b << " wynosi " << m; cout << "\nNacisnij cos"; cin >> c; } int max(int i, int j) { return i > j? i: j; } Wynik: Program wyznacza max 2 liczb Podaj 2 liczby calkowite oddzielone spacja: 4 7 Max liczb 4 i 7 wynosi 7 Nacisnij cos 2) Użycie operatora warunkowego zamiast instrukcji warunkowej: if (a<10) d=b=20; else d=c=30; To samo działanie z operatorem warunkowym: d = a<10? b=20: c=30; 3) W przypadku większej liczby przypisań można użyć operatora warunkowego w połączeniu z wyliczeniowym (przecinek), np. if (a<10) { x=12; y=13; } else { a=1; x=14; y=15; } Można napisać: a<10? x=12, y=13: a=1, x=14, y=15; 4) Przykład: Ustalenie ceny walca w zależności od objętości: /*************************************************************/ /* Program p36.c */ /* Ustalenie ceny walca ( operator warunkowy ) */ /*-----------------------------------------------------------*/ #include <stdio.h> #define PI /* C1 C2 C3 3.1415926 - cena dla objetosci mniejszej od V1 - cena dla objetosci miedzy V1 a V2 - cena dla objetosci wiekszej od V2 */ #define #define #define #define #define V1 V2 C1 C2 C3 300.0 500.0 1000 2500 1200 main() { float promien, wysokosc, objetosc; int cena; scanf("%f %f", &promien, &wysokosc); objetosc = PI * promien * promien * wysokosc; cena = (objetosc < V1) ? C1 : (objetosc > V2 ? C3 : C2 ) ; printf("\nobjetosc=%6.2f, cena=%4i ",objetosc,cena); } /*************************************************************/ Wydruk: 1.22 3.50 objetosc= 16.37, cena=1000 Operator przecinkowy/wyliczeniowy , (koma) Wyrażenie wyliczeniowe ma postać: Op1, Op2, ..., Opn gdzie Opi, (i=1..n) są operandami dowolnych typów. Opracowanie tego wyrażenia polega na obliczeniu wartości kolejnych operandów, począwszy od Op1, a skończywszy na Opn. Typ i wartość całego wyrażenia określa operand Opn. W C++ wynik wyrażenia wyliczeniowego jest l-wartością. Poprawne jest więc wyrażenie: (a+=b, c-=d, c*=a)++. Przykład: int n=10, i=2, k=4, wynik; wynik=(n-=i, k+=2, i*=5): W wyniku obliczenia powyższego wyrażenia zmienne uzyskają następujące wartości: n = n-i = 10-2=8 k = k+2 = 4+2=6 i = i*5 = 2*5=10 (ostatni operand) wynik = wartość ostatniego operandu, czyli 10 Operator przecinkowy stosowany jest m.in. w instrukcjach for, np. do sterowania równoległego 2 indeksami, a także w wywołaniach funkcji. Stosując wyrażenia wyliczeniowe w wywołaniach funkcji należy pamiętać o użyciu nawiasów, np.: func(i, (i+=k, k++), j); - funkcja otrzymuje tylko 3 parametry. Przykład programu z operatorem przecinkowym: /*************************************************************/ /* Program p37.c */ /* ( operator przecinkowy ) */ /*-----------------------------------------------------------*/ #include <stdio.h> #include <math.h> main() { int i, j; printf("\n i j sqrt(i) sin(j)"); printf("\n----------------------------------- "); for (i=0, j=10; j>=0; i++, j--) printf("\n %2i %2i %6.3f %6.3f",i,j, sqrt((double) i), sin((double) j) ); /* argument w radianach */ printf("\n----------------------------------- "); } /*************************************************************/ Wydruk: i j sqrt(i) sin(j) ----------------------------------0 10 0.000 -0.544 1 9 1.000 0.412 2 8 1.414 0.989 3 7 1.732 0.657 4 6 2.000 -0.279 5 5 2.236 -0.959 6 4 2.449 -0.757 7 3 2.646 0.141 8 2 2.828 0.909 9 1 3.000 0.841 10 0 3.162 0.000 ----------------------------------- Operatory wskazywania Operator adresu & i odwołania do zmiennej wskazywanej * &Op - pobranie adresu l-wartości Op *Op - odwołanie do zmiennej wskazywanej przez Op Operator pobrania adresu & W przypadku &Op - operand Op musi być identyfikatorem funkcji lub l-wartością, która nie jest polem bitowym i nie została zadeklarowana ze specyfikatorem register (nie można pobrać adresu zmiennej przechowywanej w rejestrze). Użycie operatora pobrania adresu w odniesieniu do funkcji jest zbędne. Operator odwołania do zmiennej wskazywanej * (operator adresowania pośredniego) W wyrażeniu *Op, operand Op musi być wskaźnikiem. Wartością wyrażenia jest zmienna wskazywana przez Op (czyli l-wartość), zaś jego typ zgodny z typem wskazywanym operandu. Jeśli Op jest wskaźnikiem funkcji, wartość wyrażenia określa wskazywaną funkcję. Wartość wyrażenia jest nieokreślona w 2 przypadkach: wyrażenie Op zawiera adres pusty (NULL) wyrażenie Op jest wskaźnikiem zmiennej automatycznej, zadeklarowanej w bloku, którego wykonanie zostało już zakończone. Przykład: #include <stdio.h> void main() { int i=10, *pi; pi = &i; printf("Adres pi=&i = %p *pi=20; printf("Adres pi=&i = %p getchar(); } *pi= %d i= %d\n",pi, *pi, i); *pi= %d i= %d",pi, *pi, i); Wydruk: Adres pi=&i = 4A27:2222 Adres pi=&i = 4A27:2222 *pi= 10 *pi= 20 Przykład na operatory & i * oraz tablice #include <stdio.h> int main(void) { int tab[3], *ptr=tab; int (*p)[]=&tab, i; ptr[0]=5; *(ptr+1)=10; (*p)[2]=2; for (i=0; i<3; i++) printf("\nTab[%d]=%d",i,tab[i]); return 0; } Wydruk: Tab[0]=5 Tab[1]=10 Tab[2]=2 Przykład na operatory & i * z funkcjami i= 10 i= 20 Wersja 1 #include <stdio.h> int func(int i); int main(void) { int (*pf1)(int)=func, (*pf2)(int); // int i; pf2=*pf1; printf("%d\n",pf1(10)); printf("%d\n",(*pf2)(20)); return 0; } int func(int i) { return i*i; } Wersja 2 - z typedef #include <stdio.h> int func(int i); typedef int (*PFUNC)(int); void main(void) { PFUNC pf1=func, pf2; pf2=*pf1; printf("%d\n",pf1(10)); printf("%d\n",(*pf2)(20)); } int func(int i) { return i*i; } Wydruk: 100 Operatory wyboru składowej . -> W celu odwołania się do skłądowych struktury, unii lub klasy (w C++) należy posłużyć się jednym z operatorów wyboru skłądowej: Op.identyfikator_składowej Op->identyfikator_składowej Operator . (kropka) umożliwia odwołanie do składowej struktury, unii lub klasy (C++) określonej przez operand Op, operator -> (minus, większe) zaś odwołanie do skłądowej struktury, unii lub klasy (C++) wskazywanej przez operand Op. Wartość i typ wyrażenia są określone typem i wartością składowej, do której nastąpiło odwołanie. Wartość wyrazeń jest l-wartością, jeśli l-wartością jest operand Op. Przykład: #include <iostream.h> struct PUNKT { double x,y; }; void main() { struct PUNKT P, *pPt; P.x=P.y=10.5; cout << "P.x= " << P.x << " P.y=" << P.y << '\n'; pPt= &P; pPt->x=12.5; pPt->y=13.5; cout << "P.x= " << P.x << " P.y=" << P.y << '\n'; cout << "pPt->x=" << pPt->x << " pPty->y=" << pPt->y; } Wydruk: P.x= 10.5 P.y=10.5 P.x= 12.5 P.y=13.5 pPt->x=12.5 pPty->y=13.5 W językach tych powstają aplikacje dla różnych systemów operacyjnych, w tym m.in. dla Windows, Unix, Linux, MacOS, BeoS. Do pisania programów można wykorzystywad edytory narzędzi programistycznych jak: Borlanda: Turbo C, Borland C, Borland C++ Builder Microsoft Visual C++, Dev C++, CodeBlocks Można użyd dowolnego edytora tekstowego zapisującego pliki w postaci czystego kodu ASCII, typu Notatnik, Edit lub np. Notepad, który pozwala sprawdzad składnię i podkolorowuje odpowiednio tekst po wybraniu języka. Do kompilacji można użyd środowiska programistycznego Borland C++ Compiler 5.5. Kompilator ten jest darmowy, generuje 32-bitowy kod dla Windows, zawiera tylko niezbędne narzędzia uruchamiane z linii poleceo, jest prosty w instalacji i konfiguracji. Najlepiej zainstalowad w C:\BCC55. W katalogu tym są podkatalogi: BIN, INCLUDE, LIB, HELP, EXAMPLES. Pliki konfiguracyjne w katalogu C:\BCC55\BIN Zawartośd plików Plik BCC32.cfg -I"c:\Bcc55\include" -L"c:\Bcc55\lib" Plik ILINK32.cfg - składa się z jednej linii -L"c:\Bcc55\lib" Można też dodad katalog C:\BCC%%\BIN do ścieżki wyszukiwania – dopisad w wierszu poleceo PATH=%PATH%;C:\BCC55\BIN Kompilacja programów przy pomocy BCC32: Bcc32 program.c lub bcc32 program cpp Program Turbo C – TC.EXE, kompilator TCC.exe -IC:\TC\INCLUDE -LC:\TC\LIB Objaśnienia: Instrukcja #include poleca kompilatorowi dołączyć do programu plik stdio.h (tzw. pseudonagłówkowy), w którym zawarta jest m.in. definicja funkcji printf. Bardzo często używa się też innych plików pseudonagłówkowych, np. conio.h, math.h itp. Wszystkie pliki *.h zawarte w nawiasach <> znajdują się w podkatalogu INCLUDE. Druga linijka z main zawiera rozpoczęcie funkcji głównej programu czyli main(). Nagłówek void main() to inaczej void main(void) void przed mian oznacza, że funkcja nie zwraca żadnego wyniku. (void )w nawiasie po main oznacza brak parametrów programu. Deklaracja funkcji main może mieć inne formy, np. int main() - funkcja w wyniku swojego działania zwróci wartość typu int i nie pobiera żadnych parametrów przy rozpoczęciu działania. int main(void) - inny zapis, ale znaczenie takie samo jak wyżej main() - jeszcze inny zapis, ale znaczenie takie samo jak wyżej float main() - w tym przypadku wynikiem działania funkcji będzie typ float. int main(int argc, char *argv[]) Po linii z main zaczyna się nawiasem klamrowym otwierającym { ciało (treść) funkcji głównej i kończy na końcu nawiasem zamykającym } Wewnątrz funkcji głównej jest instrukcja printf, powodująca wyświetlenie na ekranie tekstu, będącego jej parametrem (tekst w nawiasach w cudzysłowie). Instrukcje kończymy średnikiem. Po skompilowaniu czarny ekran i zaraz znika i dlatego trzeba dokonać modyfikacji programu. Uruchamiamy edytor Edit lub notatnik, zapisujemy plik pod inną nazwą, np. p1a.c i modyfikujemy // program p1a.c // to jest komentarz w jednej linii /* to jest też komentarz, może mied kilka linii, dłuższy, ograniczony */ #include <stdio.h> // dołączenie pliku nagłówkowego z biblioteki systemowej // potrzebny do wywołania instrukcji printf #include <conio.h> // dołączenie pliku conio.h do funkcji getch() i clrscr() int main() //funkcja główna main { // początek main clrscr(); // kasowanie ekranu printf("Nazwisko Imie: Pierwszy program w C – zmodyfikowany "); printf("\nNacisnij jakis klawisz "); getch(); // czeka na jakiś klawisz return 0; // funkcja główna zwraca 0 przy pomyślnym wyniku zakooczenia } // koniec funkcji głównej main Kompilacja: BCC32 p1a.c – w wyniku program skompilowany p1a.exe Po uruchomieniu: p1a W programie wprowadzono funkcje clrscr() – kasowanie ekranu oraz getch() – program czeka na naciśnięcie dowolnego klawisza. Definicje tych funkcji są w pliku conio.h, dlatego jest on dopisany w dyrektywie #include <conio.h>/ Zamiast getch() , można zastosowad getchar() lub while(!kbhit()) \n to znak specjalny – powoduje przejście do nowej linii. Podobnie \t – tabulacja, \a – sygnał dźwiękowy. Komentarze – oznaczone // - jednolinijkowy oraz oznaczone /* komentarz */ - dłuższe, mogą zawierad wiele linii Kompilator nie czyta komentarzy, stosuje się dla wyjaśnienia programu. Podsumowanie // program p1d.c #include <stdio.h> #include <conio.h> int main() { clrscr(); printf("Program p1d.c - podsumowanie\n"); printf("\nProgramy w C i C++ maja rozszerzenie c oraz cpp\n"); printf("Na poczatku programu #include i pliki z definicjami instrukcji\n"); printf("np. #include <stdio.h> do funkcji printf(), conio.h do clrscr()\n"); printf("\nDeklarujemy funkcje main(), np. int main() \n"); printf("Cialo funkcji main() jest w nawiasach { }\n"); printf("W ciele funkcji glownej wypisujemy wszystkie instrukcje (zakonczone srednikiem) \n"); printf("Mamy 2 rodzaje komentarzy: // - jednoliniowy oraz /* wieloliniowy */\n"); printf("\nAby zatrzymac pracc programu, uzywamy funkcji getch(); lub getchar(); \n"); printf("Do czyszczenia ekranu szuzy funkcja clrscr();. \n"); printf("Na koncu funkcji main jest return 0; - co funkcja zwraca\n"); printf("W programie mozemy uzywac tzw. znakow specjalnych, np. \\n - nowa linia. \n"); printf("\nNacisnij cos "); getchar(); return 0; TYPY ZMIENNYCH I WZORCE KONWERSJI Zmienne służą do tego, aby zapamiętać sobie tymczasową wartość (którą potem można zmienić w każdej chwili według potrzeby). Typy zmiennych: char - typ znakowy int - liczba całkowita float - liczba zmiennoprzecinkowa (rzeczywista) short - liczby całkowite krótkie long - liczby całkowite długie double - liczby zmiennoprzecinkowe podwójnej precyzji long double - liczby zmiennoprzecinkowe podwójnej precyzji długie Operatory Operacje arytmetyczne przypominają konwencjonalny matematyczny zapis. Również kolejność działań jest identyczna jak w matematyce. Najczęściej używane operatory: +, -, *, /, = % ++, -! <, > <=, >= dodawanie, odejmowanie, mnożenie, dzielenie, operator przypisania reszta z dzielenia (odpowiada operacji modulo) inkrementacja i dekrementacja negacja mniejsze, większe nie większe, nie mniejsze &&, || == +=, -=, *=, /= i, lub (logicznie) równe połączenie operatorów przypisania i innych Inkrementacja jest to proces zwiększenia zmiennej o 1, a dekrementacja zmniejszenia o 1. Zmienną a możemy inkrementować na dwa sposoby: a=a+1; a++; - sposób tradycyjny - sposób krótszy, w języku C/C++ Język C/C++ Sposób tradycyjny (też w C/C++) a+=10; a=a+10; b-=30; b=b-30; a*=20; a=a*20; b/=5; b=b/5; Programy przy zastosowaniu typów zmiennych i operacji matematycznych. możemy zabrać się za pisanie następnego programu. Najprostszym przykładem użycia zmiennych jest prosty kalkulator. Program, który poprosi nas o wpisanie dwóch liczb i wykona na nich podstawowe działania matematyczne: zsumuje je, odejmie, pomnoży i podzieli. Na początku program musi wczytać dwie liczby: //Program p2a.c // Wczytuje 2 liczby całkowite I wyświetla na ekranie #include <stdio.h> #include <conio.h> Int main () { int a,b; //deklaracja zmiennych a i b clrscr(); printf("Podaj liczbe a: "); scanf("%d",&a); // wczytanie liczby a printf("Podaj liczbe b: "); scanf("%d",&b); // wczytanie liczby b printf("Wpisane liczby a i b : %d, %d.\n",a,b); printf("\nNacisnij Enter "); getch(); // czekanie na Enter return 0 ; } Typ int (integer) oznacza, że zmienna może przyjmować wartości całkowite z zakresu +/- 32767. Jeżeli zamierzamy używać w programie dużych liczb wtedy zamiast typu int używamy typu long. Kompilator już wie, że w kodzie programu będą pojawiać się zmienne a i b i wie ile pamięci musi zarezerwować na ich przechowanie. Następnie wypisujemy na ekranie komunikat, który prosi nas o wpisanie liczby. Program zatrzyma się w tym miejscu i będzie czekał dotąd, aż napiszemy liczbę i zatwierdzimy je ENTERem. Funkcja scanf() służy do odczytu wprowadzonych danych z klawiatury Wzorzec konwersji określa typ zmiennej, którą wpiszemy z klawiatury lub wypiszemy na ekranie. Poniższa tabela przedstawia deklaracje zmiennych określonego typu, odpowiednie dla nich wzorce konwersji oraz przykłady ich użycia: Deklaracja Wzorzec Postać funkcji scanf() Postać funkcji printf() printf("Liczba A wynosi: liczba całkowita int A %d scanf("%d",&A); %d",A); liczba printf("Liczba B wynosi: float B %f scanf("%f",&B); %f",B); rzeczywista Typ zmiennej ciąg znaków char *C pojedynczy znak char D %s scanf("%s",&C); printf("Łańcuch ma postać: %s",C); %c scanf("%c",&D); printf("Znak D to: %c",D); Program zmodyfikowany, wykonujacy podstawowe obliczenia matematyczne //Program p2b.c #include <stdio.h> #include <conio.h> int main() { int a,b; //deklaracja zmiennych całkowitych a i b int suma,roznica,iloczyn; float iloraz; clrscr(); printf("Prosty kalkulator\n"); printf("\nPodaj liczbe a: "); scanf("%d",&a); printf("Podaj liczbe b: "); scanf("%d",&b); suma=a+b; roznica=a-b; iloczyn=a*b; iloraz=(float)a/(float)b; // operator rzutowania w dzieleniu printf("\nWyniki dzialan:\n"); printf("\nSuma: %d ",suma); printf("\nRoznica: %d ",roznica); printf("\nIloczyn: %d ",iloczyn); printf("\nIloraz: %f ",iloraz); getch(); return 0 ; }