Informa cz2 v5 id 213359 Nieznany

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

1

PODSTAWY

PROGRAMOWANIA

kurs I - część 2

PROWADZĄCY: dr inż. Marcin Głowacki

E-Mail:

Marcin.Glowacki@pwr.wroc.pl

Pok.907 C-5

Wrocław 2011

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

2

3.

INSTRUKCJE WEJŚCIA – WYJŚCIA


Operacje wejścia-wyjścia służą do bezpośredniej komunikacji użytkownika z programem
poprzez ekran i klawiaturę oraz do zapisu i odczytu danych z plików a także urządzeń
peryferyjnych.

W języku C występują funkcje

standardowe wejścia-wyjścia

zdefiniowane w pliku

nagłówkowym (ang. header)

<stdio.h>


W C++ używane są obiekty klas

istream

i

ostream

tzw. strumienie wejścia – wyjścia (ang.

streams).

INSTRUKCJE WYJŚCIA


Funkcja

printf

int

printf

( const char *format [, argumenty]... );


Inne funkcje z rodziny printf to:
fprintf, sprintf i snprintf


Parametry:

format

– ciąg znaków definiujący format, w jakim zostaną wypisane kolejne argumenty

%

[

flagi

] [

szerokość

] [.

precyzja

] [{h | l | I | I32 | I64}]

typ

określenie

typu

formatu.

o

opcjonalne użycie dowolnej liczby flag,

o

opcjonalne określenie minimalnej szerokości pola,

o

opcjonalne określenie precyzji – dokładności wyświetlanych liczb,

o

opcjonalne określenie rozmiaru argumentu,

Typ

Funkcje z rodziny

printf

obsługują następujące typy formatów:

d, i

- argument typu int jest przedstawiany jako liczba całkowita ze znakiem w postaci

[-]ddd

.

o, u, x, X

- argument typu unsigned int jest przedstawiany jako nieujemna liczba

całkowita zapisana w systemie oktalnym (

o

), dziesiętnym (

u

) lub heksadecymalnym (

x

i

X

).

f, F

- argument typu double jest przedstawiany w postaci

[-]ddd.ddd

.

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

3

e, E

- argument typu double jest reprezentowany w postaci

[i]d.ddde+dd

, gdzie liczba

przed kropką dziesiętną jest różna od zera, jeżeli liczba jest różna od zera, a + oznacza
znak wykładnika. Format E używa wielkiej litery E zamiast małej.

g, G

- argument typu double jest reprezentowany w formacie takim jak f lub e

(odpowiednio F lub E) zależnie od liczby znaczących cyfr w liczbie oraz określonej
precyzji.

a, A

- argument typu double przedstawiany jest w formacie [-]0xh.hhhp+d czyli

analogicznie jak dla e i E, tyle że liczba zapisana jest w systemie heksadecymalnym.

c

- argument typu int jest konwertowany do unsigned char i wynikowy znak jest

wypisywany. Jeżeli podano modyfikator rozmiaru l argument typu wint_t konwertowany
jest do wielobajtowej sekwencji i wypisywany.

s

- argument powinien być typu wskaźnik na char (lub wchar_t). Wszystkie znaki z

podanej tablicy, aż do i z wyłączeniem znaku null są wypisywane.

p

- argument powinien być typu wskaźnik na void. Jest to konwertowany na serię

drukowalnych znaków w sposób zależny od implementacji.

n

- argument powinien być wskaźnikiem na liczbę całkowitą ze znakiem, do którego

zapisana jest liczba zapisanych znaków.

Flagi

W sekwencji możliwe są następujące flagi:

-

(minus) oznacza, że pole ma być wyrównane do lewej, a nie do prawej.

+

(plus) oznacza, że dane liczbowe zawsze poprzedzone są znakiem (plusem dla liczb

nieujemnych lub minusem dla ujemnych).

spacja

oznacza, że liczby nieujemne poprzedzone są dodatkową spacją; jeżeli flaga plus i

spacja są użyte jednocześnie to spacja jest ignorowana.

#

(

hash

) powoduje, że wynik jest przedstawiony w alternatywnej postaci:

o

dla formatu

o

powoduje to zwiększenie precyzji, jeżeli jest to konieczne, aby na

początku wyniku było zero;

o

dla formatów

x

i

X

niezerowa liczba poprzedzona jest ciągiem

0x

lub

0X

;

o

dla formatów

a, A, e, E, f, F, g, G

wynik zawsze zawiera kropkę nawet jeżeli nie

ma za nią żadnych cyfr;

o

dla formatów

g

i

G

końcowe zera nie są usuwane.

0

(

zero

) dla formatów

d, i, o, u, x, X, a, A, e, E, f, F, g, G

do wyrównania pola

wykorzystywane są zera zamiast spacji za wyjątkiem wypisywania wartości
nieskończoność i NaN. Jeżeli obie flagi

0

i

-

są obecne to flaga zero jest ignorowana. Dla

formatów

d, i, o, u, x, X

jeżeli określona jest precyzja flaga ta jest ignorowana.

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

4

Szerokość pola i precyzja

Minimalna szerokość pola oznacza ile najmniej znaków ma zająć dane pole. Jeżeli wartość po

formatowaniu zajmuje mniej miejsca jest ona wyrównywana spacjami z lewej strony (chyba, że
podano flagi, które modyfikują to zachowanie). Domyślna wartość tego pola to 0.
Precyzja dla typów formatów określa:

d, i, o, u, x, X

- minimalną liczbę cyfr, które mają być wyświetlone i ma domyślną

wartość 1;

a, A, e, E, f , F

- liczbę cyfr, które mają być wyświetlone po kropce i ma domyślną

wartość 6;

g, G

- liczbę cyfr znaczących i ma domyślną wartość 1;

s

- maksymalną liczbę znaków, które mają być wypisane.

Szerokość pola może być albo dodatnią liczbą zaczynającą się od cyfry różnej od zera albo

gwiazdką. Podobnie precyzja z tą różnicą, że jest jeszcze poprzedzona kropką. Gwiazdka
oznacza, że brany jest kolejny z argumentów, który musi być typu int. Wartość ujemna przy
określeniu szerokości jest traktowana tak jakby podano flagę - (minus).


Rozmiar argumentów:

[{h | l | I | I32 | I64}]

Dla formatów

d

oraz

i

można użyć jednego z przykładowych modyfikatorów rozmiaru:

h

- oznacza, że format odnosi się do argumentu typu

short

,

l

(małe L) - oznacza, że format odnosi się do argumentu typu

long

,

I32

– oznacza, że format odnosi się do argumentu typu

_int32

I64

– oznacza, że format odnosi się do argumentu typu

_int32

I

- oznacza, że format odnosi się do argumentu typu

ptrdiff_t

, który jest

__int32

na

platformach 32-bitowych oraz

__int64

na 64-bitowych

Dla formatów typu

o, u, x, X

można użyć takich samych modyfikatorów rozmiaru jak dla

formatu

d

i oznaczają one, że format odnosi się do argumentu odpowiedniego typu bez znaku, a

dla rozmiaru I oznacza, że format odnosi się do argumentu typu

size_t

, który jest

unsigned

__int32

na platformach 32-bitowych oraz

unsigned __int64

na 64-bitowych

Dla formatu typu

n

można użyć takich samych modyfikatorów rozmiaru jak dla formatu

d

i

oznaczają one, że format odnosi się do argumentu będącego wskaźnikiem na dany typ.

Wartość zwracana

Jeżeli funkcje zakończą się sukcesem zwracają

liczbę znaków

w tekście

wypisanym na

standardowe wyjście

, do podanego strumienia lub tablicy znaków, nie wliczając kończącego '\0'.

W przeciwnym wypadku zwracana jest liczba ujemna.

Znaki specjalne

Aby wydrukować znaki specjalne należy je poprzedzić znakiem backslash:

printf("Procent: %% Backslash: \\");

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

5

Efekt:

Procent: % Backslash: \

Dygresja

:

Funkcja

wprintf

jest wersją z szerokimi znakami (ang.wide-character) funkcji printf; format jest

wtedy ciągiem wchar_t . Funkcje wprintf and printf zachowują się identycznie.

API (ang. Application Programming Interface) z „wąskimi” znakami nadaje się tylko do
kodowań, w których jeden znak zajmuje jeden bajt.

API z „szerokimi” znakami nadaje się do dowolnych kodowań obsługiwanych przez system, przy
czym programista musi podawać ciągi wchar_t (jeden cchar_t może zawierać kilka wchar_t, jeśli
to jest znak z osobno kodowanymi akcentami)

.

Przykład:

[msdn.microsoft.com]

// crt_printf.c
/* This program uses the printf function
* to produce formatted output.
*/

#include <stdio.h>

int main(){
char ch = 'h', *string = "computer";
int count = -9234;
double fp = 251.7366;
wchar_t wch = L'w', *wstring = L"Unicode";

/* Display integers. */
printf( "Integer formats:\n"
" Decimal: %d Justified: %.6d Unsigned: %u\n",
count, count, count );
printf( "Decimal %d as:\n Hex: %Xh C hex: 0x%x Octal: %o\n",
count, count, count, count );
/* Display in different radixes. */
printf( "Digits 10 equal:\n Hex: %i Octal: %i Decimal: %i\n",
0x10, 010, 10 );
/* Display characters. */

printf("Characters in field (1):\n%10c%5hc%5C%5lc\n", ch, ch, wch, wch);
wprintf(L"Characters in field (2):\n%10C%5hc%5c%5lc\n", ch, ch, wch, wch);

/* Display strings. */
printf("Strings in field (1):\n%25s\n%25.4hs\n %S%25.3ls\n",

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

6

string, string, wstring, wstring);
wprintf(L"Strings in field (2):\n%25S\n%25.4hs\n %s%25.3ls\n",
string, string, wstring, wstring);

/* Display real numbers. */
printf( "Real numbers:\n %f %.2f %e %E\n", fp, fp, fp, fp );

/* Display pointer. */
printf( "\nAddress as: %p\n", &count);

/* Count characters printed. */
printf( "\nDisplay to here:\n" );
printf( "1234567890123456%n78901234567890\n", &count );
printf( " Number displayed: %d\n\n", count );
}

Efekt:

Integer formats:
Decimal: -9234 Justified: -009234 Unsigned: 4294958062
Decimal -9234 as:
Hex: FFFFDBEEh C hex: 0xffffdbee Octal: 37777755756
Digits 10 equal:
Hex: 16 Octal: 8 Decimal: 10
Characters in field (1):
h h w w
Characters in field (2):
h h w w
Strings in field (1):
computer
comp
Unicode Uni
Strings in field (2):
computer
comp
Unicode Uni
Real numbers:
251.736600 251.74 2.517366e+002 2.517366E+002

Address as: 0022FF6C

Display to here:
123456789012345678901234567890
Number displayed: 16

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

7

Funkcja

puts

Identyczna w działaniu do wywołania: printf("%s\n", argument); może jednak działać szybciej.
Zawsze na końcu wysyłany jest znak przejścia do nowej linii.

Przykład:

#include <stdio.h>

int main(){
puts("Hello world!");
return 0;
}

Efekt:
Hello world!

Funkcja

fputs


Podobnie jak puts, z argumentem określającym strumień wyjścia, np. stdout lub pliku, który
został wcześniej otwarty do zapisu. Działa bez wypisania na końcu znaku przejścia do nowej
linii.

#include <stdio.h>

int main()
{
fputs("Hello world!\n", stdout); // lub stderr
return 0;
}


Efekt:
Hello world!

Funkcja

putchar


Służy do wypisywania pojedynczych znaków. Przykładowo jeżeli chcielibyśmy napisać program
wypisujący w prostej tabelce wszystkie liczby od 0 do 99 moglibyśmy to zrobić tak:

include <stdio.h>

int main() {
int i = 0;

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

8

for (; i<100; ++i) {
/* Nie jest to pierwsza liczba w wierszu */
if (i % 10) {
putchar(' ');
}
printf("%2d", i);
/* Jest to ostatnia liczba w wierszu */
if ((i % 10)==9) {
putchar('\n');
}
}
return 0;
}

INSTRUKCJE WEJŚCIA

Funkcja

scanf

Funkcja wczytuje dane ze standardowego strumienia wejścia stdin, które zwykle podłączone

jest do klawiatury, ale może również być dołączone w systemie operacyjnym do innego
strumienia wyjścia niż bufor obsługi klawiatury. Ważny jest nowy operator:

&

, gdyż bez niego

funkcja scanf() nie skopiuje odczytanej wartości liczby do odpowiedniej zmiennej. Operator

&

oznacza przekazanie do funkcji

adresu do zmiennej - wskaźnika

, aby funkcja mogła

zmodyfikować jej wartość. Dzięki temu funkcja scanf może zapamiętać odczytane z wejścia
wartości. Bez znajomości adresu (wskaźnika) do zmiennej funkcja otrzymałaby jedynie obecną
wartość zmiennej bez możliwości jej zmiany.

#include <stdio.h>

int main (){
int liczba = 0;
printf ("Podaj liczbę: ");
scanf ("%d",

&

liczba);

printf ("%d*%d=%d\n", liczba, liczba, liczba*liczba);
return 0;
}

Wczytanie ciągu znaków (tekstu) do tablicy znakowej.

#include <stdio.h>

int main()
{
char tablica[100]; /* 1 */
scanf("%s", tablica); /* 2 */
return 0;
}

Bezpieczna wersja programu z ograniczeniem na wczytywanie danych do 99 znaków

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

9

#include <stdio.h>

int main(){
char tablica[100];
scanf("%99s", tablica);
return 0;
}

Wczytanie liczby:

#include <stdio.h>

int main(){
int n;
while (scanf("%d", &n)==1) {
printf("%d\n", n*n*n);
}
return 0;
}

Wczytanie kolejno dwóch liczb:

#include <stdio.h>

int main(){
int a, b;
while (scanf("%d %d", &a, &b)==2) {
printf("%d\n", a+b);
}
return 0;
}

Trochę bardziej skomplikowany przykład. Podobnie jak poprzednio program będzie wypisywał 3
potęgę podanej liczby, ale tym razem musi ignorować błędne dane (tzn. pomijać ciągi znaków,
które nie są liczbami) i kończyć działanie w momencie, gdy nastąpi błąd odczytu lub koniec
pliku:

#include <stdio.h>

int main(){
int result, n;
do {
result = scanf("%d", &n);
if (result==1) {
printf("%d\n", n*n*n);
} else if (!result) { /* !result to to samo co result==0 */
result = scanf("%*s"); //ignorowanie zawartości bufora
}
} while (result!=EOF);
return 0;

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

10

}



Analiza:
Najpierw wywoływana jest funkcja scanf() i następuje próba odczytu liczby typu int. Jeżeli
funkcja zwróciła 1 to liczba została poprawnie odczytana i następuje wypisanie jej trzeciej
potęgi. Jeżeli funkcja zwróciła 0 to na wejściu były jakieś dane, które nie wyglądały jak liczba.
W tej sytuacji wywołujemy funkcję scanf() z formatem odczytującym dowolny ciąg znaków nie
będący białymi znakami z jednoczesnym określeniem, żeby nie zapisywała nigdzie wyniku. W
ten sposób niepoprawnie wpisana dana jest omijana. Pętla główna wykonuje się tak długo jak
długo funkcja scanf() nie zwróci wartości EOF.

Funkcja

gets -

nie należy jej używać !


Przyjmuje jeden argument - adres pierwszego elementu tablicy, do którego należy zapisać
odczytaną linię - i nic poza tym. Z tego powodu nie ma żadnej możliwości przekazania do tej
funkcji rozmiaru bufora podanego jako argument. Podobnie jak w przypadku scanf() może to
doprowadzić do przepełnienia bufora, co może mieć tragiczne skutki. Zamiast tej funkcji należy
używać funkcji fgets().

Funkcja

fgets

fgets

(

tablica_znaków, rozmiar_tablicy_znaków, stdin

);


Funkcja czyta tekst aż do napotkania znaku przejścia do nowej linii, który także zapisuje w
wynikowej tablicy (funkcja gets() tego nie robi). Jeżeli brakuje miejsca w tablicy to funkcja
przerywa czytanie, w ten sposób, aby sprawdzić czy została wczytana cała linia czy tylko jej
część należy sprawdzić czy ostatnim znakiem nie jest znak przejścia do nowej linii. Jeżeli
nastąpił jakiś błąd lub na wejściu nie ma już danych funkcja zwraca wartość NULL.

#include <stdio.h>

int main() {
char buffer[128], whole_line = 1, *ch;
while (fgets(buffer, sizeof buffer, stdin)) { /* 1 */
if (whole_line) { /* 2 */
putchar('>');
if (buffer[0]!='>') {
putchar(' ');
}
}
fputs(buffer, stdout); /* 3 */
for (ch = buffer; *ch && *ch!='\n'; ++ch); /* 4 */
whole_line = *ch == '\n';
}
if (!whole_line) {
putchar('\n');

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

11

}
return 0;
}

Analiza:
Powyższy kod wczytuje dane ze standardowego wejścia - linia po linii - i dodaje na początku
każdej linii znak większości, po którym dodaje spację jeżeli pierwszym znakiem na linii nie jest
znak większości. W linijce 1 następuje odczytywanie linii. Jeżeli nie ma już więcej danych lub
nastąpił błąd wejścia funkcja zwraca wartość NULL, która ma logiczną wartość 0 i wówczas
pętla kończy działanie. W przeciwnym wypadku funkcja zwraca po prostu pierwszy argument,
który ma wartość logiczną 1. W linijce 2 sprawdzamy, czy poprzednie wywołanie funkcji
wczytało całą linię, czy tylko jej część - jeżeli całą to teraz jesteśmy na początku linii i należy
dodać znak większości. W linii 3 najzwyczajniej w świecie wypisujemy linię. W linii 4
przeszukujemy tablicę znak po znaku, aż do momentu, gdy znajdziemy znak o kodzie 0
kończącym

ciąg znaków

albo znak przejścia do nowej linii. Ten drugi przypadek oznacza, że

funkcja fgets() wczytała całą linię.

Funkcja

getchar()

Jest to bardzo prosta funkcja, wczytująca 1 znak z klawiatury. W wielu przypadkach dane mogą
być buforowane przez co wysyłane są do programu dopiero, gdy bufor zostaje przepełniony lub
na wejściu jest znak przejścia do nowej linii. Z tego powodu wpisaniu danego należy nacisnąć
klawisz Enter, aczkolwiek trzeba pamiętać, że w następnym wywołaniu zostanie zwrócony znak
przejścia do nowej linii. Gdy nastąpił błąd lub nie ma już więcej danych funkcja zwraca wartość
EOF (która ma jednak wartość logiczną 1 toteż zwykła pętla

while (getchar())

nie da

oczekiwanego rezultatu):

#include <stdio.h>

int main(){
int c;
while ((c = getchar())!=EOF) {

//koniec gdy Ctrl-Z

if (c==' ') {

//zamiana spacji na podkreślenie

c = '_';
}
putchar(c);
}
return 0;
}

Ten prosty program wczytuje dane znak po znaku i zamienia wszystkie spacje na znaki
podkreślenia. Może wydać się dziwne, że zmienną c zdefiniowaliśmy jako trzymającą typ int, a
nie char. Właśnie taki typ (tj. int) zwraca funkcja getchar() i jest to konieczne ponieważ wartość
EOF wykracza poza zakres wartości typu char (gdyby tak nie było to nie byłoby możliwości
rozróżnienia wartości EOF od poprawnie wczytanego znaku).

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

12

STOSOWANIE FUNKCJI z rodziny

printf

i

scanf

:

Argumenty za:



są bardzo wygodne



cały szablon jest w jednym miejscu



umożliwiają łatwe dodawanie informacji nt. formatu

Przeciw:



trudno je rozszerzyć o nowe typy



kompilator nie zawsze może sprawdzić ich poprawność



mogą wystąpić problemy z bezpieczeństwem



konieczna znajomość typu każdego przetwarzanego wyrażenia

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

13

W języku

C++

w pliku nagłówkowym

<iostream>

predefiniowane są strumienie standardowe:

cout

– strumień standardowego wyjścia domyślnie skierowany na ekran;

cin

– strumień standardowego wejścia domyślnie dołączony do klawiatury

cerr

- strumień standardowego wyjścia komunikatów o błędach (errors) domyślnie skierowany na

ekran. Strumień niebuforowany – natychmiastowe powiadomienie o błędach.

clog

- strumień standardowego wyjścia komunikatów do dziennika (logu) domyślnie skierowany

na ekran. Strumień buforowany – może gromadzić komunikaty, a gdy zbierze się kilka wysłać do
dziennika co powoduje większą optymalizację pracy dziennika.

Do związania danych ze strumieniami służą operatory:

<<

i

>>

int k;

cin

>>

k;

//kierunek informacji ze strumienia cin do zmiennej k

cout

<<

”Wartość k: ”<<k; //kierunek informacji do strumienia cout ze zmiennej k


background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

14

FLAGI STANU FORMATOWANIA


Są to zasady formatowania zapisane w słowie typu

long


enum {

skipws

= 0x0001

//ignoruje białe znaki (spacje, tabulacje)

left

= 0x0002

//justowanie lewe

right

= 0x0004

//justowanie prawe

internal

= 0x0008

//justowanie ”wewnętrzne”

dec

= 0x0010

//konwersja dziesiętna

oct

= 0x0020

//konwersja ósemkowa

hex

= 0x0040

//konwersja hexadecymalna

showbase

= 0x0080

//pokaż podstawę konwersji

showpoint

= 0x0100

//pokaż kropkę dziesiętną

uppercase

= 0x0200

//wielkie litery w liczbach

showpos

= 0x0400

//znak + w liczbach dodatnich

scientific

= 0x0800

//notacja wykładnicza (naukowa)

fixed

= 0x1000

//notacja zwykła

unitbuf

= 0x2000

//buforowanie

stdio

= 0x4000

//współpraca z stdio

};

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

