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?
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 [...]
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.
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)
Related
this the snip of the warning i was getting when i tried to compile the program.I am just getting started with pointers and this following program is being flagged by compiler for some reason I am not able comprehend. the code is as follows:
#include <stdio.h>
int dec = 0;
int *d;
d = &dec;
int main() {
return 0;
}
there is no error when I am stuffing these declarations in to main's body. the version of gcc I am using is gcc version 12.2.0(downloaded using MSYS2) and code editor MS visual code.can anybody post an explanation for this?
as i have stated above i have randomly started typing a program to get familiar with pointers, i expected there to be no variation in the treatment of pointers regardless of where they are being declared and intialised.
You're attempting to perform an assignment outside of a function, which is not allowed. What you can do is initialize:
int *d = &dec;
You may use only declarations in file scopes.
In the provided program you are using an assignment statement
d = &dec;
in the file scope. So the compiler issues an error.
Instead you could write for example
#include <stdio.h>
int dec = 0;
int *d = &dec;
int main( void ) {
return 0;
}
As the variable dec has static storage duration then the expression &dec is an address constant and my be used as an initializer for the variable d that also has static storage duration.
From the C Standard (6.7.9 Initialization)
4 All the expressions in an initializer for an object that has static
or thread storage duration shall be constant expressions or string
literals.
and (6.6 Constant expressions)
7 More latitude is permitted for constant expressions in initializers.
Such a constant expression shall be, or evaluate to, one of the
following:
— an arithmetic constant expression,
— a null pointer constant,
— an address constant, or
— an address constant for a complete object type plus or minus an
integer constant expression.
and
9 An address constant is a null pointer, a pointer to an lvalue
designating an object of static storage duration, or a pointer to a
function designator; it shall be created explicitly using the unary
& operator or an integer constant cast to pointer type, or
implicitly by the use of an expression of array or function type. The
array-subscript [] and member-access . and -> operators, the address &
and indirection * unary operators, and pointer casts may be used in
the creation of an address constant, but the value of an object shall
not be accessed by use of these operators.
I thought I understood how C arrays, pointers and pointers to arrays worked, but now I stumbled upon a piece of working code which I don't understand:
int sum(const int * const buf, int len)
{
int result = 0;
const int (*p)[];
int n;
p = (const int(*)[]) buf;
// p = buf without cast gives compiler warning here (but works)
// p = (const int(*)[]) &buf; // Doesn't work! Segfault!
for( n=0; n<len; n++)
{
result += (*p)[n];
}
return result;
}
This actually works. But how? The question is: how does that assignment from "buf" to "p" work? I thought this declaration of p was similar to "pointer to pointer to int", so I would have expected a "&" necessesary at the assignment. Why is this not necessary?
In fact the following prototype also works (with the same function body above):
int sum(const int buf[const], int len)
Now it seems even more clear that the declaration of "p" adds one level of pointer re-direction compared to the declaration of "buf". Still ... the assignment works fine without any "&" necessary. Can someone explain it?
First of all, please note that this code is not good practice. The pointer conversion is fishy-looking and unusual, and in particular it casts away const qualifiers, which is bad practice. (Declaring a parameter as ...* const buf is pretty fishy to begin with though.)
This actually works. But how?
There is a pointer conversion from (qualified) int pointer to int array pointer. Given that these two pointer types do not have different representation or different alignment (highly unlikely but theoretically possible), the pointer conversion in itself is ok (as per C11 6.3.2.3/8).
What matters then is the effective type of the data, which is an (array of) int. Effective type is a formal C term used for determining what type that is actually stored at a location, no matter the pointer types used for accessing. As long as the data is accessed through a pointer type that is compatible with the effective type of what's stored there, the code should work fine.
The formal reason why this is fine is C11 6.5/7 ("the strict aliasing rule"):
An object shall have its stored value accessed only by an lvalue expression that has one of
the following types:
— a type compatible with the effective type of the object,
— a qualified version of a type compatible with the effective type of the object,
/--/
— an aggregate or union type that includes one of the aforementioned types among its
members
Where "aggregate" is C standard gibberish for arrays and structs. If we access the data through an expression of array type, where the array element type is a type/qualified type compatible with the actual type, int in this case, everything is fine.
As for how it works, it simply de-references an array pointer. p = (const int(*)[]) buf; says "threat what's stored in this variable as a pointer to array of integer (and qualifiers be damned)". Then (*p)[n] takes the array pointer, de-references it to get the actual array, then uses the array index.
p = buf without cast gives compiler warning here
If you compile with gcc -pedantic-errors you get a more correct error. The pointer types are not compatible and so the compiler must generate a diagnostic message here - since p = buf is not valid C.
p = (const int(*)[]) &buf; // Doesn't work! Segfault!
This is because what's stored at &buf is not an array of int, it is just the pointer buf itself, likely allocated on the stack as a parameter to your function.
The following compiles and prints "string" as an output.
#include <stdio.h>
struct S { int x; char c[7]; };
struct S bar() {
struct S s = {42, "string"};
return s;
}
int main()
{
printf("%s", bar().c);
}
Apparently this seems to invokes an undefined behavior according to
C99 6.5.2.2/5 If an attempt is made to modify the result of a function
call or to access it after the next sequence point, the behavior is
undefined.
I don't understand where it says about "next sequence point". What's going on here?
You've run into a subtle corner of the language.
An expression of array type is, in most contexts, implicitly converted to a pointer to the first element of the array object. The exceptions, none of which apply here, are:
When the array expression is the operand of a unary & operator (which yields the address of the entire array);
When it's the operand of a unary sizeof or (as of C11) _Alignof operator (sizeof arr yields the size of the array, not the size of a pointer); and
When it's a string literal in an initializer used to initialize an array object (char str[6] = "hello"; doesn't convert "hello" to a char*.)
(The N1570 draft incorrectly adds _Alignof to the list of exceptions. In fact, for reasons that are not clear, _Alignof can only be applied to a type name, not to an expression.)
Note that there's an implicit assumption: that the array expression refers to an array object in the first place. In most cases, it does (the simplest case is when the array expression is the name of a declared array object) -- but in this one case, there is no array object.
If a function returns a struct, the struct result is returned by value. In this case, the struct contains an array, giving us an array value with no corresponding array object, at least logically. So the array expression bar().c decays to a pointer to the first element of ... er, um, ... an array object that doesn't exist.
The 2011 ISO C standard addresses this by introducing "temporary lifetime", which applies only to "A non-lvalue expression with structure or union type, where the structure or union
contains a member with array type" (N1570 6.2.4p8). Such an object may not be modified, and its lifetime ends at the end of the containing full expression or full declarator.
So as of C2011, your program's behavior is well defined. The printf call gets a pointer to the first element of an array that's part of a struct object with temporary lifetime; that object continues to exist until the printf call finishes.
But as of C99, the behavior is undefined -- not necessarily because of the clause you quote (as far as I can tell, there is no intervening sequence point), but because C99 doesn't define the array object that would be necessary for the printf to work.
If your goal is to get this program to work, rather than to understand why it might fail, you can store the result of the function call in an explicit object:
const struct s result = bar();
printf("%s", result.c);
Now you have a struct object with automatic, rather than temporary, storage duration, so it exists during and after the execution of the printf call.
The sequence point occurs at the end of the full expression- i.e., when printf returns in this example. There are other cases where sequence points occur
Effectively, this rule states that function temporaries do not live beyond the next sequence point- which in this case, occurs well after it's use, so your program has quite well-defined behaviour.
Here's a simple example of not well-defined behaviour:
char* c = bar().c; *c = 5; // UB
Here, the sequence point is met after c is created, and the memory it points to is destroyed, but we then attempt to access c, resulting in UB.
In C99 there is a sequence point at the call to a function, after the arguments have been evaluated (C99 6.5.2.2/10).
So, when bar().c is evaluated, it results in a pointer to the first element in the char c[7] array in the struct returned by bar(). However, that pointer gets copied into an argument (a nameless argument as it happens) to printf(), and by the time the call is actually made to the printf() function the sequence point mentioned above has occurred, so the member that the pointer was pointing to may no longer be alive.
As Keith Thomson mentions, C11 (and C++) make stronger guarantees about the lifetime of temporaries, so the behavior under those standards would not be undefined.
I was very surprised when I saw this notation. What does it do and what kind of C notion is it?
This is a compound literal as defined in section 6.5.2.5 of the C99 standard.
It's not part of the C++ language, so it's not surprising that C++ compilers don't compile it. (or Java or Ada compilers for that matter)
The value of the compound literal is that of an unnamed object initialized by the
initializer list. If the compound literal occurs outside the body of a function, the object
has static storage duration; otherwise, it has automatic storage duration associated with
the enclosing block.
So no, it won't destroy the stack. The compiler allocates storage for the object.
Parenthesis are put around the type and it is then followed by an initializer list - it's not a cast, as a bare initialiser list has no meaning in C99 syntax; instead, it is a postfix operator applied to a type which yields an object of the given type. You are not creating { 0, 3 } and casting it to an array, you're initialising an int[2] with the values 0 and 3.
As to why it's used, I can't see a good reason for it in your single line, although it might be that a could be reassigned to point at some other array, and so it's a shorter way of doing the first two lines of:
int default_a[] = { 0, 2 };
int *a = default_a;
if (some_test) a = get_another_array();
I've found it useful for passing temporary unions to functions
// fills an array of unions with a value
kin_array_fill ( array, ( kin_variant_t ) { .ref = value } )
This is a c99 construct, called a compound literal.
From the May 2005 committee draft section 6.5.2.5:
A postfix expression that consists of
a parenthesized type name followed by
a brace- enclosed list of initializers
is a compound literal. It provides an
unnamed object whose value is given by
the initializer list.
...
EXAMPLE 1 The file scope definition
int *p = (int []){2, 4};
initializes p
to point to the first element of an
array of two ints, the first having
the value two and the second, four.
The expressions in this compound
literal are required to be constant.
The unnamed object has static storage
duration.
Allocates, on the stack, space for [an array of] two ints.
Populates [the array of] the two ints with the values 0 and 2, respectively.
Declares a local variable of type int* and assigns to that variable the address of [the array of] the two ints.
(int[2]) tells the compiler that the following expression should be casted to int[2]. This is required since {0, 2} can be casted to different types, like long[2]. Cast occurs at compile time - not runtime.
The entire expression creates an array in memory and sets a to point to this array.
{0, 2} is the notation for an array consisting of 0 and 2.
(int[2]) casts it to an array (don't know why).
int * a = assigns it to the int pointer a.
I thought I really understood this, and re-reading the standard (ISO 9899:1990) just confirms my obviously wrong understanding, so now I ask here.
The following program crashes:
#include <stdio.h>
#include <stddef.h>
typedef struct {
int array[3];
} type1_t;
typedef struct {
int *ptr;
} type2_t;
type1_t my_test = { {1, 2, 3} };
int main(int argc, char *argv[])
{
(void)argc;
(void)argv;
type1_t *type1_p = &my_test;
type2_t *type2_p = (type2_t *) &my_test;
printf("offsetof(type1_t, array) = %lu\n", offsetof(type1_t, array)); // 0
printf("my_test.array[0] = %d\n", my_test.array[0]);
printf("type1_p->array[0] = %d\n", type1_p->array[0]);
printf("type2_p->ptr[0] = %d\n", type2_p->ptr[0]); // this line crashes
return 0;
}
Comparing the expressions my_test.array[0] and type2_p->ptr[0] according to my interpretation of the standard:
6.3.2.1 Array subscripting
"The definition of the subscript
operator [] is that E1[E2] is
identical to (*((E1)+(E2)))."
Applying this gives:
my_test.array[0]
(*((E1)+(E2)))
(*((my_test.array)+(0)))
(*(my_test.array+0))
(*(my_test.array))
(*my_test.array)
*my_test.array
type2_p->ptr[0]
*((E1)+(E2)))
(*((type2_p->ptr)+(0)))
(*(type2_p->ptr+0))
(*(type2_p->ptr))
(*type2_p->ptr)
*type2_p->ptr
type2_p->ptr has type "pointer to int" and the value is the start address of my_test. *type2_p->ptr therefore evaluates to an integer object whose storage is at the same address that my_test has.
Further:
6.2.2.1 Lvalues, arrays, and function designators
"Except when it is the operand of the
sizeof operator or the unary &
operator, ... , an lvalue that has
type array of type is converted to
an expression with type pointer to
type that points to the initial
element of the array object and is not
an lvalue."
my_test.array has type "array of int" and is as described above converted to "pointer to int" with the address of the first element as value. *my_test.array therefore evaluates to an integer object whose storage is at the same address that the first element in the array.
And finally
6.5.2.1 Structure and union specifiers
A pointer to a structure object,
suitably converted, points to its
initial member ..., and vice versa.
There may be unnamed padding within a
structure object, but not at its
beginning, as necessary to achieve the
appropriate alignment.
Since the first member of type1_t is the array, the start address of
that and the whole type1_t object is the same as described above.
My understanding were therefore that *type2_p->ptr evaluates to
an integer whose storage is at the same address that the first
element in the array and thus is identical to *my_test.array.
But this cannot be the case, because the program crashes consistently
on solaris, cygwin and linux with gcc versions 2.95.3, 3.4.4
and 4.3.2, so any environmental issue is completely out of the question.
Where is my reasoning wrong/what do I not understand?
How do I declare type2_t to make ptr point to the first member of the array?
Please forgive me if i overlook anything in your analysis. But i think the fundamental bug in all that is this wrong assumption
type2_p->ptr has type "pointer to int" and the value is the start address of my_test.
There is nothing that makes it have that value. Rather, it is very probably that it points somewhere to
0x00000001
Because what you do is to interpret the bytes making up that integer array as a pointer. Then you add something to it and subscript.
Also, i highly doubt your casting to the other struct is actually valid (as in, guaranteed to work). You may cast and then read a common initial sequence of either struct if both of them are members of an union. But they are not in your example. You also may cast to a pointer to the first member. For example:
typedef struct {
int array[3];
} type1_t;
type1_t f = { { 1, 2, 3 } };
int main(void) {
int (*arrayp)[3] = (int(*)[3])&f;
(*arrayp)[0] = 3;
assert(f.array[0] == 3);
return 0;
}
An array is a kind of storage. Syntactically, it's used as a pointer, but physically, there's no "pointer" variable in that struct — just the three ints. On the other hand, the int pointer is an actual datatype stored in the struct. Therefore, when you perform the cast, you are probably* making ptr take on the value of the first element in the array, namely 1.
*I'm not sure this is actually defined behavior, but that's how it will work on most common systems at least.
Where is my reasoning wrong/what do I not understand?
type_1::array (not strictly C syntax) is not an int *; it is an int [3].
How do I declare type2_t to make ptr point to the first member of the array?
typedef struct
{
int ptr[];
} type2_t;
That declares a flexible array member. From the C Standard (6.7.2.1 paragraph 16):
However, when a . (or ->) operator has a left operand that is (a pointer to) a structure with a flexible array member and the right operand names that member, it behaves as if that member were replaced with the longest array (with the same element type) that would not make the structure larger than the object being accessed; the offset of the array shall remain that of the flexible array member, even if this would differ from that of the replacement array.
I.e., it can alias type1_t::array properly.
It's got to be defined behaviour. Think about it in terms of memory.
For simplicity, assume my_test is at address 0x80000000.
type1_p == 0x80000000
&type1_p->my_array[0] == 0x80000000 // my_array[0] == 1
&type1_p->my_array[1] == 0x80000004 // my_array[1] == 2
&type1_p->my_array[2] == 0x80000008 // my_array[2] == 3
When you cast it to type2_t,
type2_p == 0x80000000
&type2_p->ptr == 0x8000000 // type2_p->ptr == 1
type2_p->ptr[0] == *(type2_p->ptr) == *1
To do what you want, you would have to either create a secondary structure & assign the address of the array to ptr (e.g. type2_p->ptr = type1_p->my_array) or declare ptr as an array (or a variable length array, e.g. int ptr[]).
Alternatively, you could access the elements in an ugly manner : (&type2_p->ptr)[0], (&type2_p->ptr)[1]. However, be careful here since (&type2_p->ptr)[0] will actually be an int*, not an int. On 64-bit platforms, for instance, (&type2_p->ptr)[0] will actually be 0x100000002 (4294967298).