11 tablice2d

background image

Tablice dwuwymiarowe

Tablice dwuwymiarowe o wartościach liczbowych reprezentują macierze. W języku C definicja tablicy

dwuwymiarowej wygląda następująco:

typ nazwa[liczba_wierszy][liczba_kolumn];

np.

int tab[5][10];

definiuje tablicę typu

int

o 5 wierszach i 10 kolumnach. Indeksy

zmieniają się od wartości 0, zatem

tab[0][2]

jest odwołaniem do elementu tablicy z wiersza 0 i

kolumny 2 (trzeciej z kolei). Elementy tablicy umieszczone są w pamięci komputera wierszami, co

oznacza, że element

tab[i][j]

sąsiaduje z elementem

tab[i][j+1],

natomiast ostatni

element jednego wiersza sąsiaduje z pierwszym elementem kolejnego wiersza np.

tab[0][9]

sąsiaduje z

tab[1][0].

Tablicę można zainicjować podając listę wartości początkowych w

nawiasach klamrowych. Każdy wiersz inicjowany jest w osobnej podliście. Analogicznie jak w

przypadku tablic jednowymiarowych, jeśli liczba wartości początkowych jest mniejsza niż liczba

elementów tablicy, pozostałe elementy zostają wyzerowane. Definicja:

int tab[2][3]={{0, 1, 2}, {9, 8, 7}};

tworzy tablicę:

0 1 2

9 8 7

W języku C tablica dwuwymiarowa jest rzeczywiście tablicą jednowymiarową, której elementami są

tablice jednowymiarowe (wiersze tablicy dwuwymiarowej). Można ją interpretować jako tablicę

wskaźników do wierszy

(tab[0], tab[1],..). tab[0], tab[1],..

podobnie jak

tab

są stałymi, można się do nich odwoływać w programie, ale nie można ich modyfikować. Nazwa

tablicy

tab

jest zarazem adresem elementu

tab[0][0],

a także adresem wiersza zerowego

(tab[0]).

Zatem

tab, &tab[0][0], tab[0]

mają takie same wartości, natomiast

tab[1]

jest adresem pierwszego wiersza tablicy (drugiego z kolei), czyli adresem elementu

tab[1][0].

Usytuowanie elementów tablicy tab w pamięci przedstawia poniższy schemat. Czerwonymi literami

oznaczono adresy, a strzałki wskazują na docelowe miejsca w pamięci.

background image

tab

tab[0]

tab[0][0] tab[0][1] tab[0][2] tab[0][2]

tab[1]

tab[1][0] tab[1][1] tab[1][2] tab[1][2]

Wczytywanie i wypisywanie macierzy wierszami

Aby wczytać tablicę wierszami trzeba zastosować dwie pętle

for.

Zewnętrzna pętla związana jest z

numerami wierszy, natomiast wewnętrzna z numerami kolumn. Poniższy program wczytuje tablicę

dwuwymiarową, przy założeniu, że kolejne elementy wczytywane są wierszami i wyświetla ją na

ekranie w taki sposób, że każdy wiersz znajduje się w nowej linii.


#include <stdio.h>
#include <stdlib.h>
#define N 3
#define M 4

int main()
{
int a[N][M];
int i,j;
for (i=0; i<N; i++)
for (j=0; j<M; j++)
scanf("%d",&a[i][j]);
printf("\n\nmacierz wierszami:\n");
for (i=0; i<N; i++)
{
printf("\n");
for (j=0; j<M; j++)
printf("%d ",a[i][j]);
}
printf("\n");
}

Wczytywanie macierzy kolumnami

Przy wczytywaniu tablicy kolumnami zewnętrzna pętla związana jest z numerami kolumn, natomiast

wewnętrzna z numerami wierszy. Poniższy fragment program wczytuje tablicę dwuwymiarową,

której elementy wczytywane są z klawiatury kolumnami.

background image


for (j=0; j<M; i++)
for (i=0; i<N; j++)
scanf("%d",&a[i][j]);



Przykład - zliczanie elementów niezerowych nad główną przekątną wraz z przekątną

Zadanie polega na policzeniu ile jest elementów niezerowych w zadanej macierzy

kwadratowej

a[n][n]

ponad główna przekątną biorąc pod uwagę również elementy z przekątnej. Interesujący

fragment macierzy przedstawiony jest poniżej:

a[0][0] a[0] [1] a[0][2] a[0][3]

a[1][0] a[1] [1] a[1][2] a[1][3]

a[2][0] a[2] [1] a[2][2] a[2][3]