15

Modyfikacje stanu flag formatowania mogą być wprowadzone przy użyciu trzech metod:

przy użyciu elementarnych funkcji składowych klasy ios o nazwach:

setf

,

unsetf

złożonych funkcji składowych klasy ios, których nazwy przypominają to co robią:

width

,

precision

i

fill

.

manipulatorów – wpuszczania do strumienia specjalnych kodów zmieniających
formatowanie


Przykład użycia elementarnych funkcji składowych klasy ios o nazwach:

setf

,

unsetf

#include <iostream>
#include <cstdlib>

using namespace std;

int main() {
using std::cout; using std::endl; using std::cin;
float x=1175;

_Ios_Fmtflags stare_flagi;
cout << x <<endl; //domniemane ustawienia formatowania
cout<<"Zapamietanie flag formatowania\n";
stare_flagi=cout.flags();
cout<<"Stare flagi to: "<<hex<<cout.flags()<<endl;
cout.setf(ios::showpoint);
cout<<x<<endl;
cout.setf(ios::scientific, ios::floatfield);
cout<<x<<endl;
cout.setf(ios::uppercase);
cout<<x<<endl;
cout.unsetf(ios::showpoint); //wyłączenie flagi showpoint
cout<<x<<endl;
cout<<"Powrot do starych flag formatowania\n";
cout.flags(stare_flagi);
cout<<x<<endl;
return 0;
}

Funkcja

int width(int)

ustala rozmiar pola, na którym będzie wydrukowana liczba.

float x=1175;
cout.width(8);

//liczba będzie wyświetlana na ośmiu polach

lub

char napis[7];

//tekst o rozmiarze 6 znaków

cin.width(sizeof(napis));

cin>>napis;


Funkcja

char fill(char)

wypełnienie dla pustych miejsc, jeśli przewidziane pole jest dłuższe niż

zawartość zmiennej.

int saldo = 2573;

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

16

cout<<”stan konta: ”;

cout.width(9);

cout.fill(‘*’);

//dopelnienie gwiazdami pustych miejsc

cout << saldo<<”,-\n”;

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

17

Funkcja

int precision(int)

ustala poziom dokładności.

float x=72.435672591143;

Y = 10.55;

Z = 2;


cout << ”Domyślna dokładność to: ”<<( cout.precision() )<<endl;

cout <<”x: ”<<x<<” y: ”<<y<<” z: ”<<z<<endl;

cout.precision(8);

cout << ”Teraz dokładność to: ”<<( cout.precision() )<<endl;

cout <<”x: ”<<x<<” y: ”<<y<<” z: ”<<z<<endl

;


Manipulatory

umożliwiają wysyłanie do strumieni informacji o formatowaniu.

Występuje zestaw manipulatorów predefiniowanych w klasie ios:

bezargumentowe:

dec

,

hex

,

oct, flush, endl, ends i ws

int i=30;
cout<<i<<endl;

//postać dziesiętna

cout<<i<<” ,”<<hex<<i<<endl;

parametryzowane zdefiniowane w bibliotece

<iomanip>

.

o

setw(int)

– ustawia szerokość

#include <iomanip>
cout<<setw(5)<<m<<setw(9)<<m<<setw(7)<<m<<endl;
char slowo[6];

//deklaracja na slowo o rozmiarze do 5 znaków

cin>>setw(sizeof(slowo))>>slowo;

o

setfill(int)

– ustawia wypełnienie wolnej przestrzeni

int kwota=3200;
cout<<”Stan konta: ”<<setfill(‘*’)<<setw(9)<<kwota<<”-,”<<endl;

o

setprecision(int)

– ustawia dokładność

double x=99.123456789;
cout<<x<<”, ”<<setprecision(2)<<x<<”, “<<setprecision(8)<<x<<endl;

o

setiosflags(long)

oraz

resetiosflags(long)

- ustawia i kasuje wskazane flagi

int liczba=242;
cout <<hex<<liczba<<”, ”<<setiosflags(ios::uppercase)<<liczba
<<resetiosflags(ios::uppercase)<<liczba<<endl;

o

setbase(int)

– określa podstawę dla konwersji liczb, czyli to samo co manipulatory

dec

,

hex

i

oct

int liczba=100;
cout<<dec<<liczba<<hex<<liczba<<oct<<liczba;

to samo co

cout<<setbase(10)<<liczba<<setbase(16)<<liczba<<setbase(8)<<liczba;

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

18

NIEFORMATOWANE OPERACJE WEJŚCIA / WYJŚCIA


W klasie

istream

zdefiniowane są funkcje:

get

– wczytanie jednego znaku (bajtu), Funkcja jest przeciążona i może wczytywać

zadaną liczbę znaków lub do chwili napotkania wzorca.

istream&

get

(

char &

);

int

get

();

//funkcja zwraca kod znaku w postaci int

istream&

get

(

char

);

istream&

get

(

char *, int

);

//drugi argument to długość wczytywanych znaków

istream&

get

(

char *, int , int =’\n’

);

//domyślny wzorzec to znak nowej linii

Przykłady:

char

znak

;

cin.get

(

znak

);

//wczytanie bajtu ze strumienia cin

//wczytywane są także białe znaki (spacje i tabulacje)

//- w odróżnieniu od

cin

>>

znak

;

//------------------- WCZYTANIE ZNAKU ------------------------

char

znak

;

cout<<”Wciskaj klawisze (^Z-konczy)”<<endl;

while((

cin.get

(

znak

))!=0)

cout<<”Znak : ”<<

znak

<<” ma kod ”<<int(

znak

)<<endl;

//------------ WCZYTANIE ZNAKU INACZEJ – A MOśE TAK SAMO ? --------

char

znak

;

cout<<”Wciskaj klawisze (^Z-konczy)”<<endl;

while((char(znak)=

cin.get

())!=EOF ) //EOF – znak końca pliku tekstowego

//funkcja zwraca kod znaku w postaci int

cout<<”Znak : ”<<

znak

<<” ma kod ”<<int(

znak

)<<endl;

//----------------------- WCZYTANIE ZNAKÓW DO TABLICY ---------------------

char

zdanie

[

80

];

cout<<”Wpisz zdanie:”<<endl;

cin.get

(

zdanie,

sizeof

(zdanie)

);

//

cin.get

(

zdanie,

80

);

cout<<”Twoje zdanie to: ”<<

zdanie

<<endl;

//----------- WCZYTANIE ZNAKÓW DO WYSTĄPIENIA WZORCA ------------

char

zdanie

[

80

];

cout<<”Wpisz zdanie:”<<endl;

cin.get

(

zdanie,

sizeof

(zdanie),’

,

);

// wczytuj do wystąpienia przecinka

cout<<”Twoje zdanie to : ”<<

zdanie

<<endl;

UWAGA:

Nie wczytane dane z powodu limitu długości lub napotkania wzorca pozostają

w buforze strumienia i mogą być czytane następnymi instrukcjami. Napotkany znak
wzorca zostaje zwrócony do strumienia.

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

19

getline

– wczytanie zadanej liczby bajtów lub do napotkania wskazanego znaku

istream&

getline

(

char *, int , int=’\n’

); //domyślny wzorzec to znak nowej linii

Działa podobnie do

get

(

char *, int , int=’\n’

) z tą różnicą, że zabiera i usuwa ze

strumienia napotkany wzorzec. Funkcja zwraca referencję do strumienia, na którym
pracuje. Umożliwia to kaskadowe łączenie takich funkcji, np. cin.getline(...).getline(...)

read

– wczytanie określonej liczby bajtów w trybie binarnym. Nie dołącza znaku ‘\0’ na

końcu jak to robią poprzednie funkcje

istream&

read

(

char *, int

);

Funkcja zwraca referencję do strumienia, na którym pracuje. Umożliwia to kaskadowe
łączenie takich funkcji, np. cin.read(...).read(...)

ignore

– wczytuje i ignoruje grupę bajtów ze strumienia

istream&

ignore

(

int , int

);

gcount

– pozwala dowiedzieć się ile znaków zostało wczytanych za pomocą

nieformatowanej operacji wejścia/ wyjścia

int

gcount

();

Przykład:

char

zdanie

[

80

];

cout<<”Wpisz zdanie:”<<endl;

cin.get

(

zdanie,

sizeof

(zdanie),’

,

’);

// wczytuj do wystąpienia przecinka

cout<<”Zdanie: ”<<

zdanie

<<”. ma : ”<<

cin.gcount()

<<” znakow”<<endl;

peek

– służy do sprawdzenia jaki bajt czeka w strumieniu, nie wyjmuje bajtu

int

peek

();

Przykład:

char

zdanie

[

80

];

float

liczba

;

int

test

;

cout<<”Wprowadz dane (tekst lub liczbe):”;
test =

cin.peek()

;

if(isdidgit(

test

)) {

cin>>liczba;
cout<<”Wprowadziłeś liczbę: “<<

liczba

<<endl;

} else {

cin.getline(

zdanie,

sizeof

(zdanie)

);

cout<<”Wprowadziłeś tekst: “<<

zdanie

<<endl;

}

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

20

putback

– umożliwia zwrócenie do strumienia wyjętego bajtu. Bajt ten wraca do

strumienia i może następnie być wyjęty operacją wyjmowania.


istream &

putback

(

char

);


W klasie

ostream

zdefiniowane są funkcje:

put

– wkłada do strumienia jeden bajt

ostream &

put

(char)

Przykład:

char

zdanie

[]={”I do Love You”};

int i=0;

do {
cout.put(zdanie[i]).put(”_”);
} while(zdanie[++i]);

Efekt: I_ _d_o_ _ L_o_v_e_ _Y_o_u.

write

– wkłada do strumienia zadaną liczbę bajtów

ostream &

write

(char *, int)


Przykład:

char zdanie[]={”I do Love You”};

cout.write(zdanie,2);
cout<<”hate”;
cout.write(zdanie+10,4);

Efekt:

I hate You.

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

21

OPERATORY ARYTMETYCZNE

Operator

Działanie

Postać matematyczna

=

instrukcja przypisania

z = x;

+

dodawanie

z = x + y;

-

odejmowanie

z = x – y;

*

mnożenie

z = x * y;

/

dzielenie

z = x / y;

%

dzielenie modulo = reszta z dzielenia

z = x % y;

--

zmniejszanie o jeden (dekrementacja)

z = z – 1;

++

zwiększanie o jeden (inkrementacja)

z = z + 1;

+=

skrót przypisania

z += x;

to samo co:

z = z + x;

-=

skrót odejmowania

z -= x;

to samo co:

z = z – x;

*=

skrót mnożenia

z *= x;

to samo co:

z = z * x;

/=

skrót dzielenia

z /= x;

to samo co:

z = z / x;


Ogólna postać instrukcji przypisania wygląda następująco:

zmienna = wyrażenie;

