Asigne múltiples valores a la matriz en C

5 minutos de lectura

avatar de usuario
Fractal inestable

¿Hay alguna manera de hacer esto en forma condensada?

GLfloat coordinates[8];
...
coordinates[0] = 1.0f;
coordinates[1] = 0.0f;
coordinates[2] = 1.0f;
coordinates[3] = 1.0f;
coordinates[4] = 0.0f;
coordinates[5] = 1.0f;
coordinates[6] = 0.0f;
coordinates[7] = 0.0f;
return coordinates;

Algo como coordinates = {1.0f, ...};?

  • ¿Está devolviendo un puntero a una variable local, allí? Algunas de las cosas que la gente ha dicho en las respuestas/comentarios a continuación suponen que las variables involucradas son automáticas o que no lo son. Podría ayudar si lo especifica.

    –Steve Jessop

    20 de agosto de 2010 a las 23:45


  • Una vez que se inicializa la estructura, no hay una manera fácil de asignar miembros en masa (aparte de hacer una copia de otra estructura con memcpy). A menudo me encuentro deseando tener esta característica.

    – bta

    21 de agosto de 2010 a las 0:20

  • Creo que su respuesta original es la mejor: es intuitiva, aunque un poco detallada, pero eso no es una preocupación para los compiladores modernos.

    – Yan Rey Yin

    29 de octubre de 2015 a las 4:28

avatar de usuario
james curran

si realmente quieres asignar valores (a diferencia de inicializar), puedes hacerlo así:

 GLfloat coordinates[8]; 
 static const GLfloat coordinates_defaults[8] = {1.0f, 0.0f, 1.0f ....};
 ... 
 memcpy(coordinates, coordinates_defaults, sizeof(coordinates_defaults));

 return coordinates; 

  • Mejor aún, hágalo “const. estática” y los compiladores pueden optimizar la variable directamente desde el código.

    – Zan Lince

    20 de agosto de 2010 a las 23:03

  • @Zan Lynx: ¿La mayoría de los compiladores no serán lo suficientemente inteligentes como para hacer eso de todos modos? Oh bien. Buena práctica para ser explícito, supongo.

    – Chris Cooper

    20 de agosto de 2010 a las 23:42

  • @Chris Cooper: no si es global (que podría modificarse en el código que el compilador no puede ver). Realmente no se puede saber a partir de estos fragmentos de código si “…” elude el inicio de una función.

    –Steve Jessop

    20 de agosto de 2010 a las 23:49


  • @Steve: Buena decisión. Gracias por aclararlo.

    – Chris Cooper

    21 de agosto de 2010 a las 0:06

avatar de usuario
cúpula

Aunque en su caso, bastará con una simple inicialización, hay un truco para envolver la matriz en una estructura (que se puede inicializar después de la declaración).

Por ejemplo:

struct foo {
  GLfloat arr[10];
};
...
struct foo foo;
foo = (struct foo) { .arr = {1.0, ... } };

La manera de la vieja escuela:

GLfloat coordinates[8];
...

GLfloat *p = coordinates;
*p++ = 1.0f; *p++ = 0.0f; *p++ = 1.0f; *p++ = 1.0f;
*p++ = 0.0f; *p++ = 1.0f; *p++ = 0.0f; *p++ = 0.0f;

return coordinates;

  • Elegante, le doy eso, pero administrar un conjunto razonable de datos de inicialización (con la eventual necesidad de ajustarlos) será engorroso. Preferiría alguna sintaxis donde solo los datos (y pueden ser algunos delimitadores para fines de visibilidad) serían suficientes. Además es aritmética de punteros. MISRA se volvería loca por eso.

    – Opal Apps

    4 de abril de 2019 a las 13:53

Puedes usar:

GLfloat coordinates[8] = {1.0f, ..., 0.0f};

pero esta es una inicialización en tiempo de compilación: no puede usar ese método en el estándar actual para reiniciar (aunque creo que hay formas de hacerlo en el próximo estándar, que puede que no lo ayude de inmediato).

Las otras dos formas que me vienen a la mente son eliminar los contenidos si están arreglados:

GLfloat base_coordinates[8] = {1.0f, ..., 0.0f};
GLfloat coordinates[8];
:
memcpy (coordinates, base_coordinates, sizeof (coordinates));

