Array de longitud variable en struct

4 minutos de lectura

avatar de usuario
moray95

He creado 2 estructuras para representar imágenes (un píxel y una imagen) en C.

typedef struct pixel {
    unsigned char red;
    unsigned char green;
    unsigned char blue;
};

typedef struct image {
    int width;
    int heigth;
    struct pixel pixels[width][heigth];
    };

Recibo un error que dice que el ancho y el alto no están definidos en la definición de la imagen. No entiendo por qué recibo ese error y cómo puedo solucionarlo.

  • C99 no permite que VLA aparezca en la estructura. la razón es simple: si el campo de la estructura es VLA, ¿cómo podría decidir qué tan grande es esta estructura?

    – Jason Hu

    3 oct 2014 a las 17:29

  • Sí, C necesita saber el tamaño de la matriz en tiempo de compilación. Las imágenes en C generalmente se representan mediante un puntero a los datos que se ubican una vez que se conocen la altura y el ancho.

    – jee7s

    03/10/2014 a las 17:32

En C99 y posteriores, puede tener un (unidimensional) miembro de matriz flexible (FAM) al final de una estructura:

§6.7.2.1 Especificadores de estructura y unión

¶18 Como caso especial, el último elemento de una estructura con más de un miembro nombrado puede tener un tipo de matriz incompleta; esto se llama un miembro de matriz flexible. En la mayoría de las situaciones, se ignora el miembro de matriz flexible. En particular, el tamaño de la estructura es como si se hubiera omitido el miembro de matriz flexible, excepto que puede tener más relleno final de lo que implicaría la omisión. Sin embargo, cuando un . (o ->) tiene un operando izquierdo que es (un puntero a) una estructura con un miembro de matriz flexible y el operando derecho nombra ese miembro, se comporta como si ese miembro fuera reemplazado con la matriz más larga (con el mismo tipo de elemento) que no hacer que la estructura sea más grande que el objeto al que se accede; el desplazamiento de la matriz seguirá siendo el del miembro de matriz flexible, incluso si esto fuera diferente al de la matriz de reemplazo. Si esta matriz no tuviera elementos, se comporta como si tuviera un elemento, pero el comportamiento no está definido si se intenta acceder a ese elemento o generar un puntero uno más allá.

Eso significa que podrías escribir:

typedef struct image
{
    int width;
    int height;
    struct pixel pixels[];
} image;

pero tendría que hacer el mapeo de índice 2D a 1D usted mismo. También debe tener cuidado con la forma en que asigna la estructura (necesariamente, será asignada por malloc() ya que de lo contrario el tamaño de la matriz será cero).

Tenga en cuenta la corrección ortográfica de height; tenga en cuenta también la adición de un nombre para el typedef (Elegí image para que coincida con la etiqueta de estructura, pero puede elegir cualquier otro nombre que desee). A typedef sin nombre es ‘válido’ pero no útil; puede omitir typedef y obtener el mismo resultado.

Podrías usar:

image *ip = malloc(sizeof(image) + width * height * sizeof(struct pixel));

if (ip != 0)
{
    ip->width = width;
    ip->height = height;
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
            ip->pixels[i*width + j] = default_pixel_value;
    }
    …use ip…
    free(ip);
}

No estoy seguro de que haya una buena manera de obtener una matriz 2D como FAM.

avatar de usuario
nombre falso123

Estás usando lo que se llama un matriz de longitud variable, sin embargo, hay un problema. En C, cada estructura debe tener una longitud de bytes específica, de modo que, por ejemplo, sizeof(struct image) puede ser evaluado. En su caso, el tamaño de la matriz de longitud variable no se puede determinar en el momento de la compilación, por lo que es ilegal.

En otra nota, probablemente desee punteros allí, en lugar de matrices de longitud declarada:

typedef struct image
{
    int width;
    int heigth;
    struct pixel **pixels;
};

Descargos de responsabilidad: los VLA en estructuras se permiten ocasionalmente, aunque es una cuestión de opinión si esta extensión es más un error que una característica. Ver: Extensión GCC no documentada: instrucción VLA

Editar: remyabel señala los documentos de GCC que hablan sobre las raras situaciones en las que los VLA en las estructuras están bien: https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html#Variable-Length

  • Considere enlazar a la documentos gcc. Creo que ahora han agregado documentación para las estructuras de VLA.

    usuario3920237

    03/10/2014 a las 17:37

avatar de usuario
jason hu

Yo sugeriría una alternativa como esta:

typedef struct 
{
int width;
int heigth;
struct pixel *pixels;
} image;

cada vez, necesita asignar:

image img;
/* init */
img.pixels=malloc(sizeof(struct pixel)*img.width*img.height);

*(img.pixels+img.height*i+j) representa img.pixels[i][j].

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad