Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Industrial programming >> Lenguaje C

Dominando punteros y arrays multidimensionales en C

En lenguaje C, un array es una colección de valores de tipo similar almacenados en ubicaciones de memoria continuas. Cada elemento en un array (unidimensional o multidimensional) es identificado por uno o más índices enteros únicos.

Un puntero, por otro lado, almacena la dirección de una variable. La dirección del elemento 0 en un array es el puntero del array. Puedes usar el "operador de desreferencia" para acceder al valor al que se refiere un puntero.

Puedes declarar un array unidimensional, bidimensional o multidimensional en C. El término "dimensión" se refiere al número de índices requeridos para identificar un elemento en una colección.

Punteros y arrays unidimensionales

En un array unidimensional, cada elemento es identificado por un solo entero:

int a[5] = {1, 2, 3, 4, 5};

Aquí, el número "1" está en el índice 0, "2" en el índice 1, y así sucesivamente.

Una variable que almacena la dirección del elemento 0 es su puntero:

int *x = &a[0];

Simplemente, el nombre del array también apunta a la dirección del elemento 0. Así que también puedes usar esta expresión:

int *x = a;

Ejemplo

Dado que el valor del puntero se incrementa por el tamaño del tipo de dato, "x++" mueve el puntero al siguiente elemento en el array.

#include <stdio.h>
int main(){
    int arr[] = {1, 2, 3, 4, 5};
    int length = sizeof(arr) / sizeof(arr[0]);
    int i = 0;
    int *ptr = arr;
    while (i < length){
        printf("arr[%d]: %d \n", i, *(ptr + i));
        i++;
    }
    return 0;
}

Salida

arr[0]: 1
arr[1]: 2
arr[2]: 3
arr[3]: 4
arr[4]: 5

Punteros y arrays bidimensionales

Si un array unidimensional es como una lista de elementos, un array bidimensional es como una tabla o una matriz.

Los elementos en un array 2D pueden considerarse lógicamente organizados en filas y columnas. Por tanto, la ubicación de cualquier elemento se decide por dos índices, su número de fila y número de columna. Ambos índices de fila y columna comienzan desde "0".

int arr[2][2];

Tal array se representa como:

Col0Col1Col2
Row0arr[0][0]arr[0][1]arr[0][2]
Row1arr[1][0]arr[1][1]arr[1][2]
Row2arr[2][0]arr[2][1]arr[2][2]

Se puede notar que la disposición tabular es solo una representación lógica. El compilador asigna un bloque de bytes continuos. En C, la asignación del array se hace de manera row-major (por filas), lo que significa que los elementos se leen en el array de manera fila por fila.

Aquí declaramos un array 2D con tres filas y cuatro columnas (el número en el primer corchete siempre se refiere al número de filas) como:

int arr[3][4] = {
    {1, 2, 3, 4},
    {5, 6, 7, 8},
    {9, 10, 11, 12}
};

El compilador asignará memoria para el array 2D anterior en orden por filas. Asumiendo que el primer elemento del array está en la dirección 1000 y el tamaño del tipo "int" es 4 bytes, los elementos del array obtendrán las siguientes ubicaciones de memoria asignadas:

Fila 0Fila 1Fila 2
Valor1 2 3 45 6 7 89 10 11 12
Dirección1000 1004 1008 10121016 1020 1024 10281032 1036 1040 1044

Asignaremos la dirección del primer elemento del array num al puntero ptr usando el operador de dirección &.

int *ptr = &arr[0][0];

Ejemplo 1

Si el puntero se incrementa en 1, se mueve a la siguiente dirección. Todos los 12 elementos en el array "3x4" pueden accederse en un bucle como sigue:

#include <stdio.h>
int main(){
    int arr[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12},
    };
    // puntero ptr apuntando al array num
    int *ptr = &arr[0][0];
    int i, j, k = 0;
    // imprimir los elementos del array num via puntero ptr
    for (i = 0; i < 3; i++){
        for (j = 0; j < 4; j++){
            printf("%d ", *(ptr + k));
            k++;
        }
        printf("\n");
    }
    return 0;
}

Salida

1 2 3 4
5 6 7 8
9 10 11 12

En general, la dirección de cualquier elemento del array se puede obtener usando la siguiente fórmula:

dir de elemento en fila i-ésima y columna j-ésima = direcciónBase + [(i * num_cols + j) * sizeof(tipo_array)]

En nuestro array 3x4:

dir de arr[2][2] = 1000 + (2*4 + 2)*4 = 1044

Puedes referirte a la figura anterior y confirma que la dirección de "arr[2][2]" es 1044.

Ejemplo 2

Usa el puntero de desreferencia para obtener el valor en la dirección. Usemos esta fórmula para recorrer el array con la ayuda de su puntero:

