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

I am filling this struct and then using the values. On the next iteration, I want to reset all the fields to 0 or null before I start reusing it.

How can I do that? Can I use memset or I have to go through all the members and then do it individually?

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
hari
  • 9,439
  • 27
  • 76
  • 110

11 Answers11

128

Define a const static instance of the struct with the initial values and then simply assign this value to your variable whenever you want to reset it.

For example:

static const struct x EmptyStruct;

Here I am relying on static initialization to set my initial values, but you could use a struct initializer if you want different initial values.

Then, each time round the loop you can write:

myStructVariable = EmptyStruct;
Community
  • 1
  • 1
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • 1
    @David Heffernan: is this better than using `memset` if I only want to reset everything to `0`?? – hari Jul 31 '11 at 19:31
  • 11
    @hari I'd prefer this approch myself. Using `memset` makes me feel dirty. I prefer to let the compiler worry about memory layout wherever possible. Strictly speaking such use of `memset` is non-portable but in practice I'd be astounded if you ever compiled your code anywhere that mattered. So, you can likely use memset safely if you prefer it. – David Heffernan Jul 31 '11 at 19:33
  • 2
    @hari, it is conceptually better, as you provide a default initialization values (something like a object factory pattern.) – Diego Sevilla Jul 31 '11 at 19:34
  • David Heffernan and @Diego Sevilla Thanks to both of you. – hari Jul 31 '11 at 19:45
  • @David Heffernan: for my education, why you declared `EmptyStruct` as `static const`? – hari Jul 31 '11 at 19:49
  • const so that it can't be modified. static is optional. If you want to link to it from other translation units then don't use static. – David Heffernan Jul 31 '11 at 19:55
  • Well, if the struct contains some floats, `memset` won't be much help to zero them. – cnicutar Jul 31 '11 at 19:57
  • @cnicutar actually 0 bits equals 0.0 in all floating point representations I know. – David Heffernan Jul 31 '11 at 20:01
  • @David Heffernan See the C FAQ: http://c-faq.com/malloc/calloc.html ... "*But it does not guarantee useful null pointer values (see section 5 of this list) or floating-point zero values*". – cnicutar Jul 31 '11 at 20:11
  • 1
    @cnicutar I know this. Note that my answer recommends not using memset. Note also the comment about where I point out the non-portability of using memset as a means to assign null values. My previous comment just points out the reality that 0 bits invariably does correspond to floating point zeros. – David Heffernan Jul 31 '11 at 20:19
  • @David Heffernan I am sorry I didn't take the time to carefully read the comments. Of course, you are completely correct. – cnicutar Jul 31 '11 at 20:26
  • @David Heffernan: Also, I need to: EmptyStruct.a[0] = '\0'; EmptyStruct.b[0] = '\0'; EmptyStruct.i = 0; EmptyStruct.c = NULL; EmptyStruct.d = {0}; ---- and then use is later on, correcT? – hari Jul 31 '11 at 21:38
  • write it like I did or EmptyStruct = { 0 } and all the fields will be initialised to null values – David Heffernan Jul 31 '11 at 21:49
  • Assignment of structure variables calls 'memcpy' internally. – kp11 Oct 15 '14 at 05:22
  • 1
    @kp11 citation please – David Heffernan Oct 15 '14 at 05:25
  • Works fine on C, but not on C++ – Cyan Mar 10 '15 at 13:54
  • @Devid : had an error while trying C++ version with g++. Complain about lack of constructor, or lack of implicit construction values. (Note : can't use a constructors, as I'm trying to write a code which compiles on both C & C++ compilers without modification) – Cyan Mar 10 '15 at 14:01
  • @Cyan This question is about C. – David Heffernan Mar 10 '15 at 14:04
  • After reading your answer, I wasn't sure if it would work for structs with floating point members when the implementation is not IEEE-compliant, or for structs with pointers when the implementation has non-zero null pointers. But according to this other SO question, static initialization assigns to each type its correct zero no matter if its not all-bits-zero: https://stackoverflow.com/questions/17012707/initialization-global-and-static-variable-to-0-is-always-unnecessary BTW, maybe you could edit your answer adding this clarification, so that it's more complete. – cesss Dec 10 '20 at 11:10
  • 1
    @cesss I'd be very happy for you to edit the answer. Then when the edit got approved you would get credited. – David Heffernan Dec 10 '20 at 11:39
109

The way to do such a thing when you have modern C (C99) is to use a compound literal.

a = (const struct x){ 0 };