Można też stosować wielokrotnie takie instrukcje, np.:

z = x = y = 0;


Program realizujący operację dodawania dwóch liczb typu float.

#include <iostream>
#include <conio.h>
int main()
{
float x, y, z; // deklaracja zmiennych
using std::cout; using std::endl; using std::cin;
cout << endl << "Podaj dwie liczby " << endl;
cin >> x >> y;
z = x + y;
cout << x << " + " << y <<" = " << z<<endl;
return 0;
}


W przykładzie wykorzystano operatory

dodawania

+

oraz

przypisania

=

.


background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

22

OPERATORY RELACYJNE i LOGICZNE

Każda różna od zera liczba, z którą spotykamy się w C, posiada wartość

TRUE

(prawda) ,

natomiast liczba 0 posiada wartość

FALSE

(nieprawda). Wyrażenia, w których występują

operatory relacyjne bądź logiczne, zwracają wartość

1

(

TRUE

) lub

0

(

FALSE

). W zależności

od potrzeb posługujemy się następującymi operatorami:

Operatory relacyjne

Operator

Działanie

>

większy

<

mniejszy

>=

większy lub równy

<=

mniejszy bądź równy

==

równy

!=

różny

Operatory logiczne

Operator

Działanie

&&

koniunkcja AND (i)

||

alternatywa OR (lub)

!

negacja NOT (nie)


Posługując się przedstawionymi operatorami należy zawsze pamiętać, że posiadają one różny
priorytet wykonywania kolejnych działań. Rozpatrzmy to na przykładzie wyrażenia

5-4 != 0

.

Jego wartość obliczana jest w taki sposób, że najpierw zostanie wykonana operacja odejmowania
liczb, a dopiero potem sprawdzony warunek, czy rezultat odejmowania jest różny od zera, tzn.:

(5-4) != 0

. Należy też pamiętać, że operator

()

ma największy priorytet. Jeżeli nie jesteśmy

pewni priorytetów stosowanych operatorów zawsze w wątpliwych sytuacjach możemy posłużyć
się właśnie operatorem

()

.

OPERATORY BITOWE

Operator

Działanie

&

bitowa koniunkcja AND (i)

|

bitowa alternatywa OR (lub)

~

bitowa negacja NOT (nie)

^

bitowa różnica symetryczna XOR

<<

przesuniecie bitów w lewo (mnożenie przez 2)

>>

przesuniecie bitów w prawo (dzielenie przez 2)

Możliwe jest w pewnych szczególnych zastosowaniach wykonywanie operacji na liczbach w
logice bitowej.

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

23

PRZEDROSTKI I PRZYROSTKI

Zarówno operator inkrementacji (

++

), jak i dekrementacji (

--

) występuje w dwóch odmianach:

przedrostkowej (np.

++x

) jest obliczany przed przypisaniem (zwiększ wartość zmiennej i

zapamiętaj ją)

x=5;
int y = ++x;
cout <<x<<”\t”<<y;

//po wykonaniu: x jest równe 6, y jest równe 6

przyrostkowej (np. x++) jest obliczany po przypisaniu (pamiętaj pierwotną wartość
zmiennej, po czym zwiększ wartość)

x=5;
int y = x++;
cout <<x<<”\t”<<y;

//po wykonaniu: x jest równe 6, y jest równe 5


Przykład działania operatora przedrostkowego i przyrostkowego

1: #include <iostream>
2: int main() {
3: using std::cout;
4: int mojWiek = 39; // inicjalizujemy dwie zmienne całkowite
5: int twojWiek = 39;
6: cout << "Ja mam: " << mojWiek << " lat.\n";
7: cout << "Ty masz: " << twojWiek << " lat\n";
8: mojWiek++; // inkrementacja przyrostkowa
9: ++twojWiek; // inkrementacja przedrostkowa
10: cout << "Minal rok...\n";
11: cout << "Ja mam: " << mojWiek << " lat.\n";
12: cout << "Ty masz: " << twojWiek << " lat\n";
13: cout << "Minal kolejny rok\n";
14: cout << "Ja mam: " << mojWiek++ << " lat.\n";
15: cout << "Ty masz: " << ++twojWiek << " lat\n";
16: cout << "Wypiszmy to jeszcze raz.\n";
17: cout << "Ja mam: " << mojWiek << " lat.\n";
18: cout << "Ty masz: " << twojWiek << " lat\n";
19: return 0;
20: }


Efekt:

Ja mam: 39 lat.
Ty masz: 39 lat
Minal rok...
Ja mam: 40 lat.
Ty masz: 40 lat
Minal kolejny rok
Ja mam: 40 lat.
Ty masz: 41 lat
Wypiszmy to jeszcze raz.
Ja mam: 41 lat.
Ty masz: 41 lat

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

24

INSTRUKCJA DECYZYJNA

if

Instrukcja

if

jest pytaniem czy jest spełniony

warunek

, który może być wyrażeniem logicznym

TRUE/ FALSE lub wprost wartością odpowiednio różną od zera (!=0) lub równą zero (==0).


if

(

warunek

) {

//jeśli warunek spełniony TRUE (!=0)

instrukcja;

instrukcja;

...

};
lub

if

(

warunek

)

instrukcja;

//jeśli jedna instrukcja to może być bez klamry


if (warunek)

TAK

NIE

instrukcja;
instrukcja;

...

Można też stosować wielobok zamiast rombu.

if (warunek)

TAK

NIE


background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

25

INSTRUKCJA DECYZYJNA

if ... else

Instrukcja

if ... else

jest pytaniem czy jest spełniony

warunek

, który może być wyrażeniem

logicznym TRUE/ FALSE lub wprost wartością odpowiednio różną od zera (!=0) lub równą zero
(==0). W przypadku nie spełnienia

warunku

następuje wykonanie instrukcji występujących po

else

. Dopiero wtedy wykonywane są następne instrukcje w programie. W przypadku spełnienia

warunku

instrukcje po

else

są omijane.

if

(

warunek

) {

//jeśli warunek spełniony TRUE (!=0)

instrukcja;

instrukcja;

...

}

else

{

//jeśli warunek nie jest spełniony FALSE (0)

instrukcja;

instrukcja;

...

};
lub

if

(

warunek

)

instrukcja;

//jeśli jedna instrukcja to może być bez klamry

else

instrukcja;

if (warunek)

TAK

NIE

instrukcja;
instrukcja;

...

instrukcja;
instrukcja;

...

else

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

26

Program – ilustracja złożonych warunków logicznych dla

if ... else

#include <iostream>

int main()
{
using std::cout; using std::endl; using std::cerr;
enum KOLORY {bialy=1, czerwony, zielony, zolty, niebieski, fioletowy};
KOLORY kolor=zielony;
int liczba=2;

//liczba musi być w zakresie koloru i nieparzysta to kolor też musi być nieparzysty lub
// gdy parzysta to kolor też parzysty

if

(((liczba<=6)&&(liczba>=1))&&(((!(kolor%2))&&(!(liczba%2)))||((kolor%2)&&(liczba%2))))

cout<<"Liczba: "<<liczba<<"\tKolor: "<<kolor<<endl;

else

cerr<<"Bledna kombinacja liczb i kolorow"<<endl;

return 0;
}

UWAGA: Przy niespełnionym warunku przy

if

nie wiemy, które z kryteriów nie było spełnione

Program – Ten sam program i te same warunki logiczne rozbite na kaskadę wielu

if ... else


#include <iostream>

int main()
{
using std::cout; using std::endl; using std::cerr;
enum KOLORY {bialy=1, czerwony, zielony, zolty, niebieski, fioletowy};
KOLORY kolor=bialy;
int liczba=4;
//jesli liczba jest w zakresie koloru i parzysta to kolor tez parzysty

if

((liczba<=6)&&(liczba>=1))

{

//sprawdzanie zakresu liczby

if

((!(kolor%2))&&(!(liczba%2)))

//sprawdzanie parzystej liczby i koloru

cout<<"Liczba parzysta: "<<liczba<<"\tKolor parzysty: "<<kolor<<endl;

else
if

((kolor%2)&&(liczba%2))

//sprawdzanie nieparzystej liczby i koloru

cout<<"Liczba nieparzysta: "<<liczba<<"\tKolor nieparzysty: "<<kolor<<endl;

else

cerr<<"Liczba w zakresie, ale nie pasuje do koloru"<<endl;

}

else

cerr<<"Liczba poza zakresem"<<endl;

return 0;
}

Sprawdzane są poszczególne kryteria i wiadomo jakie występują kombinacje liczby i koloru. W
ten sposób użytkownik jest dokładnie informowany o szczegółach zarówno wyników
sprawdzania oraz występujących błędów.

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

27

INSTRUKCJA DECYZYJNA

switch


Instrukcja

switch

porównuje wyrażenie z wartością dla wybranych przypadków (

case

). Przy

zgodności wartości wykonane zostaną instrukcje zawarte po

case

oraz wszystkie instrukcje po

case

umieszczonych poniżej oraz po

default

, chyba że pojawi się rozkaz wyjścia z instrukcji:

break

. W przypadku braku zgodności ze wszystkimi wartościami po

case

może być wykonany

ciąg instrukcji dla przypadku domyślnego

default

.

switch

(

wyrażenie

) {

case

wartość_1:

instrukcja;
instrukcja;
...

break;

case

wartość_2:

instrukcja;

instrukcja;

...

break;

...

case

wartość_n:

instrukcja;

instrukcja;

...

break;

default

:

//fragment wykonywany domyślnie dla braku zgodności
//wartości wyrażenia w sprawdzanych przypadkach

case

instrukcja;

instrukcja;

};
lub

switch

