background image

 

 

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

background image

 

 

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 ]

background image

 

 

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 ];

background image

 

 

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

background image

 

 

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 )

background image

 

 

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 ];

background image

 

 

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!

background image

 

 

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

background image

 

 

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 ]

background image

 

 

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

background image

 

 

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...

background image

 

 

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.

background image

 

 

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 );

background image

 

 

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... ?

background image

 

 

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

background image

 

 

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

background image

 

 

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

background image

 

 

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

background image

 

 

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

background image

 

 

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

background image

 

 

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+

background image

 

 

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+

background image

 

 

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+

background image

 

 

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++

background image

 

 

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++

background image

 

 

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++

background image

 

 

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

background image

 

 

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

background image

 

 

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

background image

 

 

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.

background image

 

 

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:

background image

 

 

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 s1s2s3:

Następujący fragment kodu:

strcpy5( s2, s1 );
strcpy5( s3, s2 );
puts( s3 );

Można zapisać krócej:

puts( strcpy5( s3, strcpy5( s2, s1 ) ) );

background image

 

 

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:

background image

 

 

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             

ź

background image

 

 

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ć!

background image

 

 

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;
}

background image

 

 

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:

background image

 

 

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;
}

background image

 

 

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;
}

background image

 

 

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...

background image

 

 

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

background image

 

 

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

background image

 

 

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

background image

 

 

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

background image

 

 

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

background image

 

 

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

background image

 

 

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

background image

 

 

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

background image

 

 

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:

background image

 

 

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:

background image

 

 

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:

background image

 

 

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ą.

background image

 

 

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";

ę

}

background image

 

 

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.

background image

 

 

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:

background image

 

 

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 )

background image

 

 

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

;

}

background image

 

 

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

;

}

background image

 

 

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.

background image

 

 

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.

background image

 

 

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

background image

 

 

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?

background image

 

 

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

background image

 

 

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

background image

 

 

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 

background image

 

 

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

background image

 

 

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


Document Outline