This is somewhat similar to David's solution, only that you don't have to worry to declare an the empty structure or whether to declare it static. If you use the const as I did, the compiler is free to allocate the compound literal statically in read-only storage if appropriate.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
  • Does that create an instance of x on the stack to then copy it to a? For big structures/small stacks that could be a problem. – Étienne Jun 17 '14 at 11:37
  • 1
    Like all optimizations, this is completely compiler dependent, so you'd have to check what your compiler produces. "Usually" on modern compilers it doesn't, these can trace initializations very well and only do what is necessary, not more. (And don't think that such things are problems before you measure a real slow down. They usually aren't.) – Jens Gustedt Jun 17 '14 at 11:59
  • With problem I meant stack overflow, thank you for your answer! – Étienne Jun 17 '14 at 14:09
  • What is so special about new notation that it is supported only by C99? – Trismegistos Jul 17 '14 at 12:45
  • @Trismegistos, I am not sure that I understand your question. Compound literals were introduced by C99, so compilers that only support ancient versions of the the standard, don't support that feature. – Jens Gustedt Jul 17 '14 at 17:10
  • @JensGustedt Compound Literals is what I meant. I will google what it is exactly. – Trismegistos Jul 17 '14 at 17:30
  • The problem with this approach is, that it may give a 'missing initializer' warning for something like `struct x { int prop[3]; }; struct x a = (const struct x){ 0 };` while the `startic const struct x EMPTY_STUCT` method does not. – con-f-use Apr 05 '15 at 15:02
  • 3
    "missing initializer" warnings are really bogus. The C standard prescribes exactly what has to happen than, and forsees the `{ 0 }` as the default initializer. Switch that warning off, it is spurious false alarm. – Jens Gustedt Apr 05 '15 at 16:00
  • 2
    Is the "const" really necessary? Surely the compiler could optimize it properly from the fact that it is a literal that is only used for this assignment. – Sam Watkins Nov 12 '15 at 10:09
  • If you're using GCC, you can even do `*ptr = (typeof(*ptr)){};` – Jonathon Reinhart Jun 14 '16 at 19:20
  • 1
    @JensGustedt Does this typecasting really needed? Can't I write it like this? struct x a = (const){0}; – Patrick Feb 18 '17 at 14:11
  • 1
    @Patrick, although the syntax is similar this is not a cast but a "compound literal". And you are mixing up initialization and assignment. – Jens Gustedt Feb 18 '17 at 20:31
  • Can we do this for an array or matrix of struct? – Daniel Jan 15 '20 at 11:08
67

Better than all above is ever to use Standard C specification for struct initialization:

struct StructType structVar = {0};

Here are all bits zero (ever).

