METODY I JĘZYKI PROGRAMOWANIA Programowanie w języku C
Transkrypt
METODY I JĘZYKI PROGRAMOWANIA Programowanie w języku C
METODY I JĘZYKI PROGRAMOWANIA Programowanie w języku C notatki z wykładów - Różnice zapisu algorytmu w C i PASCALu Formatowane WE/WY w C. Funkcje printf() i scanf() Stałe i zmienne języku C. Typy wartości. Podstawowe instrukcje Operatory Funkcje Tablice 1 Programowanie w C dla znających PASCAL /* 1 przykladowy program C */ { 1 przykladowy program PAS } #include <stdio.h> void main(void) { printf(”Dzien ”); printf(”dobry!\n”); } begin write(‘Dzien ‘); writeln(‘dobry!’); end. #include ← dyrektywa dołączenia tekstu zawartego w pliku stdio.h ← (StandardInputOutput) plik definicji funkcji Wej/Wyj main ← zastrzeżona nazwa głównej funkcji programu void ← typ danej “pustej” \n ← przejscie do nowego wiersza \t ← znak tabulacji \” ← znak cudzysłowu \\ ← jeden znak \ // 2 przyklad → dodawanie liczb (* 2 przyklad → dodawanie *) #include <stdio.h> #include <conio.h> uses crt; int x,y,s; void main(void) { clrscr(); printf(”Podaj x = ”); scanf( ”%d” , &x ); printf(”Podaj y = ”); scanf( ”%d” , &y ); s = x+y; printf(”Suma x+y = %d\n”, s ); getch(); } var x,y,s:integer; begin clrscr; write(‘Podaj x = ‘); readln( x ); write(‘Podaj y = ‘); readln( y ); s := x+y; writeln(‘Suma x+y = ’, s ); readkey; end. 2 Ilustracja podstawowych różnic pomiędzy składnią języków C PASCAL −−− program nazwa_programu ; #include <nazwa_biblioteki> uses nazwa_biblioteki ; #define Pi 3.14 const Pi = 3.14; typedef int tablica[10]; type tablica=array[0..9]of integer; int i, j, k; float x, y, z; char znak; var i, j, k : integer; x, y, z : real; znak : char; void NazwaProc( void ) { int x; x = 10 * 5; scanf( ”%f”, &y ); }//-------------------------NazwaProc procedure NazwaProc; var x : integer; begin x := 10 * 5; read( y ); end; (*----------------NazwaProc*) float NazwaF( float x ) { float z; if( x == 0 ) z = -1; else z = 1/x; return( z ); }//-----------------------------NazwaF function NazwaF( x:real ):real; var z:real; begin if x = 0 then z := -1 else z := 1/x; NazwaF := z; end;(*----------------------NazwaF*) void main( void) { double wynik; printf(”Podaj liczbe y = ”); NazwaProc(); wynik = NazwaF( y ); if( wynik != -1 ) printf(”Wynik = %f” , wynik ); else printf(”Dzielenie przez zero”); znak=getch(); } var wynik : real; begin write(‘Podaj liczbe y = ’); NazwaProc; wynik := nazwaf( y ); if wynik <> -1 then write(‘Wynik =’ , wynik ) else write(‘Dzielenie przez zero’); znak:=readkey; end. 3 Stałe i zmienne w języku C Definiowanie zmiennych → ustalenie nazwy, typu, rezerwacja pamięci nazwa_typu nazwa_zmiennej ; nazwa_typu zmienna_1, zmienna_2, zmienna_3 ; Podstawowe typy: Nazwa typu Zawartość Przedział wartości Zajęt. pamięć char znak -128 ÷ 127 1 bajt int liczba całkowita -32768 ÷ 32767 2 bajty long liczba całkowita -2147mln ÷ 2147mln float liczba rzeczyw. 10-38 ÷ 1038 (7cyfr) 4 bajty double liczba rzeczyw. 10-308 ÷ 10308 (15 cyfr) 8 bajtów 4 bajty Modyfikatory typu: signed unsigned short long → → → → ze znakiem (±), bez znaku, krótka (mniejsza), długa (większa) int int int int char − char − − − − double np. unsigned long int dluga_liczba_bez_znaku ; Wartości domyślne: Type unsigned char char enum unsigned int short int int unsigned long long float double long double long int char Length 8 bits 8 bits 16 bits 16 bits 16 bits 16 bits 32 bits 32 bits 32 bits 64 bits 80 bits = = = long int signed int signed char Range 0 ÷ 255 -128 ÷ 127 -32,768 ÷ 32,767 0 ÷ 65,535 -32,768 ÷ 32,767 -32,768 ÷ 32,767 0 ÷ 4,294,967,295 -2,147,483,648 ÷ 2,147,483,647 3.4 * (10**-38) ÷ 3.4 * (10**+38) 1.7 * (10**-308) ÷ 1.7 * (10**+308) 3.4 * (10**-4932) ÷ 1.1 * (10**+4932) 4 Formatowane WE/WY w języku C Funkcja: printf() <stdio.h> wysyła sformatowane dane do standardowego strumienia wyjściowego int printf ( format , argument_1 , argument_2 , . . . ) ; format jest to stała łańcuchowa (w podwójnych cudzysłowach) zawierająca: − zwykłe znaki (które są po prostu kopiowane na ekran) − kody formatujące kolejnych argumentów: %c %s %d %f %e %g %u %x %o l − − − − − − − − − − pojedynczy znak łańcuch znaków liczba dziesiętna ze znakiem liczba zmiennoprzecinkowa (notacja dziesiętna) liczba zmiennoprzecinkowa (notacja wykładnicza) liczba zmiennoprzecinkowa (krótszy z formatów %f %e) liczba dziesiętna bez znaku liczba w kodzie szesnastkowym (bez znaku) liczba w kodzie ósemkowym (bez znaku) przedrostek (long) stosowany przed: d u x o np. #include <stdio.h> void main(void) { int x = 10; long y = 20; double s; s = x + y; printf ( ”%s obliczen %d + %ld = %f” , ”Wynik” , x , y , s ); } efekt na ekranie → Wynik obliczen 10 + 20 = 30.000000 Aby określić ilość drukowanych cyfr do kodu formatującego można dodać kody długości: %Xd %X.Xf np. %4d − liczba dziesiętna na czterech pozycjach %10f − liczba rzeczywista na 10 pozycjach %10.2f − liczba rzeczywista na 10 pozycjach, 2 cyfry po przecinku %.3f − liczba rzeczywista z dokladnoscią do 3 cyfr po przecinku 5 Funkcja: scanf() <stdio.h> odczytuje dane ze standardowego strumienia wejściowego w/g zadanego formatu i zapamiętuje je pod zadanymi adresami pamięci int scanf ( format , adres_1 , adres_2 , . . . ) ; format → jest to stała łańcuchowa (w podwójnych cudzysłowach) zawierająca instrukcję jak traktować kolejne dane wczytywane ze strumienia (jakie typy zmiennych są pod adresami adres_1, adres_2, ... ) Kody formatujące (podobne jak dla printf() ): %c %s %d %f lub %e %u %x %o l l L − − − − − − − − − − pojedynczy znak łańcuch znaków liczba dziesiętna ze znakiem liczba zmiennoprzecinkowa liczba dziesiętna bez znaku liczba w kodzie szesnastkowym (bez znaku) liczba w kodzie ósemkowym (bez znaku) przedrostek stosowany przed: d u x o (long int) przedrostek stosowany przed: f e (double) przedrostek stosowany przed: f e (long double) & − operator referencji (zwraca adres zmiennej podanej po operatorze) np. #include <stdio.h> void main(void) { int x; double y; char znak; printf( ”Podaj jedna liczbe calkowita: ” ); scanf ( ”%d” , &x ); printf( ”Podaj jedna liczbe rzeczywista i jeden znak: ”); scanf ( ”%lf %c” , &y , &znak ); } Wydruk → Odczyt ← Wydruk → Odczyt ← Podaj jedna liczbe calkowita: 123 ↵ Podaj jedna liczbe rzeczywista i jeden znak: 456.789 a ↵ Wynik wczytywania: x == 123, y == 456.789, znak == ’a’ 6 OPERATORY operatory arytmetyczne: + − ∗ / % dodawanie odejmowanie mnożenie dzielenie reszta z dzielenia operatory przypisania: = += −= ∗= /= %= zwykłe przypisanie przypisanie sumy przypisanie różnicy przypisanie iloczynu przypisanie ilorazu przypisanie reszty x = 2; x+=2; x−=2; x∗=2; x /=2; x%=2; → → → → → x = x + 2; x = x − 2; x = x ∗ 2; x = x / 2; x = x % 2; operatory inkrementacji i dekrementacji: zmienna++ − inkrementacja zmiennej po wyliczeniu wyrażenia ++zmienna − inkrementacja zmiennej przed wyliczeniem wyrażenia zmienna−− − dekrementacja zmiennej po wyliczeniu wyrażenia −−zmienna − dekrementacja zmiennej przed wyliczeniem wyrażenia np. int x, y = 1; x = ++ y ; /∗ rezultat: x=2, y=2∗/ x = y ++ ; /∗ rezultat: x=1, y=2∗/ operatory relacyjne: == != < > <= >= równe różne mniejsze większe mniejsze lub równe większe lub równe operatory logiczne: && || ! koniunkcja (AND) alternatywa (OR) negacja (NOT) bitowe operatory logiczne: & | ^ << >> ~ bitowa koniunkcja (AND) bitowa alternatywa (OR) bitowa różnica symetryczna (XOR) przesunięcie bitów w lewo przesunięcie bitów w prawo negacja bitów 7 Priorytety operatorów w języku C: Operator () [] . −> ! ~ − ++ −− & ∗ (type) sizeof ∗ / % + − << >> < <= > >= == != & ^ | && || ?: = ∗= /= %= += −= <<= >>= &= ^= |= , Opis Przykład wywołanie funkcji sin() element tablicy tab[10] element struktury osoba.nazwisko wskazanie elemenu struktury wsk_osoby−>nazwisko negacja logiczna if( ! (x >max) ) kontynuuj; negacja bitowa ~(001101) ≡ (110010) zmiana znaku (negacja) x = 10 ∗ (− y) inkrementacja (zwiększenie o 1) x + + + y ≡ (x+ +) + y dekrementacja (zmiejszenie o 1) − − y ≠ − − y ≡ − (− y) operator referencji (adres elementu) wsk_x = &x operator dereferencji ∗wsk_x = 10 zmiana typu (typecast) (double) 10 ≡ 10.0 rozmiar zmiennej lub typu (w bajtach) sizeof( int ) ≡ 2 mnożenie dzielenie operacja modulo (reszta z dzielenia) if( x%2 == 0 ) parzyste; dodawanie odejmowanie przesunięcie bitowe w lewo 1 << 2 ≡ (0001) << 2 ≡ (0100) przesuniecie bitowe w prawo x = 4 >>1 ≡ x=2 mniejszy niż if( liczba < max ) max = liczba; mniejszy lub równy wiekszy niż wiekszy lub równy równy nierówny (różny od) iloczyn bitowy suma bitowa modulo (różnica symetryczna) suma bitowa iloczyn logiczny suma logiczna wyrażenie warunkowe przypisanie wartości skrócone formy przypisania arytmetycznego operator przecinka 8 JĘZYK C → PODSTAWOWE INSTRUKCJE • Nawiasy klamrowe { } są używane do grupowania wielu deklaracji i instrukcji w jedną instrukcję złożoną (jeden blok). • Instrukcja warunkowa: if ( wyrażenie ) instrukcja_1 ; else instrukcja_2 ; − część od słowa else można pominąć, − instrukcja sprawdza czy wyrażenie jest różne od zera tzn. if ( wyrażenie ) jest równoważne if ( wyrażenie != 0 ) • Konstrukcja else-if: if ( wyrażenie_1 ) instrukcja_1; else if ( wyrażenie_2 ) instrukcja_2; else if ( wyrażenie_3 ) instrukcja_3; else instrukcja_4; • Instrukcja wyboru: switch ( wyrażenie_całkowite ) { case wartość_1 : instrukcja_1; break; case wartość_2 : case wartość_3 : case wartość_4 : instrukcja_234; break; default : instrukcja_domyslna; break; } 9 Przykłady dla instrukcji warunkowej: #include <stdio.h> // Wartość maksymalna z trzech wczytanych liczb void main(void) { int A, B, C, max; printf( ”Podaj pierwsza liczbe: ” ); scanf( ”%d” , &A ); printf( ”Podaj druga liczbe: ” ); scanf( ”%d” , &B ); printf( ”Podaj trzecia liczbe: ” ); scanf( ”%d” , &C ); max = A; if( max < B ) max = B; if( max < C ) max = C; printf( ”\n Maksymalna wartosc = %d” , max ); getchar(); } #include <stdio.h> // Pierwiastki trójmianu kwadratowego Ax2+Bx+C=0 #include <conio.h> #include <math.h> void main( void ) { double a, b, c, delta, x1, x2; clrscr(); printf( "Podaj pierwsza liczbe A= " ); scanf( "%lf" , &a ); // Uwaga !!! %lf a nie %f printf( "Podaj druga liczbe B= " ); scanf( "%lf" , &b ); printf( "Podaj trzecia liczbe C= " ); scanf( "%lf" , &c ); delta = b∗b − 4∗a∗c; if( delta < 0 ) printf( "\n Brak rozwiazan" ); else if( delta == 0 ) { x1 = x2 = −b/(2∗a); printf( "Jest jedno rozwiazanie x1=x2= %f", x1 ); } else { x1 = (−b − sqrt(delta)) / (2∗a); x2 = (−b + sqrt(delta)) / (2∗a); printf( "Sa dwa rozwiazania x1= %.2f, x2= %.2f", x1, x2 ); } } 10 Przykład dla instrukcji wyboru: #include <stdio.h> // Program zawierający proste “menu” void main( void ) { char znak; double a, b, wynik; printf( "Podaj pierwsza liczbe A =" ); scanf( "%lf" , &a ); printf( "Podaj druga liczbe B =" ); scanf( "%lf" , &b ); printf( "\n\nMozliwe operacje:" ); printf( "\n (+) wynik = A + B" ); printf( "\n (−) wynik = A − B" ); printf( "\n (∗) wynik = A ∗ B" ); printf( "\n ( / ) wynik = A / B" ); printf( "\n\nPodaj znak operacji: " ); flushall( ); // wczytanie dwóchliczb z klawiatury // wyswietlenie “menu” // wyczyszczenie wszystkich buforów (tutaj->klawiatury) znak = getchar( ); // wczytanie znaku wybranej operacji switch( znak ) // instrukcja wyboru jednej z operacji arytmetycznych { case '+' : wynik = a + b; break; case '−' : wynik = a − b; break; case '∗' : wynik = a ∗ b; break; case '/' : wynik = a / b; break; default: wynik = 0; printf( "\nBład operatora: podano zły znak operacji" ); break; } // wydruk liczb i wyniku z zadana dokladnoscia miejsc po przecinku printf( "\nWynik obliczen: %.1f %c %.1f = %.2f " , a , znak , b , wynik ); printf( "\n\nKoniec programu. Nacisnij dowolny klawisz" ); fflush( stdin ); getchar( ); // wyczyszczenie bufora strumienia <stdin> tzn. klawiatury } 11 Programowanie iteracji - INSTRUKCJE PĘTLI • Pętla while( ): while ( wyrażenie ) instrukcja; while ( wyrażenie ) { instrukcja_1; instrukcja_2; ... instrukcja_N; } Pętla wykonywana jest tak długo jak wartość wyrażenie jest różna od zera int i = 10; while( i != 0 ) { printf ( ”%2d\n” , i ); i = i − 1; } int i = 10; while( i ) printf ( ”%2d\n” , i −− ); • Pętla do while( ): do instrukcja; while ( wyrażenie ); do { instrukcja_1; instrukcja_2; ... instrukcja_N; } while ( wyrażenie ); Pętla wykonywana jest tak długo jak wartość wyrażenie jest różna od zera 12 • Pętla for( ): for( wyrazenie_inicjujace ; wyrazenie_testujace ; wyrazenie_modyfikujace ) wykonywana_instrukcja ; jest równoważna konstrukcji: wyrazenie_inicjujace ; while( wyrazenie_testujace ) { wykonywana_instrukcja ; wyrazenie_modyfikujace ; } int i ; i = 10; while( i != 0 ) { printf ( ”%2d\n” , i ); i = i − 1; } int i ; for( i = 10; i != 0 ; i = i − 1 ) printf( ”%2d\n” , i ); lub int i ; for( i = 10; i ; printf(”%2d\n” , i −−) ) ; //przykładowy program wypisujacy tabele kodów ASCII #include <stdio.h> void main(void) { int n; printf( ”\n” ); for( n=32; n<256; n++ ) printf( ”%3d = %c\n” , n , n ); } //prymitywny kalkulator biurowy #include <stdio.h> void main(void) { double suma=0, liczba; while( scanf( ”%lf” , &liczba ) > 0 ) printf( ”\t%.2f\n” , suma+=liczba ); } 13 #include <stdio.h> // program zliczający naciskane klawisze #include <conio.h> void main(void) { int licznik = 0, klawisz; printf( ”Program zliczajacy naciskane klawisze. Koniec = ESC” ); do { klawisz = getch(); licznik++; } while( klawisz != 27 ) // 27 = kod klawisza Escape printf( ”\n Ilosc nacisnietych klawiszy = %d” , licznik ); } ••• // ten sam program z użyciem pętli for int licznik; for( licznik = 0 ; getch() != 27 ; licznik++ ) ••• #include <stdio.h> //program klasyfikujący naciskane klawisze #include <conio.h> #define ESC 27 //definicja kodu klawisza «Escape» void main(void) { int klawisz=0; clrscr(); while( klawisz != ESC ) { printf( ”\n\nNacisnij jakis klawisz (ESC->Koniec): ” ); klawisz = getch(); if( ‘a’<=klawisz && klawisz<=’z’ ) printf( ”-> To jest mala litera.” ); else if( ‘A’<=klawisz && klawisz<=’Z’ ) printf( ”-> To jest duza litera.” ); else if( ‘0’<=klawisz && klawisz<=’9’ ) printf( ”-> To jest cyfra.” ); else if( klawisz == 13 ) printf( ”-> To jest klawisz ENTER.” ); else if( klawisz == ‘ ‘ ) printf(“-> To jest klawisz spacji”); else printf(“-> To jest inny klawisz.”); } } 14 #include <stdio.h> //program rozpoznajacy klawisze funkcyjne #include <conio.h> #include "def_klaw.h" //dołaczenie pliku zawierajacego definicje klawiszy void main( void ) { int klawisz; clrscr(); do { printf( "\n\n Nacisnij jakis klawisz: " ); klawisz = getch( ); switch( klawisz ) { case ENTER : printf( "To jest ENTER" ); break; case ESC : printf( "To jest ESCAPE" ); break; case ZERO : // pierwszy odczytany znak mial kod równy 0 klawisz = getch( ); switch( klawisz ) { case DELETE : printf( "Delete" ); break; case UP_ARROW : printf( "Up arrow" ); break; case DOWN_ARROW : printf( "Down arrow" ); break; } break; case BACKSPACE : printf( "To jest BACKSPACE" ); break; default : printf( "Nieznany pojedynczy klawisz" ); break; } 15 Funkcja (podprogram) Funkcja jest częścią programu, realizującą pewne ściśle określone zadanie. Program w języku C składa się ze zbioru funkcji napisanych prze programistę. Ponadto, może on korzystać z funkcji zewnętrznych, np. napisanych przez twórców systemu operacyjnego, kompilatora, a także inne osoby. Funkcje te umieszczone są w specjalnych plikach nazywanych bibliotekami. Każdy program w języku C/C++ MUSI zawierać przynajmniej jedną funkcję o predefiniowanej nazwie: main( ). Składnia definicji funkcji: zwracany_typ NAZWA_FUNKCJI ( lista parametrów ) { instrukcja lub sekwencja instrukcji ; } przykład: int MAX ( int liczba_1 , int liczba_2 ) { if( liczba_1 > liczba_2 ) return liczba_1 ; else return liczba_2 ; } ⇒ lista parametrów może być pusta lub zawierać opisy kolejnych parametrów (pooddzielane przecinkami): main( ) ⇒ main( void ) main( int argc , char∗ argv[ ] ) parametry definiowane są tak jak zmienne. Uwaga: nie można grupować sekwencji parametrów tego samego typu: int MAX ( int liczba_1, liczba_2 ) ← źle ! ⇒ „ciało” funkcji jest zawarte pomiędzy nawiasami: { ... } (bez średnika na końcu) ⇒ działanie funkcji kończy się po napotkaniu polecenia return lub po wykonaniu sekwencji wszystkich instrukcji zawartych w ciele funkcji, ⇒ jeżeli funkcja jest typu void, to używamy samego słowa return, bez żadnego wyrażenia po nim, ⇒ jeżeli funkcja jest typu innego niż void to po poleceniu return musi się pojawić wyrażenie odpowiedniego typu (może być w nawiasach), np.: 16 return liczba_1; lub return( liczba_1 ) ; Prototyp funkcji → deklaracja „uprzedzająca”, (objaśnienie identyfikatora funkcji) określa tylko nazwę funkcji oraz typy zwracanej wartości i parametrów (sam nagłówek funkcji zakończony średnikiem) Deklaracja funkcji jest konieczna w przypadkach, gdy wywołanie funkcji występuje wcześniej niż jej definicja. Np. // program wyznaczający maksimum 3 liczb poprzez wywołanie funkcji MAX #include <stdio.h> int MAX ( int , int ) ; // Prototyp - deklaracja funkcji MAX void main( void ) { int a , b , c , m. ; printf( " Podaj liczbe A = " ); scanf( " %d " , &a ); printf( " Podaj liczbe B = " ); scanf( " %d " , &b ); printf( " Podaj liczbe C = " ); scanf( " %d " , &c ); m = MAX( a , b ); // Wywolanie funkcji MAX printf( " \n\nMaksimum z liczb A i B rowna sie = %d " , m ) ; printf( " \n\nMaksimum z liczb B i C rowna sie = %d " , MAX( b,c ) ) ; printf( " \n\nMaksimum z A,B,C rowna sie = %d " , MAX( a, MAX(b,c) ) ) ; flushall(); getchar(); } int MAX ( int liczba_1, int liczba_2 ) { if( liczba_1 > liczba_2 ) return liczba_1 ; else return liczba_2 ; } // Definicja funkcji MAX 17 FUNKCJE / PRZEKAZYWANIE PARAMETRÓW 1. Funkcja bezparametrowa nie zwracająca żadnej wartości void nazwa_funkcji(void) { ••• } return; // powoduje natychmiastowe zakończenie wykonywania funkcji // na końcu funkcji można pominąć przykład void odwrotność(void) { // obliczenie odwrotności liczby wczytanej z klawiatury double liczba; scanf( ”%lf” , &liczba ); if( liczba == 0 ) return; printf( ”%f” , 1/liczba ); return; // to «return» można pominąć } 2. Funkcja pobierająca parametr i zwracająca wartość UWAGA ! w języku C parametry przekazywane są tylko przez wartość tzn. po wywołaniu funkcji tworzone są nowe zmienne (lokalne), których zawartość inicjowana jest wartościami parametrów (zmiennych, stałych lub wyrażeń) podanych przy wywołaniu. przykład double odwrotność( double liczba ) { if( liczba == 0 ) return( 0 ); else return( 1/liczba ); } // definicja funkcji «odwrotność» void main( void ) { double x=10, y; y = odwrotnosc( 20 ); // przykłady wywoływania funkcji «odwrotnosc» y = odwrotnosc( x ); odwrotnosc( 3∗(15-x) ); } 18 przykład // przykład funkcji zwracającej wartość większego z argumentów double maksimum( double a, double b ) { if( a > b) return( a ); return( b ); } przykład void posortuj_1 ( double a, double b ) { // UWAGA !!! double buf; // błędny sposób przekazywania if( a > b) // paramerów (przez wartość). { // Sortowane są zmienne lokalne a i b buf = a; // (kopie parametrów x i y). a = b; // Zawartość x i y nie ulegnie zmianie ! b = buf; } } void main( void ) { double x=7, y=5; posortuj_1( x, y ); } // do funkcji przekazywane są wartości zmiennych przykład void posortuj_2 ( double ∗a, double ∗b ) { // przekazywanie parametrów „przez adres” double buf; if( ∗a > ∗b) // porównywane są zawartości miejsc { // wskazywanych przez wskazniki a i b buf = ∗a; ∗a = ∗b; ∗b = buf; } } void main( void ) { double x=7, y=5; posortuj_2( &x, &y ); } //do funkcji przekazywane są adresy zmiennych 19 W języku C++ parametry mogą być przekazywane przez wartość lub przez referencję (przekazywanie przez referencję jest odpowiednikiem przekazywania przez zmienną) Typ referencyjny → zmienne tego typu nie zajmują nowego miejsca w pamięci, służą do reprezentacji innych zmiennych w programie. nazwa_typu nazwa_zmiennej; ← utworzenie zwykłej zmiennej nazwa_typu & nazwa_zmiennej_referencyjnej = nazwa_zmiennej; (jest to zdefiniowanie aliasu − innej nazwy dla tej samej zmiennej) przykład int wzrost=175; int sredni_wzrost = wzrost; int& wysokosc = wzrost; // utworzenie zmiennej referencyjnej // związanej z tym samym obszarem // pamięci co wzrost wysokosc = wysokosc + 1; // równoważne: wzrost = wzrost + 1 przykład void posortuj_3 ( double & a, double & b ) { double buf; // przekazywanie parametrów if( a > b) // przez referencję { buf = a; // a i b są referencyjnymi nazwami x i y a = b; b = buf; } } void main( void ) { double x=7, y=5; posortuj_3( x, y ); } // parametry x i y inicjują zmienne referencyjne 20 Argumenty domniemane. W deklaracji funkcji można podać jej argumenty domniemane, tj. takie które będą użyte gdy funkcja zostanie wywołana z niekompletną listą argumentów. Argument domniemany występuje w deklaracji odpowiedniego parametru jako wyrażenie po znaku '='. Przykład. Char buffer[256] = "bufor testowy"; int cnt = 5; int Init(char* buf=NULL, int arg1=cnt, char arg2='\n'); main() { int err = 0; err += Init(); // Init(NULL, 5, '\n'); err += Init(buffer); // Init(buffer, 5, '\n'); err += Init(buffer, 6); // Init(buffer, 6, '\n'); err += Init(buffer, 6, '\0'); return err; } int Init(char* buf, int arg1, char arg2) { if(buf == NULL) return –1; if(arg1 < 0 || arg1 > strlen(buf)) return –2; buf[arg1] = arg2; return 0; } 21 Funkcje przeciążone. Funkcją przeciążona jest rodzina funkcji o takich samych nazwach, ale różnych sygnaturach. Wywołanie funkcji przeciążonej polega na wyborze tego aspektu (wersji), który najlepiej zgadza się z argumentami podanymi przy wywołaniu. Przykład. // deklaracje zmiennych glob. double dbl = 5.0; struct complex { double re; double im } comp = { 1., 5.}; /* struktury nie były dotąd omawiane */ /* tak używano struktur w klasycznym C */ // deklaracje funkcji double Abs(double d); double Abs(struct complex c); //definicje funkcji main() { double dlug; dlug = Abs(dbl); dlug = Abs(comp); return 0; } double Abs(double d) { return d; } double Abs(struct complex c) { return sqrt(c.re * c.re + c.im * c.im); } } while( klawisz != ESC ); } 22 // Zbior «def_klaw.h» zawierający definicje kodów klawiszy #ifndef DEF_KLAW #define DEF_KLAW #define ZERO 0 // klawisze "zwykle" - kodowane za pomoca jednego znaku #define ESC 27 #define ENTER 13 #define BACKSPACE 8 //klawisze "funkcyjne" - kodowane za pomoca dwoch znakow #define DELETE 83 // 0, 83 #define UP_ARROW 72 // 0, 72 #define DOWN_ARROW 80 // 0, 80 #define LEFT_ARROW 75 // 0, 75 #define RIGHT_ARROW 77 // 0, 77 #define HOME 71 // 0, 71 #define END 79 // 0, 79 #endif 23 Tablice w języku C/C++ Ogólna postać definicji tablicy: typ_elementu nazwa_tablicy [wymiar_1][wymiar_2] . . . [wymiar_N] ; np. int tablica [ 10 ]; // 10-cio elementowa tablica liczb całkowitych char tekst [ 255 ]; // 255-cio elementowa tablica znaków float macierz [ 5 ] [ 2 ]; // dwuwymiarowa tablica: 5 wierszy po 2 kolumny, UWAGA: ⇒ w języku C tablice są zawsze indeksowane od zera np. pierwszym elementem tablicy «macierz» jest: macierz[ 0 ][ 0 ] a ostatnim elementem jest:macierz[ wymiar_1 − 1 ][wymiar_2 − 1] tzn. ⇒ macierz[ 4 ][ 1 ] w języku C nie jest sprawdzana zgodność indeksu z wymiarami tablicy !!! często jest to przyczyną trudnych do wykrycia błędów. np. odwołanie: macierz[ 1 ][ 2 ] zwróci w rzeczywistości wartość pierwszego elementu z trzeciego wiersza tzn. macierz[ 2 ][ 0 ] 0,0 0,1 1,0 1,1 2,0 2,1 3,0 3,1 4,0 4,1 reprezentacja tej macierzy 0,0 0,1 1,0 1,1 2 ,0 ↓ 1,2 w pamięci komputera 2,1 3,0 3,1 4,0 4 ,1 ↑ macierz[ 1 ][ 2 ] ⇒ Obszar pamięci zajmowany przez tablicę musi być mniejszy od 64 kB W implementacji C++ firmy Borland to ograniczenie można obejść używając przy definicji tablicy słowo kluczowe huge . np. definicja: long double huge tab[ 20000 ]; jest poprawna, chociaż tablica «tab» zajmuje 200 000 bajtów ≈ 196 kB 24 Definicję tablicy można połączyć z inicjacją jej zawartości: // ← sama definicja bez inicjacji int tab[ 10 ]; int tab_inicjowana[ 10 ] = { 20, -3, 12, 1, 0, 7, -5, 100, 2, 5 }; char tab_znakow[ 5 ] { ‘a’, ‘B’, ‘\n’, ‘1’, ‘\0’ }; float macierz_A[ 3 ][ 2 ] = { {1,1}, {3.5,7.0}, {-15,100} }; float macierz_B[ 3 ][ 2 ] = { 1, 1, 3.5, 7.0, -15, 100 }; = ⇒ Kolejne „inicjatory” zawsze wstawiane są do kolejnych „komórek” tablicy (w związku z tym można pominąć wewnętrzne nawiasy klamrowe). ⇒ Jeżeli lista inicjatorów jest krótsza niż ilość elementów tablicy to pozostałe elementy są uzupełniane zerami lub wskaźnikami NULL np. definicja: int tab[ 10 ] = { 20, -3, 12, 1 }; jest równoważna: int tab[ 10 ] = { 20, -3, 12, 1, 0, 0, 0, 0, 0, 0 }; a definicja: float macierz[ 3 ][ 2 ] = { {1}, {3.5,7.0} }; jest równoważna: float macierz[ 3 ][ 2 ] = { {1,0}, {3.5,7.0}, {0,0} }; lub: float macierz[ 3 ][ 2 ] = { 1, 0, 3.5, 7.0, 0, 0 }; ⇒ W języku C inicjatorami muszą być stałe, natomiast w języku C++ inicjatorami mogą być zarówno stałe jak i zmienne. Wykorzystanie stałych do definiowania ilości elementów tablicy: int tablica [ 100 ] ; // rozmiar zadany bezpośrednio #define ROZMIAR 100 int tablica [ ROZMIAR ] ; // definicja stałej w stylu języka C const ROZMIAR_2 = 100 ; int tablica_2 [ ROZMIAR_2 ] ; // definicja stałej w stylu języka C++ for( int i=0 ; i < ROZMIAR ; i++ ) printf ( ”%d” , tablica[ i ] ); // przykład dalszego wykorzystania stałej 25 Przypisywanie / odczytywanie wartości elementów tablicy void main( ) { const ROZM = 4 ; int Tab [ ROZM ] ; // bezpośrednie przypisanie wartości Tab[ 0 ] = 0 ; Tab[ 1 ] = 10 ; Tab[ 2 ] = - 20 ; Tab[ 3 ] = 3 ; // wczytanie zawartości z klawiatury scanf( ”%d” , &Tab[ 0 ] ) ; scanf( ”%d %d” , &Tab[ 1 ] , &Tab[ 2 ] ) ; printf( ” Podaj 4 element tablicy = ” ); scanf( ”%d” , &Tab[ 3 ] ) ; // wykorzystywanie i wyświetlanie zawartości elementów tablicy long suma = Tab[0] + Tab[1] + Tab[2] + Tab[3] ; printf( ” Tab[1] = %5d ” , Tab[0] ); printf( ” Tab[2] = %5d ” , Tab[1] ); printf( ” Tab[3] = %5d ” , Tab[2] ); printf( ” Tab[4] = %5d ” , Tab[3] ); // pośrednie zadawanie wartości indeksu za pomocą zmiennej pomocniczej int i = 2 ; Tab[ i ] = 10; // równoważne poleceniu: Tab[ 2 ] = 10; // zadawanie indeksu elementu z klawiatury printf( ” Podaj indeks elementu którego wartość chcesz wczytać ” ); scanf( ”%d” , &i ); printf( ” Podaj nową wartość Tab[ %d ] = ” , i ); scanf( ”%d” , &Tab[ i ] ); printf( ” Nowa wartość Tab[ %d ] wynosi %d ” , i , Tab[ i ] ); } 26 Zastosowanie instrukcji pętli ”for” do operacji na tablicach #include <stdio.h> void main( void ) { #define ROZMIAR 10 float tablica[ ROZMIAR ]; int i ; // definicja tablicy liczb rzeczywistych // inicjowanie zawartości tablicy liczbami parzystymi: 0, 2, 4, 6, ... for( i = 0 ; i < ROZMIAR ; i++ ) tablica[ i ] = 2∗i ; // wczytanie zawartości elementów tablicy z klawiatury for( i = 0 ; i < ROZMIAR ; i++ ) { printf( ” Podaj Tab[%2d] = ”, i+1 ); scanf( ” %f ” , &tablica[ i ] ); } // wyświetlenie zawartości elementów tablicy for( i = 0 ; i < ROZMIAR ; i++ ) printf( ” Tab[%2d] = %10.3f ”, i+1 , tablica[ i ] ); // zsumowanie wartości elementów tablicy float suma = 0 ; for( i = 0 ; i < ROZMIAR ; i++ ) suma = suma + tablica[ i ]; // suma += tablica[ i ]; printf( ”Suma wartości elementów tablicy wynosi: %.2f ” , suma ); // zliczenie ilości elementów o dodatnich wartościach int ilosc = 0 ; for( i = 0 ; i < ROZMIAR ; i++ ) if( tablica[ i ] > 0 ) ilosc = ilosc + 1 ; // ilość += 1; lub ilość++; if( ilość>0 ) printf( ”Ilość dodatnich elementów = %d ” , ilosc ); else printf( ”W tablicy nie ma ani jednego dodatniego elementu ” ); 27 Przykłady prostych algorytmów „tablicowych” #include <stdio.h> void main( void ) { #define ROZMIAR 10 int tab[ ROZMIAR ]; int i, ilosc, max, poz; long suma; double srednia; for( i = 0 ; i < ROZMIAR ; i++ ) { printf( ”Tab[%2d] = ”, i+1 ); scanf( ”%d” , &tablica[ i ] ); } //--------- wczytanie liczb z klawiatury i=0; //--------------------------- zliczenie elementów niezerowych ilosc=0; while( ROZMIAR − i ) if( tab[i++] ) ilosc++; suma=0; //----------- wyznaczenie średniej z elementów niezerowych ilosc=0; i=0; do if( tab[ i ] != 0 ) { suma += tab[ i ]; ilosc++; } while( ++i < ROZMIAR ); if( ilosc ) { srednia = (double)suma / ilosc; printf( "\nSrednia niezerowych = %.2f" , srednia ); } else printf( "\nNie ma elementow niezerowych" ); max=tab[0]; //----------- wyznaczenie wartości i pozycji maksimum poz=0; for( i=1; i<ROZMIAR ; i++ ) if( max<tab[ i ] ) { max = tab[ i ]; poz = i ; } printf( "\nNajwieksza wartosc jest rowna %d" , max ); printf( "i wystapila na pozycji %d" , poz+1 ); } 28 Przekazywanie tablic jednowymiarowych przez parametry funkcji #include <stdio.h> #include <conio.h> #define ROZMIAR 10 void WczytajTablice( double tablica[ ] ) { clrscr(); printf( ” Podaj wartości elementów tablicy \n” ); for( int i = 0 ; i < ROZMIAR ; i++ ) { printf( ”Tab[%2d] = ”, i+1 ); scanf( ”%lf” , &tablica[ i ] ); } } //------------------------------------------------------------ funkcja WczytajTablicę void WyswietlTablice( double tablica[ ] ) { clrscr(); printf( ” Wartości elementów tablicy są równe: \n” ); for( int i = 0 ; i < ROZMIAR ; i++ ) printf( ”Tab[%2d] = %f”, i+1 , tablica[ i ] ); printf( ” Nacisnij dowolny klawisz” ); getch(); } //------------------------------------------------------------ funkcja WyswietlTablicę void DodajTablice( double wejscie_1[ ] , double wejscie_1[ ], double wynik [ ] ) { for( int i = 0 ; i < ROZMIAR ; i++ ) wynik[ i ] = wejscie_1[ i ] + wejscie_2[ i ] ; } //------------------------------------------------------------ funkcja DodajTablice void main( void ) { double A[ ROZMIAR ] ; double B[ ROZMIAR ], C[ ROZMIAR ] ; WczytajTablice( A ); WyswietlTablice( A ); WczytajTablice( B ); DodajTablice( A, B, C ); WyswietlTablice( C ); } 29