Lecture 10 Program - Organization - Programming Language
Lecture 10 Program - Organization - Programming Language
1
Local Variables
A variable declared in the body of a function is said
to be local to the function:
int sum_digits(int n)
{
int sum = 0; /* local variable */
while (n > 0) {
sum += n % 10;
n /= 10;
}
return sum;
}
2
Local Variables
Default properties of local variables:
Automatic storage duration. Storage is
“automatically” allocated when the enclosing
function is called and deallocated when the
function returns.
Block scope. A local variable is visible from
its point of declaration to the end of the
enclosing function body.
3
Static Local Variables
Including static in the declaration of a local variable
causes it to have static storage duration.
A variable with static storage duration has a permanent
storage location, so it retains its value throughout the
execution of the program.
Example:
void f(void)
{
static int i; /* static local variable */
…
}
A static local variable still has block scope, so it’s not
visible to other functions.
5
Parameters
Parameters have the same properties—
automatic storage duration and block scope—
as local variables.
Each parameter is initialized automatically
when a function is called (by being assigned
the value of the corresponding argument).
6
External Variables
Passing arguments is one way to transmit
information to a function.
Functions can also communicate through
global variables.
7
External Variables
Properties of external variables:
Static storage duration
◼ External variables have static storage duration, just like
local variables that have been declared static. A
value stored in an external variable will stay there
indefinitely.
File scope
◼ An External variable has file scope: it is visible from its
point of declaration to the end of the enclosing file. As
a result, an external variable can be accessed (and
potentially modified) by all functions that follow its
declaration. 8
Example: Using External Variables
to Implement a Stack
To illustrate how external variables might be
used, let’s look at a data structure known as a
stack.
A stack, like an array, can store multiple data
items of the same type.
The operations on a stack are limited:
Push an item (add it to one end—the “stack top”)
Pop an item (remove it from the same end)
11
Example: Using External Variables
to Implement a Stack
#include <stdbool.h> /* C99 only */
#define STACK_SIZE 100
/* external variables */
int contents[STACK_SIZE];
int top = 0;
void make_empty(void)
{
top = 0;
}
bool is_empty(void)
{
return top == 0;
}
12
Example: Using External Variables
to Implement a Stack
bool is_full(void)
{
return top == STACK_SIZE;
}
void push(int i)
{
if (is_full())
stack_overflow();
else
contents[top++] = i;
}
int pop(void)
{
if (is_empty())
stack_underflow();
else
return contents[--top];
}
13
Pros and Cons of External
Variables
External variables are convenient when many functions
must share a variable or when a few functions share a
large number of variables.
In most cases, it’s better for functions to communicate
through parameters rather than by sharing variables:
If we change an external variable during program maintenance
(by altering its type, say), we’ll need to check every function in
the same file to see how the change affects it.
If an external variable is assigned an incorrect value, it may be
difficult to identify the guilty function.
Functions that rely on external variables are hard to reuse in
other programs. 14
Practice
The code below is supposed to display a 10 × 10 arrangement of
asterisks:
15
Practice
16
Program: Guessing a Number
The guess.c program generates a random number
between 1 and 100, which the user attempts to guess in as
few tries as possible:
Guess the secret number between 1 and 100.
A new number has been chosen.
Enter guess: 55
Too low; try again.
Enter guess: 65
Too high; try again.
Enter guess: 60
Too high; try again.
Enter guess: 58
You won in 4 guesses!
17
Program: Guessing a Number
Play again? (Y/N) y
A new number has been chosen.
Enter guess: 78
Too high; try again.
Enter guess: 34
You won in 2 guesses!
Play again? (Y/N) n
Tasks to be carried out by the program:
Initialize the random number generator
Choose a secret number
Interact with the user until the correct number is picked
Each task can be handled by a separate function.
18
guess.c
/* Asks user to guess a hidden number */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
/* external variable */
int secret_number;
/* prototypes */
void initialize_number_generator(void);
void choose_new_secret_number(void);
void read_guesses(void);
19
int main(void)
{
char command;
printf("Guess the secret number between 1 and %d.\n\n",
MAX_NUMBER);
initialize_number_generator();
do {
choose_new_secret_number();
printf("A new number has been chosen.\n");
read_guesses();
printf("Play again? (Y/N) ");
scanf(" %c", &command);
printf("\n");
} while (command == 'y' || command == 'Y');
return 0;
}
20
/**********************************************************
* initialize_number_generator: Initializes the random *
* number generator using *
* the time of day. *
**********************************************************/
void initialize_number_generator(void)
{
srand((unsigned) time(NULL));
}
/**********************************************************
* choose_new_secret_number: Randomly selects a number *
* between 1 and MAX_NUMBER and *
* stores it in secret_number. *
**********************************************************/
void choose_new_secret_number(void)
{
secret_number = rand() % MAX_NUMBER + 1;
}
21
/**********************************************************
* read_guesses: Repeatedly reads user guesses and tells *
* the user whether each guess is too low, *
* too high, or correct. When the guess is *
* correct, prints the total number of *
* guesses and returns. *
**********************************************************/
void read_guesses(void)
{
int guess, num_guesses = 0;
for (;;) {
num_guesses++;
printf("Enter guess: ");
scanf("%d", &guess);
if (guess == secret_number) {
printf("You won in %d guesses!\n\n", num_guesses);
return;
} else if (guess < secret_number)
printf("Too low; try again.\n");
else
printf("Too high; try again.\n");
}
}
22
Program: Guessing a Number
Although guess.c works fine, it relies on the
external variable secret_number.
By altering choose_new_secret_number and
read_guesses slightly, we can move
secret_number into the main function.
The new version of guess.c follows, with
changes in bold.
23
guess2.c
/* Asks user to guess a hidden number */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
/* prototypes */
void initialize_number_generator(void);
int new_secret_number(void);
void read_guesses(int secret_number);
24
int main(void)
{
char command;
int secret_number;
return 0;
} 25
/**********************************************************
* initialize_number_generator: Initializes the random *
* number generator using *
* the time of day. *
**********************************************************/
void initialize_number_generator(void)
{
srand((unsigned) time(NULL));
}
/**********************************************************
* new_secret_number: Returns a randomly chosen number *
* between 1 and MAX_NUMBER. *
**********************************************************/
int new_secret_number(void)
{
return rand() % MAX_NUMBER + 1;
}
26
/**********************************************************
* read_guesses: Repeatedly reads user guesses and tells *
* the user whether each guess is too low, *
* too high, or correct. When the guess is *
* correct, prints the total number of *
* guesses and returns. *
**********************************************************/
void read_guesses(int secret_number)
{
int guess, num_guesses = 0;
for (;;) {
num_guesses++;
printf("Enter guess: ");
scanf("%d", &guess);
if (guess == secret_number) {
printf("You won in %d guesses!\n\n", num_guesses);
return;
} else if (guess < secret_number)
printf("Too low; try again.\n");
else
printf("Too high; try again.\n");
}
}
27
Blocks
In Ch05, we encountered compound statements
of the form
{ statements }
C allows compound statements to contain
declarations as well as statements:
{ declarations statements }
This kind of compound statement is called a
block.
28
Blocks
Example of a block:
if (i > j) {
/* swap values of i and j */
int temp = i;
i = j;
j = temp;
}
29
Blocks
By default, the storage duration of a variable
declared in a block is automatic: storage for the
variable is allocated when the block is entered and
deallocated when the block is exited.
The variable has block scope; it can’t be referenced
outside the block.
A variable that belongs to a block can be declared
static to give it static storage duration.
30
Blocks
The body of a function is a block.
Blocks are also useful inside a function body
31
Scope
In a C program, the same identifier may have several
different meanings.
C’s scope rules enable the programmer (and the compiler)
to determine which meaning is relevant at a given point in
the program.
The most important scope rule: When a declaration inside
a block names an identifier that’s already visible, the new
declaration temporarily “hides” the old one, and the
identifier takes on a new meaning.
At the end of the block, the identifier regains its old
meaning.
32
Scope
In Declaration 1, i is a
variable with static
storage duration and file
scope.
In Declaration 2, i is a
parameter with block
scope.
In Declaration 3, i is an
automatic variable with
block scope.
In Declaration 4, i is
also automatic and has
block scope. 33
Organizing a C Program
Major elements of a C program:
Preprocessing directives such as #include and
#define
Type definitions
Declarations of external variables
Function prototypes
Function definitions
34
Organizing a C Program
C imposes only a few rules on the order of these
items:
A preprocessing directive doesn’t take effect until the
line on which it appears.
A type name can’t be used until it’s been defined.
35
Organizing a C Program
There are several ways to organize a program so
that these rules are obeyed.
One possible ordering:
#include directives
#define directives
Type definitions
Definition of main
37
Program: Classifying a Poker
Hand
The poker.c program will classify a poker hand.
Each card in the hand has a suit and a rank.
Suits: clubs♣, diamonds♦, hearts♥, spades♠
Ranks: two, three, four, five, six, seven, eight, nine, ten, jack,
queen, king, ace
Jokers are not allowed, and aces are high.
After reading a hand of five cards, the program will
classify the hand using the categories on the next slide.
If a hand falls into two or more categories, the
program will choose the best one.
38
Program: Classifying a Poker Hand
Categories (listed from best to worst):
straight flush (both a straight and a flush)
four-of-a-kind (four cards of the same rank)
full house (a three-of-a-kind and a pair)
flush (five cards of the same suit)
straight (five cards with consecutive ranks)
three-of-a-kind (three cards of the same rank)
two pairs
pair (two cards of the same rank)
high card (any other hand)
39
Program: Classifying a Poker Hand
For input purposes, ranks and suits will be single letters
(upper- or lower-case):
Ranks: 2 3 4 5 6 7 8 9 t j q k a
Suits: c d h s
Actions to be taken if the user enters an illegal card or
tries to enter the same card twice:
Ignore the card
Issue an error message
Request another card
Entering the number 0 instead of a card will cause the
program to terminate.
40
Program: Classifying a Poker Hand
A sample session with the program:
Enter a card: 2s
Enter a card: 5s
Enter a card: 4s
Enter a card: 3s
Enter a card: 6s
Straight flush
41
Program: Classifying a Poker Hand
Enter a card: 8c
Enter a card: as
Enter a card: 8c
Duplicate card; ignored.
Enter a card: 7c
Enter a card: ad
Enter a card: 3h
Pair
42
Program: Classifying a Poker Hand
Enter a card: 6s
Enter a card: d2
Bad card; ignored.
Enter a card: 2d
Enter a card: 9c
Enter a card: 4h
Enter a card: ts
High card
Enter a card: 0
43
Program: Classifying a Poker Hand
The program has three tasks:
Read a hand of five cards
Analyze the hand for pairs, straights, and so forth
44
Program: Classifying a Poker Hand
The functions will need to share a fairly large
amount of information, so we’ll have them
communicate through external variables.
read_cards will store information about the
hand into several external variables.
analyze_hand will then examine these variables,
storing its findings into other external variables for
the benefit of print_result.
45
Program: Classifying a Poker Hand
Program outline:
/* #include directives go here */
/* prototypes */
void read_cards(void);
void analyze_hand(void);
void print_result(void);
46
Program: Classifying a Poker Hand
/**********************************************************
* main: Calls read_cards, analyze_hand, and print_result *
* repeatedly. *
**********************************************************/
int main(void)
{
for (;;) {
read_cards();
analyze_hand();
print_result();
}
}
/**********************************************************
* read_cards: Reads the cards into external variables; *
* checks for bad cards and duplicate cards. *
**********************************************************/
void read_cards(void)
{
…
}
47
Program: Classifying a Poker Hand
/**********************************************************
* analyze_hand: Determines whether the hand contains a *
* straight, a flush, four-of-a-kind, *
* and/or three-of-a-kind; determines the *
* number of pairs; stores the results into *
* external variables. *
**********************************************************/
void analyze_hand(void)
{
…
}
/**********************************************************
* print_result: Notifies the user of the result, using *
* the external variables set by *
* analyze_hand. *
**********************************************************/
void print_result(void)
{
…
}
48
Program: Classifying a Poker Hand
How should we represent the hand of cards?
analyze_hand will need to know how many cards
are in each rank and each suit.
This suggests that we use two arrays, num_in_rank
and num_in_suit.
num_in_rank[r] will be the number of cards with rank r.
num_in_suit[s] will be the number of cards with suit s.
We’ll encode ranks as numbers between 0 and 12.
Suits will be numbers between 0 and 3.
49
Program: Classifying a Poker Hand
We’ll also need a third array, card_exists, so
that read_cards can detect duplicate cards.
Each time read_cards reads a card with rank r
and suit s, it checks whether the value of
card_exists[r][s] is true.
If so, the card was previously entered.
If not, read_cards assigns true to
card_exists[r][s].
50
Program: Classifying a Poker Hand
Both the read_cards function and the
analyze_hand function will need access to the
num_in_rank and num_in_suit arrays, so
they will be external variables.
The card_exists array is used only by
read_cards, so it can be local to that function.
As a rule, variables should be made external only if
necessary.
51
poker.c
/* Classifies a poker hand */
NUM_RANKS
#define NUM_RANKS 13 2 3 4 5 6 7 8 9 T J Q K A
#define NUM_SUITS 4
#define NUM_CARDS 5 0 1 2 3
NUM_SUITS
/* external variables */
int num_in_rank[NUM_RANKS]; C D H S
int num_in_suit[NUM_SUITS];
bool straight, flush, four, three;
int pairs; /* can be 0, 1, or 2 */
52
/* prototypes */
void read_cards(void);
void analyze_hand(void);
void print_result(void);
/**********************************************************
* main: Calls read_cards, analyze_hand, and print_result *
* repeatedly. *
**********************************************************/
int main(void)
{
for (;;) {
read_cards();
analyze_hand();
print_result();
}
}
53
/**********************************************************
* read_cards: Reads the cards into the external *
* variables num_in_rank and num_in_suit; *
* checks for bad cards and duplicate cards. *
**********************************************************/
void read_cards(void)
{
bool card_exists[NUM_RANKS][NUM_SUITS];
char ch, rank_ch, suit_ch;
int rank, suit;
bool bad_card;
int cards_read = 0;
54
while (cards_read < NUM_CARDS) {
bad_card = false;
printf("Enter a card: ");
rank_ch = getchar();
switch (rank_ch) {
case '0': exit(EXIT_SUCCESS);
case '2': rank = 0; break;
case '3': rank = 1; break;
case '4': rank = 2; break;
case '5': rank = 3; break;
case '6': rank = 4; break;
case '7': rank = 5; break;
case '8': rank = 6; break;
case '9': rank = 7; break;
case 't': case 'T': rank = 8; break;
case 'j': case 'J': rank = 9; break;
case 'q': case 'Q': rank = 10; break;
case 'k': case 'K': rank = 11; break;
case 'a': case 'A': rank = 12; break;
default: bad_card = true;
} 55
suit_ch = getchar();
switch (suit_ch) {
case 'c': case 'C': suit = 0; break;
case 'd': case 'D': suit = 1; break;
case 'h': case 'H': suit = 2; break;
case 's': case 'S': suit = 3; break;
default: bad_card = true;
}
while ((ch = getchar()) != '\n')
if (ch != ' ') bad_card = true;
if (bad_card)
printf("Bad card; ignored.\n");
else if (card_exists[rank][suit])
printf("Duplicate card; ignored.\n");
else {
num_in_rank[rank]++;
num_in_suit[suit]++;
card_exists[rank][suit] = true;
cards_read++;
}
}
}
56
/**********************************************************
* analyze_hand: Determines whether the hand contains a *
* straight, a flush, four-of-a-kind, *
* and/or three-of-a-kind; determines the *
* number of pairs; stores the results into *
* the external variables straight, flush, *
* four, three, and pairs. *
**********************************************************/
void analyze_hand(void)
{
int num_consec = 0;
int rank, suit;
straight = false;
flush = false;
four = false;
three = false;
pairs = 0;
57
/* check for flush */
for (suit = 0; suit < NUM_SUITS; suit++)
if (num_in_suit[suit] == NUM_CARDS)
flush = true;
/* check for straight */
rank = 0;
while (num_in_rank[rank] == 0) rank++;
for (; rank < NUM_RANKS && num_in_rank[rank] > 0; rank++)
num_consec++;
if (num_consec == NUM_CARDS) {
straight = true;
return;
}
/* check for 4-of-a-kind, 3-of-a-kind, and pairs */
for (rank = 0; rank < NUM_RANKS; rank++) {
if (num_in_rank[rank] == 4) four = true;
if (num_in_rank[rank] == 3) three = true;
if (num_in_rank[rank] == 2) pairs++;
}
} 58
/**********************************************************
* print_result: Prints the classification of the hand, *
* based on the values of the external *
* variables straight, flush, four, three, *
* and pairs. *
**********************************************************/
void print_result(void)
{
if (straight && flush) printf("Straight flush");
else if (four) printf("Four of a kind");
else if (three &&
pairs == 1) printf("Full house");
else if (flush) printf("Flush");
else if (straight) printf("Straight");
else if (three) printf("Three of a kind");
else if (pairs == 2) printf("Two pairs");
else if (pairs == 1) printf("Pair");
else printf("High card");
printf("\n\n");
}
59
Practice
Rewrite the poker.c program to automatically
produce five cards instead of manual input.
(hint: refer to Ch08, deal.c program.)
60