a[3][0] a[3] [1] a[3][2] a[3][3]

Warto zauważyć, że elementy tablicy, które będziemy rozważać, mają oba indeksy, czyli numer

wiersza i numer kolumny, identyczne (są to elementy z przekątnej) lub indeks drugi, określający

numer kolumny jest większy od indeksu pierwszego, określającego numer wiersza. Przeglądanie

tablicy można więc zorganizować w ten sposób, że w zewnętrznej pętli zmienna sterująca

i

będzie

wskazywała numer wiersza i będzie się zmieniała od

0

do

n-1,

natomiast pętla wewnętrzna będzie

sterowana indeksem kolumny

j

i będzie się zmieniała od aktualnego numeru wiersza

- i,

czyli od

elementu z przekątnej do końca wiersza

(n-1).

Oto kod programu:
















background image

#include <stdio.h>
#include <stdlib.h>
#define W 4
#define K 4

int main()
{
int i,j,s=0;
int a[W][K];
for(i=0;i<W;i++)
for(j=0;j<K;j++)
scanf("%d",&a[i][j]);
for(i=0;i<W;i++)
{
printf("\n");
for(j=0;j<K;j++)
printf("%3d ",a[i][j]);
}
for (i=0;i<W;i++)
for(j=i;j<K;j++)
if(a[i][j]!=0) s++;
printf("\n\t%d el. niezerowych nad gl. przekatna\n",s);
}

A oto przykładowy wynik działania programu z obrysowanym czerwoną linią obszarem ponad

przekątną:

Tablice dwuwymiarowe jako parametry funkcji

Programy przetwarzające tablice dwuwymiarowe wygodnie jest podzielić na funkcje, których

zadaniem będzie wczytanie, wypisywanie tablic oraz inne operacje. Jak już wiemy tablice są

przekazywane przez adres, co oznacza, że w odniesieniu do tablic funkcja działa w samej przestrzeni

adresowej, co funkcja wywołująca. Aby przekazać do funkcji tablicę dwuwymiarową jako parametr

trzeba podać poza nazwą również liczbę kolumn tablicy. Liczba kolumn wraz z wskaźnikiem do

początku tablicy wnosi wystarczą informację o rozmieszczeniu elementów, liczba wierszy nie jest

istotna. Definiując parametry formalne można podać oba wymiary tablicy:

int n,m,a[n][m];

background image

jak np. w funkcji

czytaj_wierszami

lub tylko liczbę kolumn:

int m,a[][m];

jak w funkcji

pisz_wierszami.

Funkcje występujące w programie są typu

void

, co oznacza, że nie zwracają one żadnej wartości,

ich zadaniem jest wypełnienie tablicy, lub wypisanie jej zawartości na ekranie.

Oto kod programu:

#include <stdio.h>
#include <stdlib.h>
#define N 3
#define M 4

void czytaj_wierszami(a,n, m)
int n,m,a[n][m];
{
int i,j;
for (i=0; i<n; i++)
{
for (j=0; j<m; j++)
scanf("%d",&a[i][j]);
}
}

void czytaj_kolumnami(a, n, m)
int n,m,a[n][m];
{
int i,j;
for (i=0; i<m; i++)
{
printf("\n");
for (j=0; j<n; j++)
scanf("%d",&a[j][i]);
}
}

void pisz_wierszami(a, m)
int m,a[][m];
{
int i,j;
for (i=0; i<n; i++)
{
printf("\n\t");
for (j=0; j<m; j++)
printf("%3d ",a[i][j]);
}
printf("\n");
}

background image

void pisz_kolumnami(a, n, m)
int n,m,a[n][m];
{
int i,j;
for (i=0; i<m; i++)
{
printf("\n\t");
for (j=0; j<n; j++)
printf("%3d ",a[j][i]);
}
printf("\n");
}

int main(int argc, char *argv[])
{
int a[N][M];
int i,j;
printf("\n\n");
czytaj_wierszami(a,N,M);
printf("\n\n\tmacierz wierszami:\n");
pisz_wierszami(a,N,M);
printf("\n\n\tmacierz kolumnami:\n");
pisz_kolumnami(a, N, M);
}

A oto efekt przykładowego uruchomienia programu:

Tablice dwuwymiarowe – wskaźniki, alokacja pamięci

Tablice w języku C mogą być zadeklarowane z użyciem dwóch wskaźników

(int **a;).

Wówczas pamięć dla tablicy należy zarezerwować korzystając z funkcji

malloc.

Ilustruje to

poniższy program. Program wczytuje tablicę dwuwymiarową

a

