Arrays en C

Author
By Darío Rivera
Posted on 2022-08-03 in Lenguaje C

Generalmente cuando hablamos de arrays en C debemos hablar también de punteros. Ambos conceptos están estrechamente relacionados y es de vital importancia tener un conocimiento claro de estos incluso para construir programas simples como concatenar dos cadenas de caracteres.

Definición

Los arrays son variables indexadas que contienen muchos datos del mismo tipo. Existe una gran diferencia en el tratamiento de arrays en C comparado con otros lenguajes. En C los arrays no son un tipo de dato primitivo, sino un tipo construido por agregación a partir de otros tipos de datos.

Los arrays tienen las siguientes propiedades que los identifican de manera inequivoca.

- Los datos individuales del array se llaman elementos
- Todos los elementos tienen que pertenecer al mismo tipo de dato.
- El subindice del primer elemento es cero.
- El nombre del array es una constante que representa la direccion del primer elemento del array.
- Todos los elementos son almacenados de forma contigua en la memoria de la computadora.

Declaracion e inicialización

Un array puede ser declarado indicando el tipo de dato, seguido del nombre del array, los corchetes y entre estos la cantidad de elementos que va a tener el array. La siguiente instrucción declara un array de cinco enteros.

int array_uno[5];

El tamaño del array debe ser indicado en tiempo de compilación. Es decir, que no podemos indicar el tamaño con una variable en tiempo de ejecución ya que el compilador necesita saber cuánto espacio reservar para el array.

Para incializar un array después de su declaración podemos utilizar índices empezando desde el número cero con cada uno de los elementos (inicialización explícita).

array_uno[0] = 10;
array_uno[1] = 4;
array_uno[2] = 85;
array_uno[3] = 100;
array_uno[4] = 50;

También hubiera sido posible declarar e inicializar el array en una sola instrucción tal y cómo sucede con los demás tipos.

int array_uno[5] = {10, 4, 85, 100, 50};

Para acceder por ejemplo al tercer elemento del array utilizaríamos el índice número dos así:

array_uno[2];

Inicialización por defecto

Tambien es posible inicializar solo ciertos elementos de un array en su inicializacion. En el siguiente ejemplo se inicializan solamente los tres primeros elementos de un array de cinco posiciones.

int array_uno[5] = {10, 4, 85};

En este caso los dos elementos restantes son inicializados con ceros (inicialización implícita). La siguiente instrucción es equivalente a la anterior.

int array_uno[5] = {10, 4, 85, 0, 0};

Este comportamiento es igual si se declara e inicializa el array tanto a nivel interno como a nivel global. Sin embargo, si el array no se inicializa y solo se declara, hay una sutíl diferencia respecto a si se declaró a nivel interno o a nivel global. Observa el siguiente ejemplo en donde hemos utilizado el debugger para observar el array justo después de una declaración a nivel interno.



Cómo puedes ver, los valores obtenidos son aleatorios (basura). sin embargo, esto no sucede si declaramos el array a nivel global, en cuyo caso son inicializados a cero.



Mientras que los valores numéricos son inicializados a cero a nivel global, los char son inicializados con el carácter nulo ('\0' o ASCII 0) al igual que los punteros (0x0). Los punteros a nivel interno serán direcciones de memoria aleatorias, muchas veces inaccesibles mientras que los char a nivel interno generalmente son inicializados a nulo.

Siempre es recomendable inicializar los elementos de un array. Podemos aprovechar el hecho de que al inicializar un valor se inicializan los demás de manera implícita tanto a nivel interno como a nivel global.



Como un plus, es posible inicializar explícitamente ciertos valores en la declaración así:

int array[5] = { [1] = 30, [3] = 5 };

En este caso, los demás valores serán inicializados de manera implícita resultando en el siguiente array:

[0, 30, 0, 5, 0]

Comprobación de rangos

El compilador de C no hace comprobaciones de arrays fuera de rango. El siguiente programa compilará pero se obtendrán resultados inesperados.

#include <stdio.h>
  
int main()
{
    int arr[2];
  
    printf("%d ", arr[3]);
    printf("%d ", arr[-2]);
  
    return 0;
}

Recorrer arrays

Recorrer los elementos de un array es bastante sencillo utilizando los bucles disponibles en C. Veamos el siguiente ejemplo en donde se recorre un array usando el bucle for.

#include <stdio.h>
  
int main(void)
{
    int arr[6] = {11, 12, 13, 14, 15, 16};
    
    for(int i = 0; i < 6; i++)
          printf("%i ", arr[i]);

    printf("\n");
  
    return 0;
}

Otra manera de recorrer el mismo array con una sintaxis levemente diferente es la siguiente. Observa el leve cambio accediendo al elemento n del array.

for(int i = 0; i < 6; i++)
    printf("%i ", i[arr]);

Arrays como cadenas

A diferencia de otros lenguajes de programación C no soporta un tipo de dato primitivo de cadena. Esto significa que las cadenas son formadas de otros tipos básicos, en este caso el tipo char. Para definir el valor de una cadena utilizamos comillas dobles.

char saludo[5] = "Hola";

Te preguntarás por qué hemos indicado que el tamaño del array es cinco y no cuatro. Esto es porque el compilador utiliza el último espacio para insertar un caracter nulo ('/0'). También hubieramos podido definir este array de la siguiente manera:

char saludo[5] = {'H', 'o', 'l', 'a', '/0'};

Una forma más sencilla de declarar e inicializar una cadena de caracteres de dejando que el compilador decida que tamaño es el indicado para el array así:

char saludo[] = "Hola";

Arrays multidimensionales

El término multidimensional representa la cantidad de índices necesarios para acceder a un elemento. Podemos definir arrays multidimensionales indicando otro par de corchetes y su tamaño respectivo.

int array_multi[3][10];

Observemos el siguiente ejemplo en donde aplicamos todo lo visto hasta ahora para mostrar las sillas disponibles y ocupadas de un cine. Cada fila está identificada con una letra de la A hasta la E y cada fila tiene diez sillas. Para efectos de este ejemplo, solamente las filas B y D estarán ocupadas. Se utilizará un uno (1) para indicar si está ocupada y un cero (0) para indicar que está disponible.

#include <stdio.h>
#define FILAS 5
#define ASIENTOS 10

int main()
{
    int nombre_filas[] = {'A', 'B', 'C', 'D', 'E'};
    int asientos[FILAS][ASIENTOS], fila, asiento;

    for (fila = 0; fila < FILAS; fila++) {
        for (asiento = 0; asiento < ASIENTOS; asiento++) {
            asientos[fila][asiento] = (fila % 2 == 0) ? 1 : 0;
        }
    }

    for (fila = 0; fila < FILAS; fila++) {
        for (asiento = 0; asiento < ASIENTOS; asiento++) {
            int occupied = asientos[fila][asiento] == 0 ? '*' : ' ';
            printf("%c%d%c ", nombre_filas[fila], asiento+1, occupied);
        }
        printf("\n");
    }
}

La salida del programa será simiar a la siguiente:

A1  A2  A3  A4  A5  A6  A7  A8  A9  A10  
B1* B2* B3* B4* B5* B6* B7* B8* B9* B10* 
C1  C2  C3  C4  C5  C6  C7  C8  C9  C10  
D1* D2* D3* D4* D5* D6* D7* D8* D9* D10* 
E1  E2  E3  E4  E5  E6  E7  E8  E9  E10 

También hubieras podido inicializar el array multidimensional en su declaración y con esto no tendríamos que llenarle los valores con un bucle. El siguiente ejemplo es equivalente al anterior.

#include <stdio.h>
#define FILAS 5
#define ASIENTOS 10

int main()
{
    int nombre_filas[] = {'A', 'B', 'C', 'D', 'E'};
    int asientos[FILAS][ASIENTOS] = {
        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
        {1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
        {1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    }, fila, asiento;

    for (fila = 0; fila < FILAS; fila++) {
        for (asiento = 0; asiento < ASIENTOS; asiento++) {
            int occupied = asientos[fila][asiento] == 0 ? '*' : ' ';
            printf("%c%d%c ", nombre_filas[fila], asiento+1, occupied);
        }
        printf("\n");
    }
}

Arrays en funciones

Podemos pasar arrays como argumentos de funciones de una manera similar a cómo se declaran. La única diferencia es que no se indica el tamaño del array. Veamos el siguiente ejemplo en donde pasamos un conjunto de enteros para calcular su promedio.

#include <stdio.h>

float promedio(int valores[], int num_elementos)
{
    int i;
    float suma = 0.0;

    for (i = 0; i < num_elementos; i++) {
        suma += (float) valores[i];
    }

    return suma / num_elementos;
}

int main()
{
    int valores[5] = {4, 4, 3, 5, 5};

    printf("Promedio: %.2f\n", promedio(valores, 5));
    return 0;
}

Arrays como punteros

El nombre de un array es en realidad un puntero a la dirección de memoria del primer elemento del array. Observa como en el ejemplo anterior hubieramos podido usar esta misma instrucción.

printf("Promedio: %.2f\n", promedio(&valores[0], 5));

Además podemos imprimir la dirección de memoria del array utilizando su nombre, esto no se puede hacer con los nombres de otras variables ya que no son punteros (a menos que se utilice explícitamente el operador de dirección &).

printf("Dirección %p\n", valores);

La salida sería similar a la siguiente:

Dirección 0x7ffe1dbcfd70

Dado que los nombres de arrays en realidad se pasan como punteros en las funciones, es posible cambiar el valor de un array una vez se ejecuta una función sobre ellos. Veamos el siguiente ejemplo en donde se incrementa el array al doble para cada elemento del mismo.

#include <stdio.h>

void duplicar(int valores[], int num_elementos)
{
    int i;
    for (i = 0; i < num_elementos; i++) {
        valores[i] = valores[i] * 2;
    }
}

int main()
{
    int valores[5] = {4, 4, 3, 5, 5}, i;
    duplicar(valores, 5);

    for (i = 0; i < 5; i++) {
        printf("%d ", valores[i]);
    }

    printf("\n");

    return 0;
}

Acerca de Darío Rivera

Author

Ingeniero de desarrollo en PlacetoPay , Medellín. Darío ha trabajado por más de 6 años en lenguajes de programación web especialmente en PHP. Creador del microframework DronePHP basado en Zend y Laravel.

Sólo aquellos que han alcanzado el éxito saben que siempre estuvo a un paso del momento en que pensaron renunciar.