Saltar ao contido

C/Matrices

En Galilibros, o Wikibooks en galego.
< C
C
← Volver a Moldes Matrices Seguir con Cadeas de caracteres


Unha matriz (array en inglés) permite almacenar un grupo de datos relacionados e do mesmo tipo nunha única variable cun índice ─que permite traballar con cada un dos elementos individuais─. Para traballar cunha matriz o mellor é pensar nela como se se tratase dun grupo de variables individuais. As matrices adoitan permitirlle ao programador organizar grupos de datos de forma eficiente e intuitiva.

Declaración

[editar]

Ao declarar unha matriz, o que en realidade se está a facer é declarar un punteiro a un espazo de memoria que conterá os datos da matriz. Dito punteiro estará protexido (const), é dicir, non se poderá modificar o enderezo de memoria que contén, sempre estará apuntado a dito enderezo.

A declaración da matriz supón ademais reservar en memoria estática espazo para unha certa cantidade de elementos do tipo da matriz. Ao contrario do que pasa cos punteiros, no caso das matrices será o propio programa quen a xestione a memoria asignada ao punteiro da matriz (reservala, usala e liberala).

Elementos

[editar]

As matrices estás compostas por:

  • Identificador. É o enderezo simbólico do comezo da matriz na memoria.
  • Extensión. Expresada mediante constantes numéricas enteiras. É a cantidade de celas que hai en cada dimensión da matriz. A extensión non ten por que ser a mesma en todas as dimensións.
  • Índice. Exprésase coma un enteiro ─variable, constante ou expresión de tipo enteiro─ e utilízase para facer referencia a cada unha das celas da matriz.
  • Dimensións. As matrices poden ter unha ou varias dimensións, e segundo o caso o traballo con elas pode variar bastante. A cantidade de dimensións é ilimitada, e establécese sufixando o nome da variable ao declarala con corchetes, unha parella ([]) por cada dimensión, dentro dos cales irá a extensión da dimensión.

Matrices unidimensionais

[editar]

Declaración de matrices unidimensionais

[editar]

A sintaxe fundamental para declarar matrices dunha soa dimensión é a seguinte:

tipo identificador[tamaño];

Onde:

tipo é un tipo de dato,
identificador é o identificador da matriz, e
extensión é un número enteiro positivo, a cantidade de celas do tipo da matriz que terá a matriz.

Un exemplo de uso podería ser o seguinte:

int notas[6];

Existen certos casos en que se pode omitir a extensión da matriz unidimensional:

  • se se inicializa a matriz na declaración, ou
  • se se declara coma un parámetro formal nunha función.

O tamaño que ocupe en memoria a matriz enteira dependerá do produto do tamaño en bytes do tipo pola extensión. No exemplo anterior sería (sizeof(int)*6) 24 bytes.

Inicializar matrices unidimensionais

[editar]

Se ao declarar unha matriz se inicializa non é necesario especificar a súa extensión, pois esta dedúcese dos valores asignados á matriz. Véxase o seguinte exemplo:

unsigned short int matriz[]={1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};

Porén tamén se pode inicializar unha matriz indicando asemade a cantidade de celas que esta vai conter. Nese caso, se non se inicializan tantos datos como celas se indican, o resto de celas inicializarase co valor nulo. O seguinte podería valer como exemplo:

char matriz[10]={'e','x','e','m','p','l','o'};

Neste exemplo, as tres últimas celas valerán 0.

Cálculo da cantidade de celas

[editar]

Para calcular a cantidade de celas dunha matriz nalgunha parte do programa, poderase deducir dun cálculo sinxelo: dividir o tamaño total da matriz polo tamaño dunha das súas celas. Sirva o seguinte exemplo ─baseado no anterior─ para ilustralo:

celas = sizeof(matriz)/sizeof(unsigned short int);
// Outra alternativa podería ser:
celas = sizeof(matriz)/sizeof(matriz[0]);

Traballar con matrices unidimensionais

[editar]

Para facer referencia a cada unha das celas dunha matriz, utilízase o índice da cela. A sintaxe para isto é:

identificador[índice]

Onde índice é o número da cela menos un. Ao declarar unha matriz de X celas, o identificador de cada cela será un número entre 0 e X-1, isto é, se declaramos unha matriz con 100 celas, irá da cela 0 á 99 da matriz. O índice da primeira cela será o 0, a segunda o 1, a terceira o 2, etc. No exemplo anterior:

notas[0] // Primeira cela
notas[5] // Última cela

Cada cela será coma unha variable do tipo de dato da matriz. Pero cómpre ter en conta que ao contrario que a extensión, o índice dunha matriz (o que utilizamos para facer referencia a unha cela individual da matriz) pode ser unha variable susceptible de cambiar no tempo de execución. Pero en caso de facelo, haberá que asegurarse de que dito índice non sexa menor que cero nin maior que a extensión menos un, é dicir, un número positivo menor que a extensión ─en caso contrario non se trataría dunha das celas da matriz─.

Ao pasarlle a unha función unha matriz unidimensional, hai dous datos que hai que pasarlle como mínimo á función: o enderezo da matriz e maila súa extensión (ou a extensión da parte da matriz que na práctica vai utilizar a función).

