Tadeusz KLASEK
WITAM
NA
WYKŁADZIE
Wbrew powszechnie panującym
opiniom programowanie jest
gałęzią magii.
W Nowej Encyklopedii Powszechnej PWN możemy
znaleźć następujące określenie magii: „zespół
działań, zasadniczo pozaempirycznych,
symbolicznych, których celem jest bezpośrednie
osiągnięcie [...] pożądanych skutków [...]”.
Wyróżniamy przy tym następujące składniki działań
magicznych:
zrutynizowane działania (manipulacje),
materialne obiekty magiczne (amulety, eliksiry itp.),
reguły obowiązujące przy praktykach magicznych
(zasady czystości, reguły określające czas i miejsce
rytuałów),
formuły tekstowe mające moc sprawczą (zaklęcia).
Programowanie mieści się w ramach
ostatniego z powyższych punktów –
użycie zaklęć.
Programy komputerowe są zapisanymi w specjalnych
językach (zwanymi językami programowania) zaklęciami.
Zaklęcia te są przeznaczone dla specjalnego rodzaju
duchów żyjących w komputerach, zwanych procesami
obliczeniowymi.
Ze względu na to, że komputery są obecnie
produkowane seryjnie, stwierdzenie to może budzić
kontrowersje. Zastanówmy się jednak chwilę, czym
charakteryzują się duchy. Są to obiekty niematerialne,
zdolne do działania. Procesy obliczeniowe ewidentnie
spełniają te warunki: nie można ich dotknąć ani
zobaczyć, nic nie ważą, a można obserwować ich skutki
działania czy wręcz uzyskać od nich interesujące nas
informacje.
Jako adepci magii związanej z
zaklinaniem procesów obliczeniowych
będziemy nazywać siebie
informatykami.
W naszych działaniach będziemy
sobie stawiać cele, które chcemy
osiągnąć i, używając rozumu,
będziemy formułować zaklęcia
mające zmusić procesy obliczeniowe
do doprowadzenia do postawionych
celów oraz upewniać się, że cele te
będą osiągnięte.
Czarowanie
Formułowane zaklęcia będziemy nazywać
programami, a ich formułowanie
programowaniem. Upewnianie się, co do
skutków zaklęć będziemy nazywać
weryfikacją programów.
Chociaż Procesy obliczeniowe imponują
szybkością, nie są zbyt inteligentnymi
duchami. Dlatego też programy muszą
szczegółowo opisywać czynności, jakie
mają wykonać te duchy.
ABRAKADABRA
Sposób postępowania opisany przez
program, w oderwaniu od sposobu jego
zapisu w konkretnym języku programowania,
będziemy nazywać algorytmem.
Procesy obliczeniowe zmieniają dane.
Nasze zaklęcia wyrażają w określonym
języku (programowania) przepis na
przetwarzanie danych
Program = algorytm+dane+język
Języki i systemy
Języki programowania C i C++
Nowego języka uczymy się nie tylko dla poznania nowej
składni (i robienia po staremu), lecz głównie w celu
nauczenia się nowego, lepszego budowania systemów
Z nowymi możliwościami można zostać lepszym projektantem
łatwiej i szybciej, ale nie aż tak łatwo i szybko, jak się wielu
marzy
B. Stroustrup
Literatura
Turbo Pascal i Borland C++ Przykłady Jakubczyk K.
Jak przejść z TP na C++ Shammas N.M.
Symfonia C++ autorstwa Jerzego Grębosza
ABC programowania w C++ Autor: Jan Rusek
PODSTAWY JĘZYKA C++ Lippman S.B., Lajoie J.
Czym jest C/C++
Język programowania
- wysokiego poziomu
- proceduralny, algorytmiczny, obiektowy
- uniwersalny
Bardzo popularny wśród programistów
Dobry program w C jest nim w C++
Każdy z nas korzysta z produktów tych
(głównie C++) języków – prawie wszystkie
interfejsy (MSWindows, Mac, X Unixa/Linuxa)
i znaczna część samych systemów
Oba języki
Rozwiązania językowe są odpowiedzią na
konkretne problemy z jakimi spotkali się
autorzy i użytkownicy, a mówiąc mniej
elegancko – logika języka C została
„nadbudowana” na sztuczkach i skrótach
wprawnych programistów
Mają długi czas porodu – C (Kernigham) z
inspiracji BCPL (Richards) – języka sprawnego
pisania niskopoziomowego (lata 70-te)
Oba języki
Są bardzo podobne, język C++
(Stroustroup) jest nadzbiorem C
Zmiany w C++ były inspirowane j. Simula
67, Algol 68, Ada i Clu (podobnie jak
Pascal/Delphi/Kylix)
C++ jest nieco późniejszy (pierwsza wersja
’83 a komercyjna ’85, standaryzacja do 98)
Istnieje wiele różnic implementacyjnych tak
w obrębie C (ANSI C) jak i C++
C/C++
Języki te są „czystym” sposobem opisu
struktur i akcji – WSZYSTKO INNE POCHODZI
Z ZEWNĘTRZNYCH BIBLIOTEK (WE/WY TEŻ)
„Raport języka” – najważniejszy dokument
definiujący – mógł zawierać tylko elementy
wspólne dla rozmaitości warunków
środowiskowych w jakich funkcjonował
(z podkreśleniem sprawnego pisania
niskopoziomowego)
Tworzenie programu
Tworzenie programu odbywa się w
dwóch etapach:
opracowanie kodu źródłowego, który jest
plikiem tekstowym zawierającym zapis
algorytmu i opis struktur danych oraz
komentarze i dyrektywy
generowanie kodu wynikowego –operacja ta
składa się z dwóch faz: kompilacji i
linkowania czyli łączenia
Co robi kompilator i
linker?
Kompilator - Tworzy z naszego programu
wersję programu w języku maszyny.
Jest ona jednak niepełna - brakuje tam
wywoływanych przez nas
funkcji bibliotecznych. Tym zajmie się
Linker - łączy on kod po kompilacji ze
wskazanymi bezpośrednio lub pośrednio
bibliotekami.
UWAGA ORTODOKSI
Fazy kompilacji i linkowania mogą być
realizowane przez „ręczne” ich
uruchomienia
W sieci istnieje wiele (także darmowych)
wersji kompilatorów/linkerów
Istnieje też wiele aplikacji tworzących
środowisko ułatwiające proces
edycji/kompilacji/linku/debugowania
Jak wygląda tekst
programu?
W każdym programie musi być
funkcja
o nazwie main. Od niej rozpoczyna się
działanie programu.
Wszystkie zdania tej funkcji są
zawarte pomiędzy znakami { oraz }.
Każda instrukcja kończy się znakiem ;
(średnik).
Struktura programu
źródłowego
1. dyrektywy dołączające pliki nagłówkowe bibliotek
standardowych i zdefiniowanych przez użytkownika
2. prototypy funkcji lub definicje funkcji
3. deklaracje zmiennych globalnych
4. słowo kluczowe main()
5. klamra {
6. deklaracje zmiennych lokalnych
7. treść programu (a właściwie funkcji głównej)
8. klamra }
9. definicje funkcji
Pascal a C
C (a zwłaszcza C++) jest bardziej
elastyczny w organizacji
programów i modułów
Programy składają się z globalnych
deklaracji i jednopoziomowych
funkcji
Tekst programu
Podobnie jak w Pascalu ale UWAGA
w C zawsze a w C++ opcjonalnie (ale
standardowo) rozróżnia się małe i duże
litery
Słowa kluczowe zawsze pisze się małymi
Układ typograficzny nie ma znaczenia
Komentarze /* .......... */
a w C++ dodatkowo // ... Do końca wiersza
/* A oto nasz pierwszy program */
#include <iostream.h>//Tu mówię kompilatorowi z jakich
// dodatkowych źródeł będę ewentualnie korzystał
main()//Ta funkcja musi się znajdować w każdym programie
{ //Ciało funkcji zaczyna się znakiem {
cout << "To program pierwszy";//Tu właśnie wypisuje tekst na
//standardowe urządzenie wyjściowe
//(tu strumień - ekran)
} //Ciało funkcji kończy się znakiem }
TEKST PROGRAMU WINIEN BYĆ CZYTELNY – JEST DLA NAS
Jak wygląda program?
Uwagi ogólne cd
W języku C/C++ wszystkie „byty” muszą
być zadeklarowane przed ich użyciem
(podobnie jak we wszystkich językach
mających znaczenie praktyczne), lecz
inaczej niż np. w PL/I, Pascal, ADA itp.
instrukcje i deklaracje zmiennych
mogą być „wymieszane”
Takie deklaracje wewnątrz tekstu
obowiązują zwykle do końca bloku (zwykle
funkcji), ale są tu różnice implementacyjne
Nazwy w C
Uwaga na standardowe rozróżnianie DUŻYCH i
małych
liter
Nazwy nie mogą być tożsame ze słowami
kluczowymi: asm auto break case catch char
class const continue default delete do
double else enum extern float for
friend goto if inline int long
new operator private protected public register
return short signed sizeof static struct
switch template this throw try typedef
union unsigned virtual void volatile while
Styl operacji wejścia i
wyjścia
C++ oraz rodzicielski C nie posiadają
wbudowanych funkcji we/wy
To niezwykłe rozwiązanie pozwoliło na
posługiwanie się funkcjami we/wy
dostosowanymi do zastosowań (i
środowiska)
Różnica (widoczna na pierwszy rzut oka)
zaczyna się od dyrektyw dołączających pliki
nagłówkowe
Styl we/wy
Pliki nagłówkowe zawierają definicje
stałych i zmiennych globalnych oraz
funkcji (są podobne do części
INTERFACE pascalowych modułów)
stdio.h i conio.h najczęściej używane
przez programistów C, iostream.h
przez C++
Styl we/wy (C)
Wejście – funkcja scanf elastyczna
funkcja (ze zmienną liczbą parametrów)
wprowadzania danych, nazwy danych
na liście nie wystarczą – trzeba
podać ich adres &nazwa
Wyjście – funkcja printf formatująca
wyjście (uwaga: taki styl formatowania
rozpoznamy w wielu aplikacjach –
warto go przyswoić)
Styl we/wy ( C )
Wprowadzanie znaków getchar(),
łańcuchów gets()
Dla użytkowników conio.h (C
Borlanda) czyszczenie ekranu
clrscr(), czytanie znaku getch() lub
getche(), pozycjonowanie itp.
Styl C
#include <stdio.h>
int main()
{
int x=65;
printf(”Liczba jest równa”);
printf(”\nx=%d\n”,x);
return 0;
}
Styl we/wy (C++)
Nowy mechanizm rozszerzający we/wy
nazwany strumieniami. Predefiniowane
strumienie cout, cin i cerr
Strumienie używają wielu funkcji a
także operatorów: pobierania danych ze
strumienia >> i umieszczania danych w
strumieniu <<
W dyrektywach żąda się dołączenia
iostream.h
Styl C++
#include <iostream.h>
main()
{
int x=65;
cout << ”Liczba jest równa” << ”\nx=”
<< x <<”\n”;
}
Ta rzucająca się w oczy
różnica to inne biblioteki
we/wy
Operacje we/wy
Język C/C++ nie posiada zdefiniowanych instrukcji
realizujących operacje we/wy. Do tego celu służą funkcje
znajdujące się w „standardowych” bibliotekach.
standardowe strumienie predefiniowane wejścia/wyjścia
stdin
- strumień wejściowy (konsola)
stduot
- strumień wyjściowy (konsola)
stderr
- strumień komunikatów błędów (konsola)
stdaux
- strumień pomocniczy (konsola)
stdprn
- strumień drukarki
np.:
fputs (″Nazwa firmy″, stdprn);
Funkcja printf();
Składnia funkcji jest następująca:
int printf (const char *format
[,argument,...]);
Parametr format wskazuje tzw. łańcuch
formatujący. Pewne sekwencje tego łancucha
są specjalnie traktowane przez funkcje
printf().
Ogólny format sekwencji
formatującej przedstawia
się następująco:
%[flagi][szerokość][.precyzja][h|l|
L]znak-typu
flag
i
znaczenie
default
-
dosunięcie argumentu do lewego krańca
jego pola
znak tylko dla
ujemnej
+
liczba zawsze ze znakiem +/-
#
dla formatu x,X, poprzedzenie liczby 0x,
0X
dla formatu o, poprzedzenie liczby 0
dla formatu e,E,f wstawia zawsze znak
kropki
bez znaków
wiodących
Szerokość
szerokość:
n - wyświetlanych jest przynajmniej n znaków. Jeśli
wartość zajmuje mniej niż n znaków szerokość pola
jest uzupełniana dodakowymi spacjami z lewej lub
prawej strony w zależności od ustawionej flagi
int i = 12;
printf (y=%#x,y); y=0xc.
int y=23;
printf (y=%6d,y); y = 23_
printf (y=%-6d,y); y =23 _
printf (y=%+6d,y);
y = +23 _
Znak typu
znak argument
wejściowy
argument wejściowy
d ,i
całkowity
liczba dziesiętna ze znakiem
o
całkowity
liczba ósemkowa bez znaku
x,X
całkowity
liczba szesnastkowa bez znaku
u
całkowity
liczba dziesiętna bez znaku
c
znak
pojedynczy znak
s
wskaźnik
łańcucha
ciąg znaki łańcucha, aż do wystapienia ‘\0’ lub tyle ile
określono w precyzji
f
zmiennoprzecinko
wy
[-]m.ddd gdzie liczbę cyfr d określa precyzja
(domyślnie 6).
e, E
zmiennoprzecinko
wy
[-]m.dde+-xx. Przed kropką dokładnie jedna cyfra, liczba
cyfr po kropce zależna od precyzji(domyślnie 6).
g, G
zmiennoprzecinko
wy
liczba będzie wyświetlana w postaci e lub f w zależności
od zadanej precyzji. Nie wypisuje zbędnej kropki
dziesiętnej i nie znaczących zer.
Modyfikatory
znaczenie
h
argument traktowany jak typu short int dla
znaków typu d,i,o,u,x,X
l
argument traktowany jak long int dla znaków
typu d,i,o,u,x,X
dla znaków e, E, g, G jako typu double
L
argument traktowany jak long double dla
znaków typu e,E,f,g,G
Precyzja
znak
typu
znaczenie
d,i,o,u,x,X n cyfr znaczących zostanie
wydrukowanych, jeśli jest ich mniej
uzupełnienie zerami z lewej strony.,
jeśli więcej nie będzie obcięta.
e,E, f
n cyfr znaczących zostanie
wydrukowanych po przecinku
dziesiętnym. Ostatnia cyfra jest
zaokrąglana.
s
co najmniej n znaków zostanie
wydrukowanych
Domyślne
Przyjmowane precyzje domyślne:
1 - dla znaków typu d, i ,o, u, x, X
6 - dla znaków typu e, E, f
- wszystkie cyfry znaczące dla znaków typu G, g
- łańcuchy są drukowane do pierwszego znaku
‘\0’., znaków c nie dotyczy.
Jeśli wartość zajmuje mniej niż n znaków szerokość
pola jest uzupełniana dodatkowymi
spacjami z
lewej lub prawej strony w zależności od ustawionej
flagi.
Wejście C
Funkcja scanf()
Funkcja scanf() służy do realizacji formatowanego
wejścia. Składnia tej funkcji jest następująca:
int scanf (const char* format [,address, ...]);
Parametr format wskazuje tzw. łańcuch formatujący.
łańcuch ten zawiera sekwencje określające typy
wprowadzanych danych.
Funkcja wczytuje znaki ze standardowego wejścia,
interpretuje je zgodnie ze specyfikacjami zawartymi w
formacie i zapamiętuje wyniki w miejscach
określonych przez pozostałe argumenty.
Argumenty muszą być adresami, określają adres
obszaru pamięci gdzie dane mają być umieszczone.
Ogólny format sekwencji formatującej
przedstawia się następująco:
%[*][szerokość][h|l|L] znak-typu.
*
oznacza, że dane pole zostanie odczytane ale nie
zostanie zapamiętane we wskazanym miejscu
szerok
ość
określa maksymalną liczbę znaków danego pola
znak-
typu
tak jak opisane w funkcji printf(), dodatkowo można
używać dużych liter:
D, O, I, U
gets() i puts()
Funkcja gets(), puts()
char *gets (char *s); // #include <stdio.h>
Funkcja odczytuje znaki ze standardowego
strumienia wejściowego (stdin) i umieszcza je
w łańcuchu s;
char znaki[20];
gets (znaki);
Czytanie jest przerywane po napotkaniu znaku
końca wiersza, który zostaje zamieniony na
znak końca łańcucha(NULL).
Operatory - duuużo
Priorytety operatorów (od najwyższego) podaję zestawienie:
15.
() [] ->
L (zagnieżdżenia)
14.
! ~ ++ -- + - * & sizeof
P (unarne)
13.
* / %
L (mnożenia)
12.
+ -
L (sumy)
11.
<< >>
L (bitowe)
10.
< <= > >=
L (relacji)
9.
== !=
L (relacji)
8.
&
L (bitowe)
7.
^
L (bitowe)
6.
|
L (bitowe)
5.
&&
L (logiczne)
4.
||
L (logiczne)
3.
? :
P (z wyborem)
2.
= += -= *= /= %= ^= |= <<= >>= P (podstawienia)
1.
,
L (przecinkowe)
JAK WIDAĆ NIEWIELE ZNAKÓW A WIELE ZNACZEŃ