3

A very simple question regarding initializing an int pointer in C. I was just informed that:

int *varname = {0};  

Is not valid.

I have not yet been able to find the explicit reference that points this out, but have confidence (based on commenters rep) that it probably is not valid, Even though it compiles, builds and accepts memory from calloc/malloc statements okay.

Can someone please point out the specifics of why the above expression is not valid?

Community
  • 1
  • 1
ryyker
  • 22,849
  • 3
  • 43
  • 87
  • @molbdnilo - Okay, but is that statement similar to saying ***[duff's device](http://stackoverflow.com/questions/514118/how-does-duffs-device-work)*** is not valid, because it is not part of the C syntax?. It is a hybrid, that through some coincidence happens to provide a way to do something, that is not explicitly pointed out in the standard. Is this not similar? – ryyker Nov 12 '14 at 20:46
  • 3
    You were misinformed. The C standard allows this form of initialization explicitly: **The initializer for a scalar shall be a single expression, optionally enclosed in braces.** – Jens Gustedt Nov 12 '14 at 20:47
  • This maybe useful if you intend to use an array: http://stackoverflow.com/questions/2589749/initialize-array-to-0-in-c – Jens Wirth Nov 12 '14 at 20:53
  • @ryyker, never mind, Grzegorz Szpetkowski had a decent answer first. – Jens Gustedt Nov 12 '14 at 20:55
  • Are you trying to simultaneously define `varname `as a pointer and create an object for it to point to, similar to `char *ptr = "hello";`? If so, see my answer. If not, my answer is completely off the mark. – Keith Thompson Nov 12 '14 at 20:58
  • @KeithThompson - No, that was not my intent. However I do disagree with you on one point: Your answer is never that far _off the mark_. I always walk away from them with a better understanding of some subtlety you are able to convey. Thanks. – ryyker Nov 12 '14 at 21:20
  • the right way to init a pointer is int *varname = NULL; – user3629249 Nov 13 '14 at 06:24
  • @user3629249 - which is equivalent to `0`, which in turn is equivalent to {0}. – ryyker Nov 13 '14 at 14:19

3 Answers3

4

This is valid, we can see this by going to the C99 draft standard section 6.7.8 Initialization paragraph 11 which says:

The initializer for a scalar shall be a single expression, optionally enclosed in braces. [...]

So:

int *varname = {0}; 

will initialize varname to a null pointer, since 0 is a null pointer constant as per section 6.3.2.3 Pointers:

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.55) If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer [...]

and for completeness sake we know pointers are scalar types based on section 6.2.5 Types:

Arithmetic types and pointer types are collectively called scalar types [...]

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
3

As Grzegorz Szpetkowski's answer says, that syntax:

int *varname = {0};

is valid. It just doesn't do what I suspect you think it should do. It's equivalent to

int *varname = 0;

which is equivalent to

int *varname = NULL

(assuming NULL is visible).

If my guess about what you're trying to do is wrong, the rest of this answer doesn't apply.


Based on the comments, it looks like that's not what the OP was trying to do. Not sure whether to delete this answer or not; it could be a good answer to some other question.


You can initialize a char* pointer to point to a string literal:

char *cptr = "hello";

The string literal "hello" implicitly creates an anonymous array object with static storage duration; the initialization causes cptr to point to that array's initial element.

Prior to C99, there was no equivalent syntax for defining a non-character pointer and simultaneously creating something for it to point to.

C99 added compound literals. For example, this:

(int){42}

creates an int object with the value 42. Unlike a literal 42, this actually creates an object, not just a value -- which means it has an address. So this:

int *iptr = &((int){42});

creates an anonymous int object with an initial value of 42, and initializes iptr to point to it. (If your compiler supports compound literals.)

Compound literals are usually used for array and structure types, but they're also valid for scalar types.

One thing to watch out for: the array created by a string literal always has static storage duration, meaning it exists during the entire execution of the program. The storage duration of the anonymous object created by a compound literal depends on where it appears. If it's inside a function, the object has automatic storage duration, which means it ceases to exist as soon as execution leaves the nearest enclosing block.

So given:

char *cptr = "hello";

you can safely return the value of cptr from a function, and it will continue to be valid. But given:

int *iptr = &((int){42});

returning the value of iptr from a function would be dangerous, since the object it points to will cease to exist before the caller gets the pointer value.

A simpler way to do this kind of thing is to define the object yourself:

int obj = 42;
int *iptr = &obj;

You can define obj as static if necessary.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • @ryyker: "My intent is to initialize `int *array` to `0`." -- Just to be clear, you mean you want to make `array` a null pointer, right? (In the linked answer, the initialization isn't strictly necessary at all, since the object is unconditionally assigned a different value. BTW, `{0}` is a valid initializer for an object of any type. – Keith Thompson Nov 12 '14 at 21:10
2

The:

int *varname = {0};

is just equivalent to:

int *varname = 0;

It's one of valid replacements of NULL object-like macro (either as 0 integer constant or such constant casted to void * type).

N1570 (C11 draft), 6.3.2.3/3:

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.

Example (http://ideone.com/9917zk):

#include <stdio.h>

int main(void)
{
    int *varname = {0};

    printf("%p\n", (void *) varname);

    return 0;
}

Its output is just:

(nil)

(as a bonus part note that nil term was invented by Alfred Tarski)

Grzegorz Szpetkowski
  • 36,988
  • 6
  • 90
  • 137
  • Correct me if I'm wrong, but what's going on here is that since the boundary of the array has not been defined, setting int *varname = {0} thus only initialises the very first element of the array, right? – AntikM Nov 12 '14 at 20:46
  • @antikbd Not at all. What array? `varname` is *only* a pointer. – Jonathon Reinhart Nov 12 '14 at 20:47
  • @antikbd: What array? The declaration creates a pointer object, not an array. The initialization `= {0}` is equivalent to `= 0`, which is equivalent to `= NULL`. – Keith Thompson Nov 12 '14 at 20:47
  • 1
    @antikbd: It's just a weirdness of C syntax, not really array initializer. – Grzegorz Szpetkowski Nov 12 '14 at 20:47
  • Oh I see. I have been heavily programming with pointers for the past couple of weeks and still get confused on stuff like these! – AntikM Nov 12 '14 at 20:49
  • So there is NO difference whatsoever between int *varname = {0} and int *varname = NULL? If that's the case, then why is even the {} braces allowed? – AntikM Nov 12 '14 at 20:54
  • @antikbd: `NULL` may be defined also as `(void *) 0` (I would it's say that one is common definition). It's slight difference, but it matters in some cases, but `0` (or `{0}`) is also valid representation of `NULL`. – Grzegorz Szpetkowski Nov 12 '14 at 20:57