#include <stdio.h>
int main(){
    // array 2d
    int arr[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    };
    int ROWS = 3, COLS = 4;
    int i, j;
    // puntero
    int *ptr = &arr[0][0];
    // imprimir el elemento del array via puntero ptr
    for (i = 0; i < ROWS; i++){
        for (j = 0; j < COLS; j++) {
            printf("%4d ", *(ptr + (i * COLS + j)));
        }
        printf("\n");
    }
    return 0;
}

Salida

1 2 3 4
5 6 7 8
9 10 11 12

Punteros y arrays tridimensionales

Un array tridimensional es un array de arrays bidimensionales. Tal array se declara con tres subíndices:

int arr[x][y][j];

Este array puede considerarse como "x" número de capas de tablas, cada tabla teniendo "x" filas y "y" número de columnas.

Un ejemplo de un array 3D es:

int arr[3][3][3] = {
    { {11, 12, 13}, {14, 15, 16}, {17, 18, 19} },
    { {21, 22, 23}, {24, 25, 26}, {27, 28, 29} },
    { {31, 32, 33}, {34, 35, 36}, {37, 38, 39} }
};

Un puntero al array 3D puede declararse como:

int *ptr = &arr[0][0][0];

Sabiendo que el nombre del array en sí es la dirección del elemento 0, podemos escribir el puntero de un array 3D como:

int *ptr = arr;

Cada capa de "x" filas y "y" columnas ocupa:

x * y * sizeof(tipo_dato)

Número de bytes. Asumiendo que la memoria asignada al array 3D "arr" como se declaró arriba comienza en la dirección 1000, la segunda capa (con "i = 1") comienza en la posición de byte 1000 + (3 * 3) * 4 = 1036.

ptr = dirección base del array 3D arr

Si JMAX es el número de filas y KMAX es el número de columnas, entonces la dirección del elemento en la fila 0 y columna 0 de la primera rebanada es:

arr[1][0][0] = ptr + (1 * JMAX * KMAX)

La fórmula para obtener el valor de un elemento en la fila j-ésima y columna k-ésima de la i-ésima rebanada puede darse como:

arr[i][j][k] = *(ptr + (i * JMAX * KMAX) + (j * KMAX + k))

Ejemplo: Imprimir un array 3D usando desreferencia de puntero

Usemos esta fórmula para imprimir el array 3D con la ayuda de la desreferencia del puntero:

#include <stdio.h>
int main(){
    int i, j, k;
    int arr[3][3][3] = {
        { {11, 12, 13}, {14, 15, 16}, {17, 18, 19} },
        { {21, 22, 23}, {24, 25, 26}, {27, 28, 29} },
        { {31, 32, 33}, {34, 35, 36}, {37, 38, 39} }
    };
    int JMAX = 3, KMAX = 3;
    int *ptr = arr; // &arr[0][0][0];
    for(i = 0; i < 3; i++){
        for(j = 0; j < 3; j++){
            for(k = 0; k < 3; k++){
                printf("%d ", *(ptr + (i * JMAX * KMAX) + (j * KMAX + k)));
            }
            printf("\n");
        }
        printf("\n");
    }
    return 0;
}

Salida

11 12 13 14 15 16 17 18 19
21 22 23 24 25 26 27 28 29
31 32 33 34 35 36 37 38 39

En general, acceder a un array con un puntero es bastante similar a acceder a un array con representación de subíndices. La principal diferencia entre los dos es que la declaración de array con subíndices asigna la memoria estáticamente, mientras que podemos usar punteros para asignación de memoria dinámica.

Para pasar un array multidimensional a una función, necesitas usar punteros en lugar de subíndices. Sin embargo, usar un array con subíndices es más conveniente que usar punteros, que pueden ser difíciles para nuevos aprendices.

Lenguaje C

  1. Preprocesador y macros en C: Dominando #include, #define y compilación condicional
  2. Configuración del entorno de programación C: Herramientas esenciales y consejos
  3. Entendiendo los Modificadores de Acceso en C# (Especificadores) con Ejemplos Prácticos
  4. Dominando clases y métodos abstractos en C#: Guía práctica
  5. Entendiendo las variables en C: Tipos, reglas de nomenclatura y gestión de memoria
  6. Top 100 Preguntas y respuestas de entrevistas de programación en C (2024)
  7. Dominando los Bucles for en C++: Guía Paso a Paso
  8. Bucles en C#: Técnicas eficientes de repetición de código
  9. Dominar el manejo de señales en C++: Gestión segura de interrupciones y terminación limpia del programa
  10. Constantes y Literales en C++: Tipos, Sintaxis y Mejores Prácticas
  11. Dominando arrays en C#: Declaración, inicialización y operaciones