Initialization vs Assignment in C

My instructor recently told that array initialization in C happens in two ways, namely:

  1. Manually like int a[5]={1,2,3,4,5};
  2. Using scanf() like int a[5], i; for(i=0;i<5;i++) scanf("%d", &a[i]);

In my opinion the second "way" is a way of assignment and not initialization. So I decided to check what people over here have to say about this. I stumbled upon this post where one answer claims:

If all you are asking about is terminology (*which isn't really clear from your question), "Initialization" of a variable is, literally, the first time a value is assigned to it. This term comes from the fact that you are giving the variable it's "initial" value.

This should (obviously) happen before it is used the first time.

int x=5; is a declaration and an initialization, and is really just convenient shorthand for

int x; x=5;

If I'm to follow what this particular answer claims, then the second way of "initialization" is correct, because no value was assigned prior to the scanf() statement. However, thanks to my knowledge on static variables a new doubt arises in my mind. Consider the following code:

#include <stdio.h>

void first_way(){
    static int x[2]={1,2};
    printf("first_way called %d time(s)\n",++x[0]);
}

void second_way(){
    int i;
    static int x[2];
    for(i=0;i<2;i++)scanf("%d",&x[i]);
    printf("second_way called %d time(s)\n",++x[0]);
}

int main(void){
    int i;
    for(i=0;i<3;i++)
        first_way();
    printf("\n#######\n");
    for(i=0;i<3;i++)
        second_way();
    return 0;
}

Its output is like this:

first_way called 2 time(s)
first_way called 3 time(s)
first_way called 4 time(s)

#######
1 2
second_way called 2 time(s)
1 2
second_way called 2 time(s)
1 2
second_way called 2 time(s)

This output again leads me to think of scanf() version more like an assignment version rather than initialization even though no value to elements of x[] were assigned before the scanf() statement. Back to square one.

So, is the second version really an initialization like my instructor claims or merely an assignment (which is what I believe)?

Edit:

After someone pointed out, I feel my static array example is a poor one as static variables are implicitly initialized to 0 no matter what. Then again, someone else pointed me towards const variables.

Consider const int x = 2; Here one can initialize x, but cannot assign any value to it after initialization. But this is conflicting with the answer that claims (I quote it again):

int x = 5; is a declaration and an initialization, and is really just convenient shorthand for int x; x=5;

So, after all this, does the scanf() version qualify as an initializer?


Solution 1:

In the C Standard, only option (1) is initialization.

In programming jargon, both may be considered initialization. Your question is really asking about the meanings of words.

It's normal for people to use words with various common meanings, instead of switching terminology for particular languages. Another example is "pass by reference". Does C have pass by reference or not? Some would argue it only has pass by value, others would argue that passing by pointer implements the concept of "pass by reference".

Then we could talk about deep copy vs shallow copy (which is not mentioned by the C Standard at all), or the terms "stack" and "heap" (which are not mentioned by the C Standard either, but commonly used by C programmers), and so on.

If you say { int b; b = 5; } isn't initialization (because the C Standard says it isn't) then, to be consistent, you should also say that b is not a stack variable.

Solution 2:

There are two very closely related concepts in play here.

An initializer is a specific syntactic construct. In the declaration

int n = 42;

the 42 is an initializer. In the statement

n = 42;

the 42 is not an initializer; n = 42 is syntactically an assignment-expression.

On the other hand, the standard also uses the word "initialized" to refer to things other than initializers. For example, quoting N1570 section 6.3.2.1:

If the lvalue designates an object of automatic storage duration that could have been declared with the register storage class (never had its address taken), and that object is uninitialized (not declared with an initializer and no assignment to it has been performed prior to use), the behavior is undefined.

So an initializer is always part of a declaration, not an assignment -- but an object is said to be initialized either if it was defined with an initializer, if it was implicitly initialized because it's static, or if a value has been assigned to it.

Solution 3:

1) Declaration

 int a;

2) Initialization

int a=10;

3) Assignmen

a=10;

Arrays can be initialized, but not assigned to.

int arrA[3] = {1,3,2};

This will be illegal:

arrB = arrA; 

Solution 4:

According to N1570 6.7.9.1:

  initializer:
           assignment-expression
           { initializer-list }
           { initializer-list , }
  initializer-list:
           designationopt initializer
           initializer-list , designationopt initializer
  designation:
         designator-list =
  designator-list:
         designator
         designator-list designator
  designator:
         [ constant-expression ]
         . identifier

So obviously, the second way isn't actually an "initialisation". However, it is functionally identical to an initialisation in most cases. What's more, you won't want to use an initialiser-list when specifying the initial value stored in an array containing 10000 elements.