Inicializar / restablecer la estructura a cero / nulo


92
struct x {
    char a[10];
    char b[20];
    int i;
    char *c;
    char *d[10];
};

Estoy llenando esta estructura y luego usando los valores. En la próxima iteración, quiero restablecer todos los campos 0o nullantes de comenzar a reutilizarlos.

¿Cómo puedo hacer eso? ¿Puedo usar memseto tengo que pasar por todos los miembros y luego hacerlo individualmente?

Respuestas:


109

Defina una instancia estática constante de la estructura con los valores iniciales y luego simplemente asigne este valor a su variable siempre que desee restablecerla.

Por ejemplo:

static const struct x EmptyStruct;

Aquí confío en la inicialización estática para establecer mis valores iniciales, pero podría usar un inicializador de estructura si desea valores iniciales diferentes.

Luego, cada vez que recorra el ciclo, puede escribir:

myStructVariable = EmptyStruct;

1
@David Heffernan: ¿es esto mejor que usar memsetsi solo quiero restablecer todo a 0?
hari

9
@hari Preferiría este enfoque yo mismo. Usar memsetme hace sentir sucio. Prefiero dejar que el compilador se preocupe por el diseño de la memoria siempre que sea posible. Estrictamente hablando, dicho uso memsetno es portátil, pero en la práctica me sorprendería si alguna vez compilaras tu código en cualquier lugar que importara. Por lo tanto, es probable que pueda usar Memset de forma segura si lo prefiere.
David Heffernan

2
@hari, es conceptualmente mejor, ya que proporciona valores de inicialización predeterminados (algo así como un patrón de fábrica de objetos)
Diego Sevilla

1
@cnicutar Lo sé. Tenga en cuenta que mi respuesta recomienda no usar memset. Tenga en cuenta también el comentario sobre dónde señalo la no portabilidad de usar memset como un medio para asignar valores nulos. Mi comentario anterior solo señala la realidad de que 0 bits corresponden invariablemente a ceros de coma flotante.
David Heffernan

1
@ kp11 citation please
David Heffernan

85

La forma de hacer tal cosa cuando tiene C (C99) moderno es usar un literal compuesto .

a = (const struct x){ 0 };

Esto es algo similar a la solución de David, solo que no tiene que preocuparse por declarar una estructura vacía o si declararla static. Si usa el constcomo yo lo hice, el compilador es libre de asignar el literal compuesto de forma estática en el almacenamiento de solo lectura si corresponde.


¿Eso crea una instancia de x en la pila para luego copiarla en a? Para estructuras grandes / pilas pequeñas, eso podría ser un problema.
Étienne

1
Como todas las optimizaciones, esto depende completamente del compilador, por lo que tendría que verificar lo que produce su compilador. "Normalmente" en los compiladores modernos no lo hace, estos pueden rastrear las inicializaciones muy bien y solo hacen lo que es necesario, no más. (Y no piense que tales cosas son problemas antes de medir una desaceleración real. Por lo general, no lo son.)
Jens Gustedt

3
Las advertencias de "falta de inicializador" son realmente falsas. El estándar C prescribe exactamente lo que tiene que suceder que y prevé { 0 }como inicializador predeterminado. Apague esa advertencia, es falsa falsa alarma.
Jens Gustedt

1
@JensGustedt ¿Realmente se necesita este encasillamiento? ¿No puedo escribirlo así? estructura xa = (constante) {0};
Patrick

1
@Patrick, aunque la sintaxis es similar, esto no es un molde sino un "literal compuesto". Y está mezclando inicialización y asignación.
Jens Gustedt

58

Mejor que todo lo anterior es usar la especificación C estándar para la inicialización de la estructura:

struct StructType structVar = {0};

Aquí están todos los bits cero (siempre).


13
Sin embargo
David Heffernan

2
De hecho, se supone que esto funciona. Pero desafortunadamente, gcc & g ++ se quejan de ello. gcc genera advertencias, mientras que g ++ genera un error. Sé que gcc & g ++ tienen la culpa en esto (se supone que deben seguir la especificación estándar C), pero no obstante, para una buena portabilidad, es obligatorio tener en cuenta dicha limitación.
Cyan

3
@Cyan Puede usar {}en C ++. Los desarrolladores de gcc parecen no{0} estar seguros de si se supone que C ++ es compatible y no estoy familiarizado con esa parte del estándar.
Mateo Leer

@Matthew: Sí, de hecho, terminé usando memset () porque había demasiados problemas de portabilidad con {0}o {}. No estoy seguro si los estándares de C & C ++ son claros y sincronizados en este tema, pero aparentemente, los compiladores no lo son.
Cyan

¿Funcionará esto en tal caso? struct StructType structVar = malloc (sizeof(StructType)); structVar ={0}
Sam Thomas

34

En C, es un modismo común poner a cero la memoria para un structuso memset:

struct x myStruct;
memset(&myStruct, 0, sizeof(myStruct));

Técnicamente hablando, no creo que esto sea portátil porque asume que el NULL puntero en una máquina está representado por el valor entero 0, pero se usa ampliamente porque en la mayoría de las máquinas este es el caso.

Si pasa de C a C ++, tenga cuidado de no utilizar esta técnica en todos los objetos. C ++ solo hace que esto sea legal en objetos sin funciones miembro y sin herencia.


2
El estándar C establece que NULL es siempre 0. Si la máquina está diseñada de manera que una dirección no válida predeterminada no sea literalmente 0, el compilador de esa arquitectura debe ajustarse durante la compilación.
Kevin M

8
@KevinM Sí, el símbolo "0" siempre corresponde al puntero NULL incluso si es todo cero; pero el compilador no puede hacer nada si pone los bits a cero usando memset.
Adrian Ratnapala

"C ++ solo hace que esto sea legal en objetos sin funciones miembro y sin herencia". Se trata de si el tipo se considera "datos antiguos sin formato". Los criterios dependen de la versión del lenguaje C ++.
Max Barraclough

19

Si tiene un compilador compatible con C99, puede usar

mystruct = (struct x){0};

de lo contrario, debería hacer lo que escribió David Heffernan, es decir, declarar:

struct x empty = {0};

Y en el bucle:

mystruct = empty;

6

Puede usar memsetcon el tamaño de la estructura:

struct x x_instance;
memset (&x_instance, 0, sizeof(x_instance));

1
No creo que el elenco sea necesario aquí. ¿Lo es?
templatetypedef

Bueno, estoy tan acostumbrado a C ++ que ... bueno, también funcionará en C ++, así que no lo veo como una carga.
Diego Sevilla

Sí, no fui lo suficientemente específico. Es cualquier puntero a cv calificado T se puede convertir a cv calificado void *. Cualquier puntero de datos, punteros de función son un asunto completamente diferente. Felicitaciones @Kevin
Marcus Borkenhagen

memsetes una opción, pero al usarla, debe asegurarse de que la memoria en la que se escribe sea exactamente del mismo tamaño que el tercer parámetro, por eso es mejor referirse al tamaño del objeto real, no al tamaño del tipo que sé que lo es actualmente . IOW memset (&x_instance, 0, sizeof(x_instance));es una opción mucho mejor. Por cierto: el (void*)elenco es superfluo en C ++ también.
Wolf

(lo siento, me perdí de atender la pregunta, es mejor ahora)
Wolf

5

Creo que puede simplemente asignar el conjunto vacío ( {}) a su variable.

struct x instance;

for(i = 0; i < n; i++) {
    instance = {};
    /* Do Calculations */
}


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.