Nótese que pasarlle unha matriz a unha función equivale a un paso por referencia dende un punto de vista global. É dicir, pásanselle á función dous datos, un por valor (a extensión da matriz) e outro por referencia (o enderezo da matriz). Isto resulta nunha función que non traballa cunha copia local (local para a función) da matriz, senón coa matriz orixinal, e os cambios nela afectarán a todas as funcións do programa, incluída a principal. Nalgúns casos quizais sexa mellor declarar na función outra matriz para copiar nela os datos da matriz orixinal e traballar con ela sen modificar a orixinal.

Para enviarlle a unha función o enderezo dunha matriz, faise prefixando o identificador da matriz co operador de enderezo, «&» (paso por referencia) na chamada á función, e sufixándoo co número da primeira cela da matriz ([0]). A súa sintaxe sería a seguinte:

función(&matriz[0],extensión);

Para simplificar as cousas, cómpre ter en conta algo que non se comentou ata agora: o identificador dunha variable equivale ao enderezo na memoria da súa primeira cela. É dicir, o exemplo anterior tería o mesmo efecto que o seguinte:

función(matriz,extensión);

E na cabeceira da definición da función declárase o enderezo de memoria da matriz recibido mediante o operador de apuntado, «*». A súa sintaxe fundamental sería a seguinte:

función(*matriz,extensión){
  // [...]
}

Ás veces pode resultar útil mandarlle a unha función unha matriz mentíndolle sobre onde comeza. É dicir, mandarlle a unha función unha matriz especificando dende que parte ten que lela. Para iso, cámbiase a cela inicial ([0]) por calquera outra. No seguinte exemplo, chamaremos á función de xeito que interprete a matriz dende a terceira cela e ata a oitava:

función(&matriz[2],7); // Compre lembrar que se comeza a conta das celas dende 0, non dende 1

Matrices de dúas dimensións

[editar]

As celas das matrices poden repartirse en distintas dimensións para facilitar a visualización dos datos que contén ou o traballo con elas. En realidade, as celas dunha matriz en varias dimensións gárdanse en memoria do mesmo xeito que as matrices unidimensionais. De feito, pódese traballar cunha matriz de varias dimensións coma se en realidade tivese unha única dimensión.

Aínda máis, podería darse o caso dun programa en que se traballe de xeito distinto ─cunha matriz como se tivese unha dimensións ou coma se tivese as que en realidade ten─ segundo a parte do programa de que se trate.

Cómpre ter en conta que ao pasarlle unha matriz de varias dimensións a unha función como se fai no caso das dunha soa dimensión, en principio terase que traballar coa matriz coma se tivese unha soa dimensión. Isto supón que sexa preciso calcular previamente o valor do índice para as celas. No caso dunha matriz de dúas dimensións, isto resulta unha tarefa bastante doada de realizar:

extensión da segunda dimensión * lugar da cela na primeira dimensión + lugar da cela na segunda dimensión

Ou o que é o mesmo, se interpretamos a matriz de dúas dimensións coma unha táboa con filas (primeira dimensión) e columnas (segunda dimensión):

número total de columnas * fila actual + columna actual

Se queremos seguir traballando con todas as dimensións dunha matriz nunha función, é necesario contarlle na chamada a esa función dúas cousas:

  1. A cantidade de dimensións que ten a matriz.
  2. A extensión da matriz en cada unha das dimensións.

Isto faise mediante:

int matriz[][extensión da segunda dimensión][extensión da terceira dimensión]...

Vexamos un exemplo:

signed int funcion(signed int matriz[][66], int filas, int columnas)
{
  ...
}

A extensión das dimensións adicionais (a partires da primeira) non pode fornecérselle á función de forma dinámica. É unha constante literal, e simplemente teremos que asegurarnos de que o seu valor é grande abondo para as distintas matrices que se lle podan fornecer á función, pois á hora da verdade os límites veñen establecidos por variables fornecidas á función, no exemplo anterior: filas e columnas, que serían a extensión real das dimensións primeira e segunda da matriz, respectivamente.

As extensións que necesariamente temos que especificar ao definir a función (as das dimensións adicionais), que abonda con que sexan superiores ás reais de cada caso, podemos controlalas mediante directrices #define, para que se nun futuro fose preciso ampliar estes valores, se poida facer con poucos cambios e sen ter que andar a buscar a función (ou funcións) no código.

De todos xeitos, salvo que vaiamos utilizar unha función só con matrices das que coñecemos a extensión de cada unha das súas dimensións, o mellor será que se traballe coa matriz de varias dimensións coma se en realidade fose unha matriz dunha soa dimensión, pois isto posibilitará que unha mesma función poida traballar con funcións con dimensións de extensión moi variable.

En caso de que vaiamos traballar unicamente con unha parte da matriz, non vale simplemente traballar con ela coma se fose de menor tamaño do que en realidade é. Tense que traballar de xeito que o programa sexa consciente en todo momento da verdadeira extensión das dimensións da matriz. E o que hai que facer é, a maiores, conseguir que a función ignore as celas que non interesen.


C
← Volver a Moldes Matrices Seguir con Cadeas de caracteres