-2

I am aware that if I declare an array with a capacity of 10 and initialize only 5 values in it, then the remaining 5 elements will be uninitialized and their values will be unpredictable, which means they may contain garbage values. However, when I write a code like the one shown below:

#include <stdio.h>

int main()
{
    int arr[10];
    printf("%d\n",arr[3]);
    printf("%d\n",arr[4]);
    printf("%d\n",arr[5]);
    printf("%d\n",arr[6]);
    printf("%d\n",arr[7]);
    printf("%d\n",arr[8]);
    printf("%d\n",arr[9]);
}

The output is 0 for all the elements which means by default the uninitialized elements are initialized to 0 rather than having garbage values. But why? Why is the local array initialized to 0 by default? When will an uninitialized array have garbage values

As it was 0 when we uninitialized I was able to find the size by simply using a for loop and checking for a non-zero number. But it contradicts this fact:-

How can I find the number of elements in an array?

Please help me with this fundamental concept.

I am expecting to get clarity on array fundamentals.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 2
    It doesn't mean anything. It's just by accident that they contained 0. – Barmar May 09 '23 at 20:07
  • 1
    Some compilers will assign 0 (especially for debug builds), or 0 will happen to be the initial state of memory. The value is undefined, not defined, not known. 0 is one of those possible undefined values. – Dave S May 09 '23 at 20:07
  • 3
    "unpredictable" doesn't mean they have to be random values. That would require that there be deliberate code that initializes them to something random. – Barmar May 09 '23 at 20:08
  • So that means we cannot find the number of elements in an integer array when we the capacity is not equal to number of elements? – Sundaragiri Rishi May 09 '23 at 20:10
  • And what will happen when declare use an array as global or static, will the be initialized to '0' by default rather than unpredictable? – Sundaragiri Rishi May 09 '23 at 20:13
  • 1. Keep track of that manually with another "count" variable. 2. static or global *will* be zero initialized. – Jason May 09 '23 at 20:15
  • The elements of global and static arrays are initialized to 0, unless you provide an initializer. If the initializer does not initialize all of the elements, then the uninitialized elements are 0. – user3386109 May 09 '23 at 20:16
  • @SundaragiriRishi "The output is 0 for all the elements which means by default the uninitialized elements are initialized to 0" --> No. It may differ on another run. The array elements are indeterminant. Also, there is _never_ a partial _initialization_. It is all or nothing. – chux - Reinstate Monica May 09 '23 at 20:16
  • @SundaragiriRishi Accessing the array outside it limits [0...9] is undefined behavior. "I was able to find the size by simply using an for loop and checking for a non zero number." is a poor idea. – chux - Reinstate Monica May 09 '23 at 20:19
  • 1
    If the array size is bigger than the number of elements being used, you have two options. 1) Keep a separate `count` variable. 2) Use a [sentinel value](https://en.wikipedia.org/wiki/Sentinel_value). – user3386109 May 09 '23 at 20:22
  • [not all zero here](https://godbolt.org/z/9h73z7Tzf), for instance. Play with the flags, different compilers, even hit the refresh button. ASLR alone will most likely change the values. You certainly cannot count on initialization of 0 if you're not doing it manually. – yano May 09 '23 at 20:30
  • Put the array into a function. Do the printing from that function. Call your function (which might print zeros), then call `printf()` from `main()`, then call your new function. Are the values still zero? It's rather unlikely. On a Mac, compiled with relaxed options (it doesn't compile with strict options), the output from your code is not a set of zeros, which is fine since printing uninitialized values is undefined behaviour (UB) and can produce any values whatsoever. With the call/print/call scheme, the output changes between the two calls. That, too, is fine because it is still UB. – Jonathan Leffler May 09 '23 at 21:40
  • There is no case where a C array contains a different number of elements than its capacity. It may be that some elements have indeterminate values, but that's not the same thing. And in any case, you cannot recognize those from the values themselves. It is your responsibility to track, somehow, which elements you should use. Valid-element counts and sentinel values are two common ways of doing that, but if the valid elements do not occupy a contiguous range of the array then you'll need to come up with something cleverer. – John Bollinger May 09 '23 at 21:53

2 Answers2

3

… the remaining 5 elements will be uninitialized and their values will be unpredictable,…

This is generally not correct. The C standard does not say whether the values will be predictable or not. In many circumstances, knowledge of the C implementation can be used to predict some values, and this conforms to (does not violate the requirements of) the C standard. In many circumstances, knowledge of the C implementation cannot be used to predict values, and this conforms to (does not violate the requirements of) the C standard.

The C standard says the value of an uninitialized object is indeterminate, which means it can be either an unspecified value or a trap representation. The standard says an unspecified value is a valid value for which the standard imposes no requirements on which value is chosen in any instance. Being unpredictable would be a requirement in some sense.

Note that the fact the C standard does not impose any requirements does not mean a C implementation may not add its own. A C implementation could add its own specification that all objects are initialized with zeros or with trap values.

… which means they may contain garbage values.

This is a bad feature of human language. A “garbage value” is not actually a value. Similarly, an “unspecified value” is not actually a value. The sentence “X has an unspecified value” actually means “X is not required to have any fixed value; the program may behave as if it has a different value each time it is used (or it may behave as if it does have a fixed value; there are no requirements).” In other words, the sentence “X has an unspecified value” does not mean there is some value that X actually has; the sentence is an idiom with a different meaning.

So there is no thing that is a garbage value. You cannot point to any particular number and say it is or is not a garbage value. There are occasions on which an object with an indeterminate value or a “garbage value” may appear to contain 0, and there are occasions on which it might not appear to contain 0. Or it might appear to contain 317. Any value of the object’s type is allowed to appear for an uninitialized object.

The output is 0 for all the elements which means by default the uninitialized elements are initialized to 0 rather than having garbage values.

Zeros are allowed for garbage values, per above.

[Why] is the local array initialized to 0 by default?

In typical start-up of processes on general purpose multi-user systems, the process is given some zero-initialized memory by the operating system and the program loader. (It is also given some memory initialized from the executable file being loaded.) Before your main routine runs, there is a startup routine that runs and does some work to initialize the C environment. This startup routine leaves some of its data behind.

When you use an uninitialized array, you may see some of the residue from these loading and startup activities. If you access the memory not used by the startup routine, it will still contain zeros from the initial memory the operating system provided. If you access memory used by the startup routine, it will contain whatever data the startup routine left there.

Further complications can occur due to program optimization by the compiler.

Also, these observations of initial zeros or residue from the startup routine largely apply only at the beginning of your program. Once your program has called various subroutines and done substantial work, some memory will contain data left over from earlier parts of your program rather than from the initial zero memory or the startup routine.

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

Can we find the number of elements in an integer array when the capacity is greater the number of elements?

If by "find" you mean "have the compiler or run-time system to keep track of it for us, so we can ask", the answer is an emphatic no. With the exception of character arrays containing strings (which are always terminated by a \0 character, which strlen or the equivalent can definitively find), there is no mechanism in C, not even a language-defined convention, for keeping track of the "used" size of an array. You must keep track of it yourself somehow. The usual way is with an auxiliary "count" value held in a separate variable. It is also possible to use a sentinel value, such as 0 or -1 or -999, if you know that those values won't occur in normal data.

I am aware that if I declare an array with a capacity of 10 and initialize only 5 values in it, then the remaining 5 elements will be uninitialized and their values will be unpredictable, which means they may contain garbage values.

That's correct if the array is allocated locally to a function (formally, if it has automatic duration). That's true for the array arr in your example, although it would not be true for a global array (declared outside of any function), or one declared with the static qualifier. (Those other kinds of arrays — formally, the ones with static duration — are guaranteed to be initialized to 0.)

The output is 0 for all the elements which means by default the uninitialized elements are initialized to 0 rather than having garbage values.

No, it just means the initial, "garbage" values happened to be 0 — this time.

Think about it this way. Suppose you go to the store and buy a brand-new garbage can. But it's completely clean! There's no garbage in it at all! It's so clean you could eat out of it! Was this false advertising? Did the store fraudulently sell you a non-garbage can?

Why is the local array initialized to 0 by default?

It is not initialized to 0 by default.

When will an uninitialized array have garbage values?

There are several answers:

  1. "Sometimes."
  2. Whenever it's least convenient for you.
  3. When the stack space has been previously used.

To say a little more about numbers 1 and 2: I like to call this the "confounding expectations" rule of uninitialized local variables in C. Uninitialized local variables never start out holding what you expect. If you expected them to be random, you'll find that (at least on any given day) they're utterly repeatable and predictable, and often 0. But if you expect them to be predictable (and, god help you, if you write code that depends on it), then by jingo, you'll find that they're quite random.

To say a little more about number 3: There are no hard-and-fast rules here, but in general, local variables are allocated on the stack, and although the stack usually starts out containing all 0's, once you've had a few functions called and returned, they'll have left the last values of their local variables scattered all over the memory formerly occupied by their stack frames, and at that point, newly-called functions will find that their uninitialized local variables do not start out containing 0, but do start out containing "garbage".

In other words, the very first time a function gets called, and if it's got a brand-new region of the stack for its stack frame (that is, if no previous function has called deeper into the stack), it's like buying that brand-new, so-clean-you-could-eat-out-of-it garbage can, and uninitialized local variables in that function are likely to be 0, as they were in your example. But if it's not the first call, if its stack frame gets placed in a region of stack memory that has been used before, then it's likely to be garbage galore.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • "The usual way is with an auxiliary "count" value held in a separate variable" does this mean I need to have a variable which I need to increment everytime I feed or load a value into the array so that I can keep track of number of current elements in that array? – Sundaragiri Rishi May 10 '23 at 00:42
  • @SundaragiriRishi Yes, exactly. – Steve Summit May 10 '23 at 10:33
  • @SundaragiriRishi If you were using C++, you could use a `std::vector`, and it would keep track for you. – Steve Summit May 10 '23 at 11:46