Memset for Initialization in C++

memset() or value initialization to zero out a struct?

Those two constructs a very different in their meaning. The first one uses a memset function, which is intended to set a buffer of memory to certain value. The second to initialize an object. Let me explain it with a bit of code:

Lets assume you have a structure that has members only of POD types ("Plain Old Data" - see What are POD types in C++?)

struct POD_OnlyStruct
{
int a;
char b;
};

POD_OnlyStruct t = {}; // OK

POD_OnlyStruct t;
memset(&t, 0, sizeof t); // OK as well

In this case writing a POD_OnlyStruct t = {} or POD_OnlyStruct t; memset(&t, 0, sizeof t) doesn't make much difference, as the only difference we have here is the alignment bytes being set to zero-value in case of memset used. Since you don't have access to those bytes normally, there's no difference for you.

On the other hand, since you've tagged your question as C++, let's try another example, with member types different from POD:

struct TestStruct
{
int a;
std::string b;
};

TestStruct t = {}; // OK

{
TestStruct t1;
memset(&t1, 0, sizeof t1); // ruins member 'b' of our struct
} // Application crashes here

In this case using an expression like TestStruct t = {} is good, and using a memset on it will lead to crash. Here's what happens if you use memset - an object of type TestStruct is created, thus creating an object of type std::string, since it's a member of our structure. Next, memset sets the memory where the object b was located to certain value, say zero. Now, once our TestStruct object goes out of scope, it is going to be destroyed and when the turn comes to it's member std::string b you'll see a crash, as all of that object's internal structures were ruined by the memset.

So, the reality is, those things are very different, and although you sometimes need to memset a whole structure to zeroes in certain cases, it's always important to make sure you understand what you're doing, and not make a mistake as in our second example.

My vote - use memset on objects only if it is required, and use the default initialization x = {} in all other cases.

memset for initialization in C++

Don't use memset. It's a holdover from C and won't work on non-PODs. Specifically, using it on a derived class that contains any virtual functions -- or any class containing a non-builtin -- will result in disaster.

C++ provides a specific syntax for initialization:

class A {
public:
A();
private:
int a;
float f;
char str[35];
long *lp;
};

A::A()
: a(0), f(0), str(), lp(NULL)
{
}

To be honest, I'm not sure, but memset might also be a bad idea on floating-points since their format is unspecified.

Memset function in C initialised all the arrays

sizeof(pointer) is the size of the entire array pointer. Multiplying integers larger than 1 to that for size to memset() will cause out-of-range access.

Remove the harmful multiplication.

int c = 15;
Struct *Pointer[c] /* = {NULL} */; /* VLA cannot be initialized */

/* some other code that uses Pointer */

memset(Pointer, 0, sizeof(Pointer));

How to initialize arrays in 2 ways using loop and memset?

A few points to help you get started:

  • You're trying to set all items to 0. Scanf requires you to input all values. This isn't necessary as you could just set them to 0 with data[count]=0.0f; inside of that for loop.
  • memset is a function that will do something similar for you (including the for loop). Have a look at the documentation of memset:

memset

void * memset ( void * ptr, int value, size_t num );

Fill block of memory Sets the first num bytes of the block of memory
pointed by ptr to the specified value (interpreted as an unsigned
char).

Parameters

  • ptr:
    Pointer to the block of memory to fill.
  • value:
    Value to be set. The value is passed as an int, but the function fills the block of memory using the unsigned char conversion of this value.
  • num:
    Number of bytes to be set to the value.
    size_t is an unsigned integral type.

You should notice that memset only works with bytes. So you can use it to set a float to 0, as it consists of 4 bytes that are all 0, but you cannot set it to 1 for instance. But as notices by other users, this just happens to be so on most hardware.

history of memcpy and memset vs assignment and initialization

It sounds like your experience is significantly different from mine, and from several of the other commentators here.

I don't know anyone who prefers

memcpy(&a, &b, sizeof(a));

over

a = b;

In my programming world (and in just about any world I can imagine), simple assignment is vastly preferable to memcpy. memcpy is for moving chunks of arbitrary data around (analogous to strcpy, but when it's arbitrary bytes instead of null-terminated strings). It's hard to imagine why anyone would advocate using memcpy instead of struct assignment. Naturally there are individual programmers everywhere who have gotten into various bad habits, so I guess I can't be too surprised if there are some who prefer the opposite, but I have to say, I would generally disagree with what they're doing.

Someone speculated in the comments that there was perhaps some historical precedent at work, but at least for the memcpy-versus-assignment questions, I can state with some certainty that this is not the case.

Once upon a time, before there was C90 memcpy, there was BSD bcopy, but before there was bcopy there wasn't a standard function for doing an efficient copy of a bunch of bytes from point a to point b. But there was struct assignment, which really has been in the language almost from the beginning. And struct assignment typically uses a nice, tight, compiler-generated byte-copying loop. So there was a time when it was fashionable to do something like this:

#define bcpy(a, b, n) (*(struct {char x[n];} *)a = *(struct {char x[n];} *)b)

I may have gotten the syntax wrong, but this hijacks the compiler's ability to do efficient struct assignment, and repurposes it to copy n bytes from arbitrary pointer b to arbitrary pointer a, i.e. just like bcopy or memcpy.

In other words, it's not like memcpy came first, followed by struct assignment -- it was actually exactly the opposite!

Now, memset versus struct initialization is a different story.

Most of the "clean" ways of zeroing a struct are initializations, but of course it's not uncommon to want to set a struct to all zero at some point later than when it was defined. It's also not uncommon to have a dynamically-allocated struct, and using malloc/realloc rather than calloc. So in those cases, memset is attractive. I think modern C has struct constants you can use at any time, but I'm guessing I'm not the only one who still hasn't learned them and so is still tending to use memset instead.

So I wouldn't consider using memset to be poor style, not in the same way as memcpy is poor style for struct assignment.

Although I have seen, and written, code that did something like

struct s zerostruct = { 0 };

and then later

a = zerostruct;

as a "better style" alternative to

memset(&a, 0, sizeof(a));   

Bottom line: I wouldn't agree that memcpy is recommended over struct assignment, and I am critical of anyone who prefers it. But memset is quite useful (and not disrecommended) for zeroing structures, because the alternatives aren't nearly as compelling.



Related Topics



Leave a reply



Submit