1

How do I do a memset for a pointer to an array?

int (*p)[2];

p=(int(*))malloc(sizeof(*p)*100);

memset(p,0,sizeof(*p)*100);

Is this allocation an correct?

unwind
  • 391,730
  • 64
  • 469
  • 606
Aragon
  • 1,551
  • 1
  • 15
  • 25
  • 2
    [Do not cast the result of malloc](http://stackoverflow.com/questions/605845), and have you tried it? What makes you think it may be not correct? – Eregrith Oct 03 '12 at 09:37
  • You need to clarify, whether you want C or C++. Because for C++ all these will not required – iammilind Oct 03 '12 at 09:38
  • my confusion was should i write memset(p,0,sizeof(*p)*100); or memset(p,0,sizeof(int[2])*100); – Aragon Oct 03 '12 at 09:39
  • I don't really understand what you're trying to do... I mean, what your goal is (it's not clear from your code). – CAFxX Oct 03 '12 at 09:43
  • Always use `sizeof(*your_variable)` so you will never be mistaken – Eregrith Oct 03 '12 at 09:48
  • @Eregrith That doesn't work. He's allocating an array of 100 elements; the resulting pointer only points to one element. The only real solution is to not use `malloc`, but `new`. (That's only for C++, of course.) – James Kanze Oct 03 '12 at 09:51
  • using `new` is not "the only real solution", especially not in C as you said. If he wants multiple 2-bytes arrays, this is done correctly, and the memset will work. `sizeof(*p)` is not dereferencing p, it only holds the type of `*p` so `int [2]` – Eregrith Oct 03 '12 at 09:53
  • @user1660982: just for future reference, you've created a firestorm here by asking in effect 4 different questions: "is the allocation correct" and "how do I do the memset", crossed with C vs. C++. And because both languages provide ways to allocate already-zeroed memory, there's an extra 2 questions in there which people can choose to answer by proposing `calloc` or `new int[100][2]()`. – Steve Jessop Oct 03 '12 at 10:01

5 Answers5

7

you can use calloc.

calloc will replace both malloc and memset.

p = calloc(100, sizeof (*p));
MOHAMED
  • 41,599
  • 58
  • 163
  • 268
2

The elegant way:

typedef int int_arr_2[2];

int_arr_2* p;

p = malloc(sizeof(int_arr_2)*100);
memset(p,0,sizeof(int_arr_2)*100);

The best way:

typedef int int_arr_2[2];

int_arr_2* p;

p = calloc(100, sizeof(int_arr_2));

calloc, unlike malloc, guarantees that all bytes are set to zero.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 1
    I'm sort of at +1 for calloc, -1 for saying that `sizeof(int_arr_2)` is more elegant than `sizeof(*p)`. But it's a bigger +1 than -1, so I can easily be convinced ;-) – Steve Jessop Oct 03 '12 at 09:49
  • @SteveJessop The code is elegant for the following reasons: It makes it impossible for the programmer to accidentally take sizeof(the pointer itself). Particularly, you are bound to get it wrong in the not too uncommon case of `bool custom_allocate (int** array);` where the allocated data is passed to main through a parameter. To get that right, you'd need to write `malloc(sizeof(**array))`. Besides that, the typedef syntax is also easier and more intuitive to read for the average C programmer who isn't used to array pointers. – Lundin Oct 03 '12 at 12:43
  • I don't think I am bound to get it wrong. I'd write `*array = malloc(number * sizeof(**array))`. Or `some_function()->member = malloc(number * sizeof(*(some_function()->member)))`. It's not a complicated rule. But I meant I can be convinced this is a good answer, not that I can be convinced to prefer your way of writing the size. I cannot be convinced of that, because you're wrong :-) I don't mind the typedef for the pointer-to-array, though, that's another plus point. – Steve Jessop Oct 03 '12 at 12:47
  • @SteveJessop But then, judging from the quality of your C-related posts on this site, I don't believe you fit in the "average C programmer" category :) To write code that can even be understood and maintained by a rookie programmer, is much more challenging than writing code that can be understood and maintained by a C guru with a couple of decades of experience. – Lundin Oct 03 '12 at 12:53
  • Flattery will get you anywhere. I entirely agree about the typedef helping noobs: pointer-to-array syntax is sometimes puzzling. I really don't agree, though, that repeating the type helps noobs. In your version, there's only one type that's correct and the programmer has to figure out what it is, perhaps update it from time to time. In my version, they indicate "the type that the LHS points to", which is *always* the right type (or else you wouldn't be assigning to it), and they do it by adding a `*`. – Steve Jessop Oct 03 '12 at 12:55
  • @SteveJessop Okay, to be mean then: suppose we have something mundane like an array pointer, to an array of function pointers, passed by reference to the "custom_alloc" function. We'd be dealing with a trivial declaration like `void(* (**fptr_arr)[] )(void);`. I'd then still write `*fptr_arr = malloc(n * sizeof(fptr));` and I will understand what that code does a lot better than `sizeof(***fptr_array)`. – Lundin Oct 03 '12 at 13:42
  • The difference is the terms in which you understand it. Your way, you understand that what it does is allocate an array of `fptr` of size `n`. My way, you understand that what it does is allocate an array of whatever the correct thing is for `*fptr_arr` to point to, of size `n`. If there's a chance that `*fptr_arr` is the *wrong* thing to assign to, but we're absolutely sure what type we're supposed to allocate, then it's clearer to do it your way (although unfortunately in C the code will compile despite being wrong). That's just not my experience. – Steve Jessop Oct 03 '12 at 13:47
  • @SteveJessop Another case that is perhaps more valid than my declaration-abonimation above, is when you do generic programming with void pointers. Suppose the result of malloc is passed to a void pointer. You would then be forced to know the type through some other mean than using the * operator. – Lundin Oct 03 '12 at 14:18
  • @Lundin: yes, that would do it. When you assign to `void*` you've got no clues. Strictly speaking similar could apply in C++ when you're `malloc`ing space for a derived class and assigning to a pointer-to-base, but I don't think I'm presuming much to say that you'd never do that. – Steve Jessop Oct 03 '12 at 15:09
