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
Programowanie w C dla znających PASCAL
/* 1 przykladowy program C */
#include <stdio.h>
void main(void) {
printf(”Dzien ”);
printf(”dobry!\n”);
}
{ 1 przykladowy program PAS }
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
#include <stdio.h>
#include <conio.h>
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();
}
(* 2 przyklad → dodawanie *)
uses crt;
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.
Ilustracja podstawowych różnic pomiędzy składnią języków
C PASCAL
− −−
#include <nazwa_biblioteki>
#define Pi 3.14
typedef int tablica[10];
int i, j, k;
float x, y, z;
char znak;
void NazwaProc( void ) {
int x;
x = 10 * 5;
scanf( ”%f”, &y );
}//---NazwaProc float NazwaF( float x )
{
float z;
if( x == 0 ) z = -1;
else z = 1/x;
return( z );
}//---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();
}
program nazwa_programu ; uses nazwa_biblioteki ; const Pi = 3.14;
type
tablica=array[0..9]of integer;
var
i, j, k : integer;
x, y, z : real;
znak : char;
procedure NazwaProc;
var x : integer;
begin
x := 10 * 5;
read( y );
end; (*---NazwaProc*) function NazwaF( x:real ):real;
var z:real;
begin
if x = 0 then z := -1 else z := 1/x;
NazwaF := z;
end;(*---NazwaF*) 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.
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 4 bajty float liczba rzeczyw. 10
-38 ÷10
38(7cyfr) 4 bajty double liczba rzeczyw. 10
-308 ÷10
308(15
cyfr)
8 bajtów Modyfikatory typu:
signed
→ze znakiem (
±), int char
−unsigned
→bez znaku, int char
−short
→krótka (mniejsza), int
− −long
→długa (większa) int
−double
np. unsigned long int dluga_liczba_bez_znaku ; Wartości domyślne: long = long int
int = signed int char = signed char
Type Length Range
unsigned char 8 bits 0 ÷ 255
char 8 bits -128 ÷ 127
enum 16 bits -32,768 ÷ 32,767
unsigned int 16 bits 0 ÷ 65,535
short int 16 bits -32,768 ÷ 32,767
int 16 bits -32,768 ÷ 32,767
unsigned long 32 bits 0 ÷ 4,294,967,295
long 32 bits -2,147,483,648 ÷ 2,147,483,647
float 32 bits 3.4 * (10**-38) ÷ 3.4 * (10**+38)
double 64 bits 1.7 * (10**-308) ÷ 1.7 * (10**+308) long double 80 bits 3.4 * (10**-4932) ÷ 1.1 * (10**+4932)
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
−pojedynczy znak
%s
−łańcuch znaków
%d
− liczba dziesiętna ze znakiem%f
−liczba zmiennoprzecinkowa (notacja dziesi ętna)
%e
−liczba zmiennoprzecinkowa (notacja wykładnicza)
%g
−liczba zmiennoprzecinkowa (krótszy z formatów %f %e)
%u
−liczba dziesiętna bez znaku
%x
−liczba w kodzie szesnastkowym (bez znaku)
%o
−liczba w kodzie ósemkowym (bez znaku)
l
−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
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
−pojedynczy znak
%s
−łańcuch znaków
%d
− liczba dziesiętna ze znakiem%f lub %e
−liczba zmiennoprzecinkowa
%u
−liczba dziesiętna bez znaku
%x
−liczba w kodzie szesnastkowym (bez znaku)
%o
−liczba w kodzie ósemkowym (bez znaku)
l
−przedrostek stosowany przed: d u x o (long int) l
−przedrostek stosowany przed: f e (double)
L
−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 → Podaj jedna liczbe calkowita:
Odczyt ← 123 ↵
Wydruk
→Podaj jedna liczbe rzeczywista i jeden znak:
Odczyt
←456.789 a ↵
Wynik wczytywania: x == 123, y == 456.789, znak == ’a’
OPERATORY
operatory arytmetyczne: + dodawanie
− odejmowanie
∗
mnożenie / dzielenie
% reszta z dzielenia
operatory przypisania: = zwykłe przypisanie x = 2;
+= przypisanie sumy x+=2;
→x = x + 2;
−= przypisanie różnicy x
−=2;
→x = x
−2;
∗
= przypisanie iloczynu x
∗=2;
→x = x
∗2;
/= przypisanie ilorazu x /=2;
→x = x / 2;
%= przypisanie reszty 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
Priorytety operatorów w języku C:
Operator 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
(type) zmiana typu (typecast) (double) 10 ≡ 10.0
sizeof 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
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;
}
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 );
} }
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 =" ); // wczytanie dwóchliczb z klawiatury scanf( "%lf" , &a );
printf( "Podaj druga liczbe B =" );
scanf( "%lf" , &b );
printf( "\n\nMozliwe operacje:" ); // wyswietlenie “menu”
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( ); // 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 ); // wyczyszczenie bufora strumienia <stdin> tzn. klawiatury getchar( );
}
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
•
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 );
}
#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.”);
}
#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;
}
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ć
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 ) // Definicja funkcji MAX {
if( liczba_1 > liczba_2 ) return liczba_1 ; else
return liczba_2 ; }
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 ) // definicja funkcji «odwrotność»
{
if( liczba == 0 ) return( 0 );
else
return( 1/liczba );
}
void main( void ) {
double x=10, y;
y = odwrotnosc( 20 ); // przykłady wywoływania funkcji «odwrotnosc»
y = odwrotnosc( x );
odwrotnosc( 3∗(15-x) );
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 }
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 }
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;
}
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 /* struktury nie były dotąd omawiane */
{
double re;
double im
} comp = { 1., 5.}; /* 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 );
}
// 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
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 1 , 2
2 , 0 2 , 1 3 , 0 3 , 1 4 , 0 4 , 1
reprezentacja tej macierzy
↓
w pamięci komputera0 , 0 0 , 1 1 , 0 1 , 1 2 , 0 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
Definicję tablicy można połączyć z inicjacją jej zawartości:
int tab[ 10 ]; // ← sama definicja bez inicjacji
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 // definicja stałej w stylu języka C int tablica [ ROZMIAR ] ;
const ROZMIAR_2 = 100 ; // definicja stałej w stylu języka C++
int tablica_2 [ ROZMIAR_2 ] ;
for( int i=0 ; i < ROZMIAR ; i++ ) // przykład dalszego wykorzystania stałej printf ( ”%d” , tablica[ i ] );
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 ] );
}
Zastosowanie instrukcji pętli ”for” do operacji na tablicach
#include <stdio.h>
void main( void ) {
#define ROZMIAR 10
float tablica[ ROZMIAR ]; // definicja tablicy liczb rzeczywistych int i ;
// 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 ” );
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++ ) //--- wczytanie liczb z klawiatury {
printf( ”Tab[%2d] = ”, i+1 );
scanf( ”%d” , &tablica[ i ] );
}
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 );
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 );
}