uninitialized character array - c

I am getting the output "ma" on executing the following code. If my understanding is correct, local variable is not initialized to 0. So in such a case, how come %s is finding 0 in a1[2] itself? Is that we cannot predict the output in such cases and I am somehow getting this result and this may not be the case always?
int main(void)
{
char a1[10];
a1[0]='m';
a1[1]='a';
a1[3]='j';
printf("%s",a1);
return(0);
}

Yes, unless a1 is static note, being an automatic local variable, this is all by-luck. Your code (snippet) produces undefined behavior by missing the terminating null.
It just happens to have the immediate next byte as null, so it is printing properly. It is nowhere guaranteed that it will work very next time.
FWIW, %s format specifier expects a string and the definition of a string in C is a null-terminated char array. To copy the exact wordings,
If no l length modifier is present, the argument shall be a pointer to the initial element of an array of character type. [..] If the
precision is not specified or is greater than the size of the array, the array shall contain a null character.
Note: Related to the initialization of static variables, quoting C11 standard, chapter §6.7.9, Initialization, (emphasis mine)
If an object that has automatic storage duration is not initialized explicitly, its value is
indeterminate. If an object that has static or thread storage duration is not initialized explicitly, then:
[...]
if it has arithmetic type, it is initialized to (positive or unsigned) zero;

Related

Initialization of int pointer in C

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)

What is the default value of char in c

When I declare an int variable, and do not not assign a value to it, and then when I print it, a random number gets printed.
but when I allocate a char variable, and print it with %c format specifier, nothing is printed. So does a char variable in C have a default value like null? Do local variables in C start with a random value? Then why doesn't a char behave in this way?
There is no default value which is assigned to it. Some values are not printable and you can assume that random value is one of them, so that is the reason why you are not able to see the result.
The C99 standard says that:
If an object that has automatic storage duration is not initialized
explicitly, its value is indeterminate.
On a side note:
As per C99
If an object that has static storage duration is not initialized
explicitly, then:
if it has pointer type, it is initialized to a null pointer;
if it has arithmetic type, it is initialized to (positive or unsigned) zero;
if it is an aggregate, every member is initialized (recursively) according to these rules;
if it is a union, the first named member is initialized (recursively) according to these rules.
Automatic variables that are not initialized have indeterminate value, we can see this by going to the draft C99 standard section 6.7.8 Initialization:
If an object that has automatic storage duration is not initialized explicitly, its value is
indeterminate.
using an indeterminate value is undefined behavior. The definition for indeterminate values is as follows:
either an unspecified value or a trap representation
It just may be the case that the values you are ending up with for char are not printable.
There is not default value assigned. Never trust in a default value you didn't assign.

Assignment of unreferenced variables?

I saw the following code in the wild and I don't know what to make of it:
more or less:
int main(void)
{
int a = 0, v;
printf("%d\n", v);
}
This code with gcc will print out 0. At first I though, oh well that's because initialized local variables are assigned 0, but in this case I never declared the type of v...so what gives?
int a = 0, v;
is equivalent to:
int a = 0;
int v;
So you did declare the type of v, just not explicitly. It's an int.
Anyway, like all uninitialized local variables, v's value isn't guaranteed to be anything. Accessing it is still undefined behavior; you just happened to get 0.
What do you think the comma does in a declaration statement?
In C - C99 and C++, an initializer is an optional part of a declarator. The init-declarator-list is a comma-separated sequence of declarators, each of which can have additional type information, or an initializer, or both.
As such, your expression int a = 0, v; does declare v as a an int.
Type of v is int. Please read the syntax of variable declaration.
You are just lucky that it is printing 0. Value of v is garbage.
From ISO/IEC 9899:TC2 section 6.7.8 Semantics
If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate. If an object that has static storage duration is not initialized explicitly,
then:
— if it has pointer type, it is initialized to a null pointer;
— if it has arithmetic type, it is initialized to (positive or unsigned) zero;
— if it is an aggregate, every member is initialized (recursively) according to these rules;
— if it is a union, the first named member is initialized (recursively) according to these
rules.
From Wiki,
Multiple variables can be declared with one statement, like this:
int anumber, anothernumber, yetanothernumber;

Are global variables always initialized to zero in C? [duplicate]

This question already has answers here:
Why are global and static variables initialized to their default values?
(5 answers)
Closed 6 years ago.
#include <stdio.h>
int a[100];
int main(){
printf("%d",a[5]);
return 0;
}
Does the above code always print '0' or is it compiler specific? I'm using gcc compiler and I got the output as '0'.
Yes, all members of a are guaranteed to be initialised to 0.
From section 3.5.7 of the C89 standard
If an object that has static storage duration is not initialized
explicitly, it is initialized implicitly as if every member that has
arithmetic type were assigned 0 and every member that has pointer type
were assigned a null pointer constant.
"Global variables" are defined at file scope, outside any function. All variables that are defined at file scope and all variables that are declared with the keyword static have something called static storage duration. This means that they will be allocated in a separate part of the memory and exist throughout the whole lifetime of the program.
It also means that they are guaranteed to be initialized to zero on any C compiler.
From the current C standard C11 6.7.9/10:
"... If an object that has static or thread storage duration is not initialized
explicitly, then:
— if it has pointer type, it is initialized to a null pointer;
— if it has arithmetic type, it is initialized to (positive or unsigned) zero;"
Practically, this means that if you initialize your global variable to a given value, it will have that value and it will be allocated in a memory segment usually referred to as .data. If you don't give it a value, it will be allocated in another segment called .bss. Globals will never be allocated on the stack.
Yes.
Any global variable is initialized to the default value of that type.
0 is the default value and is automatically casted to any type.
If it is a pointer, 0 becomes NULL
Global variables get there space in the data segment which is zeroed out.
It is not compiler specific but defined in the C standard.
So it will always print 0.
File scope objects declared without explicit initializers are initialized by 0 by default (and to NULL for pointers).
Non-static objects at block scope declared without explicit initializers are left uninitialized.
Are the globle variable always initalized to zero in C?
Yes and It's defined in the C standard.
It is not compiler specific. The code will always print 0.

Undefined behavior: when attempting to access the result of function call

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.

Resources