munotes®

Variables: Declaration, Definition and Initialisation

Chapter Eleven

Syllabus topic 1, "Introduction: Algorithms, History of C, Structure of C Program. Program Characteristics, Compiler, Linker and preprocessor, pseudo code statements and flowchart symbols, Desirable program characteristics. Program structure. Compilation and Execution of a Program, C Character Set, identifiers and keywords, data types and sizes, constants and its types, variables, Character and character strings, typedef, typecasting"

Pages 50 to 54 of 222

In one line

A variable is a named piece of memory of a known type, and you bring one into existence by writing its type and its name, after which the name stands for whatever value is currently stored there.

Why the compiler has to be told first

The compiler has to know three things before it can compile a single use of a name: how many bytes to set aside, how to read the bits, and therefore what the operators are allowed to do with it. None of that can be worked out from the way the name is used later, because the compiler reads the file once, from the top.

So C requires you to say it in advance. The statement that says it is a declaration, and in the ordinary case it is also the thing that creates the variable.

Declaration and definition

The two words are used loosely everywhere and they are not the same.

A definition creates the variable: it sets aside the memory.

int count;

A declaration describes a variable and promises that a definition exists somewhere else.

extern int count;

extern is the keyword for that promise. It is how two source files share one variable: one file defines it, the others declare it. In a single-file program you will not need extern, and you should read int count; as doing both jobs at once.

The pairing is easier to see with functions, which is where you will actually meet it. double area(double r); with a semicolon is a declaration. The same line with a body in braces is a definition. Chapter 32.

For the exam, the sentence to write is: every definition is also a declaration, but a declaration need not be a definition. A variable may be declared many times and must be defined exactly once.

Declaring a variable

int marks;
double average;
char grade;
int a, b, c;
unsigned long population;

The type comes first, then one or more names separated by commas, then a semicolon. Declaring several on one line is legal and is worth avoiding once the names stop being related: int i, j, k; is fine for loop counters, and int count, total, flag; invites a reader to think those three have something to do with each other.

Where a declaration may go. In C99 and later, anywhere a statement may go. The old rule, that declarations came first in a block, was dropped in 1999 and only the very oldest compilers still enforce it.

Declare a variable where you first need it, not at the top. A variable that comes into existence one line before its first use has a shorter life for a reader to keep track of, and often the declaration and the initial value can then be the same line.

munotes.in50

Variables: Declaration, Definition and Initialisation

Initialisation

Initialisation is giving a variable a value at the moment it is created. Assignment is giving it a value later. They look similar and they are different events.

int marks = 75;          /* initialisation: created and set at once */
int total;               /* created, holding nothing useful       */
total = 0;               /* assignment: set afterwards            */

Several at once, each with its own value:

int a = 1, b = 2, c = 3;

int a = b = c = 0; does not do what it looks like. b and c must already exist; only a is being declared. Write the three separately.

The thing that goes wrong: an uninitialised variable

This is the most important paragraph in the chapter. A variable declared inside a function without an initialiser holds whatever was in that memory already. Not zero. Not a random number in any useful sense. Simply whatever was there.

The program below is wrong on purpose, and the compiler says so.

#include <stdio.h>

int main(void)
{
    int total;
    int count = 5;

    total = total + count;
    printf("total is now %d\n", total);
    return 0;
}

The compiler's own words, which are the point of the listing:

uninitialised.c: In function ‘main’:
uninitialised.c:8:11: warning: ‘total’ is used uninitialized [-Wuninitialized]
    8 |     total = total + count;
      |     ~~~~~~^~~~~~~~~~~~~~~
uninitialised.c:5:9: note: ‘total’ was declared here
    5 |     int total;
      |         ^~~~~

The value that program prints is not a fact about your machine or ours. Reading an uninitialised automatic variable is undefined behaviour: the standard permits the program to print anything, to print a different thing each time, or to do something else entirely. A program that appears to work because the memory happened to contain zero is the worst possible outcome, because it will stop appearing to work on the day it matters.

The habit that prevents it entirely: never declare a variable without a value unless the very next thing you write gives it one. A counter starts at 0. A running total starts at 0. A running product starts at 1. A "largest so far" starts at the first element, not at zero, which is chapter 36's trap.

Where variables live, and what that changes

Three places, and where a variable is declared decides both how long it lives and who can see it.

Automatic, the default: declared inside a function or a block.

void f(void)
{
    int x = 1;       /* created when f starts, gone when f returns */
}

Created on entry, destroyed on exit, and not initialised unless you say so. Every call gets a fresh one. This is what almost every variable in this course is.

munotes.in51

Variables: Declaration, Definition and Initialisation

Static: declared with static inside a function.

void f(void)
{
    static int calls = 0;   /* created once, survives between calls */
    calls++;
}

Created once before the program starts, lives until it ends, keeps its value between calls, and is initialised to zero if you do not initialise it. Visible only inside the function.

Global, also called external: declared outside every function.

int shared = 0;

void f(void) { shared++; }

Lives for the whole program, visible to every function in the file, and is initialised to zero if you do not initialise it.

AutomaticStatic (in a function)Global
DeclaredInside a blockInside a block, with staticOutside all functions
CreatedOn entry to the blockOnce, before mainOnce, before main
DestroyedOn leaving the blockAt program endAt program end
Default valueNone. Undefined00
Visible toThat blockThat functionThe whole file