(

wyrażenie

) {

case

wartość_1:

//można łączyć wartości, które posiadają wspólne instrukcje

case

wartość_2:

instrukcja;

instrukcja;

...

break;

...

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

28

if (wyra

ż

enie==warto

ść

_1)

TAK

NIE

instrukcja;
instrukcja;

...

switch (wyra

ż

enie)

case warto

ść

_1:

if (wyra

ż

enie==warto

ść

_2)

NIE

case warto

ść

_2:

TAK

instrukcja;
instrukcja;

...

if (wyra

ż

enie==warto

ść

_n)

NIE

case warto

ść

_n:

TAK

instrukcja;
instrukcja;

...

instrukcja;
instrukcja;

...

default:

. . .

. . .

break;

break;

break;

break;

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

29

Program – przykład użycia instrukcji

switch


#include <iostream>
int main()
{
using std::cout; using std::endl; using std::cerr;
enum OCENA {mierny=1,ndst,dst,db,bdb,celujacy};
OCENA zaliczenie=mierny;

switch

(

zaliczenie

) {

case

mierny

:

case

ndst

: cout <<"Ocena: "<<int(zaliczenie)<<"\tBrak zaliczenia."<<endl;

break;

case

dst

:

case

db

:

case

bdb

:

case

celujacy

: cout <<"Ocena: "<<int(zaliczenie)<<"\tZaliczenie."<<endl;

break;

default

: cerr<<"Błędna ocena"<<endl;

}; return 0;
}

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

30

INSTRUKCJA CYKLICZNA

while


Instrukcje cykliczne nazywane w żargonie pętlami.
Instrukcja

while

sprawdza czy zachodzi

warunek

i jeśłi tak (ang.

while

= podczas gdy

warunek

spełniony) wykonuje instrukcje zawarte w klamrze. Następnie ponownie sprawdza

warunek

. Po

pierwszym wejściu w cykl instrukcja

while

może zakończyć działanie jeśli instrukcje wewnątrz

while

lub zdarzenia wejścia/wyjścia wpłyną na dane w taki sposób, że

warunek

przestanie być

spełniany lub zostanie wykonana instrukcja

break

przerywająca pętlę

while

w dowolnym

momencie. W dowolnym momencie podczas wykonywania pętli może być wydana komenda

continue

, która spowoduje przejście do ponownego sprawdzenia

warunku

.

while

(

warunek

) {

instrukcja;

instrukcja;

...

};
lub

while

(

warunek

) instrukcja; //jeśli jedna instrukcja to może być bez klamry


if (warunek)

TAK

NIE

instrukcja;
instrukcja;

...

break;

continue;

continue;

while (warunek)


background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

31

Program – demonstruje działanie

while

#include <iostream>

int main()
{
using std::cout; using std::cin;
long int iSuma=0,iIloczyn=1,iLiczba=0; //lepiej dać long int
cout<<"Podaj liczby (0 - konczy): ";
cin>>

iLiczba

;

while

(

iLiczba

) {

//zero kończy program – warunek: iLiczba!=0

iSuma+=

iLiczba

;

iIloczyn*=iLiczba;

cout<<"Suma liczb = "<<iSuma<<'\t';

cout<<"Iloczyn liczb = "<<iIloczyn<<endl;

cout<<"Nastepna liczba (0 - konczy): ";

cin>>

iLiczba

;

}

return 0;
}

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

32

INSTRUKCJA CYKLICZNA

do ... while


Instrukcja

do ... while

działa podobnie do

while

z tą różnicą, że najpierw są wykonywane

instrukcje a potem sprawdzany

warunek

. Powoduje to przynajmniej jednokrotne wykonanie

cyklu instrukcji w pętli. Po pierwszym wejściu w cykl instrukcja

do ... while

może zakończyć

działanie jeśli warunek nie jest spełniony. Przy kolejnych wykonaniach jedynie instrukcje
wewnątrz

do ...

while

lub zdarzenia wejścia/wyjścia wpłyną na dane w taki sposób, że

warunek

przestanie być spełniany lub zostanie wykonana instrukcja

break

przerywająca pętlę

do ... while

w dowolnym momencie. W dowolnym momencie podczas wykonywania pętli może być wydana
komenda

continue

, która spowoduje przejście do ponownego sprawdzenia

warunku

.

do

{

instrukcja;

instrukcja;

...

}

while

(

warunek

);


lub

do

instrukcja

while

(

warunek

);

//jeśli jedna instrukcja to może być bez klamry

if (warunek)

TAK

NIE

instrukcja;
instrukcja;

...

break;

continue;

while (warunek)

do

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

33

Program – demonstruje działanie

do ... while

#include <iostream>
int main()//Program oblicza dlugość szeregu wprowadzanych liczb
{
using std::cout; using std::cin;
int iDlugosc=0, iLiczba;

do

{

cout<<"Podaj liczbe z szeregu (0 - konczy): ";
cin >>iLiczba;
iDlugosc++;
}

while

(

liczba

);

iDlugosc--; //korekta dlugosci o liczbe 0, która jest sygnalem do wyjscia
cout<<"Dlugosc szeregu liczb wynosi " <<iDlugosc<<endl;
return 0;
}

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

34

INSTRUKCJA CYKLICZNA

for


Instrukcja cykliczna for służy do wykonywania zadań na skończonym zbiorze danych. Dzięki
wykorzystaniu dodawania (inkrementacji) lub odejmowania (dekrementacji) możliwe jest
iteracyjne (krokowe) ze zdefiniowanym krokiem przetwarzanie lub dostęp do danych, np.
operacje na tablicach, obliczenia dla ciągu argumentów itp.

for

(instrukcje_1;

warunek

;

iteracje

) {

instrukcja;
instrukcja;
...

};

lub

for

(instrukcje_1;

warunek

;

iteracje

)

//jeśli jedna instrukcja to może być bez klamry

instrukcja;

if (warunek)

TAK

NIE

instrukcja;
instrukcja;

...

break;

continue;

for(instrukcje_1; warunek; iteracje)

iteracje

instrukcje_1

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

35

Przykłady:

for(int i=1;i<11;i++)

//dziesięć cykli dla i=1,2,3,4,5,6,7,8,9,10

cout<<”Liczby rosnąco: ”<<i<<endl;


a teraz w odwrotnej kolejności:

for(int i=10;i>0;i--)

//dziesięć cykli dla i=10,9,8,7,6,5,4,3,2,1

cout<<”Liczby malejąco: ”<<i<<endl;


Jaka jest różnica ?

1

2

for

(int i=1;

i<11

;

i++

)

for

(int j=1;

j<11

;

j++

)

instrukcja1;

for

(int i=1;

i<11

;

i++

)

for

(int j=i;

j<11

;

j++

)

instrukcja2;

//Pytanie: ile cykli ?

//Pytanie: ile cykli ?

//Odpowiedź

: 100

<-

//

//Odpowiedź:

55

<-

// ?dlaczego: 10+9+8+7+6+5+4+3+2+1 <-

3

4

for

(int i=1,j=100;

i<11

;

i++,j++

)

instrukcja3;

for

(int i=1,j=100;

j<101

;

i++,j++

)

instrukcja4;

//Pytanie: ile cykli ?

//Pytanie: ile cykli ?

//Odpowiedź:

10

<-

//

//Odpowiedź:

1

<-

//

5

6

for

(int i=1,j=1;

(i<11)&&(j<101)

;

i++,j++

)

instrukcja5;

for

(int i=1,j=1;

(i<11)||(j<101)

;

i++,j++

)

instrukcja6;

//Pytanie: ile cykli ?

//Pytanie: ile cykli ?

//Odpowiedź:

10

<-

//

//Odpowiedź:

100

<-

//


Program – demonstruje działanie

for

#include <iostream>
int main() {
const unsigned int SZEROKOSC=4;
using std::cout; using std::endl;

for

(int i=1;

i<11

;

i++

) {

if (i>1) cout<<endl;

for

(int j=1;

j<11

;

j++

) {

cout.width(SZEROKOSC);

cout<<i*j;

}
}
cout<<endl;
return 0;
}

Jaki będzie rezultat wykonania programu ?

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

36

I

J

i*j

Ekran

1

1

1

1

1

2

2

1 2

1

3

3

1 2 3

...

...

...

...

2

1

2

...

...

...

10

10

100

1 2 3 4 5 6 7 8 9 10
2 4 6 8 10 ...

...
...
...
...

10 20 30 40 50 60 70 80 90 100


background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

37

INSRUKCJE CYKLICZNE – ZAGADKA

To samo ?

for

(instrukcje_1;

warunek

;

iteracje

) {

instrukcja;
instrukcja;
...
if (warunek) continue;
...
instrukcja;
instrukcja;
...
if (warunek) break;
...
instrukcja;
instrukcja;

};

instrukcje_1;

while

(

warunek

) {

instrukcja;

instrukcja;

...

if (warunek) {

iteracja;

continue;}

...
instrukcja;
instrukcja;
...

if (warunek) break;

...
instrukcja;
instrukcja;


iteracje;

};

A może są różnice ?:

sprawdź działanie break lub continue

<-

Odpowiedź –

różnica jest w działaniu: continue

<-


background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

38

4.

F

UNKCJE

1.



Można podzielić program na fragmenty - podprogramy, które realizują ściśle określone zadania.

Dlaczego stosować funkcje ?

Powtarzające się fragmenty lub realizujące ściśle określone operacje mogą być wyodrębnione
i zapisane w postaci funkcji

Bezpośrednia odpowiedniość pomiędzy algorytmem i kodem programu Można pisać i
uruchamiać fragmenty programu niezależnie – struktura modułów funkcjonalnych –
„skrzyneczki”

Można je wywoływać z dowolnego punktu programu

Skrócenie programu powoduje jego większą czytelność



Forma zapisu:






typ

fnNazwa

(

typ argument1, typ argument2

) {


def. zmiennych lokalnych
instrukcja;
...

return

(

wartość zwracana

);

...
}





Funkcja może zwracać wartość (lub nie) poprzez instrukcję:

return(wartość);

lub samo:

return;

do miejsca w którym funkcja została wywołana

np. wynik =

fnSumaKwadratow

(

n

);

Przykłady: (ang. void - znaczy nieokreślona)
void

fnFunkcja1

(

int m

)

//nie zwraca wartości – argument: int m

int

fnFunkcja2

(

void

)

//zwraca wartość int – nie posiada argumentów

void

fnFunkcja3

(

void

)

//nie zwraca wartości – nie posiada argumentów

Typ wartości zwracanej

Parametry wywołania ze

wskazaniem typów

zmiennych

Zmienne tworzone dla

potrzeb wewnątrz funkcji

Powrót z funkcji wraz z

wartością zwracaną

Operacje funkcji

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

39

F

UNKCJE

2.

Kolejność definicji funkcji:


Definicje i deklaracje globalne
Definicja funkcji 1
Definicja funkcji 2
...
Definicja funkcji głównej main

lub

Definicje i deklaracje globalne
Prototyp funkcji 1
Prototyp funkcji 2
...
Definicja funkcji głównej main
Definicja funkcji 1
Definicja funkcji 2

Program liczy sumę kwadratów liczb n zadana z klawiatury

#include <iostream>

int

fnSumaKwadratow

(

int k

); //definicja prototypu


int main(){
using std::cout; using std::cin; using std::endl;
int n, iWynik;
cout<<"Podaj wartosc zmiennej n: ";cin>>n;
iWynik =

fnSumaKwadratow(

n

)

; //wywolanie funkcji

cout << "Suma kwadratow dla n = "<<n<<" wynosi "<<iWynik<<endl;
return 0;
}
/////////////////////////////////////// FUNKCJE /////////////////////////////////////////////////
int

fnSumaKwadratow

(

int k

) { // czy może być k zamiast n ?

int i, iSuma = 0;
for (i=1; i<=

k

;i++)

// czy może być k zamiast n ?

iSuma+=i*i;

return

(iSuma);

}


Co się stanie gdy zadeklaruje się jako parametr wywołania funkcji zmienną

k

zamiast

n

?

}

podobnie jak w plikach nagłówkowych

(ang. headers) , np. plik.h

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

40

iWynik=fnSumaKwadratow(n);

int n, iWynik;

...

int main(){

}

Adres

powrotu

n

STOS

iWynik

...

...

Adres

wyjścia z main()

WYWOŁANIE FUNKCJI

