Kodewick
Lesson 9 of 30Contents

Scope and static

Lesson 9 of 30 · Part 2 · Functions and arrays · about 15 minutes

Where a variable can be used is called its scope. So far, every variable has been declared inside a function, and can only be used in that function. Two functions can each have a variable with the same name, and the two have nothing to do with each other:

main.c
1#include <stdio.h>2 3void morning(void) {4    int steps = 3200;5    printf("Morning: %d steps\n", steps);6}7 8void evening(void) {9    int steps = 5100;10    printf("Evening: %d steps\n", steps);11}12 13int main(void) {14    morning();15    evening();16    return 0;17}
Output
Morning: 3200 steps
Evening: 5100 steps

Local variables

A variable declared inside a function is a local variable. It is created each time the function is called and is gone when the function ends. Other functions can't see it, and neither can main:

main.c
1#include <stdio.h>2 3void add_tax(int price) {4    int total = price + price / 10;5    printf("With tax: %d\n", total);6}7 8int main(void) {9    add_tax(200);10    printf("%d\n", total);11    return 0;12}
Output
main.c: In function 'main':
main.c:10:20: error: 'total' undeclared (first use in this function)
   10 |     printf("%d\n", total);
      |                    ^~~~~
main.c:10:20: note: each undeclared identifier is reported only once for each function it appears in

total lives only inside add_tax. In main, the compiler doesn't know the name at all: 'total' undeclared means "total was never declared". Parameters are local variables too: price can also only be used inside add_tax.

To hand the result to main, use return, as in the last lesson.

Variables in blocks

Not only functions: any pair of curly braces { } is a block. A variable declared inside a block can't be used once you are outside those braces:

main.c
1#include <stdio.h>2 3int main(void) {4    int hours = 10;5    if (hours > 8) {6        int extra = hours - 8;7        printf("Overtime: %d hours\n", extra);8    }9    printf("Total %d hours, overtime %d hours\n", hours, extra);10    return 0;11}
Output
main.c: In function 'main':
main.c:9:58: error: 'extra' undeclared (first use in this function)
    9 |     printf("Total %d hours, overtime %d hours\n", hours, extra);
      |                                                          ^~~~~
main.c:9:58: note: each undeclared identifier is reported only once for each function it appears in

extra is declared in the if block, and line 9 is already outside it. To use it outside, declare it outside, for example with int extra = 0; before the if. The i in for (int i = 0; ...) works the same way: it exists only in that loop.

Global variables

A variable declared outside all functions is a global variable. Every function below its declaration can use it, and it lives from the start of the program to the end:

main.c
1#include <stdio.h>2 3int visitors = 0;4 5void welcome(void) {6    visitors++;7    printf("Welcome, you are visitor %d\n", visitors);8}9 10int main(void) {11    welcome();12    welcome();13    welcome();14    printf("%d visitors today\n", visitors);15    return 0;16}
Output
Welcome, you are visitor 1
Welcome, you are visitor 2
Welcome, you are visitor 3
3 visitors today

welcome and main use the same visitors. Press Step to watch: a global variable isn't in any function's stack frame. It sits on its own, and when one function changes it, everyone sees the new value.

A global variable with no starting value is 0 automatically. A local variable is not: using one before giving it a value is a mistake (you saw this in lesson 2).

Shadowing

An inner scope can declare a variable with the same name as one outside. Inside, the name then means the inner variable, and the outer one is shadowed: hidden for now.

Guess first

What does this print?

1#include <stdio.h>2 3int count = 100;4 5int main(void) {6    int count = 5;7    count++;8    printf("%d\n", count);9    return 0;10}

A block can shadow an outer variable too. Once the block ends, the outer one is back:

main.c
1#include <stdio.h>2 3int main(void) {4    int score = 70;5    if (score < 80) {6        int score = 80;7        printf("In the block: %d\n", score);8    }9    printf("Outside: %d\n", score);10    return 0;11}
Output
In the block: 80
Outside: 70

Just because you can doesn't mean you should. Two variables with one name are easy to mix up; give them different names.

static local variables

