ARREGLOS

DEFINICIÓN:  Un arreglo es una coleción de variables del mismo tipo, las cuales se referencian por el mismo nombre. Un arreglo se declara de la siguiente manera:

tipo identificador [límite];
Donde "límite" indica la cantidad de variables que se desea definir para el arreglo.

Ejemplo:
int a[10];
ð donde "a" es el nombre que identifica al arreglo de tipo int, el cual se define con 10 elementos, estos son:

a[0],   a[1],  a[2],  a[3],  a[4],  a[5],  a[6],  a[7],  a[8]  y  a[9]
INICIALIZACIÓN:  Como cualquier variable, un arreglo puede ser inicilizado en el momento de su declaración. Esta opracón se realiza de la siguiente manera:
int a[10] = {3, 5, 1, 7, 0, 2, 6, 9, 8, 4};

Esto signfica que a la variable a[0] se le asigna el valor de 3,a la variable a[1] ï 5, ... a la varble a[9] ï 4
Si se colocan menos valores de inicialización que la capacidad del arreglo, el resto de elementos del arreglo se inicializa en cero. Si por ejemplo:
int a[5] = {3, 5, 1};

Esto signfica que:
a[0] ï 3,   a[1] ï 5,  a[2] ï 1,  a[3] ï 0,   a[4] ï 0
.
También, como se muestra a continuación, al definir un arreglo con valores iniciales se puede omitir el tamaño de éste:
int a[ ] = {3, 7, 9, 5};
El número de elementos del arrglo lo define la cantidad de valores con el que se desea inicializar.
Luego   a[0] ï 8,   a[1] ï 7,  a[2] ï 9,  a[3] ï 5
Sin embargo, se debe tener en cuenta que de alguna manera se debe indiar al compilador el tamaño del arreglo, ya sea colocando un valor constante entre los corchetes ([ ]) o mediante valores iniciales, es por eso que:
int a[ ];    /*  es un error porque no se le indica el tamaño del arreglo.  */
Otro error que se comete cuando se define un arreglo es que se pretende definir el tamaño con una variable, esto es:
int n;
printf("Ingrese el tamaño del arreglo: ");
scanf("%d",  &n);
int a[n];
     /*  es un error debido a que el tamaño de un arreglo se define en tiempo de compilación y aquí se pretende definir en tiempo de ejecución.  */