RAM

zrz

ut

skok

n

...

...

int fnSumaKwadratow(n){
int i, iSuma = 0;

}

return (iSuma);

for (i=1; i<=n;i++) iSuma+=i*i;


Podczas wywołania funkcji następuje zapamiętanie na stosie (zrzut na stos) adresu powrotu
(segment i offset) do miejsca następnej instrukcji następującej po wywoływanej funkcji.
Na stos zostaje odłożona wartość argumentu wywołania funkcji, która będzie funkcjonować jak
zmienna lokalna w obszarze funkcji.

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

41

Adres

powrotu

n

STOS

iWynik

...

Adres

wyjścia z main()

DZIAŁANIE FUNKCJI

ob

lic

ze

ni

a

i

iSuma

...

n

...

iWynik=fnSumaKwadratow(n);

int n, iWynik;

...

int main(){

}

RAM

...

int fnSumaKwadratow(n){
int i, iSuma = 0;

}

return (iSuma);

for (i=1; i<=n;i++) iSuma+=i*i;


Zostają powołane do życia nowe zmienne lokalne: i oraz iSuma w postaci komórek pamięci na
stosie. Na tych zmiennych odbywa się przetwarzanie, czyli obliczenia sumy kwadratów liczb od
1 do n. Zmienna i jest liczbą podnoszoną do kwadratu w pętli for.

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

42

Adres

powrotu

n

STOS

iWynik

...

Adres

wyjścia z main()

POWRÓT Z FUNKCJI

i

iSuma

...

n

...

przepisuje
wynik

pow

rót

iWynik

Adres

wyjścia z main()

...

n

...

STOS

zwalnia

stos

...

iWynik=fnSumaKwadratow(n);

int n, iWynik;

...

int main(){

}

RAM

...

int fnSumaKwadratow(n){
int i, iSuma = 0;

}

return (iSuma);

for (i=1; i<=n;i++) iSuma+=i*i;


Powrót z funkcji następuje po napotkaniu instrukcji return lub po dotarciu do klamry zamykającej
‘}’. W tym przypadku funkcja zwraca wartość typu int i przepisuje ją do zmiennej lokalnej
funkcji main o nazwie iWynik. Musi nastąpić zatem przepisanie wartości zmiennej iSuma pod
adres zmiennej iWynik na stosie. Wszystkie zmienne lokalne w funkcji fnSumaKwadratow, czyli
iSuma, i oraz n przestają być potrzebne i zostają usunięte (zciągnięte ze stosu). Wtedy na stosie
odkryty zostanie adres powrotu, który jest wczytywany do rejestru instrukcji procesora. To
spowoduje przekazanie sterowania pod ten adres, czyli wykonana będzie instrukcja następująca
po wywołaniu funkcji. W ten sposób poza zmienioną wartością iWynik zmiennej lokalnej funkcji
main nie pozostanie żaden ślad działalności funkcji fnSumaKwadratów. Obszar stosu używany
przez tą funkcję zostanie zwolniony i może być wykorzystany do innych celów.

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

43

F

UNKCJE

3.

ZASIĘG DOSTĘPNOŚCI ZMIENNYCH:


Zmienne:

Globalne

– mają zasięg ogólny – dostępne wszędzie w programie, posiadają rezerwację w

pamięci operacyjnej i swój stały adres

Lokalne

– powoływane do życia wewnątrz funkcji, znikają po zakończeniu funkcji

(tworzone tymczasowo na stosie w pamięci operacyjnej). Przesłaniają inne zmienne o tych
samych nazwach (patrz przykład)

Statyczne

– definiowane wewnątrz funkcji – zachowują wartość do następnego wywołania

tej samej funkcji


PRZESŁANIANIE ZMIENNYCH GLOBALNYCH
:

Nazewnictwo zmiennych lokalnych nie jest dowolne, ponieważ zmienne globalne o tych

samych nazwach zostają

przesłonięte

przez nowe definicje, ale ich czas życia jest ograniczony

do wnętrza funkcji. Po zakończeniu funkcji zmienne lokalne znikają bezpowrotnie. Bierze się to
stąd, że są one tworzone tymczasowe na strukturze stosu w pamięci operacyjnej komputera.

Przykładowy program:


#include <iostream>

int

k

=50,

j

=10;

//zmienne globalne z nadaną wartością początkową


int

fnFunkcja

(

void

) {

return (

k

+100);

//obszar zasięgu zmiennej globalnej

k

=150

}


int main() {
using std::cout; using std::endl;
int

k

=3;

//zmienna lokalna

k

w funkcji main

cout<< ”Dla lokalnego k: ”<<

k

+100+

j

<<” Dla globalnego k: „<<

fnFunkcja()

+

j

<<endl;

}

Wynik : ? >

113, 160

<

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

44

Przykładowy program:

#include <iostream>

int

i

=10,

j

=200,

k

=300;

//zmienne globalne

void

fnFun

(

void

) {

using std::cout; using std::endl;
int

i

=4;

//przesłonięcie nazwy globalnej

static

int

j

=0;

//przesłonięcie nazwy globalnej – zmienna

static

i

++;

j

++;

k

++;

cout<<"W fnFun(): I= "<<

i

<<" J= "<<

j

<<" K= "<<

k

<<endl;

}
int main() {
int

i

,

k

=0;

for (

i

=0;

i

<3;

i

++)

fnFun

();

cout<<"W main(): I= "<<

i

<<" J= "<<

j

<<" K= "<<

k

<<endl;

return 0;
}

Wynik:

W fnFun(): I= 5 J= 1 K= 301
W fnFun(): I= 5 J= 2 K= 302
W fnFun(): I= 5 J= 3 K= 303
W main(): I= 3 J= 200 K= 0

int main() {
int i, k=0;
for (i=0; i<3; i++) fnFun();
cout<<"W main(): I= "<<i
<<" J= "<<j<<" K= "<<k<<endl;
return 0;
}

STOS

...

i

Adres

wyjścia z main()

RAM

powrót

k

...

i=10
j=200
k=300

zmienne
globalne

void fnFun(void) {
using std::cout; using std::endl;
int i =4;
static int j=0;
i++; j++;k++;
cout<<"W fnFun(): I= "<<i
<<" J= "<<j<<" K= "<<k<<endl;
}

Adres

powrotu z fnFun()

i

STOS

...

i

Adres

wyjścia z main()

k

...

j

j

i

i

k

skok

powrót

skok

zmienne
lokalne

zmienne
lokalne

static j=10

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

45

A

RGUMENTY

F

UNKCJI

1.

To co było do tej pory w przykładach to

przekazywanie argumentów przez wartość

Funkcja nie może wpływać na wartości zmiennych przekazywanych do funkcji jako

argumenty, ponieważ w trakcie wywołanie funkcji powoływane są do życia zmienna w sensie
lokalnym o typie i nazwie argumentu wywołania oraz z wartością początkową wywołania.
Po opuszczeniu funkcji nie pozostanie ślad po argumentach i operacjach na nich wykonanych.
Funkcja może zwrócić wartość w postaci jawnej (instrukcja return) do użycia w dalszej części
programu.

Przykładowy program:

#include <iostream>
void

fnZwieksz

(

int a, int b

) {

using std::cout; using std::endl;
a+=100;
b+=200;
cout << " a: "<<a<<" b: "<<b<<endl;
}
int main(){
using std::cout; using std::endl;
int

x

=10,

y

=10;

fnZwieksz

(

x,y

); //nie spowoduje zmiany wartości

x

i

y

w funkcji main()

cout << ” x: ”<<

x

<<” y: ”<<

y

;

return 0;
}

UWAGA

: Można to obejść używając wewnątrz funkcji zmiennych globalnych, ale nie podając

ich jako argument wywołania, lecz wykonując jedynie operacje na nich.

#include <iostream>
int

x

=10,

y

=10;

//zmienne globalne

void

fnZwieksz

(

int a, int b

) {

using std::cout; using std::endl;
x=a+100;
y=b+200;
cout << " a: "<<a<<" b: "<<b<<endl;
}
int main(){
using std::cout; using std::endl;

fnZwieksz

(

x,y

); //nie spowoduje zmiany wartości

x

i

y

w funkcji main()

cout << ” x: ”<<

x

<<” y: ”<<

y

;

return 0;
}

ODPOWIEDNIE METODY:

referencja

i

wskaźniki

– omawiane w dalszej części kursu

Wynik:

a: 110 b: 210

x: 10 y: 10

Wynik:

a: 10 b: 10

x: 110 y: 210

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

46

A

RGUMENTY

F

UNKCJI

2.

Argumenty funkcji

main()

są skojarzone z

parametrami

wywołania

programu

:

nazywanymi

linią komend

lub

wierszem polecenia


int

main

() lub int

main

(

void

) – bez parametrów,

int

main

(

int argc, char *argv[]

) – dwa parametry:

argc

– liczba argumentów wywołania programu (>=1)

argv

– tablica wskaźników do tekstów argumentów


//Program wypisze liczbę oraz zawartość wszystkich argumentów funkcji main()

#include <iostream>

int

main

(

int argc, char *argv[]

) {

using std::cout; using std::endl;
cout<<”Program ”<<

argv[0]

<<” ma ”<<

argc

-1<<” argumentów.”<<endl;

for(int i=1;i<

argc

;i++)

cout<<” Argument\t”<<i<<”\tto\t”<<

argv[i]

<<endl;

return 0;
}


Wywołanie programu: funkcje_5.exe argument1 argument2 argument3
Wynik:
Program ścieżka\ funkcje_5.exe ma 3 argumentów.
Argument 1 to argument1
Argument 2 to argument2
Argument 3 to argument3
Aby kontynuować, naciśnij dowolny klawisz . . .

UWAGA: Trzeba pamiętać, żeby dokonać ustawień dla linii komend w kompilatorze, np. w Dev-
C++ w okienku Compilation przycisk Parameters.

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

47

D

OMYŚLNE

A

RGUMENTY

F

UNKCJI


Podczas definicji funkcji można przypisać domyślne (początkowe) wartości argumentów funkcji

void

fnSuma

(

int a=10, int b=20, int c=30, int d=40

){

....
}


Wywołanie tej funkcji może się odbyć z niepełną liczbą parametrów:

fnSuma

(

1,2

); //a=1, b=2 i domyślnie c=30 i d=40


= równoważne =

fnSuma

(

1,2,30,40

);

UWAGA:

Możemy pominąć tylko

wszystkie

argumenty począwszy od tego,

którego pominiemy jako pierwszy.

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

48

5.

P

RZECIĄśANIE

F

UNKCJI

Nadajemy te same nazwy funkcjom, które realizują analogiczne operacje,

ale

różniące się typem lub liczbą parametrów

- dzięki tym różnicom kompilator

rozpoznaje, którą z funkcji ma być użyta w zależności od typu wywołania.

Przykład:

//prototypy funkcji
int

polePowierzchni

(

int bokX,int bokY

);

double

polePowierzchni

(

double bokX,double bokY

);

double

polePowierzchni

