¿Por qué las matrices C no pueden tener una longitud de 0?

13

El estándar C11 dice que las matrices, tanto de tamaño como de longitud variable "tendrán un valor mayor que cero". ¿Cuál es la justificación para no permitir una longitud de 0?

Especialmente para matrices de longitud variable, tiene mucho sentido tener un tamaño de cero de vez en cuando. También es útil para matrices estáticas cuando su tamaño es de una macro o una opción de configuración de compilación.

Es interesante que GCC (y clang) proporcionan extensiones que permiten arreglos de longitud cero. Java también permite matrices de longitud cero.

    
pregunta Kevin Cox 10.07.2014 - 23:59

6 respuestas

11

El problema que apostaría es que los arreglos C son solo indicadores hacia el comienzo de una porción de memoria asignada. Tener un tamaño 0 significaría que tienes un puntero a ... ¿nada? No puedes no tener nada, así que tendría que haber elegido algo arbitrario. No puedes usar null , porque entonces tus arreglos de longitud 0 se verían como punteros nulos. Y en ese punto, cada implementación diferente elegirá diferentes comportamientos arbitrarios, lo que llevará al caos.

    
respondido por el Telastyn 11.07.2014 - 00:08
6

Veamos cómo se presenta típicamente una matriz en la memoria:

         +----+
arr[0] : |    |
         +----+
arr[1] : |    |
         +----+
arr[2] : |    |
         +----+
          ...
         +----+
arr[n] : |    |
         +----+

Tenga en cuenta que no hay un objeto separado llamado arr que almacene la dirección del primer elemento; cuando aparece una matriz en una expresión, C calcula la dirección del primer elemento según sea necesario.

Entonces, pensemos en esto: una matriz de 0 elementos no tendría ningún almacenamiento a un lado, lo que significa que no hay nada para calcular la dirección de la matriz desde (ponga otra así, no hay asignación de objetos para el identificador). Es como decir: "Quiero crear una variable int que no ocupa memoria". Es una operación sin sentido.

Editar

Las matrices de Java son animales completamente diferentes de las matrices de C y C ++; no son un tipo primitivo, sino un tipo de referencia derivado de Object .

Editar2

Un punto destacado en los comentarios a continuación: la restricción "mayor que 0" solo se aplica a las matrices en las que el tamaño se especifica mediante una expresión constante ; un VLA puede tener una longitud 0 Declarar un VLA con una expresión no constante de valor 0 no es una violación de restricción, pero sí invoca un comportamiento indefinido.

Está claro que los VLA son diferentes animales de las matrices regulares , y su implementación puede permitir un tamaño 0 . No se pueden declarar static o en el alcance del archivo, ya que el tamaño de dichos objetos se debe conocer antes de que se inicie el programa.

Tampoco vale nada que a partir de C11, las implementaciones no sean necesarias para admitir VLA.

    
respondido por el John Bode 11.07.2014 - 17:08
2

Por lo general, desearía que su matriz de tamaño cero (de hecho variable) sepa su tamaño en el tiempo de ejecución. Luego, guárdela en struct y use miembros de matriz flexible , como por ejemplo:

struct my_st {
   unsigned len;
   double flexarray[]; // of size len
};

Obviamente, el miembro de la matriz flexible debe ser el último en su struct y debes tener algo antes. A menudo, eso sería algo relacionado con la longitud real ocupada por el tiempo de ejecución de ese miembro de matriz flexible.

Por supuesto que asignarías:

 unsigned len = some_length_computation();
 struct my_st*p = malloc(sizeof(struct my_st)+len*sizeof(double));
 if (!p) { perror("malloc my_st"); exit(EXIT_FAILURE); };
 p->len = len;
 for (unsigned ix=0; ix<len; ix++)
    p->flexarray[ix] = log(3.0+(double)ix);

AFAIK, esto ya era posible en C99, y es muy útil.

Por cierto, los miembros de la matriz flexible no existen en C ++ (porque sería difícil definir cuándo y cómo deberían construirse y destruirse). Sin embargo, vea el futuro std :: dynarray

    
respondido por el Basile Starynkevitch 11.07.2014 - 20:30
2

Si la expresión type name[count] está escrita en alguna función, le dice al compilador de C que asigne en el marco de pila sizeof(type)*count bytes y calcule la dirección del primer elemento de la matriz.

