Skip to content
VLSI Mentor

C Part I · Module 2 · Values, Variables, Types and Representation

Declarations and Initialization

Every object in this curriculum so far has been given a starting value in the same line that brought it into existence. C does not require that, and this chapter is about what happens when you leave it out. The short answer is that the object exists, occupies its storage exactly as Chapter 2.2 described, and holds a value you are not entitled to read — which is a meaningfully different statement from holding zero, and the difference is the subject of the whole chapter. You will also see the compiler warning that catches this, learn the small set of rules about where declarations may appear, and meet one multi-object declaration form that looks helpful and regularly is not.

Foundation11 min readCPart IFundamentalsCorrectness

Part I · Module 2 · Chapter 2.3 · Declarations and Initialization

1. Two Things That Usually Happen Together

int count = 3; does two separate jobs, and because they are almost always written together it is easy to miss that they are separable.

The declaration is int count; — it says an object of type int, named count, is to exist. That is what reserves the storage Chapter 2.2 described.

The initialization is = 3 — it gives the object a value at the moment it comes into existence.

C lets you do the first without the second:

Azvya Education Pvt. Ltd.VLSI Mentor
a declaration with no initialization
int count;

That is legal, complete, and creates the object. The only question is what it holds — and the answer is the most important thing in this chapter.

2. It Does Not Start at Zero

Here is what a beginner usually assumes, written as a program:

Azvya Education Pvt. Ltd.VLSI Mentor
what does this print?
#include <stdio.h>

int main(void)
{
    int count;

    printf("count is %d\n", count);
    return 0;
}

The common prediction is count is 0, on the reasoning that a fresh object must start somewhere and zero is the obvious somewhere.

That reasoning is wrong, and the correct statement is more careful than "it prints something random":

An object declared inside a function without an initializer starts with an indeterminate value. Reading it is not something C gives you an answer for.

Notice what that does not say. It does not say the object contains zero. It does not say it contains a random number. It does not say what your program will print. Chapter 1.3 gave you the vocabulary for this kind of statement: the standard imposes no requirements here, which means there is no behaviour you are entitled to predict — not the value, and not the rest of the program's conduct either.

This is why the chapter does not show you what that program prints. Running it would tell you what happened once, on one machine, with one compiler and one set of options, and would teach you the single most dangerous possible lesson: that the result is worth looking at.

3. What the Compiler Says

You do not have to catch this by reading carefully. Compile that program with the options from Chapter 1.5 and you get:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
u1.c:7:29: warning: variable 'count' is uninitialized when used here [-Wuninitialized]
    7 |     printf("count is %d\n", count);
      |                             ^~~~~
u1.c:5:14: note: initialize the variable 'count' to silence this warning
    5 |     int count;
      |              ^

Three things about this are worth noticing.

It is a warning, not an error. The program still compiles and an executable is still produced. Chapter 1.5 explained that the compiler is required to reject some things and free to stay quiet about many others; this is one it is free to stay quiet about, and -Wall is what asks it to speak. Without those options you would get nothing at all.

It names both places. The line where the value is used, and the line where the object was declared. Chapter 1.5 noted that a diagnostic's location is where the problem was noticed; here the compiler is helpfully telling you both.

The wording is Clang's. GCC words it differently. As always, match the shape — a file, a line, a category, a description — rather than the sentence.

4. Two Ways to Fix It

The fix is to make sure a value is stored before anything reads it. There are two shapes, and one is better.

Azvya Education Pvt. Ltd.VLSI Mentor
fix A — assign before use
#include <stdio.h>

int main(void)
{
    int count;

    count = 3;
    printf("count is %d\n", count);
    return 0;
}
Azvya Education Pvt. Ltd.VLSI Mentor
fix B — initialize at the declaration
#include <stdio.h>

int main(void)
{
    int count = 3;

    printf("count is %d\n", count);
    return 0;
}

Both print count is 3. Both are correct. Fix B is better, and the reason is not style.

In fix A there is a window — between the declaration and the assignment — in which the object exists and must not be read. Today that window is one line and obviously safe. It stays safe only as long as nobody adds code into it, and people add code into it constantly: a line to print progress, a condition, a calculation that seemed harmless. In fix B the window does not exist, so it cannot be widened by accident.

5. Declaring Several Objects at Once

C lets you declare more than one object of the same type in a single declaration:

Azvya Education Pvt. Ltd.VLSI Mentor
three objects, one declaration
#include <stdio.h>

int main(void)
{
    int first = 1, second = 2, third = 3;

    printf("%d %d %d\n", first, second, third);
    return 0;
}

Output:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
1 2 3

That works and is occasionally tidy. It also has a trap, which is why many codebases avoid the form entirely:

