sencillos resueltos principiantes practicar para lenguaje ejercicios ejemplos cadenas arreglos arreglo c++ c multidimensional-array compile-time

c++ - resueltos - ¿Por qué no es posible char[][]={{...},{...}} si se le da explícitamente una matriz multidimensional?



ejercicios resueltos en c++ para principiantes (5)

Con una matriz, el compilador tiene que saber qué tan grande es cada elemento para que pueda hacer un cálculo de índice. Por ejemplo

int a[3];

es una matriz de enteros. El compilador sabe qué tan grande es una int (generalmente 4 bytes) para que pueda calcular la dirección de a[x] donde x es un índice entre 0 y 2.

Una matriz bidimensional se puede considerar como una matriz unidimensional de matrices. p.ej

int b[2][3];

es una matriz bidimensional de int pero también es una matriz unidimensional de matrices de int . es decir, b[x] refiere a una matriz de tres ints .

Incluso con matrices de matrices, la regla de que el compilador debe conocer el tamaño de cada elemento aún se aplica, lo que significa que en una matriz de matrices, la segunda matriz debe ser de tamaño fijo. Si no fuera así, el compilador no podría calcular la dirección cuando indexar, es decir, b[x] sería imposible de calcular. De ahí la razón por la cual multi_arr2 en tu ejemplo está bien, pero multi_arr1 no lo es.

Lo que impide que el compilador mire hacia la derecha y afirme que estamos tratando 3 elementos para cada "subcampo" o, posiblemente, un error de retorno solo para los casos en que el programador transfiere, por ejemplo, diferentes elementos para cada subcampo como {1,2,3}, {1 , 2,3,4}

Probablemente una limitación del analizador. Cuando llega al inicializador, el analizador ya ha pasado la declaración. Los primeros compiladores de C fueron bastante limitados y el comportamiento anterior se estableció como se esperaba mucho antes de que llegaran los compiladores modernos.

Revisé this artículo. Entiendo las reglas explicadas, pero me pregunto qué es exactamente lo que impide que el compilador acepte la siguiente sintaxis al definir una matriz multidimensional constante e inicializarla directamente con valores conocidos de un tipo dado:

const int multi_arr1[][] = {{1,2,3}, {1,2,3}}; // why not? const int multi_arr2[][3] = {{1,2,3}, {1,2,3}}; // OK error: declaration of ''multi_arr1'' as multidimensional array must have bounds for all dimensions except the first

Lo que impide al compilador mirar hacia la derecha y darse cuenta de que estamos tratando con 3 elementos para cada "subcampo" o devolver un error solo en los casos en que el programador pasa, por ejemplo, un número diferente de elementos para cada subcampo como {1,2,3}, {1,2,3,4} ?

Por ejemplo, cuando se trata de una matriz de caracteres 1D, el compilador puede ver la cadena en el lado derecho de = y esto es válido:

const char str[] = "Str";

Me gustaría entender qué está pasando para que el compilador no pueda deducir las dimensiones de la matriz y calcular el tamaño para la asignación, ya que ahora me parece que el compilador tiene toda la información necesaria para hacerlo. ¿Que me estoy perdiendo aqui?


La regla es que el compilador determina solo la primera dimensión de la matriz mediante la lista de inicializadores dada. Espera que la segunda dimensión se especifique explícitamente. Período.


No hay nada imposible en la implementación de compiladores que deduzcan las dimensiones más internas de las matrices multidimensionales en presencia de un inicializador, sin embargo, es una característica que NO es compatible con los estándares C o C ++, y, evidentemente, no ha habido una gran demanda para eso. característica para molestar.

En otras palabras, lo que está buscando no es compatible con el lenguaje estándar. Podría ser respaldado si suficientes personas lo necesitaran. Ellos no.


Para ampliar brevemente el comentario:

Lo que "bloquea" al compilador es el cumplimiento del estándar (para C o C ++, son estándares diferentes, elija uno).

Lo que "bloquea" el estándar al permitir esto es que nadie escribió una propuesta de estándares para implementarlo, que posteriormente fue aceptada.

Entonces, todo lo que estás preguntando es por qué nadie estaba motivado para hacer algo que crees que sería útil, y solo puedo ver eso como basado en la opinión.

También puede haber dificultades prácticas para implementar esto o mantener una semántica consistente; esa no es precisamente la pregunta que hizo, pero al menos podría ser objetivamente responsable. Sospecho que alguien podría superar esas dificultades si estuviera lo suficientemente motivado. Presumiblemente nadie lo fue.

Por ejemplo, ( reference ), la sintaxis a[] realmente significa una matriz de límite desconocido . Debido a que el límite se puede inferir en el caso especial cuando se declara usando la inicialización agregada, lo está tratando como algo así como a[auto] . Tal vez esa sería una mejor propuesta, ya que no tiene el bagaje histórico. No dude en escribirlo usted mismo si cree que los beneficios justifican el esfuerzo.


Requerir que el compilador infiera las dimensiones internas de los inicializadores requeriría que el compilador trabaje retroactivamente de una manera que evita el estándar.

El estándar permite que los objetos que se inicialicen se refieran a ellos mismos. Por ejemplo:

struct foo { struct foo *next; int value; } head = { &head, 0 };

Esto define un nodo de una lista vinculada que apunta a sí mismo inicialmente. (Presumiblemente, más nodos se insertarían más tarde.) Esto es válido porque C 2011 [N1570] 6.2.1 7 dice que el identificador de head "tiene un alcance que comienza justo después de la finalización de su declarador". Un declarador es la parte de la gramática de una declaración que incluye el nombre del identificador junto con la matriz, la función y / o las partes del puntero de la declaración (por ejemplo, f(int, float) y *a[3] son declaradores, en declaraciones como float f(int, float) o int *a[3] ).

Debido a 6.2.1 7, un programador podría escribir esta definición:

void *p[][1] = { { p[1] }, { p[0] } };

Considere el inicializador p[1] . Esta es una matriz, por lo que se convierte automáticamente en un puntero a su primer elemento, p[1][0] . El compilador conoce esa dirección porque sabe que p[i] es una matriz de 1 void * (para cualquier valor de i ). Si el compilador no sabía qué tan grande era p[i] , no podía calcular esta dirección. Entonces, si el estándar C nos permitió escribir:

void *p[][] = { { p[1] }, { p[0] } };

entonces el compilador debería continuar escaneando más allá de p[1] para que pueda contar el número de inicializadores dados para la segunda dimensión (solo uno en este caso, pero tenemos que escanear al menos para ver eso, y podría ser muchos más), luego regrese y calcule el valor de p[1] .

El estándar evita obligar a los compiladores a hacer este tipo de trabajo de pase múltiple. Exigir a los compiladores que infieran las dimensiones internas violaría este objetivo, por lo que el estándar no lo hace.

(De hecho, creo que el estándar podría no requerir que el compilador haga más que una cantidad finita de anticipación, posiblemente solo unos pocos caracteres durante la tokenización y un solo token mientras analiza la gramática, pero no estoy seguro. Algunas cosas tener valores desconocidos hasta el tiempo de enlace, como void (*p)(void) = &SomeFunction; pero el void (*p)(void) = &SomeFunction; los rellena).