An ordinary local variable is created again on every call, so nothing is kept from last time. The count below starts at 0 every time, so it always prints 1:

main.c
1#include <stdio.h>2 3void press(void) {4    int count = 0;5    count++;6    printf("Presses so far: %d\n", count);7}8 9int main(void) {10    press();11    press();12    press();13    return 0;14}
Output
Presses so far: 1
Presses so far: 1
Presses so far: 1

Put static in front of the declaration and it becomes a static local variable. Only this function can use it (its scope is still local), but like a global it lives from the start of the program to the end. The = 0 happens once, at the very start; after that, each call finds the value from last time:

main.c
1#include <stdio.h>2 3void press(void) {4    static int count = 0;5    count++;6    printf("Presses so far: %d\n", count);7}8 9int main(void) {10    press();11    press();12    press();13    return 0;14}
Output
Presses so far: 1
Presses so far: 2
Presses so far: 3

Press Step on both and compare. In the first, every call gives press a stack frame with a new count that starts at 0. In the second, count isn't in the stack frame: it stays when the function ends, and the next call keeps adding to it.

Use globals sparingly

Globals are handy, but anyone can change them. In a long program, when a value is wrong, you have to check every function to find out who changed it. This program is meant to print 3 rows of stars, but main and print_stars share one global i:

main.c
1#include <stdio.h>2 3int i;4 5void print_stars(int n) {6    for (i = 0; i < n; i++) {7        printf("*");8    }9    printf("\n");10}11 12int main(void) {13    for (i = 0; i < 3; i++) {14        print_stars(5);15    }16    return 0;17}
Output
*****

Only 1 row. When print_stars finishes, i is already 5. Back in main, i++ makes it 6, i < 3 is false, and the loop ends. Press Step and keep an eye on i. Delete int i; and write for (int i = 0; ...) in both loops, so each has its own local variable, and it works.

Tip: Give a function the values it needs as parameters, and hand back its result with return. Then the first line of a function tells you what it uses and what it gives back.

Practice

Write the code, then press Check. A hint costs nothing; the answer is there when you need it.

Exercise 1

Take a number

Each call to next_ticket should return the next number: 1, 2, 3... Right now it returns 1 every time. Fix it so the program prints Ticket 1, Ticket 2 and Ticket 3, each on its own line.

It should print
Ticket 1
Ticket 2
Ticket 3
exercise1.c
1#include <stdio.h>2 3int next_ticket(void) {4    int number = 0;5    number++;6    return number;7}8 9int main(void) {10    printf("Ticket %d\n", next_ticket());11    printf("Ticket %d\n", next_ticket());12    printf("Ticket %d\n", next_ticket());13    return 0;14}
Output
Press Run or Ctrl+Enter
Exercise 2

Shipping

This program doesn't compile. Fix it: orders of 100 or more ship free; otherwise shipping is 12. The program should print Shipping: 12.

It should print
Shipping: 12
exercise2.c
1#include <stdio.h>2 3int main(void) {4    int amount = 85;5    if (amount < 100) {6        int shipping = 12;7    }8    printf("Shipping: %d\n", shipping);9    return 0;10}
Output
Press Run or Ctrl+Enter
Exercise 3

Shopping cart

add adds a price to the global total, yet the program ends by printing Total: 0. Find out why and fix it, so the program prints Total: 60.

It should print
Total: 60
exercise3.c
1#include <stdio.h>2 3int total = 0;4 5void add(int price) {6    total = total + price;7}8 9int main(void) {10    int total = 0;11    add(25);12    add(35);13    printf("Total: %d\n", total);14    return 0;15}
Output
Press Run or Ctrl+Enter

What you learned

  • A variable's scope is where it can be used.
  • Variables declared in a function or a block are local: they can only be used inside their own braces. Parameters are local too.
  • Variables declared outside all functions are global: every function can use them, and they start at 0 if not given a value.
  • An inner variable with the same name shadows the outer one; better not to name them that way.
  • A static local variable can only be used in its own function, but it stays alive and remembers its value.
  • Use globals sparingly: pass in what a function needs as parameters and hand back the result with return.