Azvya Education Pvt. Ltd.VLSI Mentor
only one of these has a value
int width, height = 10;

It is natural to read that as "width and height are both 10". It is not what it says. The = 10 attaches to height alone; width is declared with no initializer and has an indeterminate value — the situation §2 was about, now hiding inside a line that looks like it handles both.

The compiler will warn you if you then read width, but it cannot warn you about what you meant. Writing one declaration per line costs nothing and makes the mistake impossible:

Azvya Education Pvt. Ltd.VLSI Mentor
unambiguous
int width = 10;
int height = 10;

6. Where Declarations May Appear

Two small rules, both of which you have already seen in action.

A name exists from its declaration onward. Chapter 2.1 showed this: use a name before the line that declares it and the compiler refuses, because at that point it has never heard of the name.

A declaration may appear anywhere a statement may. It does not have to sit at the top of main. This is what makes the habit in §4 possible, and it has been true since C99 — so on this curriculum's C17 baseline you can rely on it completely. You may still see older code that declares everything at the top of a function; that was once required, and is not a style you need to copy.

7. What You Should Be Able to Say Now

  1. A declaration brings an object into existence; initialization gives it a value at that moment. They are separate, and C permits the first without the second.
  2. An object declared inside a function with no initializer has an indeterminate value. It does not start at zero.
  3. Reading such an object is not something C defines an outcome for — so no observed result from doing it is worth relying on, including zero.
  4. -Wall asks the compiler to warn about it. Without the option you are told nothing.
  5. This is a warning, not an error: the program still builds.
  6. Initializing at the declaration is safer than assigning later, because it leaves no window for someone to add code into.
  7. In int width, height = 10; only height is initialized.
  8. A declaration may appear anywhere a statement may, and a name exists from its declaration onward.

8. Exercise

Exercise 1 — say what is wrong, precisely. A colleague says: "I tested it and an uninitialized int is always 0 on our machines, so it's fine." Give two separate reasons this argument does not hold, using §2.

Exercise 2 — find the uninitialized read. One of these reads an object that has no value. Which, and on which line?

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
int a = 1;
int b;
int c = a;
b = c;
printf("%d\n", b);
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
int a = 1;
int b;
int c = b;
b = a;
printf("%d\n", c);

Exercise 3 — widen the window. Take fix A from §4 and add one line of your own between the declaration and the assignment that would turn it into a bug. Then explain in one sentence why fix B could not have been broken that way.

Exercise 4 — read the declaration. For each, say how many objects are declared and which of them have values: (a) int x = 0, y = 0; (b) int x, y = 0; (c) int x = 0, y; (d) int x, y;

Exercise 5 — predict the compiler. You write int total; and never use total anywhere. Will the compiler warn? Will it warn if you then write total = 5; and still never read it? Try both with the options from Chapter 1.5 and explain what the compiler is actually objecting to in each case.

9. Summary

  • Declaring and initializing are two jobs. int count; does the first; = 3 does the second.
  • An uninitialized object inside a function does not hold zero. It holds an indeterminate value, and C does not define what reading it produces.
  • An observed result proves nothing here. "It printed 0 on my machine" is a fact about one run, not a guarantee, and relying on it fails later and confusingly.
  • -Wall catches it. A warning, not an error — the build still succeeds, which is why the options from Chapter 1.5 are not optional.
  • Initialize at the declaration. It removes the window in which the object exists but must not be read, rather than leaving a small one for someone to grow.
  • int width, height = 10; initializes only height. One declaration per line removes the ambiguity.
  • Declarations may appear anywhere a statement may, and a name is usable only from its declaration onward.

Every object so far has held a value you could read straight off the page: 3, 10, 1. The next chapter goes underneath that. A value like 10 has to be represented in those bytes somehow, and the notation engineers use to talk about what is actually in them — bits, and the shorthand for writing groups of them — is the last piece of groundwork before the rest of this module can explain why C has more than one kind of number.

Standards & specifications

Governing standard
ISO/IEC 9899 (the C language standard)(opens ISO/IEC (JTC 1/SC 22/WG 14) in a new tab)

Defines the C language itself — the type system, expression semantics, object model, storage duration and the behaviour categories a conforming implementation must honour. It is a FAMILY of editions (C89/C90, C99, C11, C17, C23) and this curriculum names the edition wherever a claim depends on one. It does not define any foreign-function interface to a hardware description language, and it does not define platform behaviour: what a memory-mapped access does on real silicon is the implementation's and the device's contract, not this standard's. Working drafts published by WG14 are freely available and are what most engineers read day to day; a draft is not the published standard.

This page also covers RTL structure, verification approach and debugging technique. Those are engineering practice built on the standard, not requirements the standard itself imposes.

Where this fits

Part of the C Programming curriculum.