El siguiente ejemplo muestra otro error muy común:
int funcPrueba(int n)
{    int a[n];
     /*  es un error por la misma razón que la del ejemplo anterior.  */
ASIGNACIÓN DE VALORES:  Asignar valores a un elemento de un arreglo es una tarea relativamente sencilla, la asignación se realiza colocando el nombre del arreglo seguido de un par de corchetes, entre los cuales se coloca una expresión que, al ser evaluada, determine a qué elemento del arreglo se le quiere asignar un valor, luego se coloca un signo de asignación seguido de una expresión que, al ser evaluada, dará el valor que se desea asignar al alemento del arreglo.
A continuación se muestran algunos ejemplos:
int a[5],   n = 2 ,   p = 15;
a[2] = 35;
a[0] = p*3;     /* asigna 45 (resultado de evaluar p*3) al primer elemento del arreglo (a[0])  */
a[n + 1] = 17;   /* asigna 17 al cuarto elemento del arreglo (n+1 = 3)  */
a[p/3-1] = 23*n/5;  /* asigna 9 (23*n/5=9) al quinto elemento del arreglo (p/3-1 = 4)  */
La tarea de asignar valores a los elementos de un arreglo, como se ha podido ver, es una tarea sencilla, sin embargo debido a que el compilador de C/C++ no verifica los rangos para los que se ha definido el arreglo, si no se toma el cuidado necesario se podría incurrir en errores muy serios.
Cuando uno escribe una orden como "a[n] = 3", el sistema calcula la dirección donde se colocará el dato, de la siguiente manera:
DMAn = DMA + n x sizeof(TA)
Donde:
DMA   es la dirección de memoria donde empieza el arreglo a.
DMAn   es la dirección de memoria del elemnto n del arreglo a.
sizeof(TA)   es el tamaño del tipo de dato del arreglo a.
Este cálculo lo realiza el sistema a ciegas, es decir que no verifica si el valor dado como n sea positivo o negativo o si es más grande que el número de elementos definidos para el arreglo.
El siguiente ejemplo muestra claramente esta afirmación.

Ejemplos:

Grabar este ejemplo
#include <stdio.h> void main (void) { int a=10, b=20, c=30, d[5], e=40, f=50,g=60; printf("Direcciones de memoria de la variables:\n"); printf("A=%X B=%X C=%X D=%X E=%X F=%X G=%X\n\n",&a,&b,&c,d,&e,&f,&g); printf("Valores iniciales de la variables:\n"); printf("A=%d B=%d C=%d E=%d F=%d G=%d\n\n", a,b,c,e,f,g); d[-1]=22; printf("Asaignamos 22 a d[-1]\n"); printf("A=%d B=%d C=%d E=%d F=%d G=%d\n\n", a,b,c,e,f,g); d[-2]=77; printf("Asaignamos 77 a d[-2]\n"); printf("A=%d B=%d C=%d E=%d F=%d G=%d\n\n", a,b,c,e,f,g); d[6]=55; printf("Asaignamos 55 a d[6]\n"); printf("A=%d B=%d C=%d E=%d F=%d G=%d\n\n", a,b,c,e,f,g); d[7]=99; printf("Asaignamos 99 a d[7]\n"); printf("A=%d B=%d C=%d E=%d F=%d G=%d\n\n", a,b,c,e,f,g); }
Al ejecutar este programa obtendremos como resultado algo similar a esto:
Direcciones: A=FFF4 B=FFF2 C=FFF0 D=FFE6 E=FFE4 F=FFE2 G=FFE0 Valores iniciales: A=10 B=20 C=30 E=40 F=50 G=60 Asaignamos 22 a d[-1] A=10 B=20 C=30 E=22 F=50 G=60 Asaignamos 77 a d[-2] A=10 B=20 C=30 E=22 F=77 G=60 Asaignamos 55 a d[6] A=10 B=20 C=55 E=22 F=77 G=60 Asaignamos 99 a d[7] A=10 B=99 C=55 E=22 F=77 G=60
Observe las direcciones de memoria asignadas a cada variable, en la versión en que fue ejecutado el programa los entero se almacenan en dos bytes , haciendo cálculos muy sencillo se puede dar cuenta del porqué de esos resultados. En compiladores que trabajan con enteros de 4 bytes debrá corregir, en las asignaciones, los índices 6 y 7.
Es por esta razón que se debe tener mucho cuidado cuando asigna valores a los elementos de un arreglo. Si se sale del rango de elementos para los que fue definido el arreglo, si bien es cierto que el compilardor no lo hará notar, el programa puede dar como resultados valores impredecibles.

Arreglos como parámetros de funciones: Cuando se emplean arreglos como parámetro de una función, éste pasa por referencia.

Ejemplos: A continuación se muestran algunos ejemplos que utilizan areglos unidimensionales:

Grabar este ejemplo



/* Este programa lee  una  frase y verifia si ésta es palíndrome o no. La
   coincidencia la hace  notar eliminando los caracteres blancos, hacendo
   coincidir las mayúsculas y minusculas. */

#include <stdio.h>

void main (void )
{ char frase[50],esarf[50];
  int i=0, j, numCar;

  while ((frase[i++]=getchar()) != EOF);
  // Luego de la lectura, el índice i queda adelantado
  // dos posiciones, ver figura.
  numCar = i-1;

  // Eliminamos los caracteres blancos y pone en mayúsculas las letras
  for(i=0,j=0; i<numCar; i++)
   { if (frase[i] != ' ')
       frase[j++] = frase[i] - ('a'-'A')*(frase[i]>='a' && frase[i]<='z');
   }
  numCar = j; // Corregimos la nueva cantidad de caracteres

  // Copiamos los caracteres al revés
  for(i=0,j=numCar-1; i<numCar; i++,j--)
   { esarf[j] = frase[i];
   }

   // verificamos si son iguales
  for(i=0; i<numCar && esarf[i] == frase[i]; i++);
  if (i==numCar) printf("La frase es palíndrome\n");
  else printf("La frase NO es palíndrome\n");
}

/* Este programa permite elaborar una distribución de frecuencia de las letra contenidas en un archivo de textos(las mayúsculas y minúsculas se consideran iguales */ #include <stdio.h> #define TAM_ARREGLO 'z'-'a'+1 void main (void) { int c, ContCar[TAM_ARREGLO], i; // Inicializamos el arreglo con ceros for (i=0; i <= TAM_ARREGLO; i++) ContCar [i] = 0; while ((c=getchar( ))!=EOF) if(c >='a' && c <='z' || c >='A' && c <='Z') ++ ContCar[c >= 'a'? c-'a' : c-'A']; printf("Frecuencia de caracteres\n"); for (i=0; i < TAM_ARREGLO; i++) printf("%2c -> %3d\n", i+'A', ContCar[i]); }

Grabar este ejemplo /* El siguiente programa prmite leer una serie de valores enteros, llenar un arreglo con los valores, ordenar el arrreglo empleando el método de Quick Sort y finalmente imprimir los datos ordenados. */ #include <stdio.h> void leeArreglo (int [], int &); void quickSort (int [], int, int); void imprime(int [],int); void cambiar (int [], int, int); void main(void) { int dato[50], numDat; leeArreglo (dato, numDat); quickSort (dato, 0, numDat-1); imprime(dato,numDat); } void leeArreglo (int dato[], int &numDat) { int datoAux; numDat=0; while(1) { if (scanf("%d",&datoAux)==EOF)break; dato[numDat]=datoAux; numDat++; } } void quickSort (int dato[], int izq, int der) { int i, ultimo; if (izq >=der) return; cambiar (dato, izq, (izq+der)/2); ultimo=izq; for (i=izq+1; i<=der; i ++) if (dato[i] < dato[izq]) cambiar (dato, ++ultimo, i); cambiar (dato, izq, ultimo); quickSort (dato, izq, ultimo-1); quickSort (dato, ultimo+1, der); } void cambiar (int dato[], int i, int j) { int aux; aux=dato[i]; dato[i] = dato[j]; dato[j]=aux; } void imprime(int dato[], int numDat) { for (int i=0; i<numDat; i++) printf ("%4d", dato[i]); putchar('\n'); }

ARREGLOS MULTIDIMENSIONALES

Un arreglo multidimensional es aquel que se maneja con más de un índice. El lenguaje C/C++ permite la definición de este tipo de arreglos. Un arreglo multidimensional en C/C++ se define de la siguiente manera:

tipo identificador [límite1] [límite2] [límite3] ...

Ejemplo:

int M[20][20];
float f [5][10][3];
En el primer caso se definen las variable:
M [0][0],M [0][1],M [0][2],...M [0][19]
M [1][0],M [1][1],M [1][2],...M [1][19]
...
M [19][0],M [19][1],M [19][2],...M [19][19]
Se debe tener en cuenta que cada índice del arreglo se manaja por separado, de ahí que cada uno se encierra entre corchetes ([]), NO se puede escribir M [0,1] como se hace en otros lenguajes de programación como el Pascal.


Al definir un arreglo como int a[3][3], los elementos del arreglo distribuirán en la memoria el computador de la siguiente manera:


Del mismo modo que con los arreglos unidimensionales, para manejar un elemento del arrglo de dos dimensiones como "a[i][j]", el sistema debe calcular la dirección de memoria correspondiente a ese elemento. Este cálculo se realiza de la siguiente manera:
DMAi,j = DMA + (i x nCol + j) x sizeof(TA)
Donde:
DMA   es la dirección de memoria donde empieza el arreglo a.
DMAi,j   es la dirección de memoria del elemnto [i][j] del arreglo a.
nCol   es el número de elementos con el que se definió el segundo índice del arreglo.
sizeof(TA)   es el tamaño del tipo de dato del arreglo a.
Observe que en la fórmula requiere de un valor que corresponde al número de elementos con el que se definió el segundo índice del arreglo. Esto quiere decir que si se define un arreglo como float a[10][20]; el tamaño de la segunda dimensión, en este caso 20, se emplea para poder determinar la posición de memeoria de un elemento del arreglo.

Es muy importante conocer esta propiedad porque cuando se quiera dar valores iniciales a un arreglo de dos dimensiones en el momento de su declaración, no se puede obviar este valor porque el sistma no podría localizar los elementos del arreglo. Tambien, por la misma razó, debe obligatoriamente estar presente en el encabezado de una función que reciba como par´metro un arreglo de dos dimensiones.

Así:

int a[3][6] = {{0,1,2,3,4,5}, {0,2,4,6,8,10}, {1,3,5,7,9,11}};   /* es correcto.  */

int a[  ][  ] = {{2,2,2}, {1,1,1}};    /* es un ERROR porque no se indica el tamaño de la segunda dimensión del arreglo.  */

int a [  ][3]= { {2,2,2}, {1,1,1}};    /* es correcto, a pesar que no se indica el tamaño de la primera dimensión del arreglo.  */

int leeArreglo1 (float a[  ][  ]);    /* es un ERROR porque en el prototipo de la función no se indica el tamaño de la segunda dimensión del arreglo.  */

int leeArreglo2 (float a[  ][5]);    /* es correcto, a pesar que en el prototipo de la función no se indica el tamaño de la primera dimensión del arreglo.  */

Ejemplo:

Grabar este ejemplo



/* Este programa lee dos matrices y, si es que las dimensiones de ambas
   lo permite, las multiplica e imprime el resultado.
   El programa también calcula,  si  las condiciones  lo  permiten,  el
   determinante de la primera matriz */

#include <stdio.h>
const int DIMMAX=5; // Máximo número de filas y columnas de una matriz

// Prototipos de funciones:
  void leeMat (float [][DIMMAX], int &, int &);
  void multMat (float [][DIMMAX], int, int,
                float [][DIMMAX], int, int,
                float [][DIMMAX], int &, int &);
  void imprimeMat (float [][DIMMAX], int, int);
  float determinante (float [][DIMMAX], int);
  void reduceMat (float [][DIMMAX], int, int,  float [][DIMMAX]);

void main (void)
{ float a[DIMMAX][DIMMAX], b[DIMMAX][DIMMAX], c[DIMMAX][DIMMAX];
  int nFilA, nColA, nFilB, nColB, nFilC, nColC;
  float determ;

  // Lectura de las matrices y sus dimensiones
  printf("Matriz A:\n");
  leeMat (a, nFilA, nColA);

  printf("Matriz B:\n");
  leeMat (b, nFilB, nColB);

  // Verifica si se pueden multiplicar
  if (nColA != nFilB)
   { printf("Las dimensiones de las matrices no son correctas\n");
     return;
   }

  // Calcula lal multiplicación de ambas matrices
  multMat (a, nFilA, nColA, b, nFilB, nColB, c, nFilC, nColC);
  printf("El producto de A y B =\n");
  imprimeMat (c, nFilC, nColC);

  // Calcula el determinanate de la primera matriz
  if (nFilA != nColA)
   { printf("Las dimensiones de esta matriz no permiten\ncalcular el determinante\n");
      return;
   }

  determ = determinante (a,nFilA);
  printf("El determinante de esta matriz es: %f\n", determ);

}

void leeMat (float x[][DIMMAX], int &nFil, int &nCol)
{  printf("Ingrese el n£mero de filas y columnas de la matriz: ");
   scanf("%d %d", &nFil, &nCol);

   for (int fil = 0; fil < nFil; fil++)
     for (int col = 0; col < nCol; col++)
	   scanf("%f", &x [fil][col]);
}

void multMat (float a [][DIMMAX], int nFilA, int nColA,
              float b [][DIMMAX], int nFilB, int nColB,
              float c[][DIMMAX],  int &nFilC, int &nColC)
 { nFilC = nFilA;
   nColC = nColB;
   for (int fil = 0; fil < nFilC; fil++)
    for (int col = 0; col < nColC; col++)
     { c[fil][col] = 0;
       for (int k = 0; k < nColA; k++)
         c[fil][col] += a[fil][k] * b[k][col];
     }
 }

void imprimeMat (float x[][DIMMAX], int nFil, int nCol)
 { for (int fil = 0; fil < nFil; fil++)
    { for (int col = 0; col < nCol; col++)
	printf("%7.2f", x[fil][col]);
      putchar('\n');
    }
 }

float determinante (float x[][DIMMAX], int dim)
 { float det=0.0, aux[DIMMAX][DIMMAX];

   if (dim==1) return x[0][0];
   for (int col=0; col < dim; col++)
    { reduceMat (x, dim, col, aux);
      det += x[0][col] * (col%2 ? -1 : 1) * determinante (aux,dim-1);
    }
   return det;
 }

void reduceMat (float x[][DIMMAX], int dim, int colElim, float aux[][DIMMAX])
 { int fil, col;
   for (fil = 1; fil < dim; fil++)
     for (col = 0; col < dim; col++)
       aux[fil-1][col] = x[fil][col];

   for (fil = 0; fil < dim-1; fil++)
     for (col = colElim+1; col < dim; col++)
       aux[fil][col-1] = aux[fil] [col];
 }

Volver a contenidos AtrásSiguiente