(

double promien

);

int main(){
int a=5,b=4;
double c=5.8,d=3.2, r=2.11;
cout<<"Pole powierzchni z argumentami całkowitymi "<<

polePowierzchni

(

a,b

)<<'\n';

cout<<"Pole powierzchni z argumentami rzeczywistymi "<<

polePowierzchni

(

c,d

)<<endl;

cout<<"Pole powierzchni koła z argumentem rzeczywistym "<<

polePowierzchni

(

r

)<<endl;

return 0;
}
//definicja funkcji
int

polePowierzchni

(

int bokX,int bokY

){

return (bokX*bokY);
}
double

polePowierzchni

(

double bokX,double bokY

){

return (bokX*bokY);
}
double

polePowierzchni

(

double promien

){ //promień kola

return (promien*promien*3.1415);
}

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

49

T

ABLICE

1.

Struktura danych zawierająca uporządkowany zbiór obiektów tego samego typu i

odpowiada matematycznemu pojęciu wektora, macierzy.
Mogą być tablice jednowymiarowe (wektory) lub wielowymiarowe (macierze).

Tablica jednowymiarowa o rozmiarze 16 elementów po zainicjowaniu wartościami
początkowymi:

int iMoto[

16

] ={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};



Indeks

[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15]

Wartość

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16


RAM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

[0]

[1]
[2]

[3]

[4]
[5]

[6]

[7]
[8]

[9]

[10]

[11]
[12]

[13]

[14]
[15]

indeks

element


background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

50

T

ABLICE

2.


Tablica dwuwymiarowa: iMoto o rozmiarze

4x4

po zainicjowaniu wartościami początkowymi:


int iMoto[

4

] [

4

] = {

{1,2,3,4},

{5,6,7,8},

{9,10,11,12},

{13,14,15,16}

};



[0][0]

[0][1]

[0][2]

[0][3]

1

2

3

4

[1][0]

[1][1]

[1][2]

[1][3]

5

6

7

8

[2][0]

[2][1]

[2][2]

[2][3]

9

10

11

12

[3][0]

[3][1]

[3][2]

[3][3]

13

14

15

16


RAM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

indeks

element

[0]

[0]
[0]

[0]

[1]

[1]
[1]

[1]

[2]
[2]

[2]

[2]
[3]

[3]

[3]
[3]

[0]

[1]
[2]

[3]

[0]

[1]
[2]

[3]

[0]
[1]

[2]

[3]
[0]

[0]

[0]
[0]


Indeks

Wartość

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

51

T

ABLICE

3.

TABLICE SĄ INDEKSOWANE OD ZERA [0] !!!


Jeśli wpisujemy wszystkie wartości początkowe do tablicy to możemy nie podawać liczby
elementów - kompilator poradzi sobie z policzeniem elementów:

int iTab[] = {1,2,3,4,5,6};

int iTab[6]= {1,2,3,4,5,6};



Przykład: Wpisujemy wartość 2 do wszystkich elementów pewnej tablicy iTab:

Czy jest różnica ?

int iTab[

10

][

5

];

for (int i=0;i<

10

;i++)

for(int j=0;j<

5

;j++)

iTab[i][j] = 2;

int iTab[

50

];

for (int i=0;i<

50

;i++)

iTab[i] = 2;

RAM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

int iMoto[4][4] =
{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};

int iMoto[4][4] = { {1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,16} };

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

(tożsame)

[0]

[1]

[2]
[3]

[4]

[5]

[6]
[7]

[8]

[9]
[10]

[11]

[12]
[13]

[14]

[15]

indeks

[0]

[0]

[0]
[0]

[1]

[1]

[1]
[1]

[2]

[2]
[2]

[2]

[3]
[3]

[3]

[3]

[0]

[1]

[2]
[3]

[0]

[1]

[2]
[3]

[0]

[1]
[2]

[3]

[0]
[0]

[0]

[0]

indeks

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

52


Przykładowy program

//Program wynajduje element min i max w tablicy jednowymiarowej (wektorze)
#include <iostream>
const int MAXTAB=100;

int main(){
using std::cout; using std::cin; using std::endl;
int n,i,iMin,iMinIndx,iMax,iMaxIndx; //n - aktualny rozmiar wektora
int

iTab

[MAXTAB];

cout<<"Podaj liczbe elementow: (w zakresie od 1 do "<<MAXTAB; cin>>n;
for(i=0;i<n;i++){

//wprowadzenie danych do tablicy

cout<<"Podaj "<<i<<" element: "; cin>>

iTab

[i];

}

iMin=iMax=

iTab

[0];

iMinIndx=iMaxIndx=0;

//inicjalizacja parametrów do poszukiwania

for(i=1; i<n; i++){

//wyszukaj min i max

if(

iTab

[i]<iMin) {

iMin=

iTab

[i]; iMinIndx=i;

}

if(

iTab

[i]>iMax) {

iMax=

iTab

[i]; iMaxIndx=i;

}

}

cout<<"Minimum to: "<<iMin<<" na pozycji "<<iMinIndx<<endl;
cout<<"Maximum to: "<<iMax<<" na pozycji "<<iMaxIndx<<endl;
cout<<"Index\t"<<"Wartosc"<<endl;
for(i=0;i<n;i++) { //wyswietl minima i maxima

cout<<i<<"\t"<<

iTab

[i];

if(

iTab

[i]==iMax) cout<<"\tMAXIMUM";

if(

iTab

[i]==iMin) cout<<"\tMINIMUM";

cout<<endl;

}

return 0;
}

Rezultat:
Podaj liczbe elementow: 7
Podaj 0 element: 2
Podaj 1 element: 5
Podaj 2 element: 6
Podaj 3 element: 4
Podaj 4 element: 2
Podaj 5 element: 6
Podaj 6 element: 3
Minimum to: 2 na pozycji 0
Maximum to: 6 na pozycji 2
Index Wartosc
0

2

MINIMUM

1

5

2

6

MAXIMUM

3

4

4

2

MINIMUM

5

6

MAXIMUM

6

3

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

53

T

ABLICE I

W

SKAŹNIKI

1.

WPROWADZENIE do WSKAŹNIKÓW

Informacja przechowywana jest w pamięci operacyjnej w sposób ciągły
podobnie jak w tablicy jednowymiarowej, z tą różnicą, że zamiast
indeksów występują adresy komórek pamięci. Korzystając z takiej
analogii można operować nazwą tablicy jednowymiarowej podobnie jak
zmienną wskaźnikową przechowującą adres początku tablicy.

Nazwa tablicy

podaje adres -

jest wskazaniem

na pierwszy element

tablicy – o indeksie

0

.

RAM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

int iMoto[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};

[0]

[1]

[2]
[3]

[4]

[5]
[6]

[7]

[8]

[9]
[10]

[11]

[12]
[13]

[14]

[15]

indeks

tablica iMoto
=> wskaźnik iMoto

wskaźnik
iMoto + 3

wskaźnik
iMoto + 15

element iMoto[0]
element *(iMoto)

element iMoto[3]
element *(iMoto+3)

element iMoto[15]
element *(iMoto+15)

Wartość

Adres

iTab

[0] to jest to samo co: *

iTab

(wartość spod adresu

iTab

)

iTab

[i] to jest to samo co: *(

iTab

+i) (zwiększamy adres o i)


iTab

nie powinno

być zmieniany pod żadnym pozorem


Błąd:

iTab

+=i Błąd

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

54

T

ABLICE I

W

SKAŹNIKI

2.

Informacja przechowywana jest w pamięci operacyjnej w sposób ciągły
podobnie jak w tablicy jednowymiarowej, z tą różnicą, że zamiast
indeksów występują adresy komórek pamięci.

Tablice

wielowymiarowe

traktowane są specjalnie przez kompilatory – inaczej niż zwykłe
wskaźniki.

RAM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

int iMoto[4][4] = { {1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};

indeks

[0]

[0]
[0]

[0]

[1]

[1]
[1]

[1]

[2]
[2]

[2]
[2]
[3]
[3]

[3]
[3]

[0]

[1]
[2]

[3]

[0]

[1]
[2]

[3]

[0]
[1]

[2]
[3]
[0]
[1]

[2]
[3]

iMoto[0][0]
**(iMoto)
*

wi

iMoto[0][3]
*(*iMoto+3)
*(

wi

+3)

tablica iMoto
=> wskaźnik

wi

wskaźnik

wi

+ 3

wskaźnik

wi

+ 3*4 +3

iMoto[2][2]
*(*(iMoto+2)+2)
*(

wi

+ 2*4 +2)

int *

wi

= iMoto[0][0];

wskaźnik

wi

+ 2*4 +2

Wartość

Adres

iMoto[3][3]
*(*(iMoto+3)+3)
*(

wi

+ 3*4 +3)

Istotna różnica polega na tym, że nazwa tablicy wielowymiarowej nie
jest traktowane jak zwykła zmienne wskaźnikowa. Dla przykładu
odwołanie do tablicy dwuwymiarowej iMoto[4][4] w następujące
sposoby: *(iMoto+2) oraz (iMoto +2) daje w efekcie dostęp do adresu
trzeciego wiersza. Gdyby iMoto była zwykłą zmienną wskaźnikową to
operator ‘*’ umożliwił by dostęp do wartości pod adresem iMoto. Dzieje
się tak jedynie w tablicy jednowymiarowej. Dla tablic
wielowymiarowych można używać podwójnego operatora ‘*’ i kolejno

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

55

dokonywać przesunięcia na szukany wiersz i szukaną kolumnę. Inną
metodą jest użycie dodatkowo zdefiniowanej zmiennej wskaźnikowej
zainicjowanej adresem pierwszego elementu tablicy.


Przykładowy program

include <iostream>

using namespace std;

int main()
{
int

tab

[10] = {1,2,3,4,5,6,7,8,9,10};

int

iMoto

[4][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};

//double dd=10.10;
int *wa;
cout << "Wskaznik wa ma wartosc poczatkowa = "<<wa<<endl;
int a=10,b=20;
cout << "Komorki pamieci zmiennej a maja adres = " << &a<<endl;
wa=&a;
cout << "Wskaznik wa ma wartosc = "<<wa<<endl;
cout << "Komorki pamieci wskazywane przez wa = " << *wa<<endl;
wa=&b;
cout << "Komorki pamieci wskazywane przez wa = " << *wa<<endl;
wa=tab+4;
cout << "Komorki pamieci wskazywane przez wa = " << *wa<<endl;
//wa=&dd;
a=*wa;
cout<<"Element tablicy

tab

[4] = "<<

tab

[4]

<<" to jest to samo co *(

tab

+4) = "<<*(

tab

+4)<<endl;


// Tablica dwuwymiarowa
cout<<"Element iMoto to "<<

iMoto

<<endl;

cout<<"Element tablicy

iMoto

[0][0] = "<<

iMoto

[0][0]

<<" to jest to samo co **

iMoto

= "<<**

iMoto

<<endl;

cout<<"Element tablicy

iMoto

[0][3] = "<<

iMoto

