Podstawy programowania
Podstawy programowania
w j
w języku C++
ęzyku C++
Tablice a zmienne wskaźnikowe
Część dziewiąta
Niniejsze opracowanie zawiera skrót treści wykładu, lektura tych materiałów nie zastąpi uważnego w nim uczestnictwa.
Opracowanie to jest chronione prawem autorskim. Wykorzystywanie jakiegokolwiek fragmentu w celach innych niż nauka własna jest nielegalne.
Dystrybuowanie tego opracowania lub jakiejkolwiek jego części oraz wykorzystywanie zarobkowe bez zgody autora jest zabronione.
Roman Simiński
roman.siminski@us.edu.pl
www.us.edu.pl/~siminski
Autor
Kontakt
Nazwa tablicy jako wskaźnik na jej początek
Nazwa tablicy jako wskaźnik na jej początek
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
2
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
Nazwa tablicy jest interpretowana jako ustalony wskaźnik na jej początek
(pierwszy element).
int tab[ 10 ];
0
1
2
3
4
5
tab
6
7
8
9
10 elementów
Pierwszy element: tab[ 0 ]
Nazwa tablicy jako wskaźnik na jej początek, cd. ...
Nazwa tablicy jako wskaźnik na jej początek, cd. ...
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
3
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
int tab[ 10 ];
int * p;
. . .
p = tab
;
0
1
2
3
4
5
tab
6
7
8
9
10 elementów
Pierwszy element: tab[ 0 ]
p
Przypisanie:
Jest równoznaczne z:
p = tab;
p = &tab[ 0 ];
Nazwa tablicy jako wskaźnik na jej początek, cd. ...
Nazwa tablicy jako wskaźnik na jej początek, cd. ...
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
4
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
tab[ 0 ] = 5;
tab[ 1 ] = 1;
tab[ 2 ] = 10;
. . .
tab[ i ] = 22;
0
1
2
3
i
tab
8
9
p + 0
*p = 5
*( p + 1 ) = 1
*( p + 2 ) = 10
. . .
*( p + i ) = 22
p + 1
p + 2
p + 3
p + i
p
Odwołania równoważne
Nazwa tablicy jako wskaźnik na jej początek, cd. ...
Nazwa tablicy jako wskaźnik na jej początek, cd. ...
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
5
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
Nazwa tablicy z
indeksem
0
1
2
3
i
tab
8
9
Wska nik z
ź
przesuni ciem
ę
p
Odwołania równoważne
Odwołanie:
tab[ i ]
Odwołanie:
*( p + i )
Nazwa tablicy jako wskaźnik na jej początek, cd. ...
Nazwa tablicy jako wskaźnik na jej początek, cd. ...
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
6
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
Wyrażenie p + i jest wyrażeniem wskaźnikowym, wskazuje ono na obiekt oddalony
o i obiektów danego typu od p.
Wartość dodawana do wskaźnika jest skalowana rozmiarem typu obiektu
wskazywanego.
Każde odwołanie:
Oraz
tab[ i ];
można zapisać tak:
*( tab + i )
Każde odwołanie:
*( p + i )
można zapisać tak:
p[ i ];
Uwaga, wskaźnik to nie tablica!
Uwaga, wskaźnik to nie tablica!
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
7
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
int tab[ 10 ];
int * p = tab;
0
1
2
3
4
5
tab
6
7
8
9
10 elementów
p
Nazwa tablicy
int tab[ 10 ]
→
obszar danych + wskaźnika na jego początek
int * p = tab
→
wskaźnik zakotwiczony o początek tablicy
Czy to jest to samo? Nie!
Nazwa tablicy to
Nazwa tablicy to
ustalony
ustalony
wskaźnik na jej początek
wskaźnik na jej początek
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
8
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
Nazwa tablicy jest ustalonym (niemodyfikowalnym) wskaźnikiem na pierwszy jej
element. Nazw tablic nie wolno modyfikować! Zwykłe wskaźniki można.
int tab[ 10 ];
int * p = tab;
tab = p;
tab++;
p = tab + 8;
p++;
OK
Źle
Ciekawostka
Ciekawostka
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
9
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
Wiemy, że odwołanie:
tab[ i ]
można zapisać tak:
*( tab + i )
Wiemy również, że dodawanie jest przemienne, zatem każde odwołanie:
*( tab + i )
można zapisać tak:
*( i + tab )
Czy zatem odwołanie:
*( i + tab )
można zapisać tak:
i[ tab ]
?
Oraz, że odwołanie
*( tab + i )
można zapisać tak:
tab[ i ]
Ciekawostka, cd. ...
Ciekawostka, cd. ...
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
10
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
Tak, można, dla kompilatora nie ma to większego znaczenia.
char napis[] = "j zyk c";
ę
. . .
cout << napis << endl;
0[ napis ] = 'J'
;
// Zamiast napis[ 0 ]
6[ napis ] = 'C'
;
// Zamiast napis[ 6 ]
cout << napis << endl;
język c
Język C
Dlaczego nie wolno przypisywać tablic, posługując się ich nazwami?
Dlaczego nie wolno przypisywać tablic, posługując się ich nazwami?
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
11
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
int a[ 10 ];
int b[ 10 ];
b = a
; // Nie wolno przypisywać do siebie tablic!
Gdyby przypisywanie było możliwe...
0
1
2
3
4
5
a
6
7
8
9
0
1
2
3
4
5
b
6
7
8
9
To po wykonaniu tej linii:
b = a
;
gubimy obszar danych tablicy b!
0
1
2
3
4
5
a
6
7
8
9
0
1
2
3
4
5
b
6
7
8
9
Gdyby przypisywanie było możliwe...
Arytmetyka na wskaźnikach — podsumowanie
Arytmetyka na wskaźnikach — podsumowanie
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
12
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
Dozwolone operacje wskaźnikowe to:
przypisywanie wskaźników do obiektów tego samego typu,
przypisywanie wskaźników do obiektów innego typu po konwersji,
dodawanie lub odejmowanie wskaźnika i liczby całkowitej,
odejmowanie lub porównanie dwóch wskaźników związanych z ta samą tablicą,
przypisanie wskaźnikowi wartości zero (lub wskazania puste NULL) lub
porównanie ze wskazaniem pustym.
Wskaźniki w akcji — metamorfoza funkcji put_string
Wskaźniki w akcji — metamorfoza funkcji put_string
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
13
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
void put_string( char s[] )
{
int i;
for( i = 0; s[ i ] != '\0'; i++ )
putchar( s[ i ] );
}
Wersja pierwotna
char napis[] = "J zyk C i C++";
ę
put_string( napis );
Wskaźniki w akcji — metamorfoza funkcji put_string
Wskaźniki w akcji — metamorfoza funkcji put_string
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
14
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
void put_string2( char * s )
{
for( ; *s != '\0'; s++ )
putchar( *s );
}
Eliminujemy zmienną i
char napis[ 80 ] = "C++";
put_string( napis );
Jak to działa... ?
Wywołanie funkcji put_string
Wywołanie funkcji put_string
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
15
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
void put_string2(
char * s
)
{
for( ; *s != '\0'; s++ )
putchar( *s );
}
Kopiowanie parametru aktualnego napis do parametru s
char napis[ 80 ] = "C++";
put_string( napis )
;
C
+
+
\0
napis
s
Parametr s jest kopią wskaźnika napis
Parametr s jest kopią wskaźnika napis
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
16
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
void put_string2(
char * s
)
{
for( ; *s != '\0'; s++ )
putchar( *s );
}
Kopiowanie parametru aktualnego napis do parametru s
char napis[ 80 ] = "C++";
put_string( napis )
;
C
+
+
\0
napis
s
Czy obiekt wskazywany przez s jest znacznikiem końca napisu?
Czy obiekt wskazywany przez s jest znacznikiem końca napisu?
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
17
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
void put_string2( char * s )
{
for( ;
*s != '\0'
; s++ )
putchar( *s );
}
Parametr s wskazuje na pierwszy element tablicy napis
char napis[ 80 ] = "C++";
put_string( napis );
C
+
+
\0
napis
s
Znak wskazywany przez s wyprowadzamy jest do stdout
Znak wskazywany przez s wyprowadzamy jest do stdout
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
18
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
void put_string2( char * s )
{
for( ; *s != '\0'; s++ )
putchar( *s )
;
}
Parametr s wskazuje na pierwszy element tablicy napis
char napis[ 80 ] = "C++";
put_string( napis );
C
+
+
\0
napis
s
C
Wskaźnik s przesuwamy na następny znak
Wskaźnik s przesuwamy na następny znak
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
19
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
void put_string2( char * s )
{
for( ; *s != '\0';
s++
)
putchar( *s );
}
Parametr s wskazuje na kolejny element tablicy napis
char napis[ 80 ] = "C++";
put_string( napis );
C
+
+
\0
napis
s
C
Czy obiekt wskazywany przez s jest znacznikiem końca napisu?
Czy obiekt wskazywany przez s jest znacznikiem końca napisu?
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
20
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
void put_string2( char * s )
{
for( ;
*s != '\0'
; s++ )
putchar( *s );
}
Parametr s wskazuje na kolejny element tablicy napis
char napis[ 80 ] = "C++";
put_string( napis );
C
+
+
\0
napis
s
C
Znak wskazywany przez s wyprowadzamy jest do stdout
Znak wskazywany przez s wyprowadzamy jest do stdout
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
21
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
void put_string2( char * s )
{
for( ; *s != '\0'; s++ )
putchar( *s )
;
}
Parametr s wskazuje na kolejny element tablicy napis
char napis[ 80 ] = "C++";
put_string( napis );
C
+
+
\0
napis
s
C+
Wskaźnik s przesuwamy na następny znak
Wskaźnik s przesuwamy na następny znak
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
22
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
void put_string2( char * s )
{
for( ; *s != '\0';
s++
)
putchar( *s );
}
Parametr s wskazuje na kolejny element tablicy napis
char napis[ 80 ] = "C++";
put_string( napis );
C
+
+
\0
napis
s
C+
Czy obiekt wskazywany przez s jest znacznikiem końca napisu?
Czy obiekt wskazywany przez s jest znacznikiem końca napisu?
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
23
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
void put_string2( char * s )
{
for( ;
*s != '\0'
; s++ )
putchar( *s );
}
Parametr s wskazuje na kolejny element tablicy napis
char napis[ 80 ] = "C++";
put_string( napis );
C
+
+
\0
napis
s
C+
Znak wskazywany przez s wyprowadzamy jest do stdout
Znak wskazywany przez s wyprowadzamy jest do stdout
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
24
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
void put_string2( char * s )
{
for( ; *s != '\0'; s++ )
putchar( *s )
;
}
Parametr s wskazuje na kolejny element tablicy napis
char napis[ 80 ] = "C++";
put_string( napis );
C
+
+
\0
napis
s
C++
Wskaźnik s przesuwamy na następny znak
Wskaźnik s przesuwamy na następny znak
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
25
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
void put_string2( char * s )
{
for( ; *s != '\0';
s++
)
putchar( *s );
}
Parametr s wskazuje na kolejny element tablicy napis
char napis[ 80 ] = "C++";
put_string( napis );
C
+
+
\0
napis
s
C++
Czy obiekt wskazywany przez s jest znacznikiem końca napisu?
Czy obiekt wskazywany przez s jest znacznikiem końca napisu?
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
26
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
void put_string2( char * s )
{
for( ;
*s != '\0'
; s++ )
putchar( *s );
}
Parametr s wskazuje na kolejny element tablicy napis
char napis[ 80 ] = "C++";
put_string( napis );
C
+
+
\0
napis
s
C++
Wskaźniki w akcji — metamorfoza funkcji
Wskaźniki w akcji — metamorfoza funkcji
put_string,
put_string,
wersja 3 i 4
wersja 3 i 4
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
27
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
void put_string3( char * s )
{
for( ; *s != '\0' ;
putchar( *s++ )
)
;
}
„Kompresja” iteracji for
++
*s
Najpierw pobierz znak
wskazywany przez s, użyj
go.
Potem zwiększ o jeden wartość
wskaźnika s — będzie on wtedy
wskazywał na następny element tablicy.
void put_string4( char * s )
{
while( *s )
putchar( *s++ );
}
Iteracja while nie jest taka zła...
Znak '\0' to bajt o wartości 0
Wskaźniki pod lupą — metamorfoza funkcji
Wskaźniki pod lupą — metamorfoza funkcji
strcpy
strcpy
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
28
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
char s1[ 80 ] = "Język C";
char s2[ 20 ];
. . .
strcpy( s2, s1 );
0
1
2
3
4
5
J
ę
z
y
k
. . .
79
C
\ 0
6
0
1
2
3
4
5
J
ę
z
y
k
. . .
19
C
\ 0
6
i++
. . .
s1
s2
s
d
void strcpy( char d[], char s[] )
{
int i;
for( i = 0; s[ i ] != '\0'; i++ )
d[ i ] = s[ i ];
d[ i ] = '\0';
}
Wersja początkowa
Przypomnienie jak to działa
Wskaźniki pod lupą — metamorfoza funkcji
Wskaźniki pod lupą — metamorfoza funkcji
strcpy
strcpy
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
29
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
void strcpy1( char * d, char * s )
{
while( *s != '\0' )
{
*d = *s;
d++;
s++;
}
*d = '\0';
}
Odwołania wskaźnikowe
To właściwie nie wiele zmienia,
poza wyeliminowaniem
zmiennej i
void strcpy2( char * d, char * s )
{
while( *s != '\0' )
*d++ = *s++;
*d = '\0';
}
„Kompresja” — krok pierwszy
Wskaźniki pod lupą — metamorfoza funkcji
Wskaźniki pod lupą — metamorfoza funkcji
strcpy
strcpy
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
30
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
void strcpy3( char * d, char * s )
{
while( ( *d++ = *s++ ) != '\0' )
;
}
„Kompresja” — krok drugi
!= '\0'
(
=
)
*d++
*s++
Wartością tego wyrażenia jest znak
(bajt) przepisany z obszaru
wskazywanego przez s do obszaru
wskazywanego przez d.
Pobierz znak wskazywany, wykorzystaj go,
zwiększ wskaźnik tak, by pokazywał na następny
element tablicy.
Wskaźniki pod lupą — metamorfoza funkcji
Wskaźniki pod lupą — metamorfoza funkcji
strcpy
strcpy
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
31
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
void strcpy4( char * d, char * s )
{
while( *d++ = *s++ )
;
}
„Kompresja” — krok trzeci
Znak '\0' to bajt o wartości 0
char * strcpy5( char * d, char * s )
{
while( *d++ = *s++ )
;
return d;
}
Tablica d jako rezultat funkcji
Często spotykaną praktyką w funkcjach bibliotecznych jest udostępnianie wskaźnika
do tablicy (jednej z tablic) będącej parametrem:
Wskaźniki pod lupą — metamorfoza funkcji
Wskaźniki pod lupą — metamorfoza funkcji
strcpy
strcpy
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
32
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
char s1[ 80 ] = "C i C++";
char s2[ 80 ];
char s3[ 80 ];
Pozwala to na skrócenie kodu, załóżmy następujące definicje tablic s1, s2, s3:
Następujący fragment kodu:
strcpy5( s2, s1 );
strcpy5( s3, s2 );
puts( s3 );
Można zapisać krócej:
puts( strcpy5( s3, strcpy5( s2, s1 ) ) );
Wskaźniki pod lupą — metamorfoza funkcji
Wskaźniki pod lupą — metamorfoza funkcji
strcpy
strcpy
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
33
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
char * strcpy5( char * d, char * s )
{
*s = 'A'
;
. . .
}
Modyfikacja tablicy źródłowej
dozwolona, choć merytorycznie
niepoprawna
char * strcpy6( char * d,
const char * s
)
{
*s = 'A'
;
. . .
}
Tablica źródłowa jest chroniona
Aby temu zaradzić, można zadeklarować parametr reprezentujący tablicę źródłową
w specyficzny sposób:
W dotychczasowych realizacjach funkcji strcpyX, funkcja może modyfikować
zawartość tablicy źródłowej:
Wskaźniki pod lupą — zastosowanie modyfikatora
Wskaźniki pod lupą — zastosowanie modyfikatora
const
const
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
34
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
Można wyróżnić następujące kombinacje definicji wskaźnika z/bez const:
Aby funkcja nie mogła zmodyfikować parametru przekazanego za pośrednictwem
wskaźnika, należy w deklaracji użyć słowa const. Deklaracja:
const char * s;
oznacza, że s jest wskaźnikiem na stały (niemodyfikowalny) obiekt typu char.
const int * const p;
// Ustalony wska nika na niemodyfikowalny obiekt
ź
int * const p;
// Ustalony wska nika na modyfikowalny obiekt
ź
const int * p;
// Zwykły wska nika na niemodyfikowalny obiekt
ź
int * p;
// Zwykły wska nik na zwykły obiekt
ź
Wskaźniki pod lupą — zastosowanie modyfikatora
Wskaźniki pod lupą — zastosowanie modyfikatora
const
const
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
35
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
Wersja najbardziej restrykcyjna pod lupą:
const int * const p;
int i = 10;
const int * const
p = &i
;
. . .
j = *p + 10
;
. . .
*p = 20
;
. . .
p = &j
;
Niedozwolone, odwołanie modyfikujące obiekt
To jest OK, odwołanie nie modyfikujące obiektu
Niedozwolone, odwołanie modyfikujące wskaźnik
Posługiwanie się ustalonym wskaźnikiem do stałego obiektu:
To się nie uda, ustalony wskaźnik należy zainicjować!
Wyznaczanie długości napisu — funkcja strlen klasycznie
Wyznaczanie długości napisu — funkcja strlen klasycznie
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
36
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
Realizacja w wykorzystaniem iteracji while:
int strlen( char s[] )
{
int len = 0;
while( s[ len ] != '\0' )
len++;
return len;
}
Realizacja w wykorzystaniem iteracji for:
int strlen( char s[] )
{
int len;
for( len = 0; s[ len ] != '\0'; len++ )
;
return len;
}
Wyznaczanie długości napisu — funkcja strlen wskaźnikowo
Wyznaczanie długości napisu — funkcja strlen wskaźnikowo
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
37
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
int strlen( char * s )
{
char * ptr = s;
while( *ptr != '\0' )
ptr++;
return ( int )( ptr – s );
}
int strlen( char * s )
{
char * ptr;
for( ptr = s; *ptr != '\0'; ptr++ )
;
return ( int )( ptr – s );
}
Realizacja w wykorzystaniem iteracji while:
Realizacja w wykorzystaniem iteracji for:
Odwracanie kolejności znaków w napisie — strrev klasycznie
Odwracanie kolejności znaków w napisie — strrev klasycznie
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
38
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
char * strrev( char s[] )
{
int begin, end;
// Szukanie konca napisu
for( end = 0; s[ end ] != '\0'; end++ )
;
// Zamiana znakow miejscami
for( begin = 0, end--; begin < end; begin++, end-- )
{
char c = s[ begin ];
s[ begin ] = s[ end ];
s[ end ] = c;
}
return s;
}
Odwracanie kolejności znaków w napisie — strrev wskaźnikowo
Odwracanie kolejności znaków w napisie — strrev wskaźnikowo
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
39
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
char * strrev( char * s )
{
char * begin, * end;
// Szukanie znacznika konca
for( end = s; *end ; end++ )
;
// Zamiana znakow miejscami
for( begin = s, end--; begin < end; begin++, end-- )
{
char c = *begin;
*begin = *end;
*end = c;
}
return s;
}
Dynamiczna alokacja tablic — konwencja języka C
Dynamiczna alokacja tablic — konwencja języka C
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
40
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
char * s = NULL
;
int n
;
/* Tu ustalenie liczby potrzebnych elementów i zapami tanie w zmiennej n */
ę
s = malloc( n * sizeof( char ) )
;
if(
s != NULL
)
{
strcpy( s, "J zyk C " );
ę
strcat( s, "fajny jest!" );
puts( s );
. . .
free( s )
;
}
Na tablicach alokowanych dynamicznie na stercie, można wykonywać takie same
operacje, jak na tablicach statycznych. Należy tylko uważnie przydzielać i zwalniać
pamięć.
Zobaczmy, jak wyglądają kolejne etapy definiowania i wykorzystania takiej tablicy...
Dynamiczna alokacja tablic — konwencja języka C, etap 1-szy
Dynamiczna alokacja tablic — konwencja języka C, etap 1-szy
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
41
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
char * s = NULL
;
int n;
/* Tu ustalenie liczby potrzebnych elementów i zapami tanie w zmiennej n */
ę
s = malloc( n * sizeof( char ) );
if( s != NULL )
{
strcpy( s, "J zyk C " );
ę
strcat( s, "fajny jest!" );
puts( s );
. . .
free( s );
}
Definicja wskaźnika — typ obiektu wskazywanego taki, jak typ elementów tablicy
jakich potrzebujemy. Zerowanie wskaźnika to dobra praktyka.
Pamięć operacyjna
Sterta
s
Dynamiczna alokacja tablic — konwencja języka C, etap 2-gi
Dynamiczna alokacja tablic — konwencja języka C, etap 2-gi
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
42
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
char * s = NULL;
int n
;
/* Tu ustalenie liczby potrzebnych elementów i zapami tanie w zmiennej n */
ę
s = malloc( n * sizeof( char ) );
if( s != NULL )
{
strcpy( s, "J zyk C " );
ę
strcat( s, "fajny jest!" );
puts( s );
. . .
free( s );
}
Zwykle korzystamy ze zmiennej, która pozwoli zapamiętać ilu elementową tablicę
potrzebujemy.
Pamięć operacyjna
Sterta
s
Dynamiczna alokacja tablic — konwencja języka C, etap 3-ci
Dynamiczna alokacja tablic — konwencja języka C, etap 3-ci
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
43
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
char * s = NULL;
int n;
/* Tu ustalenie liczby potrzebnych elementów i zapami tanie w zmiennej n */
ę
s = malloc( n * sizeof( char ) );
if( s != NULL )
{
strcpy( s, "J zyk C " );
ę
strcat( s, "fajny jest!" );
puts( s );
. . .
free( s );
}
Przed utworzeniem tablicy musimy ustalić konkretną liczbę elementów tablicy. Jak
ustalimy tę liczbę zależy od konkretnego zastosowania.
Pamięć operacyjna
Sterta
s
Dynamiczna alokacja tablic — konwencja języka C, etap 4-ty
Dynamiczna alokacja tablic — konwencja języka C, etap 4-ty
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
44
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
char * s = NULL;
int n;
/* Tu ustalenie liczby potrzebnych elementów i zapami tanie w zmiennej n */
ę
s = malloc( n * sizeof( char ) )
;
if( s != NULL )
{
strcpy( s, "J zyk C " );
ę
strcat( s, "fajny jest!" );
puts( s );
. . .
free( s );
}
Przydział pamięci dla tablicy — funkcja malloc otrzymuje liczbę bajtów potrzebnych
do przechowania ustalonej liczby elementów tablicy.
Pamięć operacyjna
s
Pamięć operacyjna
?....................?
Sterta
Dynamiczna alokacja tablic — konwencja języka C, etap 5-ty
Dynamiczna alokacja tablic — konwencja języka C, etap 5-ty
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
45
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
char * s = NULL;
int n;
/* Tu ustalenie liczby potrzebnych elementów i zapami tanie w zmiennej n */
ę
s = malloc( n * sizeof( char ) );
if( s != NULL )
{
strcpy( s, "J zyk C " );
ę
strcat( s, "fajny jest!" );
puts( s );
. . .
free( s );
}
Kontrola poprawności przydziału pamięci. Uwaga — to koniecznie niezbędny etap!
Przydzielony obszar pamięci ma przypadkową zawartość.
Pamięć operacyjna
s
Pamięć operacyjna
???..................?
Sterta
Dynamiczna alokacja tablic — konwencja języka C, etap 6-ty
Dynamiczna alokacja tablic — konwencja języka C, etap 6-ty
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
46
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
char * s = NULL;
int n;
/* Tu ustalenie liczby potrzebnych elementów i zapami tanie w zmiennej n */
ę
s = malloc( n * sizeof( char ) );
if( s != NULL )
{
strcpy( s, "J zyk C " );
ę
strcat( s, "fajny jest!" );
puts( s );
. . .
free( s );
}
Tak utworzona tablicę można używać tak samo, jak każdą inną tablicę w języku C.
Wszystkie funkcje do manipulowania np. napisami działają bez problemu.
Pamięć operacyjna
s
Pamięć operacyjna
J zyk C fajny jest!
ę
Sterta
Dynamiczna alokacja tablic — konwencja języka C, etap 6-ty
Dynamiczna alokacja tablic — konwencja języka C, etap 6-ty
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
47
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
char * s = NULL;
int n;
/* Tu ustalenie liczby potrzebnych elementów i zapami tanie w zmiennej n */
ę
s = malloc( n * sizeof( char ) );
if( s != NULL )
{
strcpy( s, "J zyk C " );
ę
strcat( s, "fajny jest!" );
puts( s );
. . .
free( s )
;
}
Gdy tablica nie jest już potrzebna, zwalniamy przydzieloną pamięć i oddajemy do
puli wolnych bloków. Uwaga, wskaźnik pokazuje dalej na zwolniony obszar pamięci!
Pamięć operacyjna
s
Pamięć operacyjna
J zyk C fajny jest!
ę
Sterta
Dynamiczna alokacja tablic — konwencja języka C, etap 6-ty
Dynamiczna alokacja tablic — konwencja języka C, etap 6-ty
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
48
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
char * s = NULL;
int n;
/* Tu ustalenie liczby potrzebnych elementów i zapami tanie w zmiennej n */
ę
s = malloc( n * sizeof( char ) );
if( s != NULL )
{
strcpy( s, "J zyk C " );
ę
strcat( s, "fajny jest!" );
puts( s );
. . .
free( s );
s = NULL
;
}
Zerowanie wskaźnika po zwolnieniu pamięci jest dobrą praktyką.
Pamięć operacyjna
Sterta
s
Dynamiczna alokacja tablic — konwencja języka C++
Dynamiczna alokacja tablic — konwencja języka C++
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
49
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
char * s = 0;
int n;
// Tu ustalenie liczby potrzebnych elementów i zapami tanie w zmiennej n
ę
s = new char [ n ]
;
if(
s != 0
)
{
strcpy( s, "J zyk C " );
ę
strcat( s, "fajny jest!" );
puts( s );
. . .
delete [] s
;
}
W języku C++ wykorzystujemy operatory new i delete. „Stara” wersja, zakładająca,
że operator new oddaje wskaźnik zerowy w przypadku braku wolnej pamięci:
Dynamiczna alokacja tablic — konwencja języka C++
Dynamiczna alokacja tablic — konwencja języka C++
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
50
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
char * s = 0;
int n;
// Tu ustalenie liczby potrzebnych elementów i zapami tanie w zmiennej n
ę
try
{
s = new char [ n ];
strcpy( s, "J zyk C " );
ę
strcat( s, "fajny jest!" );
puts( s );
. . .
delete [] s;
}
catch( ... )
{
cout << "Brak pami ci dla wykonania tej operacji";
ę
}
„Nowa” wersja, zakładająca, że operator new generuje wyjątek w przypadku braku
wolnej pamięci:
Dynamiczna alokacja tablic — konwencja języka C++
Dynamiczna alokacja tablic — konwencja języka C++
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
51
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
char * s = 0
;
int n;
// Tu ustalenie liczby potrzebnych elementów i zapami tanie w zmiennej n
ę
s = new (nothrow) char [ n ]
;
if(
s != 0
)
{
strcpy( s, "J zyk C " );
ę
strcat( s, "fajny jest!" );
puts( s );
. . .
delete [] s
;
}
Wykorzystanie operatora new (nothrow) nie generującego wyjątków, obsługa jak w
„starej” wersji:
Dynamiczna alokacja tablic — konwencja języka C++
Dynamiczna alokacja tablic — konwencja języka C++
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
52
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
char * s = 0;
int n;
// Tu ustalenie liczby potrzebnych elementów i zapami tanie w zmiennej n
ę
s = new (nothrow) char [ n ];
if( s != 0 )
{
strcpy( s, "J zyk C " );
ę
strcat( s, "fajny jest!" );
puts( s );
. . .
delete [] s;
s = 0
;
}
Zerowanie wskaźnika po zwolnieniu pamięci jest dobrą praktyką.
Dynamiczna alokacja tablic — konwencja języka C++
Dynamiczna alokacja tablic — konwencja języka C++
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
53
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
Zerowanie wskaźnika po zwolnieniu pamięci jest dobrą praktyką.
char * s = 0;
int n;
// Tu ustalenie liczby potrzebnych elementów i zapami tanie w zmiennej n
ę
try
{
s = new char [ n ];
strcpy( s, "J zyk C " );
ę
strcat( s, "fajny jest!" );
puts( s );
. . .
delete [] s;
s = 0
;
}
catch( ... )
{
cout << "Brak pami ci dla wykonania tej operacji";
ę
}
Ważna sprawa — ostrożnie z parametrami wskaźnikowymi!
Ważna sprawa — ostrożnie z parametrami wskaźnikowymi!
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
54
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
W funkcjach bibliotecznych języka C i C++ stałą praktyką jest deklarowanie
parametrów tablicowych z wykorzystaniem wskaźników, np:
int strlen( char * s );
int strlen( char s[] );
zamiast
Wymaga to dokładnego przeczytania dokumentacji, bowiem programiści często się
mylą. Rozważmy następujący przykład (fragment systemu pomocy firmy Borland):
Prototype
char *gets(char *s);
Description
Gets a string from stdin.
gets collects a string of characters terminated by a new line from the standard input stream stdin and
puts it into s. The new line is replaced by a null character (\0) in s.
gets allows input strings to contain certain whitespace characters (spaces, tabs). gets returns when it
encounters a new line; everything up to the new line is copied into s.
Ważna sprawa — ostrożnie z parametrami wskaźnikowymi!
Ważna sprawa — ostrożnie z parametrami wskaźnikowymi!
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
55
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
Niedokładna lektura dokumentacji może sugerować, że funkcji należy użyć tak:
char * imie;
printf( "Podaj imie: " );
gets( imie );
Pamięć operacyjna
imie
Pamięć operacyjna
Aga
???
gets( imie )
Gdyby wskaźnik był wyzerowany, kompilator czasem pomoże:
char * imie = NULL;
printf( "Podaj imie: " );
gets( imie );
Pamięć operacyjna
imie
Pamięć operacyjna
gets( imie )
Null pointer assignment
Stare kompilatory firmy Borland:
Ważna sprawa — ostrożnie z parametrami wskaźnikowymi!
Ważna sprawa — ostrożnie z parametrami wskaźnikowymi!
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
56
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
A trzeba np. tak:
char imie[ 80 ];
printf( "Podaj imie: " );
gets( imie );
Pamięć operacyjna
imie
Pamięć operacyjna
Aga
gets( imie )
Lub tak:
char * imie = NULL;
imie = new (nothrow) char[ 80 ];
if( imie != 0 )
{
printf( "Podaj imie: " );
gets( imie );
. . .
delete [] imie;
}
Pamięć operacyjna
imie
Pamięć operacyjna
Aga
gets( imie )
Można tworzyć dynamicznie tablice dowolnych typów
Można tworzyć dynamicznie tablice dowolnych typów
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
57
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
double * dochody = 0;
int liczbaMiesiecy;
// Tu ustalenie liczby miesiecy okresu rozrachunkowego
dochody = new (nothrow) double [ liczbaMiesiecy ]
;
if(
dochody != 0
)
{
for( int miesiac = 0; miesiac < liczbaMiesiecy; miesiac++ )
dochody[ miesiac ] = 0
;
. . .
delete [] dochody
;
}
Można tworzyć dynamicznie tablice dowolnych typów
Można tworzyć dynamicznie tablice dowolnych typów
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
58
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
typedef unsigned char byte;
byte * bitmapa = 0;
int rozmiarRysunku;
// Tu ustalenie liczby bajtów rysunku bitmapowego
bitmapa = new (nothrow) byte [ rozmiarRysunku ]
;
if(
bitmapa != 0
)
{
// Zaladuj bitmape
// Zrob z nia co trzeba
// Gdy juz niepotrzebna
delete [] bitmapa
;
}
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
59
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
Tablice a problem ich początkowego rozmiaru
Tablice a problem ich początkowego rozmiaru
Według standardu C89 i C++:
tablica zawsze składa się z ustalonej, i znanej na etapie kompilacji liczby
elementów,
liczba elementów tablicy nie ulega zmianie w trakcie działania programu ―
tablice są statyczne.
W standardzie C99 istnieją tablice VLA (ang. variable length array):
liczba elementów tablicy może być zdefiniowany w trakcie wykonania
programu — może być określona wartością zmiennej, ta wartość nie musi być
znana na etapie kompilacji,
liczba elementów tablicy nie ulega zmianie w trakcie działania programu ― raz
stworzona tablica zachowuje swój rozmiar.
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
60
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
Tablice a problem ich początkowego rozmiaru — przykład
Tablice a problem ich początkowego rozmiaru — przykład
Problem
Należy napisać program pozwalający na ewidencjonowanie czasów
osiągniętych przez zawodników maratonu.
Liczba zawodników nie jest dokładnie znana, zakłada się jednak, że startowa
pula numerów jest ograniczona do
300
.
Należy ewidencjonować dokładnie tyle czasów ile to potrzebne, program będzie
być może uruchamiany na starym komputerze przenośnym.
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
61
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
C89 i tablica czasów dla liczby zawodników nie większej niż 300
C89 i tablica czasów dla liczby zawodników nie większej niż 300
int
lb_zawodnikow
;
printf( "\nPodaj liczbe zawodnikow (maks. 300): " );
scanf( "%d",
&lb_zawodnikow
);
if( lb_zawodnikow > 0 && lb_zawodnikow <= 300 )
{
float * czasy;
int nr_zawodnika;
if( ( czasy = malloc( lb_zawodnikow * sizeof( float ) ) ) != NULL )
{
printf( "\nPodaj czasy kolejnych zawodnikow:\n" );
for( nr_zawodnika = 0; nr_zawodnika < lb_zawodnikow; nr_zawodnika++ )
{
printf( "%d>", nr_zawodnika + 1 );
scanf( "%f", &czasy[ nr_zawodnika ] );
}
/* Jakies operacje na tablicy czasy */
printf( "\n\nZawodnik Czas" );
for( nr_zawodnika = 0; nr_zawodnika < lb_zawodnikow; nr_zawodnika++ )
printf( "\n%-10d%-.2f", nr_zawodnika + 1, czasy[ nr_zawodnika ] );
free( czasy );
}
else
printf( "\nBrak pamieci!" );
}
else
printf( "Zbyt duza liczba zawodnikow" );
Ustalenie liczby zawodników, których
czasy będą ewidencjonowane
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
62
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
C89 i tablica czasów dla liczby zawodników nie większej niż 300
C89 i tablica czasów dla liczby zawodników nie większej niż 300
int
lb_zawodnikow
;
printf( "\nPodaj liczbe zawodnikow (maks. 300): " );
scanf( "%d",
&lb_zawodnikow
);
if(
lb_zawodnikow > 0 && lb_zawodnikow <= 300
)
{
float * czasy;
int nr_zawodnika;
if( ( czasy = malloc( lb_zawodnikow * sizeof( float ) ) ) != NULL )
{
printf( "\nPodaj czasy kolejnych zawodnikow:\n" );
for( nr_zawodnika = 0; nr_zawodnika < lb_zawodnikow; nr_zawodnika++ )
{
printf( "%d>", nr_zawodnika + 1 );
scanf( "%f", &czasy[ nr_zawodnika ] );
}
/* Jakies operacje na tablicy czasy */
printf( "\n\nZawodnik Czas" );
for( nr_zawodnika = 0; nr_zawodnika < lb_zawodnikow; nr_zawodnika++ )
printf( "\n%-10d%-.2f", nr_zawodnika + 1, czasy[ nr_zawodnika ] );
free( czasy );
}
else
printf( "\nBrak pamieci!" );
}
else
printf( "Zbyt duza liczba zawodnikow" );
Czy liczba zawodników nie przekracza
zadanego maksimum?
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
63
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
C89 i tablica czasów dla liczby zawodników nie większej niż 300
C89 i tablica czasów dla liczby zawodników nie większej niż 300
int
lb_zawodnikow
;
printf( "\nPodaj liczbe zawodnikow (maks. 300): " );
scanf( "%d",
&lb_zawodnikow
);
if( lb_zawodnikow > 0 && lb_zawodnikow <= 300 )
{
float * czasy
;
int nr_zawodnika;
if( ( czasy = malloc( lb_zawodnikow * sizeof( float ) ) ) != NULL )
{
printf( "\nPodaj czasy kolejnych zawodnikow:\n" );
for( nr_zawodnika = 0; nr_zawodnika < lb_zawodnikow; nr_zawodnika++ )
{
printf( "%d>", nr_zawodnika + 1 );
scanf( "%f", &czasy[ nr_zawodnika ] );
}
/* Jakies operacje na tablicy czasy */
printf( "\n\nZawodnik Czas" );
for( nr_zawodnika = 0; nr_zawodnika < lb_zawodnikow; nr_zawodnika++ )
printf( "\n%-10d%-.2f", nr_zawodnika + 1, czasy[ nr_zawodnika ] );
free( czasy );
}
else
printf( "\nBrak pamieci!" );
}
else
printf( "Zbyt duza liczba zawodnikow" );
Tablica ewidencjonująca czasy
zostanie przydzielona dynamicznie
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
64
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
C89 i tablica czasów dla liczby zawodników nie większej niż 300
C89 i tablica czasów dla liczby zawodników nie większej niż 300
int
lb_zawodnikow
;
printf( "\nPodaj liczbe zawodnikow (maks. 300): " );
scanf( "%d",
&lb_zawodnikow
);
if( lb_zawodnikow > 0 && lb_zawodnikow <= 300 )
{
float * czasy
;
int nr_zawodnika;
if( (
czasy = malloc( lb_zawodnikow * sizeof( float ) )
) != NULL )
{
printf( "\nPodaj czasy kolejnych zawodnikow:\n" );
for( nr_zawodnika = 0; nr_zawodnika < lb_zawodnikow; nr_zawodnika++ )
{
printf( "%d>", nr_zawodnika + 1 );
scanf( "%f", &czasy[ nr_zawodnika ] );
}
/* Jakies operacje na tablicy czasy */
printf( "\n\nZawodnik Czas" );
for( nr_zawodnika = 0; nr_zawodnika < lb_zawodnikow; nr_zawodnika++ )
printf( "\n%-10d%-.2f", nr_zawodnika + 1, czasy[ nr_zawodnika ] );
free( czasy );
}
else
printf( "\nBrak pamieci!" );
}
else
printf( "Zbyt duza liczba zawodnikow" );
Przydział pamięci dla tablicy czasów i
kontrola poprawności jego wykonania
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
65
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
C89 i tablica czasów dla liczby zawodników nie większej niż 300
C89 i tablica czasów dla liczby zawodników nie większej niż 300
int
lb_zawodnikow
;
printf( "\nPodaj liczbe zawodnikow (maks. 300): " );
scanf( "%d",
&lb_zawodnikow
);
if( lb_zawodnikow > 0 && lb_zawodnikow <= 300 )
{
float * czasy
;
int nr_zawodnika;
if( (
czasy = malloc( lb_zawodnikow * sizeof( float ) )
) != NULL )
{
printf( "\nPodaj czasy kolejnych zawodnikow:\n" );
for( nr_zawodnika = 0; nr_zawodnika <
lb_zawodnikow
; nr_zawodnika++ )
{
printf( "%d>", nr_zawodnika + 1 );
scanf( "%f", &czasy[ nr_zawodnika ] );
}
/* Jakies operacje na tablicy czasy */
printf( "\n\nZawodnik Czas" );
for( nr_zawodnika = 0; nr_zawodnika <
lb_zawodnikow
; nr_zawodnika++ )
printf( "\n%-10d%-.2f", nr_zawodnika + 1, czasy[ nr_zawodnika ] );
free( czasy );
}
else
printf( "\nBrak pamieci!" );
}
else
printf( "Zbyt duza liczba zawodnikow" );
Operacje na tablicy — przetwarzana
jest rzeczywista liczba elementów
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
66
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
C89 i tablica czasów dla liczby zawodników nie większej niż 300
C89 i tablica czasów dla liczby zawodników nie większej niż 300
int
lb_zawodnikow
;
printf( "\nPodaj liczbe zawodnikow (maks. 300): " );
scanf( "%d",
&lb_zawodnikow
);
if( lb_zawodnikow > 0 && lb_zawodnikow <= 300 )
{
float * czasy
;
int nr_zawodnika;
if( (
czasy = malloc( lb_zawodnikow * sizeof( float ) )
) != NULL )
{
printf( "\nPodaj czasy kolejnych zawodnikow:\n" );
for( nr_zawodnika = 0; nr_zawodnika <
lb_zawodnikow
; nr_zawodnika++ )
{
printf( "%d>", nr_zawodnika + 1 );
scanf( "%f", &czasy[ nr_zawodnika ] );
}
/* Jakies operacje na tablicy czasy */
printf( "\n\nZawodnik Czas" );
for( nr_zawodnika = 0; nr_zawodnika <
lb_zawodnikow
; nr_zawodnika++ )
printf( "\n%-10d%-.2f", nr_zawodnika + 1, czasy[ nr_zawodnika ] );
free( czasy )
;
}
else
printf( "\nBrak pamieci!" );
}
else
printf( "Zbyt duza liczba zawodnikow" );
Tablica nie jest już dłużej potrzebna,
zwolnienie pamięci jej przydzielonej
Podstawy programowania w C++
Podstawy programowania w C++
Copyright © Roman Simiński
67
Strona :
T a b l i c e a z m i e n n e w s k a ź n i k o w e
T a b l i c e a z m i e n n e w s k a ź n i k o w e
C99 i tablica czasów dla liczby zawodników nie większej niż 300
C99 i tablica czasów dla liczby zawodników nie większej niż 300
#include <stdlib.h>
#include <stdio.h>
int main()
{
int lb_zawodnikow;
printf( "\nPodaj liczbe zawodnikow (maks. 300): " );
scanf( "%d", &lb_zawodnikow );
if( lb_zawodnikow > 0 && lb_zawodnikow <= 300 )
{
float czasy[ lb_zawodnikow ]
;
int nr_zawodnika;
printf( "\nPodaj czasy kolejnych zawodnikow:\n" );
for( nr_zawodnika = 0; nr_zawodnika < lb_zawodnikow; nr_zawodnika++ )
{
printf( "%d>", nr_zawodnika + 1 );
scanf( "%f", &czasy[ nr_zawodnika ] );
}
/* Jakies operacje na tablicy czasy */
printf( "\n\nZawodnik Czas" );
for( nr_zawodnika = 0; nr_zawodnika < lb_zawodnikow; nr_zawodnika++ )
printf( "\n%-10d%-.2f", nr_zawodnika + 1, czasy[ nr_zawodnika ] );
}
else
printf( "Zbyt duza liczba zawodnikow" );
return EXIT_SUCCESS;
}
Tablica VLA o rozmiarze początkowym
definiowanym w trakcie działania
programu