o proporcione una función que se parezca a su código de inicialización de todos modos:

void setCoords (float *p0, float p1, ..., float p8) {
    p0[0] = p1; p0[1] = p2; p0[2] = p3; p0[3] = p4;
    p0[4] = p5; p0[5] = p6; p0[6] = p7; p0[7] = p8;
}
:
setCoords (coordinates, 1.0f, ..., 0.0f);

teniendo en cuenta esos puntos suspensivos (...) son marcadores de posición, no cosas para insertar literalmente en el código.

Exacto, casi lo tienes:

GLfloat coordinates[8] = {1.0f, ..., 0.0f};

  • @smsteel Esa sintaxis solo se aplica a las declaraciones

    – Michael Mrozek

    20 de agosto de 2010 a las 22:58

  • Esto es malo… ¿Hay otra forma de simplificarlo? 🙂

    – Fractal inestable

    20 de agosto de 2010 a las 22:58

Fui con un método de inicialización de matriz:

#include <stdarg.h>

void int_array_init(int *a, const int ct, ...) {
  va_list args;
  va_start(args, ct);
  for(int i = 0; i < ct; ++i) {
    a[i] = va_arg(args, int);
  }
  va_end(args);
}

llamado como,

const int node_ct = 8;
int expected[node_ct];
int_array_init(expected, node_ct, 1, 3, 4, 2, 5, 6, 7, 8);

La inicialización de la matriz C99, así:

const int node_ct = 8;
const int expected[node_ct] = { 1, 3, 4, 2, 5, 6, 7, 8 };

Y en el configure.ac:

AC_PROG_CC_C99

tenía el compilador en mi caja de desarrollo perfectamente feliz. El compilador en el servidor se quejó con:

error: variable-sized object may not be initialized
   const int expected[node_ct] = { 1, 3, 4, 2, 5, 6, 7, 8 };

y

warning: excess elements in array initializer
   const int expected[node_ct] = { 1, 3, 4, 2, 5, 6, 7, 8 };

para cada elemento

No se queja en absoluto de, por ejemplo:

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

Me gusta la verificación del tamaño y que la compatibilidad con varargs actúa de manera más sólida que la compatibilidad con el inicializador de matriz.

Encuentre PR con código de muestra en https://github.com/wbreeze/davenport/pull/15/files

Respecto a https://stackoverflow.com/a/3535455/608359 de @paxdiablo, me gustó; pero se sentía inseguro acerca de tener sincronizado el número de veces que avanza el puntero de inicialización con el número de elementos asignados a la matriz. En el peor de los casos, el puntero de inicialización se mueve más allá de la longitud asignada. Como tal, la diferencia en el PR contiene,

  int expected[node_ct];
- int *p = expected;
- *p++ = 1; *p++ = 2; *p++ = 3; *p++ = 4;
+ int_array_init(expected, node_ct, 1, 2, 3, 4);

los int_array_init El método asignará basura de forma segura si el número de argumentos es menor que el node_ct. La asignación basura debería ser más fácil de detectar y depurar.

  • @smsteel Esa sintaxis solo se aplica a las declaraciones

    – Michael Mrozek

    20 de agosto de 2010 a las 22:58

  • Esto es malo… ¿Hay otra forma de simplificarlo? 🙂

    – Fractal inestable

    20 de agosto de 2010 a las 22:58

avatar de usuario
ppp

Si está haciendo muchas veces estas mismas tareas en su programa y desea un atajo, la solución más sencilla podría ser simplemente agregar una función

static inline void set_coordinates(
        GLfloat coordinates[static 8],
        GLfloat c0, GLfloat c1, GLfloat c2, GLfloat c3,
        GLfloat c4, GLfloat c5, GLfloat c6, GLfloat c7)
{
    coordinates[0] = c0;
    coordinates[1] = c1;
    coordinates[2] = c2;
    coordinates[3] = c3;
    coordinates[4] = c4;
    coordinates[5] = c5;
    coordinates[6] = c6;
    coordinates[7] = c7;
}

y luego simplemente llamar

GLfloat coordinates[8];
// ...
set_coordinates(coordinates, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f);

¿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