2

I'll summarize a lot of answers (although I've ignored some of the stylistic variants in favor of my own preferences).

In C:

How to use malloc:

int (*p)[2] = malloc(100 * sizeof(*p));

How to use memset:

memset(p, 0, 100 * sizeof(*p));

How to do both in one statement:

int (*p)[2] = calloc(100, sizeof(*p));

In C++, the same is possible except that you need to cast the results of malloc and calloc: static_cast<int(*)[2]>(std::malloc(100 * sizeof(*p)).

However, C++ provides alternative ways to allocate this:

int (*p)[2] = new int[100][2](); // like calloc.
delete[] p; // *not* delete p

C++ also provides vector, which is usually nice, but unfortunately you cannot create a vector of C-style arrays. In C++03 you can workaround like this:

struct my_array {
    int data[2];
};

std::vector<my_array> p(100);
// no need to free/delete anything

I don't think that zeros the elements, although I might be wrong. If I'm right, then to zero you need:

my_array initvalue = {0};
std::vector<my_array> p(100, initvalue);

another way to represent 2 ints:

std::vector<std::pair<int,int> > p(100);

If you can use Boost:

std::vector<boost::array<int, 2> > p(100);

In C++11:

std::vector<std::array<int, 2>> p(100);

I've listed these in increasing order of how good they usually are, so use the last one that isn't blocked by whatever constraints you're working under. For example, if you expect to take a pointer to the first element of one of the inner arrays-of-2-int, and increment it to get a pointer to the second, then std::pair is out because it doesn't guarantee that works.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • Whether the struct will contain garbage or zero by default will of course depend on in which scope it was declared (global/static vs automatic). In C++, it would be better to add a constructor to the struct, so that you wouldn't need to rely on the explicit initialization. – Lundin Oct 03 '12 at 13:18
  • @Lundin: I nearly added a constructor, but (a) I didn't want to needlessly make it non-POD, and (b) just because I want this vector zero-ed doesn't necessarily mean I want every instance of the class ever to be zeroed. My basic confusion is that I can't remember whether the temporary `my_array()` is default initialized or zero initialized. It's neither global not automatic! – Steve Jessop Oct 03 '12 at 13:42
  • It will run the default constructor, which does nothing. So the data will be garbage unless you add a constructor. You could always add one like `my_array(int arr[2] = NULL)` and make the zero initialization conditional. – Lundin Oct 03 '12 at 14:13
0

The memset() line is proper.

For C you don't need malloc casting.
In C++ if you still want to do this, the type cast should be as:

p = (int(*)[2]) malloc(sizeof(*p)*100);  // or `static_cast<...>
  // ^^^^^^^^^

But I would suggest to change your approach for using std::vector instead. Cleaner, better and "semi-automatic":

std::vector<int*> vi(100);  // or std::vector vi(100, nullptr);

Another way with raw pointers is to use new[]:

int **p = new[100]();  // allocates and sets to 0

But you have to manage this memory later on by deallocating with delete[]

Community
  • 1
  • 1
iammilind
  • 68,093
  • 33
  • 169
  • 336
  • 1
    In C++, the cast is mandatory and good style. In C, the cast is dangerous and can create severe bugs. They are different languages. This is why you should only program in one programming language at a time :) – Lundin Oct 03 '12 at 09:46
  • 1
    @Lundin: I think iammilind's point was that in C++ the *malloc* isn't mandatory. Hence "you can have this", but his suggestion is that you don't :-) – Steve Jessop Oct 03 '12 at 09:52
  • In C++, you would use `new`, so no cast is needed. And just adding a `()` at the end of the `new` expression will effectively set all of the allocated values to 0. – James Kanze Oct 03 '12 at 09:54
  • @JamesKanze, ideally I use `new/new[]` only if there is a specific programming requirement (i.e. copying is expensive or multi-threading environment). Always advisable to use `std::vector` which internally does that and takes care of deleting the memory. – iammilind Oct 03 '12 at 09:56
  • @iammilind Good point. `std::vector` would be even better here. – James Kanze Oct 03 '12 at 10:00
0

In C (not C++) you would just do

int (*p)[2] = malloc(sizeof(*p)*100);

memset(*p,0,sizeof(*p)*100);

that is, variables can be initialized with expressions and malloc doesn't need (and should not have) a cast. Then *p is an "lvalue" of your array type that decays to a pointer when passed to memset.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177