3 Wykład: Język C



Pobieranie 87,4 Kb.
Data15.04.2018
Rozmiar87,4 Kb.

Tablice w języku C/C++


Ogólna postać definicji tablicy:

typ_elementu nazwa_tablicy [wymiar_1][wymiar_2] . . . [wymiar_N] ;

np.


int tablica [ 10 ]; // 10-cio elementowa tablica liczb całkowitych

char tekst [ 255 ]; // 255-cio elementowa tablica znaków

float macierz [ 5 ] [ 2 ]; // dwuwymiarowa tablica: 5 wierszy po 2 kolumny,
UWAGA:

  • w języku C tablice są zawsze indeksowane od zera
    np. pierwszym elementem tablicy «macierz» jest: macierz[ 0 ][ 0 ]

a ostatnim elementem jest: macierz[ wymiar_1 1 ][wymiar_2 1]
tzn. macierz[ 4 ][ 1 ]

  • w języku C nie jest sprawdzana zgodność indeksu z wymiarami tablicy !!!
    często jest to przyczyną trudnych do wykrycia błędów.
    np. odwołanie: macierz[ 1 ][ 2 ] zwróci w rzeczywistości wartość pierwszego elementu z trzeciego wiersza tzn. macierz[ 2 ][ 0 ]

0 , 0

0 , 1




1 , 0

1 , 1

1 , 2

2 , 0

2 , 1




3 , 0

3 , 1




4 , 0

4 , 1




reprezentacja tej macierzy w pamięci komputera

0 , 0

0 , 1

1 , 0

1 , 1

2 , 0

2 , 1

3 , 0

3 , 1

4 , 0

4 , 1



macierz[ 1 ][ 2 ]


  • Obszar pamięci zajmowany przez tablicę musi być mniejszy od 64 kB

W implementacji C++ firmy Borland to ograniczenie można obejść używając przy definicji tablicy słowo kluczowe huge .
np. definicja: long double huge tab[ 20000 ];
jest poprawna, chociaż tablica «tab» zajmuje 200 000 bajtów  196 kB
Definicję tablicy można połączyć z inicjacją jej zawartości:

int tab[ 10 ]; //  sama definicja bez inicjacji

int tab_inicjowana[ 10 ] = { 20, -3, 12, 1, 0, 7, -5, 100, 2, 5 };

char tab_znakow[ 5 ] = { ‘a’, ‘B’, ‘\n’, ‘1’, ‘\0’ };

float macierz_A[ 3 ][ 2 ] = { {1,1}, {3.5,7.0}, {-15,100} };

float macierz_B[ 3 ][ 2 ] = { 1, 1, 3.5, 7.0, -15, 100 };

  • Kolejne „inicjatory” zawsze wstawiane są do kolejnych „komórek” tablicy
    (w związku z tym można pominąć wewnętrzne nawiasy klamrowe).

  • Jeżeli lista inicjatorów jest krótsza niż ilość elementów tablicy to pozostałe elementy są uzupełniane zerami lub wskaźnikami NULL

np. definicja:

int tab[ 10 ] = { 20, -3, 12, 1 };

jest równoważna:



int tab[ 10 ] = { 20, -3, 12, 1, 0, 0, 0, 0, 0, 0 };

a definicja:

float macierz[ 3 ][ 2 ] = { {1}, {3.5,7.0} };

jest równoważna:



float macierz[ 3 ][ 2 ] = { {1,0}, {3.5,7.0}, {0,0} };

lub:


float macierz[ 3 ][ 2 ] = { 1, 0, 3.5, 7.0, 0, 0 };



Sposoby dostępu do elementów tablicy:

poprzez podanie pozycji / indeksu elementu tablicy
(w nawiasach kwadratowych analogicznie jak w języku PASCAL) np.

int i, tablica[ 10 ]; // wczytanie 10 liczb (z ew. zmianą znaku)

for( i = 0 ; i < 10 ; i++ )

{

printf( ”Tab[%2d] = ”, i+1 );

scanf( ”%d” , &tablica[ i ] );

if( tablica[ i ] < 0 ) // jeżeli liczba ujemna

tablica[ i ] = (1)tablica[ i ]; // to zmień znak



}

poprzez podanie wskaźnika / adresu elementu w pamięci komputera
(przykład znajduje się na stronie nr 6)

Przykłady operacji na tablicach


#include

void main( void )

