2

I am allocating memory for a pointer array. The result has a fixed number of items and I want all of them initialised to NULL.

char **result = (char **)calloc(12, sizeof(char *));

Can I now be sure that elements result[0] to result[11] are NULL?

starsplusplus
  • 1,232
  • 3
  • 19
  • 32
Bart Friederichs
  • 33,050
  • 15
  • 95
  • 195
  • You may find this interesting http://stackoverflow.com/questions/13251499/calloc-pointers-and-all-bits-zero – hmjd Feb 21 '14 at 13:56
  • And [this excerpt from the C FAQ](http://c-faq.com/null/machexamp.html) as well. – glglgl Feb 21 '14 at 14:08
  • And, the rule [not to cast the result of `malloc()`](http://stackoverflow.com/q/605845/296974) holds for `calloc()` as well. – glglgl Feb 21 '14 at 14:17

4 Answers4

4

As 0-ing out a pointer p's value by doing

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

not necessary needs to be equal to doing

p = NULL;

on each and every platform, you'd be on the safe side doing:

SomeType ** result = malloc(12 * sizeof(*result));
if (NULL != result)
{
  for (size_t i = 0; i < 12; ++i)
  {
    result[i] = NULL;
  }
}

You could wrap this in a macro like so:

#define ALLOCARRAY(result, size) \
  do { \
    result = malloc(size * sizeof(*result)); \
    if (NULL != result) \
    { \
      for (size_t i = 0; i < size; ++i) \
      { \
        result[i] = NULL; \
      } \
    } \
  } while (0)

Then use the macro like this:

#include <stdlib.h>

[...]

SomeType ** result = NULL;
ALLOCARRAY(result, 12);
if (NULL == result)
{
  /* Handle error here. */
}
else 
{
  /* Use array here. */

  /* Free array. */
  free(result);
}
alk
  • 69,737
  • 10
  • 105
  • 255
3

calloc() sets the allocated space to all bits-zero, but a null pointer may not be bits-zero in some implementations. For a portable solution, you still need to set them to a null pointer manually.

for (int i = 0; i < 12; i++)
{
    result[i] = NULL;
}
Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • 2
    `s/many/some/`. I don't think there are many implementations out there which act this way, just a handful. – glglgl Feb 21 '14 at 14:05
  • @glglgl Done. Perhaps most time I heard examples for this issue, I focused on the exceptions :). – Yu Hao Feb 21 '14 at 14:10
  • @glglgl You beat me to the comment! Other than the old 8086 memory models where the effective pointer value was the offset sum of a non-zero segment and a zero offset, I've never seen non-zero null pointers. What others are there? Embedded systems? – Gene Feb 21 '14 at 14:12
  • As I commented below the answer, the [C FAQ mentions](http://c-faq.com/null/machexamp.html) some of these. Mostly historical things... – glglgl Feb 21 '14 at 14:14
  • @glglgl I'd be unable to name even one. I'll need to read some of those links. – Mark Ransom Feb 21 '14 at 14:49
  • @MarkRansom Me as well. It is interesting to have read about this phaenomenon and to take care, but otherwise I'm not affected by this. – glglgl Feb 21 '14 at 15:15
3

This issue is, IMO, a bit overblown. Yes, it is absolutely true that some machines, somewhere, do not use the all-bits-zero pattern for null, just like there are machines that have (or had, historically,) oddball byte sizes of 9 or 11 bits for example.) And knowing that is occasionally useful in winning a free beer from another programmer who doesn't know that, but not much beyond that. (It is, of course, vitally useful to those who write the C standards or compilers.)

I'm willing to be that several of the readers/commenters in this thread have worked on, or run across machines like that; but you have to understand that the stackoverflow-answering population at large is somewhat skewed towards the guru-types who have seen and done it all. (I don't count myself in that group, by the way..) The vast majority of 'normal' C programmers in the world (who are writing C code to run under a common Windows/Mac/Linux/Unix/(**) platform, or writing embedded code to run on just about any of the common embedded architecture platforms out there) will never in their lifetimes work on a system where calloc doesn't give you effectively NULL pointers, and darned few will work on a machine where an unsigned char is not 8 bits wide -- and the odds are nearly as good that their code will never get ported to one of those systems.

So, while I wholeheartedly agree that it's a good thing to understand technical nuances of the standards -- knowing more never hurts -- I think you also have to apply some common sense in deciding which kinds of portability your code needs to worry about. Unless you actually have access to a machine with a weird byte size, or a non-zero-bit null pointer, you won't actually be able to test the portability of your code (let alone any libraries you depend on,) across those conditions, and unless you know you are writing code that needs to be that widely portable, your mental energy is better spent on finding and fixing more prosaic bugs in your system.

(**) Do I still need to mention VMS in this list or get pounced upon by zealots? :)

JVMATL
  • 2,064
  • 15
  • 25
2

This is explicitly stated in non-normative footnote 296 of the C 2011 standard: “Note that this [calloc’s initialization of all bits to zero] need not be the same as the representation of floating-point zero or a null pointer constant.”

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312