[0][3]

<<" to jest to samo co *(*

iMoto

+3) = "<<*(*

iMoto

+3)<<endl;

cout<<"Element (

iMoto

+2) to "<<(

iMoto

+2)<<endl;

cout<<"Element *(

iMoto

+2) to "<<*(

iMoto

+2)<<endl;

cout<<"Element (*(

iMoto

+2)+2) to "<<(*(

iMoto

+2)+2)<<endl;

cout<<"Element *(*(

iMoto

+2)+2) to "<<*(*(

iMoto

+2)+2)<<endl;

cout<<"Element tablicy

iMoto

[2][2] = "<<

iMoto

[2][2]

<<" to jest to samo co *(*(

iMoto

+2)+2) = "<<*(*(

iMoto

+2)+2)<<endl;

cout<<"Element tablicy

iMoto

[3][3] = "<<

iMoto

[3][3]

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

56

<<" to jest to samo co *(*(

iMoto

+3)+3) = "<<*(*(

iMoto

+3)+3)<<endl;


// Tablica dwuwymiarowa z dodatkowym wskaźnikiem
int *wi=&iMoto[0][0];
cout<<"Wskaźnik wi to "<<wi<<endl;
cout<<"Wskaźnik (wi+2) to "<<(wi+2)<<endl;
cout<<"Wskaźnik *(wi+2) to "<<*(wi+2)<<endl;
cout<<"Wskaźnik *(wi+2*4) to "<<*(wi+2*4)<<endl;
cout<<"Element tablicy

iMoto

[2][2] = "<<

iMoto

[2][2]

<<" to jest to samo co *(wi+2*4+2) = "<<*(wi+2*4+2)<<endl;
// Wskaźnik na wskaźnik
int **ww=&wa;
cout << "Komorki pamieci wskazywane przez *ww = " << *ww<<endl;
cout << "Komorki pamieci wskazywane przez **ww = " << **ww<<endl;
system("PAUSE");
return 0;
}


Rezultat:

Wskaznik wa ma wartosc poczatkowa = 0x77c4fc80
Komorki pamieci zmiennej a maja adres = 0x22fef8
Wskaznik wa ma wartosc = 0x22fef8
Komorki pamieci wskazywane przez wa = 10
Komorki pamieci wskazywane przez wa = 20
Komorki pamieci wskazywane przez wa = 5
Element tablicy tab[4] = 5 to jest to samo co *(tab+4) = 5
Element iMoto to 0x22ff00
Element tablicy iMoto[0][0] = 1 to jest to samo co **iMoto = 1
Element tablicy iMoto[0][3] = 4 to jest to samo co *(*iMoto+3) = 4
Element (iMoto+2) to 0x22ff20
Element *(iMoto+2) to 0x22ff20
Element (*(iMoto+2)+2) to 0x22ff28
Element *(*(iMoto+2)+2) to 11
Element tablicy iMoto[2][2] = 11 to jest to samo co *(*(iMoto+2)+2) = 11
Element tablicy iMoto[3][3] = 16 to jest to samo co *(*(iMoto+3)+3) = 16
Wskačnik wi to 0x22ff00
Wskačnik (wi+2) to 0x22ff08
Wskačnik *(wi+2) to 3
Wskačnik *(wi+2*4) to 9
Element tablicy iMoto[2][2] = 11 to jest to samo co *(wi+2*4+2) = 11
Komorki pamieci wskazywane przez *ww = 0x22ff50
Komorki pamieci wskazywane przez **ww = 5
Aby kontynuować, naciśnij dowolny klawisz . . .

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

57

W

SKAŹNIKI

1.

Zmienne wskaźnikowe

wartościami są adresy wskazujące na miejsce w

pamięci operacyjnej pewnego obiektu (segment + offset).

int *wa

; //deklaracja zmiennej wskaźnikowej wa na obiekt int

int *wa

, a=10, b=20;

wa=&a

; // wa zaczyna wskazywać na zmienna ‘a’

Dostęp do wartości zmiennej ‘a’:

cout<<a<<”,”;

lub

cout<<*wa;

//przez

operator

wyłuskania

//(nie mylić z wyłuzdaniem)

Efekt: 10,10

Można teraz

*wskaźnik

traktować jak zmienną na którą obecnie wskazuje (w przykładzie na a),

np.

*wa = 100

; zapisze wartość 100 do zmiennej ‘a’

b=*wa+1;
c=(*wa)++;

//operatory działają od prawej do lewej to trzeba nawiasy

c=++*wa;

//to samo

ale nie:

c=*wa++;

//spowoduje zwiększenie adresu wskazania wa o jeden i dopiero przypisanie do c

//zwykle NIEUśYWANE















Adres a składa się z adresu Segmentu i Offset fizycznego adresu RAM w komputerze.
Wskaźnik zatem zajmuje 2 bajty adresu segmentu i 2 bajty adresu offsetu = 4 bajty.

wa

a

b

int *wa

?

10

20

int a=10, b=20;

wa

wa=&a

wskazanie na a
(zaadresowanie a)

adres a

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

58

W

SKAŹNIKI

2.

PRZEKAZYWANIE PARAMETRÓW DO FUNKCJI:

Poprzednio poznaliśmy przekazywanie parametrów funkcji przez wartość. Były na to

przykłady, które pokazywały, że zmienne nawet o tej samej nazwie nie mają ze sobą nic
wspólnego – jedynie ich wartość przekazywana jest do wnętrza funkcji.

Przykład:

void

fnZwieksz

(

int a, int b

) {

a +=100;

b+=200;

}

Wywołanie:

int x = 10, y = 10;

fnZwieksz

(

x,y

);

//nie zmienia wartości x i y

Efekt: //bez zmian: x = 10, y=10

Jak to zmienić ?


1. Nie zmieniać –

używać zmiennych globalnych

,

2. Wykorzystać

wskaźniki

(C, C++) – przekazywanie przez wskaźniki

3. Wykorzystać

referencję

(C++) – przekazywanie adresu


Ad.2

Wskaźniki

– przekazanie przez wskaźniki

void

fnZwiekszInny

(

int *a, int *b

) {

*a+=100;
*b+=200;
}

Wywołanie:

int x=10, y =10;

fnZwiekszInny

(

&x,&y

); //zmienia wartość x i y

Efekt: x=110, y=210

Ad.3

Referencja

- przekazywanie adresu

void

fnZwiekszRef

(

int &a, int &b

){ // Zmienia się jedynie deklaracja funkcji

a+=100;
b+=200;
}

Wywołanie:

int x = 10, y = 10;

fnZwiekszRef

(

x,y

); // zmienia wartość x i y

Efekt: x=110, y=210

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

59

W

SKAŹNIKI

3.


Przykład - zamiana wartości argumentów:

void

fnZmien

(

int &a, int &b

){

int pom=b;
b=a;
a=pom;
}


Wywołanie:

int x=10, y=30;

fnZmien

(

x,y

);


Efekt: x=30, y=10

TABLICE i FUNKCJE

Nazwa tablicy jest wskaźnikiem na zerowy element tablicy

, zatem przekazanie

tablicy poprzez nazwę jest jednocześnie

przekazywaniem przez adres

.

UWAGA:

Rozmiar tablic może być różny, zatem należy pamiętać o przekazaniu do funkcji

rozmiaru tablicy przez wartość poprzez inny argument wywołania.

Przykłady:

//Program liczy sumę wszystkich elementów tablicy
int

fnSumaWekt(

int t[], int m

){ //m – rozmiar tablicy

int sum=0;
for(int i=0;i<m;i++)

sum+=t[i];

return sum;
}


Wywołanie:

int x[20],iWynik;
iWynik=

fnSumaWekt

(

x,20

);


lub: dla określonego wiersza tablicy dwuwymiarowej

int y[20][20],iWynik;
iWynik=

fnSumaWekt

(

y[1],20

); //obliczy sumę drugiego wiersza y[1] tablicy y

background image

WYKŁADY cz.2 v.5 (2011) Podstawy programowania 1

(dr.inż Marcin Głowacki)

60

Przykład:

wyświetla wynik funkcji przeciążonych suma wektora i tablic dwuwymiarowych

#include <iostream>
#define MMAX 3
#define NMAX 3
using namespace std;
int

fnSuma

(

int iTab[][NMAX], int m, int n

){

int iSuma=0;
for (int i=0;i<m;i++){

cout<<endl;

for(int j=0;j<n;j++){

iSuma+=iTab[i][j];

cout<<'\t'<<iTab[i][j];

}

}
cout<<"\nSuma tablicy naturalnej: "<<iSuma<<endl;

return

iSuma;

}
double

fnSuma

(

double dTab[][NMAX], int m, int n

){

double dSuma=0;
for (int i=0;i<m;i++){

cout<<endl;

for(int j=0;j<n;j++){

dSuma+=dTab[i][j];

cout<<'\t'<<dTab[i][j];

}

}
cout<<"\nSuma tablicy zmiennoprzecinkowej: "<<dSuma<<endl;

return

dSuma;

}
int

fnSuma

(

int iTab[], int m

){

int iSuma=0;
for (int i=0;i<m;i++){

iSuma+=iTab[i];

cout<<'\t'<<iTab[i];

}
cout<<"\nSuma wektora naturalnego: "<<iSuma<<endl;

return

iSuma;

}
int

main

(){

int

iTablica

[MMAX][NMAX] = {1,2,3,4,5,6,7,8,9};

double

dTablica

[MMAX][NMAX] =

{ {1.1,2.2,3.3},{4.4,5.5,6.6},{7.7,8.8,9.9}};

fnSuma

(

iTablica,MMAX,NMAX

);

fnSuma

(

dTablica,MMAX,NMAX

);

fnSuma

(

iTablica[1],NMAX

);

return

0; }

Efekt:

1 2 3
4 5 6
7 8 9
Suma tablicy naturalnej: 45

1.1 2.2 3.3
4.4 5.5 6.6
7.7 8.8 9.9
Suma tablicy
zmiennoprzecinkowej: 49.5
4 5 6
Suma wektora naturalnego: 15


Wyszukiwarka

Podobne podstrony:
Informa cz2 v3 id 213358 Nieznany
Informa cz1 v5 id 213357 Nieznany
Informa cz3 v5 id 213360 Nieznany
Informacje dla inwestora id 213 Nieznany
Informa cz4 v6 id 213362 Nieznany
Informa wyklad petle id 716506 Nieznany
inform r1 rozw id 288565 Nieznany
Informacja pod ochrona id 21351 Nieznany
informatyka model PP id 214055 Nieznany
informatyka pp arkusz1 id 21382 Nieznany
Informa cz4 v9 id 213363 Nieznany
Informa cz4 v3 id 213361 Nieznany
Informacje dla inwestora id 213 Nieznany
Informa cz4 v6 id 213362 Nieznany
INFORM EXCEL2007 2 id 716490 Nieznany
artykul profilaktyka cz2 id 695 Nieznany (2)
metale niezelazne cz2 id 293802 Nieznany

więcej podobnych podstron