Aunque el concepto de “tabla” en un lenguaje de
programación es intuitivo, en C las tablas se manipulan de una forma
especial que debe ser entendida para evitar errores al combinar su uso con
memoria dinámica. Para el lenguaje de programación C, una tabla se
representa internamente sólo como la dirección de memoria a partir de la
cual está almacenado su primer elemento. Otra forma de verlo, en C se define
una tabla de 100 elementos de tipo T
como T
tabla[100]
, pero una vez definida (y reservado su espacio
correspondiente ya sea en la memoria global o en la pila), en adelante, el
nombre de la tabla y la dirección de su primer elemento es exactamente lo mismo. Esta
particularidad de C se puede resumir diciendo que para toda tabla en C la
siguiente expresión es siempre cierta:
tabla == &tabla[0]
La principal consecuencia es que cuando es preciso reservar
espacio en memoria dinámica para una tabla, la reserva devuelve un puntero,
pero este puede utilizarse directamente como una tabla. Por ejemplo, el
siguiente código crea una tabla de tantos elementos como indica la variable
size
y los inicializa:
struct element { float number1; int number2; char letter; }; struct element *table; table = (struct element *)malloc(sizeof(struct element) * size); for (i = 0; i < size; i++) { table[i].number1 = 0.0; table[i].number2 = 10; table[i].letter = 'B'; }
Nótese que el acceso a los elementos de la tabla, tras incluir el índice entre corchetes, se realiza como una estructura, y no como un puntero.
Por lo tanto existe una gran relación entre punteros y tablas. Con una variable puntero que apunta al primer elemento de una tabla, se pueden realizar las mismas operaciones (y con la misma notación) que las que se pueden hacer con la tabla definida. Sin embargo, no todas las operaciones que se pueden realizar con un puntero son válidas para realizarlas con una tabla. Así a un puntero se le puede asignar otro puntero o la dirección inicial de una tabla, mientras que sin embargo a una tabla declarada no se le puede asignar otro puntero o la dirección inicial de otra tabla. Esto es porque al declarar una tabla su dirección permanece fija, mientras que el puntero puede admitir nuevas asignaciones. El siguiente código ilustra esta situación:
1 2 3 4 5 | #define SIZE 30 char cadena1[SIZE]; char *cadena2; cadena1 = "Pulsa espacio para continuar"; /* Incorrecto */ cadena2 = "Pulsa espacio para continuar"; /* Correcto */ |
La línea 4 es incorrecta porque a la tabla
cadena1
no se le puede asignar una dirección nueva, ya se le
asigna al ser declarada. Por el contrario, cadena2
se declara
como puntero, y sí se le puede asignar una dirección cualquiera, y en la
línea 5 se le asigna la de la cadena “Pulsa espacio para
continuar”.