Si la expresión type name[count] se escribe fuera de todas las funciones y definiciones de estructuras, entonces le indica al compilador de C que asigne el segmento de datos sizeof(type)*count bytes y calcule la dirección del primer elemento de la matriz.

name en realidad es un objeto constante que almacena la dirección del primer elemento en la matriz y cada objeto que almacena una dirección de alguna memoria se llama puntero, por lo que esta es la razón por la que trata a name como un puntero en lugar de una matriz. Tenga en cuenta que solo se puede acceder a las matrices en C a través de los punteros.

Si count es una expresión constante que se evalúa en cero, entonces le indica al compilador de C que asigne cero bytes en el marco de la pila o en el segmento de datos y devuelva la dirección del primer elemento de la matriz, pero el problema está en hacer esto es que el primer elemento de la matriz de longitud cero no existe y no puede calcular la dirección de algo que no existe.

Esto es racional que el elemento no. count+1 no existe en la matriz count -length, por lo que esta es la razón por la que el compilador de C prohíbe definir una matriz de longitud cero como variable dentro y fuera de una función, porque cuál es el contenido de name entonces ? ¿Qué dirección name almacena exactamente?

Si p es un puntero, la expresión p[n] es equivalente a *(p + n)

Donde el asterisco * en la expresión correcta es una operación de desreferencia de puntero, lo que significa acceder a la memoria apuntada por p + n o acceder a la memoria cuya dirección está almacenada en p + n , donde p + n es una expresión de puntero, se necesita La dirección de p y agrega a esta dirección el número n multiplica el tamaño del tipo del puntero p .

¿Es posible agregar una dirección y un número?

Sí, es posible, porque la dirección es un entero sin signo comúnmente representado en notación hexadecimal.

    
respondido por el user307542 06.06.2018 - 07:08
1

Si desea un puntero a una dirección de memoria, declare uno. Una matriz en realidad apunta a un trozo de memoria que ha reservado. Las matrices decaen a los punteros cuando se pasan a las funciones, pero si la memoria a la que apuntan está en el montón, no hay problema. No hay ninguna razón para declarar una matriz de tamaño cero.

    
respondido por el ncmathsadist 11.07.2014 - 03:26
1

Desde los días del C89 original, cuando un estándar de C especificaba que algo tenía un comportamiento indefinido, lo que significaba era "Hacer lo que haría una implementación en una plataforma de destino particular más adecuada para el propósito previsto". Los autores del Estándar no querían intentar adivinar qué comportamientos podrían ser más adecuados para un propósito en particular. Las implementaciones C89 existentes con extensiones de VLA pueden haber tenido comportamientos diferentes, pero lógicos, cuando se les da un tamaño de cero (por ejemplo, algunas podrían haber tratado la matriz como una expresión de dirección que produce NULL, mientras que otras la tratan como una expresión de dirección que podría ser igual a la dirección de otra variable arbitraria, pero con seguridad se podría agregar cero sin interceptación). Si algún código se hubiera basado en un comportamiento tan diferente, los autores del Estándar no querrían prohibir a los compiladores que continúen admitiendo dicho código.

En lugar de tratar de adivinar qué podrían hacer las implementaciones, o sugerir que cualquier comportamiento debería considerarse superior a cualquier otro, los autores de la Norma simplemente permitieron a los implementadores usar el juicio para manejar ese caso de la mejor manera Ellos vieron en forma. Las implementaciones que usan malloc () detrás de escena pueden tratar la dirección de la matriz como NULL (si malloc de tamaño cero produce un valor nulo), aquellas que usan cálculos de direcciones de pila pueden producir un puntero que coincida con la dirección de alguna otra variable, y otras implementaciones podrían hacerlo. otras cosas. No creo que esperaran que los escritores de compiladores hicieran todo lo posible para que el caso de la esquina de tamaño cero se comporte de forma deliberadamente inútil.

    
respondido por el supercat 07.03.2017 - 19:26

Lea otras preguntas en las etiquetas

Comentarios Recientes

Hipotéticamente podría recorrer cada N longitud de matriz binaria, poner a cero los puntos o escribir matrices directamente en un archivo en texto sin formato antes de llegar a la longitud misma, ni siquiera necesita ser comprimido. (O como lo han escrito diferentes personas, podría simplemente estar usando un mecanismo de extensión que no necesita usar compresión) Gracias Stefan por la sugerencia. También surgió mientras se preguntaba por qué MySQL nunca podría manejar -N porque la toma previa completa la... Lee mas