i tworzy tablicę jednowymiarową

background image

(wektor

b

), której elementy są maksymalnymi elementami poszczególnych wierszy tablicy

wejściowej, a także wektor minimalnych elementów z poszczególnych kolumn danej tablicy (wektor

c

):

a[0][0] a[0] [1] a[0][2] … a[0][m] b[0] =max( a[0][i],i=0,..m)

a[1][0] a[1] [1] a[1][2]…. a[1][m] b[1] =max( a[1][i],i=0,..m)

a[2][0] a[2] [1] a[2][2] … a[2][m] b[2] =max( a[2][i],i=0,..m)

…. ….. …. …….. ……

a[n][0] a[n] [1] a[n][2] … an][m] b[m] =max( a[n][i],i=0,..m)

c[0] c[1] c[2] … c[n]


#include <stdio.h>
#include <stdlib.h>
#define N 5
#define M 5

int ffmax(int *x, int n)
{
int mm,i;
mm=x[0];
for(i=1; i<n; i++)
{
if( x[i] > mm )
mm=x[i];
}
return mm;
}

int ffmin(int **x, int k, int n)
{
int mm,i;
mm=x[0][k];
for(i=1; i<n; i++)
{
if( x[i][k] < mm )
mm=x[i][k];
}
return mm;
}



void czytaj_wierszami(int **a, int n, int m)

background image

{
int i,j;
for (i=0; i<n; i++)
{
printf("\n");
for (j=0; j<m; j++)
scanf("%d",&a[i][j]);
}
}

void pisz_wierszami(int **a, int n, int m)
{
int i,j;
for (i=0; i<n; i++)
{
printf("\n");
for (j=0; j<m; j++)
printf("%d ",a[i][j]);
}
}

void maxwier(int **a, int *b, int n, int m)
{
int i,j;
for(i=0;i<n;i++)
b[i]=ffmax(a[i],m);

}

void minkol(int **a, int *b, int n, int m)
{
int i,j;
for(i=0;i<m;i++)
b[i]=ffmin(a,i,n);
}

int main(int argc, char *argv[])
{
int **a;
int *b,*c;
int i,j;

if(!(a=(int**)malloc(N*sizeof(int*))))return 1;
for(j=0;j<N;j++)
if(!(a[j]=(int*)malloc(M*sizeof(int))))return 1;
if(!(b=(int*)malloc(N*sizeof(int))))return 1;
if(!(c=(int*)malloc(M*sizeof(int))))return 1;

czytaj_wierszami(a, N, M);
printf("\n\nmacierz wierszami:\n");
pisz_wierszami(a, N, M);

background image

maxwier(a,b,N,M);
printf ("\n\nwynik:\n");
for (i=0;i<M;i++)
printf("%d ",b[i]);
printf ("\n\n\n");
minkol(a,c,N,M);
printf ("\n\nwynik:\n");
for (i=0;i<N;i++)
printf("%d ",c[i]);
printf ("\n\n\n");
for(i=0;i<M;i++)
free(a[i]);
free (a);
free(b);
free(c);
}

Rezerwacja pamięci dla tablicy a została wykonana za pomocą poleceń:

if(!(a=(int**)malloc(N*sizeof(int*))))return 1;

for(j=0;j<N;j++)

if(!(a[j]=(int*)malloc(M*sizeof(int))))return 1;

Najpierw zarezerwowane zostało N*sizeof( *int) (4*N) bajtów na tablicę wskaźników do wierszy, a

następnie N*M*4 bajtów na N wierszy po M elementów typu

int.

Jeśli funkcja

malloc

zakończy się

niepowodzeniem, co oznacza, że nie udało się zarezerwować miejsca w pamięci operacyjnej (na

stercie procesu) program kończy się zwracając kod błędu = 1. Zwolnienie pamięci realizowane jest za

pomocą funkcji

free.

A oto efekt przykładowego uruchomienia programu:

background image


Wyszukiwarka

Podobne podstrony:
11-Tablica8
11-Tablica8
11 TABLICA 8
11-Tablica8
11 TABLICA 9
11 TABLICA 8
11 Tablica8id 28161
11 Tablica8id 28192
11 Tablica8
11 Tablica 9
formularzcenowy (14-49), Przegrane 2012, Rok 2012, mail 05.11 Krasnosielc tablice
13 TABLICA 11
13 TABLICA 11
2012 11 14 zapytanie ofertowe tablice informacyjneid 28108
owiadczenie (14-49), Przegrane 2012, Rok 2012, mail 05.11 Krasnosielc tablice

więcej podobnych podstron