{

#define ROZMIAR 10



int tab[ ROZMIAR ];

int i, ilosc, max, poz;

long suma;

double srednia;

for( i = 0 ; i < ROZMIAR ; i++ ) //--------- wczytanie liczb z klawiatury

{

printf( ”Tab[%2d] = ”, i+1 );

scanf( ”%d” , &tablica[ i ] );

}

i=0; //--------------------------- zliczenie elementów niezerowych

ilosc=0;

while( ROZMIAR  i )

if( tab[i++] )

ilosc++;


suma=0; //----------- wyznaczenie średniej z elementów dodatnich

ilosc=0;


i=0;

do

if( tab[ i ] > 0 )

{

suma += tab[ i ];

ilosc++;

}

while( ++i < ROZMIAR );

if( ilosc )

{

srednia = (double)suma / ilosc;

printf( "\nSrednia dodatnich = %.2f" , srednia );

}

else

printf( "\nNie ma elementow dodatnich" );

max=tab[0]; //----------- wyznaczenie wartości i pozycji maksimum

poz=0;


for( i=1; i
if( max
{

max = tab[ i ];

poz = i ;

}

printf( "\nNajwieksza wartosc jest rowna %d" , max );

printf( "i wystapila na pozycji %d" , poz+1 );

}

WSKAŹNIKI / ADRESY


Wskaźnik  jest zmienną, która zawiera adres (wskazanie) początku dowolnego obszaru w pamięci komputera,
(np. może być to adres obszaru danych lub adres kodu programu)
Ogólna postać definicji wskaźnika:

typ_danych identyfikator wskaźnika ;

Najczęściej używane są wskaźniki „zdefiniowane” zawierające adres innej zmiennej. Taki wskaźnik zawiera informację o:



  • adresie zmiennej w pamięci komputera

  • typie danych przechowywanych w tej zmiennej

Przykłady definicji:

int wskaznik; // wskaźnik na zmienną całkowitą

double  wsk_liczby; // wskaźnik na zmienną rzeczywistą

char  wsk_znaku; // wskaźnik na pojedynczy znak

char  tekst; // wskaźnik na początek łańcucha znaków

(na pierwszy znak tego łańcucha)

Można również korzystać ze wskaźników „niezdefiniowanych” (anonimowych).


Taki wskaźnik zawiera tylko informację o adresie obszaru pamięci (bez określenia typu wskazywanych danych). Definicja takiego wskaźnika ma postać:

void identyfikator wskaźnika ;

jest to wskaźnik na „dowolny” ciąg bajtów danych.



Ze wskaźnikami i adresami związane są dwa operatory:

  • operator referencji & zwracający adres zmiennej podanej po prawej stronie tego operatora.

  • operator dereferencji identyfikujący obszar wskazywany przez wskaźnik podany po prawej stronie tego operatora.

int liczba ;

int wskaźnik ;

wskaznik = &liczba; // przypisanie zmiennej wskaźnik


// adresu zmiennej liczba

wskaźnik = 10; // przypisanie 10 zawartości zmiennej


// wskazywanej przez wskaźnik

// tutaj równoważne liczba = 10


Arytmetyka wskaźników


Na wskaźnikach mogą być wykonywane następujące operacje:

  • przypisania ( = )

wsk = wskaznik_zmiennej_lub_obszaru_pamięci ;
(w przypadku niezgodności typów konieczne jest dokonanie konwersji typu)

wsk_1 == wsk_2 // sprawdzenie czy zmienne zawierają te same adresy
wsk_1 < wsk_2 // czy zmienna wsk_1 zawiera adres mniejszy
// od adresu zawartego w zmiennej wsk_2

  • operacje powiększania lub pomniejszania wskaźnika ( +, , ++, , +=, = ) o liczbę całkowitą (tylko dla wskaźników zdefiniowanych)

 powiększenie (pomniejszenie) wskaźnika o wartość N powoduje wyznaczenie adresu przesuniętego o:

N sizeof( typ_zmiennej_wskazywanej )

bajtów w kierunku rosnących (malejących) adresów.



np. int x;













x
















x+3





































































































adresy 

. . .

35

36

37

38

39

40

41

42

43

44

45

46

. . .

  • operacje odejmowania wskaźników tego samego typu  wyznaczenie „odległości” pomiędzy dwoma adresami w pamięci.
    ( odległości w sensie N sizeof ( typ_elementu_wskazywanego ) )


Inne przykłady:

int wsk_liczby; // wskaźnik na liczbę typu int

int tab_A[10]; // 10-cio elementowa tablica liczb int
( identyfikator tab_A jest stałą równą adresowi
pierwszego elementu tablicy o tej samej nazwie
tzn.
tab_A == &( tab_A[0] )

int tab_B[10]; // 10-cio elementowa tablica wskaźników na liczby int

int  ( tab_C[10] ); // jak wyżej

( int ) tab_D[10]; // jak wyżej



int (tab_E)[10]; // wskaźnik na 10-cio elementową tablicę liczb int

PRZYKŁADY: Dostęp do tablic za pomocą indeksów i/lub wskaźników


#include // Część wspólna przykładów na tej stronie

#define ROZMIAR 10



void main(void)

{

int tab[ ROZMIAR ];

// wczytanie liczby do tablicy

   // przemnożenie elementu tablicy przez 2

// wyświetlenie elementu tablicy



}

a) int i; // dostęp za pomocą indeksu



for( i = 0; i < ROZMIAR; i++ )

{

scanf( ”%d”, &tab[ i ] );

tab[ i ] = 2  tab[ i ]; // tab[ i ] = 2;
printf( ”Tab[ %d ] = %d \n”, i+1 , tab[ i ] );

}

b) int i; // dostęp za pomocą adresu i indeksu



for( i = 0; i < ROZMIAR; i++ )

{

scanf( ”%d”, tab + i ); // &(tab+i) == tab+i

(tab+i) = 2  (tab+i); // (tab+i) = 2;
printf( ”Tab[ %d ] = %d \n”, i+1 , (tab+i) );

}

c) int licznik, wsk; // dostęp za pomocą wskaźnika i licznika



for( licznik=0, wsk=tab; licznik < ROZMIAR; licznik++, wsk++ )

{

scanf( ”%d”, wsk );

wsk = 2wsk; // wsk = 2;
printf( ”Tab[ %d ] = %d \n”, licznik+1 , wsk );

}

d) int wsk; // dostęp za pomocą wskaźnika



for( wsk=tab; wsk < tab + ROZMIAR; wsk++ )

{ // wsk < &tab[ROZMIAR] adres ”końca tablicy”

scanf( ”%d”, wsk );

wsk = 2;
printf( ”Tab[ %d ] = %d \n”, wsktab+1 , wsk );

}


M.Piasecki: JĘZYKI PROGRAMOWANIA 1   (w3) Tablice w języku C/C++




©operacji.org 2017
wyślij wiadomość

    Strona główna