Use automatic variables. A global is visible to everything, so any function may have changed it, and working out what a program does then means reading all of it. Chapter 21 says the same thing about blocks.

Here are the three side by side, with the counting they make possible:

#include <stdio.h>

int total_calls = 0;              /* global: zero by default, set here for clarity */

int count_up(void)
{
    static int mine = 0;          /* static: survives between calls */
    int fresh = 0;                /* automatic: new every call */

    mine = mine + 1;
    fresh = fresh + 1;
    total_calls = total_calls + 1;
    printf("static %d, automatic %d, global %d\n", mine, fresh, total_calls);
    return mine;
}

int main(void)
{
    count_up();
    count_up();
    count_up();
    return 0;
}
static 1, automatic 1, global 1
static 2, automatic 1, global 2
static 3, automatic 1, global 3

The static variable counts. The automatic one is created afresh each time and cannot. That difference is the whole idea, and it is a standing exam question.

Naming, which is not a side issue

Chapter 6 made clarity the second characteristic after integrity, and a variable's name is where most of a program's clarity comes from.

  • Say what it holds, and in what unit. rate_percent rather than rate. seconds_elapsed rather than time.
  • Length in proportion to scope. i is a perfectly good name for a loop counter that lives three lines. A global needs a name that makes sense far from where it was declared.
  • Be consistent. total_marks and totalMarks in one program means a reader has to remember which you used where. This book uses lower case with underscores, which is the usual style in C.
  • Do not encode the type. int iCount tells a reader what the declaration already told them.
munotes.in52

Variables: Declaration, Definition and Initialisation

What this does NOT mean

Declaring a variable does not give it a value. For an automatic variable it gives you a name for some memory whose contents are whatever they were. This is the single most common first-year bug.

Initialisation is not assignment. Initialisation happens once, when the object is created, and is the only way to set a const object or an array's contents. Assignment happens whenever the statement runs. For const int n = 5; the first is legal and n = 6; is not.

static does not mean constant. A static variable can be changed as freely as any other. What static fixes is how long it lives and who can see it.

A global variable is not "faster because it is not passed". It is a name with a long life and no owner. The cost of passing a parameter is nothing; the cost of not knowing who changed a value is hours.

C does not zero your automatic variables and you must not rely on a compiler that appears to. Many compilers in a debug build fill new memory with a recognisable pattern, which makes the bug visible. The same program in a release build will do something else.

Quick revision

  • A variable is named memory of a known type. int marks; defines one.
  • A definition creates storage. A declaration, with extern, only promises one exists.
  • Every definition is a declaration; not every declaration is a definition.
  • Since C99, a declaration may go anywhere a statement may go. Declare at first use.
  • Initialisation sets a value when the object is created; assignment sets it later.
  • An uninitialised automatic variable holds rubbish, and reading it is undefined behaviour.
  • Static and global variables are zero by default. Automatic ones are not.
  • A static variable in a function is created once and keeps its value between calls.
  • Prefer automatic variables. Prefer names that say what the value is and in what unit.

Test yourself

1. What is the difference between a declaration and a definition?

A definition creates the variable and sets aside memory for it. A declaration states the name and type and promises a definition exists elsewhere, which is what extern int x; does. A variable is defined once and may be declared many times.

2. What is the value of x after int x; inside a function?

Unspecified. The variable holds whatever was in that memory, and reading it before assigning to it is undefined behaviour.

3. And after static int x; inside a function?

Zero. Static and global objects with no initialiser are set to zero before the program starts.

munotes.in53

Variables: Declaration, Definition and Initialisation

4. What does this print, and why?

void f(void) { static int n = 0; n++; printf("%d ", n); }
/* called three times */

1 2 3. The static variable is created once and keeps its value between calls.

5. Why is int a = b = 0; a mistake in a declaration?

Because only a is being declared. b must already exist, and if it does not the line does not compile. Declare and initialise each variable in its own right.

6. Give two reasons to prefer an automatic variable to a global one.

It cannot be changed by any other function, so the reasoning about its value is local. And it exists only while it is needed, so two parts of the program cannot accidentally share it.

What can be asked on this, and how to answer it

"What is a variable? How is it declared and initialised?" Define it as a named location in memory of a given type whose value can change while the program runs. Give the declaration form, the initialisation form, and the distinction between initialisation and assignment. Add that an automatic variable with no initialiser has no defined value, which is the part that earns the extra mark.

"Distinguish between declaration and definition of a variable." Give the two-sentence answer above with int x; against extern int x;, and the rule that one definition and many declarations are allowed.

"Explain the storage classes in C." Name auto, static, extern and register, and for each give where it is written, how long the variable lives, who can see it and what its default value is. The table in this chapter is the answer; register is a request that the value be kept in a processor register, which modern compilers ignore, and its one real consequence is that you cannot take its address.

"What happens if a variable is used without initialising it?" Its value is whatever was in that memory, reading it is undefined behaviour, and the program may print anything or behave differently on different runs or different compilers. Static and global variables are the exception: they are zero.

"Write a program to show the difference between an automatic and a static variable." Give the three-call program in this chapter and point at the two columns of its output.

munotes.in54

The rest of this subject

These notes are cut from the University's printed syllabus. Open the syllabus itself for the same subject.

Report or request
Done!