user411313
  • 3,930
  • 19
  • 16
  • 18
    I don't think you can do that each time around a loop though – David Heffernan Jul 31 '11 at 19:35
  • 3
    This is indeed suppose to work. But unfortunately, gcc & g++ complain about it. gcc generates warnings, while g++ generate an error. I know that gcc & g++ are at fault on this (they are supposed to follow Standard C specification), but nonetheless, for good portability, it is mandatory to take such limitation in consideration. – Cyan Mar 10 '15 at 13:00
  • 3
    @Cyan You can use `{}` in C++. The gcc devs seem [unsure whether C++ is supposed to support `{0}`](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119#c22) and I'm not familiar with that part of the standard myself. – Matthew Read Mar 24 '15 at 16:37
  • @Matthew : Yes, actually, I ended up using memset(), because there were too many portability issues with `{0}` or `{}`. Not sure if the C & C++ standards are clear and in sync on this issue, but apparently, compilers are not. – Cyan Mar 25 '15 at 07:27
  • will this work in such a case? ``struct StructType structVar = malloc (sizeof(StructType)); structVar ={0}`` – Sam Thomas Jun 13 '18 at 19:03
  • I am curious, why is this not appropriate? ```x = malloc(sizeof(x)); memset(&x, 0, sizeof(x));``` – Potion Sep 07 '19 at 18:18
  • Combined with the accepted answer this method works well. – Xofo Nov 07 '19 at 00:43
40

In C, it is a common idiom to zero out the memory for a struct using memset:

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

Technically speaking, I don't believe that this is portable because it assumes that the NULL pointer on a machine is represented by the integer value 0, but it's used widely because on most machines this is the case.

If you move from C to C++, be careful not to use this technique on every object. C++ only makes this legal on objects with no member functions and no inheritance.

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • 2
    The C standard states that NULL is always 0. If the machine is designed such that a predetermined invalid address is not literally 0, the compiler for that architecture must adjust during compilation. – Kevin M Aug 01 '11 at 05:42
  • 10
    @KevinM Yes, the symbol "0" always correspond to the the NULL pointer even if it is all-zero; but there is nothing the compiler can do if you set the bits to zero using memset. – Adrian Ratnapala Nov 30 '12 at 07:37
  • "C++ only makes this legal on objects with no member functions and no inheritance." It's about whether the type is considered 'plain old data'. The criteria depend on the version of the C++ language. – Max Barraclough Apr 27 '20 at 10:35
  • @MaxBarraclough If I use this in C++ only for resetting structures, will it work? – sukhbir1996 Aug 22 '23 at 09:18
23

If you have a C99 compliant compiler, you can use

mystruct = (struct x){0};

otherwise you should do what David Heffernan wrote, i.e. declare:

struct x empty = {0};

And in the loop:

mystruct = empty;
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
Rudy Velthuis
  • 28,387
  • 5
  • 46
  • 94
8

You can use memset with the size of the struct:

struct x x_instance;
memset (&x_instance, 0, sizeof(x_instance));
Diego Sevilla
  • 28,636
  • 4
  • 59
  • 87
  • 1
    I don't think the cast is necessary here. Is it? – templatetypedef Jul 31 '11 at 19:24
  • Well, I'm so used to C++ that... well, it will work also in C++, so I don't see it as a burden. – Diego Sevilla Jul 31 '11 at 19:25
  • Yeah, I wasn't specific enough. It's any pointer to cv qualified T can be converted to cv qualified void*. Any data pointer, function pointers are a different matter altogether. Kudos @Kevin – Marcus Borkenhagen Aug 01 '11 at 06:14
  • `memset` is an option, but when using it, you have to make sure that the memory written to is exactly the same size as the third parameter, that's why it's better to refer to the size of the actual object, not the size of the type **you know** it **currently** is. IOW `memset (&x_instance, 0, sizeof(x_instance));` is a much better choice. BTW: the `(void*)` cast is superfluous in C++ too. – Wolf Jun 22 '16 at 13:42
  • (sorry I missed to look after the question, it's better now) – Wolf Jun 30 '16 at 10:48
  • I'm surprised no-one has pointed out that this isn't correct. C does not guarantee that NULL has a bit-representation of zero, and you shouldn't use memset/calloc/etc to assign null to pointers. https://softwareengineering.stackexchange.com/a/128447/ – Max Barraclough Dec 06 '18 at 20:26
  • Several compilers will generate a warning if you do not cast this. IMHO this warning is usefull to draw attention to this function call and make sure that your operands are correct. I even need to cast the return value in some compilers that warn that the return value is not used. To indicate that this is intentional, I have to write (void) memset(...). That is good to draw attention to function calls that return a success/fail value that was not taken into account. – le_top Feb 27 '19 at 09:18
2

I believe you can just assign the empty set ({}) to your variable.

struct x instance;

for(i = 0; i < n; i++) {
    instance = {};
    /* Do Calculations */
}
Archmede
  • 1,592
  • 2
  • 20
  • 37
  • 2
    This is not valid C, not even C99. It needs to be a compound literal like in JensGustedt's answer above. – Anders Oct 31 '20 at 00:11
2

I asked a compiler engineer at work about which option is better (memset vs {0}). Instead of giving my an opinion he pointed me to Compiler Explorer. It's interesting to see how all three options compile out:

https://godbolt.org/z/bPfKeG9Yh

Here's a preview of the code:

// Type your code here, or load an example.
#include "string.h"

struct MyStruct {
    int age;
    int sin;
    char *name;
    int cats;
    char something[64];
};

const struct MyStruct empty_struct = {0};

int test() {
    struct MyStruct blah = {0};
    memset(&blah, 0, sizeof(blah));
    blah = empty_struct;

    blah.age = 99;
    blah.sin = 123456789;
}

The compiler makes different decisions on how to zero memory depending on the member types of the struct. Try commenting out something for example or choosing a non-x86 target.

RandomInsano
  • 1,204
  • 2
  • 16
  • 36
0
 struct x myX;
 ...
 memset(&x, 0, sizeof(myX));
Josh Matthews
  • 12,816
  • 7
  • 36
  • 39
0

Memset with NULL is dangerous function.

For C++ better by this way for most simple data structures >>

template<class T>
void Null_MyType(T &obj)
{
    constexpr T o_null = T{};
    obj = o_null;
}
Redee
  • 547
  • 5
  • 8
-2

debugger screenshot

Take a surprise from gnu11!

typedef struct {
    uint8_t messType;
    uint8_t ax;  //axis
    uint32_t position;
    uint32_t velocity;
}TgotoData;

TgotoData tmpData = { 0 };

nothing is zero.

JRL
  • 3,363
  • 24
  • 36
  • 4
    This does not attempt to answer the question of "How can I reset all fields to 0" – M.M Jul 21 '20 at 22:40