0% found this document useful (0 votes)
2 views

C slides

The document outlines a Computer Programming course at Politehnica Timisoara, focusing on the C programming language and fundamental programming concepts. It includes course logistics, learning objectives, textbooks, grading policies, and an overview of the von Neumann architecture. The document also discusses higher-level programming languages, compilers, and provides examples of C programs and their components.

Uploaded by

yohana.bezuayene
Copyright
© © All Rights Reserved
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views

C slides

The document outlines a Computer Programming course at Politehnica Timisoara, focusing on the C programming language and fundamental programming concepts. It includes course logistics, learning objectives, textbooks, grading policies, and an overview of the von Neumann architecture. The document also discusses higher-level programming languages, compilers, and provides examples of C programs and their components.

Uploaded by

yohana.bezuayene
Copyright
© © All Rights Reserved
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
You are on page 1/ 411

Computer Programming

Lecture Slides

Politehnica Timisoara International-


Computer Engineering Study Program
Lecture 1: Outline
• Introductions
• Course Logistics and Syllabus
– Learning Objectives
– Textbooks
– Labs
– Grading
• Some Fundamentals
• Compiling and running your first C
program
Course organization
• Ioana Şora, PhD, Associate Professor
• Lectures: Tuesday, 10-13, A204
• http://bigfoot.cs.upt.ro/~ioana/
– Course info, Lecture slides
• Email: [email protected]
• Labs: Gabriela Bobu, Teaching Assistant
– Classes: room B418, Mondays
Learning Objectives
•First course in Computer Science
– No previous knowledge is assumed !
•By the end of the course, students will:
– Understand fundamental concepts of
computer programming/imperative structured
programming languages
– Design algorithms to solve (simple) problems
– Use the C programming language
Textbooks
• Stephen Kochan, Programming in C, 3rd Edition, Sams
Publishing, 2005
– Main (first) textbook for this course
– Teaches you how to program (in C)
– Follows an approach suited for a first programming language
• Brian Kernighan and Dennis Ritchie, The C
Programming Language, 2nd Edition, Prentice Hall
– Is considered “THE” book on C : coauthor belongs to the
creators of the C programming language
– The book is not an introductory programming manual; it
assumes some familiarity with basic programming concepts
• Ioana Şora, Doru Todinca, Introducere in programarea
calculatoarelor, Editura Politehnica, 2004.
– Lecture notes for a beginner learning approach
Policies and Grading
• Lectures: can be interactive, with questions and
interactive problem solving
• Labs: mandatory attendance
– Each lab session has a practical programming
assignement to be done individually in class
– Read lecture slides and corresponding textbook
chapters before attending the lab session !
• Final grade:
– 60% written exam (answer punctual questions and
write C programs to solve given exercises)
– 30% lab sessions
– 10% course activity
Course chapters [Kochan]
• Some Fundamentals
• Compiling and Running your First C Program
• Variables, Data Types, and Arithmetic Expressions
• Program Looping
• Making Decisions
• Working with Arrays
• Working with Functions
• Working with Structures
• Character Strings
• Pointers
• Operations on Bits
• The Preprocessor
• More on Data Types
• Working with Larger Programs
• Input and Output Operations in C
• Miscellaneous and Advanced Features
Fundamentals – Chapter outline:
• Classical model for computing machines
• Programming
• Programming languages
• Compiling
• Operating system

Setting the basic


concepts and
terminology …
Model of a computing machine
• Computing machine (Computer): “a machine that stores and manipulates information
under the control of a changeable program that is stored in its memory.”

– Pocket calculator: not a computer ! Manipulates information, but is built to do a specific task (no changeable stored
program)
• This model is named the “von Neumann architecture” (John von Neumann – 1945; EDVAC - Electronic Discrete Variable
Automatic Computer – the first stored-program computer)
• Stored-program concept: earlier ideas in theoretical articles of: Alan Turing (1936), Konrad Zuse (1936)
Model of a computing machine

• Optional reading: History of computing – IEEE Computer


Society – timeline of occasions in computing history
• http://www.computer.org/cms/Computer.org/Publications/timeline.pdf
The von Neumann architecture

CPU
Input Device Output Device
ALU CU

Main memory Secondary


(RAM) storage
The von Neumann architecture
• Central Processing Unit (CPU): the “brain” of the machine.
– CU: Control Unit
– ALU: Arithmetic and Logic Unit
• Carries out all basic operations of the computer
• Examples of basic operation: adding two numbers, testing to see if two numbers are equal.
• Main memory (called RAM for Random Access Memory): stores programs and data
– Fast but volatile
• Secondary memory: provides permanent storage
• Human-computer interaction: through input and output devices.
– keyboard, mouse, monitor
– Information from input devices is processed by the CPU and may be sent to the main or secondary memory. When
information needs to be displayed, the CPU sends it to the output device(s).
How it works
• How does a computer execute a program ? (example
programs: a computer game, a word processor, etc)
• the instructions that comprise the program are copied
from the permanent secondary memory into the main
memory
• After the instructions are loaded, the CPU starts
executing the program.
• For each instruction, the instruction is retrieved from
memory, decoded to figure out what it represents, and
the appropriate action carried out. (the fetch- execute
cycle)
• Then the next instruction is fetched, decoded and
executed.
Machine level programming
• Example: suppose we want the computer to add
two numbers, and if the preliminary result is less
than 10, then add 10 to the result

• The instructions that the CPU carries out might be :


[INSTR1] Load into ALU the number from mem location 15
[INSTR2] Load into ALU the number from mem location 7
[INSTR3] Add the two numbers in the ALU
[INSTR4] If result is bigger than 10 jump to [INSTR6]
[INSTR5] Add 10 to the number in the ALU
[INSTR6] Store the result from ALU into mem location 3

• The processors instruction set: all basic operations that


can be carried out by a certain type of processor
Machine level programming
• the instructions and operands are represented in binary notation
(sequences of 0s and 1s).
– Why binary ? Because computer hardware relies on electric/electronic circuits
that have/can switch between 2 states
– bit (binary digit)
– Byte: 8 bits
• The program carried out by the CPU, on a hypothetical processor type,
could be:
1010 1111
1011 0111
0111

• This way had to be programmed the first computers !
• The job of the first programmers was to code directly in machine language
and to enter their programs using switches
Example: old computer frontpanel

LEDS display the current


memory address and
contents of current memory
location or registers

SWITCHES allow programmer to


enter binary data / instructions
Higher level languages
• Assembly language
– First step from machine language
– Uses symbolic names for operations

– Example: a hypothetical assembly language program


sequence:

1010 1111 LD1 15


1011 0111 LD2 7
0111 ADD
0011 1010
CMP 10
0010 1100 JGE 12
0110 1010 ADD 10
… …
• Assembly language (cont)
– Translation of assembly language into machine
language: in the beginning done manually, later done
by a special computer program – the assembler
– Disadvantages: Low-level language:
• programmer must learn the instruction set of the particular
processor
• Program must be rewritten in order to run on a different
processor type – program is not portable
Higher level languages
• High level languages
– Using more abstract instructions
– Portable programs result

– Example: a hypothetical program sequence:

DEFVAR a,b,c;
BEGIN
READ a
READ b
READ c
c := a+b
IF (c <10) THEN c:=c+10
PRINT c
END …
• High level languages
– Writing portable programs, using more abstract
instructions
– A high level instruction (statement) is translated into
many machine instructions
– Translation of high level language into machine
instructions: done by special computer programs –
compilers or interpreters
Compilers/Interpreters

Source Machine Source


Compiler
Code Code Code

Interpreter

Input Executable Output Input Output


data Program data data data

Compiler: analyzes program and Interpreter: analyzes and executes


translates it into machine language program statements at the same
Executable program: can be run time
independently from compiler as Execution is slower
many times => fast execution Easier to debug program
Operating Systems
• Operating system: a program that controls the
entire operation of a computer system:
– Handles all input and output (I/O) operations that are
performed on a computer
– manages the computer system’s resources
– handles the execution of programs (including
multitasking or multiuser facilities)
• Most famous OS families:
– Windows
– Unix
Higher Level Languages
• Programming Paradigms:
– Imperative Programming: describes the exact
sequences of commands to be executed
• Structured programming, procedural programming
– FORTRAN, C, PASCAL, …
• Object oriented programming
– C++, Java, C#, …
– Declarative programming: program describes what it
should do, not how
• Functional programming
– Lisp, ML, …
• Logic Programming
– Prolog
The C Programming Language
• Developed by Dennis Ritchie at AT&T Bell Laboratories
in the early 1970s
• Growth of C tightly coupled with growth of Unix: Unix
was written mostly in C
• Success of PCs: need of porting C on MS-DOS
• Many providers of C compilers for many different
platforms => need for standardization of the C language
• 1990: ANSI C (American National Standards Institute)
• International Standard Organization: ISO/IEC 9899:1990
• 1999: standard updated: C99, or ISO/IEC 9899:1999
The first C program
uses standard library
input and output functions
(printf)
#include <stdio.h>
the program
int main (void)
begin of program {
printf ("Programming is fun.\n");
statements
return 0;
end of program }

main: a special name that indicates where the program must begin execution. It is
a special function.
first statement: calls a routine named printf, with argument the string of characters
“Programming is fun \n”
last statement: finishes execution of main and returns to the system a status value
of 0 (conventional value for OK)
The format in C
• Statements are terminated with semicolons
• Indentation is nice to be used for increased readability.
• Free format: white spaces and indentation is ignored by
compiler
• C is case sensitive – pay attention to lower and upper
case letters when typing !
– All C keywords and standard functions are lower case
– Typing INT, Int, etc instead of int is a compiler error
• Strings are placed in double quotes
• New line is represented by \n (Escape sequence)
Compiling and running C programs

Editor
Source code
file.c

Compiler
Object code
file.obj

Libraries Linker
Executable code
file.exe
IDE (Integrated
Development
Environment)
C Compilers and IDE’s
• One can:
– use a text editor to edit source code, and then use independent
command-line compilers and linkers
– use an IDE: everything together + facilities to debug, develop
and organize large projects
• There are several C compilers and IDE’s that support
various C compilers
• Lab: Dev-C++ IDE for C and C++, Free Software (under
the GNU General Public License)
– Works with gcc (GNU C Compiler)
• supports the C99 standard
• available on Windows and Unix
– The GNU Project (http://www.gnu.org/): launched in 1984 in
order to develop a complete Unix-like operating system which is
free software - the GNU system.
Debugging program errors

Syntactic Editor
Source code
Errors file.c

Compiler
Object code
file.obj

Libraries Linker
Executable code
file.exe

Semantic
Errors
Syntax and Semantics
• Syntax errors: violation of programming
language rules (grammar)
– "Me speak English good."
– Use valid C symbols in wrong places
– Detected by the compiler
• Semantics errors: errors in meaning:
– "This sentence is excellent Italian."
– Programs are syntactically correct but don’t produce
the expected output
– User observes output of running program
Second program

#include <stdio.h>
int main (void)
{
printf ("Programming is fun.\n");
printf ("And programming in C is even more fun.\n");
return 0;
}
Displaying multiple lines of text

#include <stdio.h>
int main (void)
{
printf ("Testing...\n..1\n...2\n....3\n");
return 0;
}

Output:
It is not necessary
to make a separate Testing...
call to printf for each ..1
line of output ! ...2
....3
Variables
• Programs can use symbolic names for
storing computation data and results
• Variable: a symbolic name for a memory
location
– programmer doesn’t has to worry about
specifying (or even knowing) the value of the
location’s address
• In C, variables have to be declared before
they are used
Using and Displaying Variables
#include <stdio.h>
int main (void)
{
int sum;
sum = 50 + 25;
printf ("The sum of 50 and 25 is %i\n", sum);
return 0;
}

Variable sum declared of type int

Variable sum assigned expression 50+25

Value of variable sum is printed in place of %i

The printf routine call has now 2 arguments: first argument a string containing also a
format specifier (%i), that holds place for an integer value to be inserted here
Displaying multiple values

#include <stdio.h>
int main (void)
{
int value1, value2, sum;
value1 = 50;
value2 = 25;
sum = value1 + value2;
printf ("The sum of %i and %i is %i\n",value1, value2, sum);
return 0;
}

The format string must contain as many placeholders as expressions to be printed


Using comments in a program
• Comment statements are used in a program to
document it and to enhance its readability.
• Useful for human readers of the program – compiler
ignores comments
• Ways to insert comments in C:
– When comments span several lines: start marked with /*, end
marked with */
– Comments at the end of a line: start marked with //
Using comments in a program
/* This program adds two integer values
and displays the results */

#include <stdio.h>
int main (void)
{
// Declare variables
int value1, value2, sum;
// Assign values and calculate their sum
value1 = 50;
value2 = 25;
sum = value1 + value2;
// Display the result
printf ("The sum of %i and %i is %i\n",
value1, value2, sum);
return 0;
}
Computer Programming

Lecture 2
02.10.2012
Lecture 2: Outline
• Variables, Data Types, and Arithmetic Expressions [K- ch.4]
– Working with Variables
– Understanding Data Types and Constants
• The Basic Integer Type int
• The Floating Number Type float
• The Extended Precision Type double
• The Single Character Type char
• The Boolean Data Type _Bool
• Storage sizes and ranges
• Type Specifiers: long, long long, short, unsigned, and signed
– Working with Arithmetic Expressions
• Integer Arithmetic and the Unary Minus Operator
• The Modulus Operator
• Integer and Floating-Point Conversions
– Combining Operations with Assignment: The Assignment Operators
– Types _Complex and _Imaginary
Variables
• Programs can use symbolic names for storing
computation data
• Variable: a symbolic name for a memory location
– programmer doesn’t have to worry about specifying (or even
knowing) the value of the location’s address
• In C, variables have to be declared before they are used
– Variable declaration: [symbolic name(identifier), type]
• Declarations that reserve storage are called definitions
– The definition reserves memory space for the variable, but
doesn’t put any value there
• Values get into the memory location of the variable by
initialization or assignement
Variables - Examples
int a; // declaring a variable of type int

int sum, a1,a2; // declaring 3 variables

int x=7; // declaring and initializing a variable

a=5; // assigning to variable a the value 5

a1=a; // assigning to variable a1 the value of a

L-value R-value

a1=a1+1; // assigning to variable a1 the value of a1+1


// (increasing value of a1 with 1)
Variable declarations

Data type Variable name

Which data types Which variable names


are possible in C ? are allowed in C ?
Variable names
Rules for valid variable names (identifiers) in C :
• Name must begin with a letter or underscore ( _ ) and can be
followed by any combination of letters, underscores, or digits.
• Any name that has special significance to the C compiler (reserved
words) cannot be used as a variable name.
• Examples of valid variable names: Sum, pieceFlag, I, J5x7,
Number_of_moves, _sysflag
• Examples of invalid variable names: sum$value, 3Spencer, int.
• C is case-sensitive: sum, Sum, and SUM each refer to a different
variable !
• Variable names can be as long as you want, although only the first
63 (or 31) characters might be significant. (Anyway, it’s not practical
to use variable names that are too long)
• Choice of meaningful variable names can increase the readability of
a program
Data types
• Basic data types in C: int, float, double, char,
and _Bool.
• Data type int: can be used to store integer numbers (values with
no decimal places)
• Data type type float: can be used for storing floating-point
numbers (values containing decimal places).
• Data type double: the same as type float, only with roughly
twice the precision.
• Data type char: can be used to store a single character, such as
the letter a, the digit character 6, or a semicolon.
• Data type _Bool: can be used to store just the values 0 or 1 (used
for indicating a true/false situation). This type has been added by
the C99 standard (was not in ANSI C)
Example: Using data types
#include <stdio.h>
int main (void)
{
int integerVar = 100;
float floatingVar = 331.79;
double doubleVar = 8.44e+11;
char charVar = 'W';
_Bool boolVar = 0;
printf ("integerVar = %i\n", integerVar);
printf ("floatingVar = %f\n", floatingVar);
printf ("doubleVar = %e\n", doubleVar);
printf ("doubleVar = %g\n", doubleVar);
printf ("charVar = %c\n", charVar);
printf ("boolVar = %i\n", boolVar);
return 0;
}
The basic data type int
• Examples of integer constants: 158, –10, and 0
• No embedded spaces are permitted between the digits,
and values larger than 999 cannot be expressed using
commas. (The value 12,000 is not a valid integer constant
and must be written as 12000.)
• Integer values can be displayed by using the format
characters %i in the format string of a printf call.
• Also the %d format characters can be used to display an
integer (Kernighan&Ritchie C)
• Integers can also be expressed in a base other than
decimal (base 10): octal (base 8) or hexa (base 16).
Octal notation for integers
• Octal notation (base 8): If the first digit of the integer
value is 0, the integer is taken as expressed in octal
notation. In that case, the remaining digits of the value
must be valid base-8 digits and, therefore, must be 0–7.
• Example: Octal value 0177 represents the decimal value
127 (1 × 82 + 7 × 8 + 7).
• An integer value can be displayed in octal notation by
using the format characters %o or %#o in the format
string of a printf statement.
Hexadecimal notation for integers
• Hexadecimal notation (base 16): If an integer constant
is preceded by a zero and the letter x (either lowercase
or uppercase), the value is taken as being expressed in
hexadecimal. Immediately following the letter x are the
digits of the hexadecimal value, which can be composed
of the digits 0–9 and the letters a–f (or A–F). The letters
represent the values 10–15, respectively.
• Example: hexadecimal value 0xA3F represents the
decimal value 2623 (10 × 162 + 3 × 16 + 15).
• The format characters %x, %X , %#x, or %#X display a
value in hexadecimal format
Data display vs data storage
• The option to use decimal, octal or hexadecimal notation
doesn't affect how the number is actually stored internally !
• When/where to use octal and hexa: to express computer-related
values in a more convenient way

int x =16;
printf("%i %#X %#o\n", x,x,x);

0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 storage (binary)

“%i” “%#X” program


“%#o”

16 0X10 020 display


The floating number type float
• A variable declared to be of type float can be used for storing values
containing decimal places.
• Examples of floating-point constants : 3., 125.8, –.0001
• To display a floating-point value at the terminal, the printf conversion
characters %f are used.
• Floating-point constants can also be expressed in scientific notation.The
value 1.7e4 represents the value 1.7 × 104.
• The value before the letter e is known as the mantissa, whereas the value
that follows is called the exponent. This exponent, which can be preceded
by an optional plus or minus sign, represents the power of 10 by which the
mantissa is to be multiplied.
• To display a value in scientific notation, the format characters %e should be
specified in the printf format string.
• The printf format characters %g can be used to let printf decide
whether to display the floating-point value in normal floating-point notation
or in scientific notation.This decision is based on the value of the exponent:
If it’s less than –4 or greater than 5, %e (scientific notation) format is used;
otherwise, %f format is used.
The extended precision type
double
• Type double is very similar to type float, but it is used whenever
the range provided by a float variable is not sufficient. Variables
declared to be of type double can store roughly twice as many
significant digits as can a variable of type float.
• Most computers represent double values using 64 bits.
• Unless told otherwise, all floating-point constants are taken as
double values by the C compiler!
• To explicitly express a float constant, append either an f or F to
the end of the number: 12.5f
• To display a double value, the format characters %f, %e, or %g,
which are the same format characters used to display a float
value, can be used.
The character type char
• A char variable can be used to store a single character.
• A character constant is formed by enclosing the character within a pair of
single quotation marks. Valid examples: 'a', ';', and '0‘.
• Character zero ( ‘0’ ) is not the same as the number (integer constant) 0.
• Do not confuse a character constant with a character string: character ‘0’
and string “0”.
• The character constant ‘\n’—the newline character—is a valid character
constant : the backslash character is a special character in the C system
and does not actually count as a character.
• There are other special characters (escape sequences) that are initiated
with the backslash character: \\, \”, \t
• The format characters %c can be used in a printf call to display the value
of a char variable
• To handle characters internally, the computer uses a numerical code in
which certain integers represent certain characters. The most commonly
used code is the ASCII code
Assigning values to char

char letter; /* declare variable letter of type char */

letter = ‘A'; /* OK */
letter = A; /* NO! Compiler thinks A is a variable */
letter = “A"; /* NO! Compiler thinks “A" is a string */
letter = 65; /* ok because characters are really
stored as numeric values (ASCII code),
but poor style */
Data display vs data storage
/* displays ASCII code for a character */

#include <stdio.h>
int main(void)
{
char ch;
ch='A';
printf("The code for %c is %i.\n", ch, ch);
return 0;
}

0 1 0 0 0 0 0 1 storage (ASCII code)

“%c” “%d” program

A 65 display
The Boolean Data Type _Bool
• A _Bool variable is defined in the language to be large enough to
store just the values 0 and 1.The precise amount of memory that is
used is unspecified.
• _Bool variables are used in programs that need to indicate a
Boolean condition. For example, a variable of this type might be
used to indicate whether all data has been read from a file.
• By convention, 0 is used to indicate a false value, and 1 indicates a
true value. When assigning a value to a _Bool variable, a value of
0 is stored as 0 inside the variable, whereas any nonzero value is
stored as 1.
• To make it easier to work with _Bool variables in your program, the
standard header file <stdbool.h> defines the values bool, true,
and false:
bool endOfData = false;
• The _Bool type has beed added by C99.
• Some compilers (Borland C, Turbo C, Visual C) don’t support it
Storage sizes and ranges
• Every type has a range of values associated with it.
• This range is determined by the amount of storage that is allocated
to store a value belonging to that type of data.
• In general, that amount of storage is not defined in the language. It
typically depends on the computer you’re running, and is, therefore,
called implementation- or machine-dependent.
– For example, an integer might take up 32 bits on your computer, or it
might be stored in 64.You should never write programs that make any
assumptions about the size of your data types !
• The language standards only guarantees that a minimum amount of
storage will be set aside for each basic data type.
– For example, it’s guaranteed that an integer value will be stored in a
minimum of 32 bits of storage, which is the size of a “word” on many
computers.
Integer overflow
• What happens if an integer tries to get a value too big for its type
(out of range)?
#include <stdio.h>
int main(void) {
int i = 2147483647;
printf("%i %i %i\n", i, i+1, i+2);
return 0;
}

Program output:
2147483647 -2147483648 -2147483647

Explanation:
On this computer, int is stored on 32 bits: the first bit represents
the sign, the rest of 31 bits represent the value.
Biggest positive int value here: 231-1 = 2147483647
Floating point round-off error
#include <stdio.h>
int main(void)
{
float a,b;
b = 2.0e20 + 1.0;
a = b - 2.0e20;
printf("%f \n", a);
return 0;
}

Program output:
4008175468544.000000
Explanation: the computer doesn't keep track of enough decimal places !
The number 2.0e20 is 2 followed by 20 zeros and by adding 1
you are trying to change the 21st digit. To do this correctly, the program
would need to be able to store a 21-digit number. A float number is typically
just six or seven digits scaled to bigger or smaller numbers with an
exponent.
Type Specifiers: long, long long,
short, unsigned, signed
• Type specifiers: extend or limit the range of certain basic types on
certain computer systems
• If the specifier long is placed directly before the int declaration, the
declared integer variable is of extended range on some computer
systems.
• Example of a long int declaration: long int factorial;
• On many systems, an int and a long int both have the same
range and either can be used to store integer values up to 32-bits
wide (231–1, or 2,147,483,647).
• A constant value of type long int is formed by optionally appending
the letter L (upper- or lowercase) at the end of an integer constant.
• Example: long int numberOfPoints = 131071100L;
• To display the value of a long int using printf, the letter l is used
as a modifier before the integer format characters i, o, and x
Basic Data Types - Summary
Type Meaning Constants Ex. printf
int Integer value; guaranteed to contain at least 16 bits 12, -7, %i,%d, %x,
0xFFE0, 0177 %o
short int Integer value of reduced precision; guaranteed to - %hi, %hx,
contain at least 16 bits %ho
long int Integer value of extended precision; guaranteed to 12L, 23l, %li, %lx,
contain at least 32 bits 0xffffL %lo
long long Integer value of extraextended precision; 12LL, 23ll, %lli,
int guaranteed to contain at least 64 bits 0xffffLL %llx, %llo

unsigned Positive integer value; can store positive values up 12u, 0XFFu %u, %x, %o
int to twice as large as an int; guaranteed to contain at
least 16 bits (all bits represent the value, no sign bit)
unsigned - %hu, %hx,
short int %ho
unsigned 12UL, 100ul, %lu, %lx,
long int 0xffeeUL %lo

unsigned 12ull, %llu,


long long 0xffeeULL %llx, %llo
int
Basic Data Types - Summary (contd.)
Type Meaning Constants printf
float Floating-point value; a value that can contain decimal 12.34f, 3.1e- %f, %e,
places; guaranteed to contain at least six digits of 5f %g
precision.
double Extended accuracy floating-point value; guaranteed 12.34, 3.1e-5, %f, %e,
to contain at least 10 digits of precision. %g

long Extraextended accuracy floating-point value; 12.341, 3.1e- %Lf,


double guaranteed to contain at least 10 digits of 5l %Le, %Lg
precision.
char Single character value; on some systems, sign 'a', '\n' %c
extension might occur when used in an expression.

unsigned Same as char, except ensures that sign extension -


char does not occur as a result of integral promotion.

signed Same as char, except ensures that sign extension -


char does occur as a result of integral promotion.
Knowing actual ranges for types
• Defined in the system include files <limits.h> and <float.h>
• <limits.h> contains system-dependent values that specify the
sizes of various character and integer data types:
– the maximum size of an int is defined by the name INT_MAX
– the maximum size of an unsigned long int is defined by
ULONG_MAX
• <float.h> gives information about floating-point data types.
– FLT_MAX specifies the maximum floating-point number,
– FLT_DIG specifies the number of decimal digits of precision for a float
type.
Working with arithmetic expressions
• Basic arithmetic operators: +, -, *, /
• Precedence: one operator can have a higher priority, or precedence,
over another operator.
– Example: * has a higher precedence than +
– a+b*c
– if necessary, you can always use parentheses in an expression to force the
terms to be evaluated in any desired order.
• Associativity: Expressions containing operators of the same
precedence are evaluated either from left to right or from right to left,
depending on the operator. This is known as the associative property of
an operator
– Example: + has a left to right associativity

• In C there are many more operators -> later in this course !


• (Table A5 in Annex A of [Kochan]: full list, with precedence and
associativity for all C operators)
Working with arithmetic expressions
#include <stdio.h>
int main (void)
{
int a = 100;
int b = 2;
int c = 25;
int d = 4;
int result;
result = a - b; // subtraction
printf ("a - b = %i\n", result);
result = b * c; // multiplication
printf ("b * c = %i\n", result);
result = a / c; // division
printf ("a / c = %i\n", result);
result = a + b * c; // precedence
printf ("a + b * c = %i\n", result);
printf ("a * b + c * d = %i\n", a * b + c * d);
return 0;
}
Integer arithmetic and the unary
minus operator
// More arithmetic expressions
#include <stdio.h>
int main (void)
{
int a = 25;
int b = 2;
float c = 25.0;
float d = 2.0;
printf ("6 + a / 5 * b = %i\n", 6 + a / 5 * b);
printf ("a / b * b = %i\n", a / b * b);
printf ("c / d * d = %f\n", c / d * d);
printf ("-a = %i\n", -a);
return 0;
}
The modulus operator

// The modulus operator


#include <stdio.h>
int main (void)
{
int a = 25, b = 5, c = 10, d = 7;
printf ("a %% b = %i\n", a % b);
printf ("a %% c = %i\n", a % c);
printf ("a %% d = %i\n", a % d);
printf ("a / d * d + a %% d = %i\n",
a / d * d + a %
d);
return 0;
} Modulus operator: %
Binary operator
Gets the remainder resulting from integer division
% has equal precedence to * and /
Integer and Floating-Point
Conversions
• Assign an integer value to a floating variable:
does not cause any change in the value of the
number; the value is simply converted by the
system and stored in the floating
• Assign a floating-point value to an integer
variable: the decimal portion of the number gets
truncated.
• Integer arithmetic (division):
– int divided to int => result is integer division
– int divided to float or float divided to int => result is
real division (floating-point)
Integer and Floating-Point
Conversions
// Basic conversions in C
#include <stdio.h>
int main (void)
{
float f1 = 123.125, f2;
int i1, i2 = -150;
char c = 'a';
i1 = f1; // floating to integer conversion
printf ("%f assigned to an int produces %i\n", f1, i1);
f1 = i2; // integer to floating conversion
printf ("%i assigned to a float produces %f\n", i2, f1);
f1 = i2 / 100; // integer divided by integer
printf ("%i divided by 100 produces %f\n", i2, f1);
f2 = i2 / 100.0; // integer divided by a float
printf ("%i divided by 100.0 produces %f\n", i2, f2);
f2 = (float) i2 / 100; // type cast operator
printf ("(float) %i divided by 100 produces %f\n", i2, f2);
return 0;
}
The Type Cast Operator
• f2 = (float) i2 / 100; // type cast operator
• The type cast operator has the effect of converting the value of the variable
i2 to type float for purposes of evaluation of the expression.
• This operator does NOT permanently affect the value of the variable i2;
• The type cast operator has a higher precedence than all the arithmetic
operators except the unary minus and unary plus.

• Examples of the use of the type cast operator:


• (int) 29.55 + (int) 21.99 results in 29 + 21
• (float) 6 / (float) 4 results in 1.5
• (float) 6 / 4 results in 1.5
The assignment operators
• The C language permits you to join the arithmetic operators with the
assignment operator using the following general format: op=,
where op is an arithmetic operator, including +, –, ×, /, and %.
• op can also be a logical or bit operator => later in this course
• Example:
count += 10;
– Equivalent with:
count=count+10;
• Example: precedence of op=:
a /= b + c
– Equivalent with:
a = a / (b + c)
– addition is performed first because the addition operator has higher
precedence than the assignment operator
_Complex and _Imaginary types
• Supported only by a few compilers
• Complex numbers have two components: a real part and an imaginary part. C99
represents a complex number internally with a two-element array, with the first
component being the real part and the second component being the imaginary part.

• There are three complex types:


• float _Complex represents the real and imaginary parts with type float values.
• double _Complex represents the real and imaginary parts with type double values.
• long double _Complex represents the real and imaginary parts with type long
double values.

• There are three imaginary types; An imaginary number has just an imaginary part:
• float _Imaginary represents the imaginary part with a type float value.
• double _Imaginary represents the imaginary part with a type double value.
• long double _Imaginary represents the imaginary part with a type long double
value.

• Complex numbers can be initialized using real numbers and the value I, defined in
<complex.h> and representing i, the square root of –1
_Complex example

#include <complex.h> // for I


int main(void) {
double _Complex z1 = 3*I;
double _Complex z2=5+4*I;
double _Complex z;
z=z1*z2;
printf("%f+%f*I\n",creal(z),cimag(z) );
}
Declaring variables
• Some older languages (FORTRAN, BASIC) allow you to use
variables without declaring them.
• Other languages (C, Pascal) impose to declare variables
• Advantages of languages with variable declarations:
– Putting all the variables in one place makes it easier for a reader to
understand the program
– Thinking about which variables to declare encourages the programmer
to do some planning before writing a program ( What information does
the program need? What must the program to produce as output?
What is the best way to represent the data?)
– The obligation to declare all variables helps prevent bugs of misspelled
variable names.
– Compiler knows the amount of statically allocated memory needed

– Compiler can verify that operations done on a variable are allowed


by its type (strongly typed languages)
Declaration vs Definition
• Variable declaration: [Type, Identifier]
• Variable definition: a declaration which
does also reserve storage space
(memory) !
– Not all declarations are definitions
– In the examples seen so far, all declarations
are as well definitions
– Declarations which are not definitions: later in
this semester !
Computer programming

Lecture 3
Lecture 3: Outline
• Program Looping [Kochan – chap.5]
– The for Statement
– Relational Operators
– Nested for Loops
– Increment Operator
– Program Input
– for Loop Variants
– The while Statement
– The do Statement
– The break Statement
– The continue Statement
Executing a program
• Program = list of
statements
– Entrypoint: the point where Statement1
the execution starts Statement2
Statement3
– Control flow: the order in Statement4
which the individual Statement5
statements are executed Statement6
Statement7
Statement8
Structure of a C program
Entry point of a C
program
#include <stdio.h>
int main (void)
{
int value1, value2, sum; Sequential
value1 = 50; flow of control
value2 = 25;
sum = value1 + value2;
printf ("The sum of %i and %i is %i\n",value1, value2, sum);
return 0;
}
Controlling the program flow
• Forms of controlling
the program flow:
– Executing a sequence Statement1
of statements Statement2
Statement3
– Repeating a sequence Statement4
of statements (until Statement5
some condition is met) Statement6
(looping) Statement7
Statement8
– Using a test to decide
between alternative
sequences (branching)
Program Looping
• Looping: doing one thing over and over
• Program loop: a set of statements that is executed
repetitively for a number of times

• Simple example: displaying a message 100 times:


printf(“hello !\n”);
printf(“hello !\n”);
printf(“hello !\n”);
Repeat 100 times
… printf(“hello !\n”);
printf(“hello !\n”);
printf(“hello !\n”);

Program looping: enables you to develop concise programs containing


repetitive processes that could otherwise require many lines of code !
The need for program looping
Example problem: computing triangular numbers.
(The n-th triangular number is the sum of the integers from 1 through n)

#include <stdio.h>
int main (void) {
int triangularNumber;
triangularNumber = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8;
printf ("The eighth triangular number is %i\n",

triangularNumber);
return 0;
}

What if we have to compute the 200-th (1000-th, etc) triangular number ?

In C: 3 different statements for looping: for, while, do


Example – 200th triangular number
Statement before loop triangularNumber = 0

init_expression n=1

no
loop_condition n<=200

yes

statement triangularNumber =
triangularNumber + n

loop_expression n=n+1

Statement after loop Print triangularNumber


Example - for
/* Program to calculate the 200th triangular number
Introduction of the for statement */

#include <stdio.h>
int main (void)
{
int n, triangularNumber;
triangularNumber = 0;
for ( n = 1; n <= 200; n = n + 1 )
triangularNumber = triangularNumber + n;
printf ("The 200th triangular number is %i\n",
triangularNumber);
return 0;
}
The for statement
for ( init_expression; loop_condition; loop_expression )
program statement

1 init_expression

no
5 2 loop_condition

yes

3 Program statement

4 Loop expression
The for statement
no

1 2 5 4
yes
for ( n = 1; n <= 200; n = n + 1 )
triangularNumber = triangularNumber + n;
3
How for works
• The execution of a for statement proceeds as follows:
1. The initial expression is evaluated first. This expression usually
sets a variable that will be used inside the loop, generally
referred to as an index variable, to some initial value.
2. The looping condition is evaluated. If the condition is not
satisfied (the expression is false – has value 0), the loop is
immediately terminated. Execution continues with the program
statement that immediately follows the loop.
3. The program statement that constitutes the body of the loop is
executed.
4. The looping expression is evaluated. This expression is
generally used to change the value of the index variable
5. Return to step 2.
Infinite loops
• It’s the task of the programmer to design correctly the algorithms so
that loops end at some moment !

// Program to count 1+2+3+4+5


#include <stdio.h> What is wrong
int main (void) here ?
Does the loop end?
{
int i, n = 5, sum =0;
for ( i = 1; i <= n; n = n + 1 ){
sum = sum + i;
printf (“%i %i %i\n", i , sum, n);
}
return 0;
}
Relational operators
Operator Meaning
== Is equal to
!= Is not equal to
< Is less than
<= Is less or equal
> Is greater than
>= Is greater or equal

The relational operators have lower precedence than all arithmetic operators:
a < b + c is evaluated as a < (b + c)

ATTENTION ! Do not confuse:


the “is equal to” operator == and the “assignment” operator =

ATTENTION when comparing floating-point values !


Only < and > comparisons make sense !
Example – for with a body of 2
// Program to generate a table of triangular numbers
#include <stdio.h>
int main (void)
{
int n, triangularNumber;
printf ("TABLE OF TRIANGULAR NUMBERS\n\n");
printf (" n Sum from 1 to n\n");
printf ("--- ---------------\n");
triangularNumber = 0;
for ( n = 1; n <= 10; ++n ) {
triangularNumber += n;
printf (" %i %i\n", n, triangularNumber);
}
return 0;
} The body of the loop
consists in a block of 2
statements
Increment operator
• Because addition by 1 is a very common operation in
programs, a special operator was created in C for this.
• Increment operator: the expression ++n is equivalent to
the expression n = n + 1.
• Decrement operator: the expression --n is equivalent to
the expression n = n – 1
• Increment and decrement operators can be placed in front
(prefix) or after (postfix) their operand.
• The difference between prefix and postfix:
• Example: if n=4:
• a=n++ leads to a=4, n=5
• a=++n leads to a=5, n=5
Program input
#include <stdio.h> It’s polite to
int main (void) display a
{ message before
int n, number, triangularNumber;
printf ("What triangular number do you want? ");
scanf ("%i", &number);
triangularNumber = 0; Reads integer
for ( n = 1; n <= number; ++n ) from keyboard
triangularNumber += n;
printf ("Triangular number %i is %i\n", number,
triangularNumber);
return 0;
}

Scanf: similar to printf: first argument contains format characters, next


arguments tell where to store the values entered at the keyboard
More details -> in a later chapter !
Nested loops
#include <stdio.h>
int main (void)
{
int n, number, triangularNumber, counter;
for ( counter = 1; counter <= 5; ++counter ) {
printf ("What triangular number do you want? ");
scanf ("%i", &number);
triangularNumber = 0;
for ( n = 1; n <= number; ++n )
triangularNumber += n;
printf ("Triangular number %i is %i\n\n", number,

triangularNumber);
}
return 0;
} Remember indentations!
for loop variants
• Multiple expressions (comma between…)
for(i=0 , j=10 ; i<j ; i++ , j--)
• Omitting fields (semicolon have to be still…)
i=0;
for( ; i<10 ; i++ )
• Declaring variables
for(int i=0 ; i=10 ; i++ )
The while statement
while ( expression )
program statement

while ( number <= 0 ) {


printf (“The number must be >0“);
printf (“Give a new number: “);
scanf(“%i“, &number);
}
The while statement
while ( expression )
program statement
Loop with the test
in the beginning !
Body might never
be executed !

Loop_expression
no
yes
statement
Example:
• A program to find the greatest common divisor
of two nonnegative integer values …
Example - while
/* Program to find the greatest common divisor
of two nonnegative integer values */
#include <stdio.h>
int main (void)
{
int u, v, temp;
printf ("Please type in two nonnegative integers.\n");
scanf ("%i%i", &u, &v);
while ( v != 0 ) {
temp = u % v;
u = v;
v = temp;
}
printf ("Their greatest common divisor is %i\n", u);
return 0;
}
Example:
• A program to print out the digits of a number in
reverse order …
Example - while
// Program to reverse the digits of a number
#include <stdio.h>
int main (void)
{
int number, right_digit;
printf ("Enter your number.\n");
scanf ("%i", &number);
while ( number != 0 ) {
right_digit = number % 10;
printf ("%i", right_digit);
number = number / 10;
}
printf ("\n");
return 0;
}
Example – while not quite OK !

// Program to reverse the digits of a number


#include <stdio.h>
int main (void)
{
int number, right_digit;
printf ("Enter your number.\n");
scanf ("%i", &number);
while ( number != 0 ) {
right_digit = number % 10;
printf ("%i", right_digit);
number = number / 10;
}
printf ("\n");
return 0;
} What happens if you enter
number=0 ?
The do statement
do
program statement
while ( loop_expression );

Loop with the test


at the end !
Body is executed
at least once !

statement

yes
loop_expression

no
Example – do while
// Program to reverse the digits of a number
#include <stdio.h>
int main ()
{
int number, right_digit;
printf ("Enter your number.\n");
scanf ("%i", &number);
do {
right_digit = number % 10;
printf ("%i", right_digit);
number = number / 10;
}
while ( number != 0 );
printf ("\n");
return 0;
}
Which loop to choose ?
• Criteria: Who determines looping
– Entry-condition loop -> for, while
– Exit-condition loop -> do
• Criteria: Number of repetitions:
– Indefinite loops ->while
– Counting loops -> for
• In C, you can actually rewrite any while as
a for and viceversa !
Example: while vs for

#include <stdio.h> #include <stdio.h>


int main (void) int main (void)
{ {
int count = 1; int count;
while ( count <= 5 ) { for ( count=1; count<=5;
printf ("%i\n", count++ )
count); {
++count; printf ("%i\n",
} count);
return 0; }
} return 0;
}
The break Statement
• Can be used in order to immediately
exiting from a loop
• After a break, following statements in the
loop body are skipped and execution
continues with the first statement after the
loop
• If a break is executed from within nested
loops, only the innermost loop is
terminated
The break statement
• Programming style: don’t abuse break !!!
...
while ( number != 0 ) {
// Statements to do something in loop
printf("Stop, answer 1: ");
scanf ("%i", &answer);
if(answer == 1)
break; // very bad idea to do this
}
The continue statement
• Similar to the break statement, but it does
not make the loop terminate, just skips to
the next iteration
The continue statement
Continue also not so good style!!!
...
while ( number != 0 ) {
// Statements to do something in loop
printf(“Skip next statements answer 1: ");
scanf ("%i", &answer);
if(answer == 1)
continue; // not so good idea…
// Statements to do something in loop
// If answer was 1 these statements are
// not executed. They are skipped.
// Go straight to the beginning of while
}
Computer programming

Lecture 4
Lecture 4: Outline
• Making Decisions [chap 6 – Kochan]
– The if Statement
– The if-else Construct
– Logical Operators
– Boolean Variables
– Nested if Statements
– The else if Construct
– The switch Statement
– The Conditional Operator
• Character Input/Output
The if statement
if ( expression )
program statement

If expression is true
(non-zero), executes
statement.
If gives you the choice
no of executing statement
expression or skipping it.

yes

Program statement
Example - if

// Program to calculate the absolute value of an integer


int main (void)
{
int number;
printf ("Type in your number: ");
scanf ("%i", &number);
if ( number < 0 )
number = -number;
printf ("The absolute value is %i\n", number);
return 0;
}
The if-else statement
if ( expression )
program statement 1
else if-else statement:
program statement 2 enables you to
choose between
two statements

yes no
expression

Program statement 1 Program statement 2


Example: if-else
// Program to determine if a number is even or odd
#include <stdio.h>
int main ()
{
int number_to_test, remainder;
printf ("Enter your number to be tested: ");
scanf ("%i", &number_to_test);
remainder = number_to_test % 2;
if ( remainder == 0 )
printf ("The number is even.\n");
else
printf ("The number is odd.\n");
return 0;
}
Attention on if-else syntax !
In C, the ; is part
if ( expression ) (end) of a statement !
program statement 1 You have to put it
else also before an else !
program statement 2

if ( remainder == 0 )
printf ("The number is even.\n");
else
printf ("The number is odd.\n"); Syntactically OK
(void statement
on if) but
if ( x == 0 ); probably a
printf ("The number is zero.\n"); semantic error !
Example: compound relational test
// Program to determine if a year is a leap year
#include <stdio.h>
int main (void)
{
int year, rem_4, rem_100, rem_400;
printf ("Enter the year to be tested: ");
scanf ("%i", &year);
rem_4 = year % 4;
rem_100 = year % 100;
rem_400 = year % 400;
if ( (rem_4 == 0 && rem_100 != 0) || rem_400 == 0 )
printf ("It's a leap year.\n");
else
printf (“It's not a leap year.\n");
return 0;
}
Logical operators
Operator Symbol Meaning

AND && X && y is true if BOTH x and y are true


OR || X || y is true if at least one of x and y is true
NOT ! !x is true if x is false

Logical values as operands or in tests: true = non-zero, false=zero

Logical values returned as results of expressions: true = 1, false=zero

Example: 5 || 0 is 1
Example
• Program to generate a table of all prime
numbers up to 50
Boolean variables
// Program to generate a table of prime numbers
#include <stdio.h>
int main (void) {
int p, d; A flag: assumes only
int isPrime; one of two different
values. The value of a
for ( p = 2; p <= 50; ++p ) {
flag is usually tested in
isPrime = 1; the program to see if it
for ( d = 2; d < p; ++d ) is “on” (TRUE) or “off ”
if ( p % d == 0 ) (FALSE)
isPrime = 0;
if ( isPrime != 0 )
printf ("%i ", p);
}
Equivalent test:
printf ("\n");
(more in C-style):
return 0;
if (isPrime)
}
Boolean variables
// Program to generate a table of prime numbers - rewritten
#include <stdio.h>
#include <stdbool.h>
int main (void) {
int p, d;
bool isPrime;
for ( p = 2; p <= 50; ++p ) {
isPrime = true;
for ( d = 2; d < p; ++d )
if ( p % d == 0 )
isPrime = false;
if ( isPrime )
printf ("%i ", p);
}
printf ("\n");
return 0;
}
Precedence of operators
Precedence
!, ++, --, (type)
*, /, %
+, -
<, <=, >, >=, ==, !=
&&
||
=

Example for operator precedence:


a > b && b > c || b > d
Is equivalent to:
((a > b) && (b > c)) || (b > d)
Testing for ranges
if (x >= 5 && x <= 10)
printf(“in range");

if (5 <= x <= 10)


printf(“in range");
Testing for ranges
if (x >= 5 && x <= 10)
printf(“in range");

if (5 <= x <= 10)


printf(“in range");

Syntactically correct, but semantically an error !!!

Because the order of evaluation for the <= operator is left-to-right, the
test expression is interpreted as follows:
(5<= x) <= 10
The subexpression 5 <= x either has the value 1 (for true) or 0 (for
false). Either value is less than 10, so the whole expression is always
true, regardless of x !
Testing for character ranges
char ch;
scanf(“%c”,&ch);
if (ch >= 'a' && ch <= 'z')
printf("lowercase char\n");
if (ch >= ‘A' && ch <= ‘Z')
printf(“uppercase char\n");
if (ch >= ‘0' && ch <= ‘9')
printf(“digit char\n");

• This works for character codes such as ASCII, in which the codes for
consecutive letters are consecutive numbers. However, this is not true for
some codes (i.e. EBCDIC)
• A more portable way of doing this test is to use functions from <ctype.h>
islower(ch), isupper(ch), isdigit(ch)
Other operations on characters
c will be the
char ch='d'; next letter ‘e’
ch=ch+1;

c will be the
char ch='d'; corresponding
ch=ch+'A'-'a'; uppercase letter
‘D’

• This works for character codes such as ASCII, in which the codes for
consecutive letters are consecutive numbers.
• A more portable way: <ctype.h> : toupper(c), tolower(c)
Nested if statements
if (number > 5)
if (number < 10)
printf(“1111\n");
else printf(“2222\n");

Rule: an else
goes with the most
recent if, unless
if (number > 5) { braces indicate
if (number < 10) otherwise
printf(“1111\n");
}
else printf(“2222\n");
Example: else-if
// Program to implement the sign function
#include <stdio.h>
int main (void)
{
int number, sign;
printf ("Please type in a number: ");
scanf ("%i", &number);
if ( number < 0 )
sign = -1;
else if ( number == 0 )
sign = 0;
else // Must be positive
sign = 1;
printf ("Sign = %i\n", sign);
return 0;
}
Multiple choices – else-if
int number;

if
negative if ( expression 1)
program statement 1
else else if ( expression 2)
program statement 2
else
if zero
program statement 3

else

positive
Program style: this
unindented formatting
improves the readability of
the statement and makes
it
clearer that a three-way
decision is being made.
Example: else-if
// Program to categorize a single character
// that is entered at the terminal
#include <stdio.h>
int main (void)
{
char c;
printf ("Enter a single character:\n");
scanf ("%c", &c);
if ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') )
printf ("It's an alphabetic character.\n");
else if ( c >= '0' && c <= '9' )
printf ("It's a digit.\n");
else
printf ("It's a special character.\n");
return 0;
}
Example – multiple choices
/* Program to evaluate simple expressions of the form
number operator number */
#include <stdio.h>
int main (void) {
float value1, value2;
char operator;
printf ("Type in your expression.\n");
scanf ("%f %c %f", &value1, &operator, &value2);
if ( operator == '+' )
printf ("%.2f\n", value1 + value2);
else if ( operator == '-' )
printf ("%.2f\n", value1 - value2);
else if ( operator == '*' )
printf ("%.2f\n", value1 * value2);
else if ( operator == '/' )
printf ("%.2f\n", value1 / value2);
else printf ("Unknown operator.\n");
return 0;
}
Example - switch
/* Program to evaluate simple expressions of the form
value operator value */
#include <stdio.h>
int main (void) {
float value1, value2;
char operator;
printf ("Type in your expression.\n");
scanf ("%f %c %f", &value1, &operator, &value2);
switch (operator) {
case '+': printf ("%.2f\n", value1 + value2); break;
case '-': printf ("%.2f\n", value1 - value2); break;
case '*': printf ("%.2f\n", value1 * value2); break;
case '/':
if ( value2 == 0 ) printf ("Division by zero.\n")
else printf ("%.2f\n", value1 / value2);
break;
default: printf ("Unknown operator.\n"); break;
}
return 0;
}
The switch statement
switch ( expression )
{
case value1:
program statement The expression is
program statement successively compared
... against the values value1,
break; value2, ..., valuen. If a case is
case value2: found whose value is equal to
program statement the value of expression, the
program statement
program statements that follow
...
break; the case are executed.
...
case valuen:
program statement The switch test expression must be
program statement
... one with an integer value (including
break; type char) (No float !).
default: The case values must be integer-
program statement type constants or integer constant
program statement
... expressions (You can't use a
break; variable for a case label !)
}
The switch statement (cont)
Break can miss !

Statement list on
a case can
miss !
switch (operator)
{
...
case '*':
case 'x':
printf ("%.2f\n", value1 * value2);
break;
...
}
The conditional operator
condition ? expression1 : expression2

condition is an expression that is evaluated first.


If the result of the evaluation of condition is TRUE (nonzero), then expression1
is evaluated and the result of the evaluation becomes the result of the operation.
If condition is FALSE (zero), then expression2 is evaluated and its result
becomes the result of the operation

maxValue = ( a > b ) ? a : b;

Equivalent to:

if ( a > b )
maxValue = a;
else
maxValue = b;
Standard input/output
• The C language itself does not have any special
statements for performing input/output (I/O)
operations; all I/O operations in C must be
carried out through function calls.
• These functions are contained in the standard C
library.
• #include <stdio.h>
• Formatted I/O: scanf(), printf()
• Character I/O: getchar(), putchar()
Brief overview - scanf()
• scanf(control string, list of arguments)
• Control string: contains format characters
– Important: match the number and type of format characters with the
number and type of following arguments !
– Format characters: as for printf
• Arguments: variable names prefixed with the address operator (&)
• Example:
• scanf(“%i %i”,&x,&y);
How scanf works
• Scanf: searches the input stream for a value to be read, bypasses
any leading whitespace characters
• scanf ("%f %f", &value1, &value2);
• scanf ("%f%f", &value1, &value2);
• In both cases, user can type:
3 <space> 5 <enter>
<space> 3 <space> <space> 5 <space> <enter>
3 <enter> 5 <enter>
• The exceptions: in the case of the %c format characters— the next
character from the input, no matter what it is, is read
• scanf ("%f %c %f", &value1, &op, &value2);
3 <space> + <space> 5 <enter>
3 <space> + <space> <space> <enter> 5 <enter>
• scanf ("%f%c%f", &value1, &op, &value2);
3+5<enter>
Not OK: 3 <space> +5<enter> => op would take the value <space>,
character + would remain as input for value2 !
How scanf works
• When scanf reads in a particular value: reading of the value
terminates when a character that is not valid for the value type being
read is encountered.
• scanf ("%f%c%f", &value1, &op, &value2);
3+5<enter>
• Any nonformat characters that are specified in the format string of
the scanf call are expected on the input.
• scanf ("%i:%i:%i", &hour, &minutes, &seconds);
3:6:21<enter>
3<space>:<space>6<space>:<space>21<enter>
3<space>6<space>21<space> => NOT OK !
• The next call to scanf picks up where the last one left off.
• scanf ("%f", &value1);
• User types: 7 <space> 8 <space> 9 <enter>
• 7 is stored in value1, rest of the input chars remain waiting in buffer
• scanf ("%f", &value2);
• 8 from buffer is stored in value2, rest of the input remains waiting
getchar() and putchar()
• The simplest input mechanism is to read one
character at a time from the standard input,
with getchar
• To display a character: putchar
Example: getchar()

#include <stdio.h>
int main(void) { Buffered input: the
char ch; characters you type are
while ((ch = getchar()) != '#') collected and stored in a
putchar(ch); buffer. Pressing Enter
return 0; causes the block of
} characters you typed to
be made available to
your program

Hello ! I am<enter>
Hello ! I am
Joe from #3.<enter>
Joe from
Terminating keyboard input
Which character as
sign of end of input ?
#include <stdio.h> You need a
int main(void) { terminating character
int ch; that normally does
while ((ch = getchar()) != EOF) not show up in text.
putchar(ch);
return 0;
}

getchar returns the next input character each time it is called,


or EOF when it encounters end of file.
EOF is a symbolic constant defined in <stdio.h>. (The value is typically -1)

EOF from the keyboard: Ctrl+Z


Exercise: getchar()
/* Read characters from input over several lines until EOF.
Count lines and characters in input */

#include <stdio.h>
int main(void) {
int c, nl, nc;
nl = 0;
nc = 0;
while ((c = getchar()) != EOF) {
nc++;
if (c == '\n')
nl++;
}
printf("Number of lines in input: %d\n", nl);
printf("Number of characters in input: %d\n", nc);
return 1;
}
Computer programming

Lecture 5
Lecture 5: Outline
• Arrays [chap 7 – Kochan]
– The concept of array
– Defining arrays
– Initializing arrays
– Character arrays
– Multidimensional arrays
– Variable length arrays
The concept of array
• Array: a set of ordered data items
• You can define a variable called x, which represents not a single
value, but an entire set of values.
• Each element of the set can then be referenced by means of a
number called an index number or subscript.
• Mathematics: a subscripted variable, xi, refers to the ith element x in
a set
• C programming: the equivalent notation is x[i]
Declaring an array
• Declaring an array variable:
– Declaring the type of elements that will be contained in the array—
such as int, float, char, etc.
– Declaring the maximum number of elements that will be stored inside
the array.
• The C compiler needs this information to determine how much memory
space to reserve for the array.)
• This must be a constant integer value
• The range for valid index values in C:
– First element is at index 0
– Last element is at index [size-1]
– It is the task of the programmer to make sure that array elements are
referred by indexes that are in the valid range ! The compiler cannot
verify this, and it comes to severe runtime errors !
Arrays - Example
Example:
int values[10];
Declares an array of 10 elements of type int
Using Symbolic Constants for array size:
#define N 10

int values[N];

Valid indexes:
values[0]=5;
values[9]=7;
Invalid indexes:
values[10]=3;
values[-1]=6;
In memory: elements of an array are stored
at consecutive locations
Arrays - Example
#include <stdio.h> Using symbolic
#define N 6 constants for array
int main (void) size makes program
{ more general
int values[N];
int index;
for ( index = 0; index < N; ++index ) {
printf(“Enter value of element #%i \n”,index);
scanf(“%i”, &values[index]);
}
for ( index = 0; index < N; ++index )
printf ("values[%i] = %i\n", index, values[index]);
return 0;
}
Typical loop for
processing all
elements of an array
What goes wrong if an index goes
out of range ?
#include <stdio.h>
#define NA 4
#define NB 7
int main (void) {
int b[NB],a[NA];
int index;
for ( index = 0; index < NB; ++index )
b[index]=10+index;
for ( index = 0; index < NA+2; ++index )
a[index]=index;

for ( index = 0; index < NA+2; ++index )


printf ("a[%i] = %i ", index, a[index]);
printf("\n");
for ( index = 0; index < NB; ++index )
printf ("b[%i] = %i ", index, b[index]);
printf("\n");
return 0;
What goes wrong if an index goes
out of range ?
#include <stdio.h>
#define NA 4
#define NB 7
int main (void) {
int b[NB],a[NA];
int index;
for ( index = 0; index < NB; ++index )
b[index]=10+index;
for ( index = 0; index < NA+2; ++index )
a[index]=index;

for ( index = 0; index < NA+2; ++index )


printf ("a[%i] = %i ", index, a[index]);
printf("\n");
for ( index = 0; index < NB; ++index )
printf ("b[%i] = %i ", index, b[index]);
printf("\n");
return 0;
Exercise
• Suppose you took a survey to discover how people felt about a particular
television show and you asked each respondent to rate the show on a scale
from 1 to 10, inclusive. After interviewing 5,000 people, you accumulated a
list of 5,000 numbers. Now, you want to analyze the results.
• One of the first pieces of data you want to gather is a table showing the
distribution of the ratings: you want to know how many people rated the
show a 1, how many rated it a 2, and so on up to 10.
• Develop a program to count the number of responses for each rating.
Exercise: Array of counters

response
ratingCounters

++

0 1 2 9 10

ratingCounters[i] = how many persons rated the show an i


Exercise: Array of counters
#include <stdio.h>
int main (void) {
int ratingCounters[11], i, response;
for ( i = 1; i <= 10; ++i )
ratingCounters[i] = 0;
printf ("Enter your responses\n");
for ( i = 1; i <= 20; ++i ) {
scanf ("%i", &response);
if ( response < 1 || response > 10 )
printf ("Bad response: %i\n", response);
else
++ratingCounters[response];
}
printf ("\n\nRating Number of Responses\n");
printf ("------ -------------------\n");
for ( i = 1; i <= 10; ++i )
printf ("%4i%14i\n", i, ratingCounters[i]);
return 0;
}
Exercise: Fibonacci numbers
// Program to generate the first 15 Fibonacci numbers
#include <stdio.h>
int main (void)
{
int Fibonacci[15], i;
Fibonacci[0] = 0; // by definition
Fibonacci[1] = 1; // ditto
for ( i = 2; i < 15; ++i )
Fibonacci[i] = Fibonacci[i-2] + Fibonacci[i-1];
for ( i = 0; i < 15; ++i )
printf ("%i\n", Fibonacci[i]);
return 0;
}
Exercise: Prime numbers
• An improved method for generating prime numbers involves the notion that
a number p is prime if it is not evenly divisible by any other prime number
• Another improvement: a number p is prime if there is no prime number
smaller than its square root, so that it is evenly divisible by it

If you can find a


Is p the next
primes[i] < sqrt(p)
prime number
that divides evenly
here ?
p, than p is not
prime
primes

2 3 5 7 11

0 1 2

primeIndex
Exercise: Prime numbers
#include <stdio.h>
#include <stdbool.h>
// Modified program to generate prime numbers
int main (void) {
int p, i, primes[50], primeIndex = 2;
bool isPrime;
primes[0] = 2;
primes[1] = 3;
for ( p = 5; p <= 50; p = p + 2 ) {
isPrime = true;
for ( i = 1; isPrime && p / primes[i] >= primes[i]; ++i )
if ( p % primes[i] == 0 )
isPrime = false;
if ( isPrime == true ) {
primes[primeIndex] = p;
++primeIndex;
}
}
for ( i = 0; i < primeIndex; ++i )
printf ("%i ", primes[i]);
printf ("\n");
return 0;
}
Initializing arrays
• int counters[5] = { 0, 0, 0, 0, 0 };
• char letters[5] = { 'a', 'b', 'c', 'd', 'e' };
• float sample_data[500] = { 100.0, 300.0, 500.5 };
• The C language allows you to define an array without specifying the
number of elements. If this is done, the size of the array is
determined automatically based on the number of initialization
elements: int counters[] = { 0, 0, 0, 0, 0 };
Character arrays
#include <stdio.h>
int main (void)
{
char word[] = { 'H', 'e', 'l', 'l', 'o', '!' };
int i;
for ( i = 0; i < 6; ++i )
printf ("%c", word[i]);
printf ("\n");
return 0;
}

a special case of character arrays: the character string type =>in a later chapter
Example: conversion to base b
• Convert a number from base 10 into a base b, b in range [2..16]

• Example: convert number from base 10 into base b=2

Number Number % 2 Number / 2


Step1: 10 0 5
Step2: 5 1 2
Step3: 2 0 1
Step4: 1 1 0
Example: Base conversion using
arrays
// Program to convert a positive integer to another base
#include <stdio.h>
int main (void)
{
const char baseDigits[16] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
int convertedNumber[64];
long int numberToConvert;
int nextDigit, base, index = 0;
// get the number and the base
printf ("Number to be converted? ");
scanf ("%ld", &numberToConvert);
printf ("Base? ");
scanf ("%i", &base);
Example continued
// convert to the indicated base
do {

convertedNumber[index] = numberToConvert
% base;
++index;
numberToConvert =
numberToConvert / base;
}
while ( numberToConvert != 0 );
// display the results in reverse order
printf ("Converted number = ");
for (--index; index >= 0; --index ) {
nextDigit = convertedNumber[index];
printf ("%c",
baseDigits[nextDigit]);
}
printf ("\n");
Multidimensional arrays
• C language allows arrays of any number of dimensions
• Two-dimensional array: matrix

int M[4][5]; // matrix, 4 rows, 5 columns


M[i][j] – element at row i, column j

int M[4][5] = {
{ 10, 5, -3, 17, 82 },
{ 9, 0, 0, 8, -7 },
{ 32, 20, 1, 0, 14 },
{ 0, 0, 8, 7, 6 }
};
int M[4][5] = { 10, 5, -3, 17, 82, 9, 0, 0, 8, -7, 32,20,
1, 0, 14, 0, 0, 8, 7, 6 };
Example: Typical matrix processing
#define N 3
#define M 4
int main(void) {
int a[N][M];
int i,j;
/* read matrix elements */
for(i = 0; i < N; i++)
for(j = 0; j< M; j++) {
printf("a[%d][%d] = ", i, j);
scanf("%d", &a[i][j]);
}
/* print matrix elements */
for(i = 0; i < N; i++) {
for(j = 0; j< M; j++)
printf("%5d", a[i][j]);
printf("\n");
}
return 0;
}
Example: Dealing with variable
numbers of elements
#include <stdio.h>
#define NMAX 4

int main(void) {
int a[NMAX];
int n;
int i;
printf("How many elements(maximum %d)?\n",NMAX);
scanf("%d",&n);
if (n>NMAX) {
printf(“Number too big !\n”);
return 1;
}
for(i = 0; i < n; i++)
scanf("%d", &a[i]);
for(i = 0; i < n; i++)
printf("%5d", a[i]);
printf("\n");
return 0;
}
Variable length arrays
• A feature introduced by C99
• It was NOT possible in ANSI C !
• int a[n];
• The array a is declared to contain n elements. This is called a
variable length array because the size of the array is specified by a
variable and not by a constant expression.
• The value of the variable must be known at runtime when the array
is created => the array variable will be declared later in the block of
the program
• Possible in C99: variables can be declared anywhere in a program,
as long as the declaration occurs before the variable is first used.
• A similar effect of variable length array could be obtained in ANSI C
using dynamic memory allocation to allocate space for arrays while
a program is executing.
Example: Variable length arrays
#include <stdio.h>

int main(void) {
int n;
int i;

printf("How many elements do you have ? \n");


scanf("%d",&n);

int a[n]; Array a of size n


created.
for(i = 0; i < n; i++) Value of n must be
scanf("%d", &a[i]); set at runtime before
for(i = 0; i < n; i++) arriving at the array
printf("%5d", a[i]); declaration !
printf("\n");
return 0;
}
Example: variable length arrays
#include <stdio.h>

int main(void) {
int n; Array a
int i; created of size
7
n=7;
int a[n];
for(i = 0; i < n; i++)
a[i]=i Variable-length array
n=20; does NOT mean that
Wrong! for(i = 0; i < n; i++) you can modify the
a[i]=2*i; length of the array
printf("\n"); after you create it !
return 0; Once created, a VLA
} keeps the same size !
Computer programming

Lectures 6&7
Lectures 6&7: Outline
• Functions [chap 8 – Kochan]
– Defining a Function
– Arguments and Local Variables
• Automatic Local Variables
– Returning Function Results
– Declaring a Function Prototype
– Functions and Arrays
• Arrays as parameters
• Sorting Arrays
• Multidimensional Arrays
– Global Variables
– Automatic and Static Variables
– Recursive Functions
What is a function
• A function in C: is a self-contained unit of program code designed to
accomplish a particular task.
• The concept has some equivalent in all high-level programming
languages: functions, subroutines, and procedures
• The use of a function: a "black box"
– defined in terms of the information that goes in (its input) and the value
or action it produces (its output).
– what goes on inside the black box is not your concern, unless you are
the one who has to write the function.
– Think on how you used functions printf, scanf, getchar !
• What kind of “output” comes out from a function black box ?
– Some functions find a value for a program to use. Example: getchar()
returns to the program the next character from the standard input buffer.
– Some functions cause an action to take place. Example: printf() causes
data to be printed on the screen
– In general, a function can both produce actions and provide values.
Defining a function
#include <stdio.h>

void printMessage (void) Function


{ Definition
printf ("Programming is fun.\n"); -occurs ONE time for all
} -outside other functions

int main (void)


{ Function
printMessage (); calls (invocations)
printMessage (); -occurs ANY (0-N) times
return 0; -statement inside (other) functions body
}
Transfer of control flow

main printf
printMesage

{ { {

} }

When a function call is executed, program execution is transferred


directly to the indicated function. After the called routine is finished
(as signaled by the closing brace) the program returns to the calling routine,
where program execution continues at the point where the
function call was executed.
Function definitions
General form of function definition:
return-type function-name(argument declarations)
{
declarations and statements
}

return-type arguments
void printMessage ( void )
{
printf ("Programming is fun.\n");
}
Function prototype
• The first line of the function definition
• Contains everything that others (other functions) need to
know about the function in order to use it (call it)

• void printMessage (void)


• void calculateTriangularNumber (int n)

Function prototype

return-type function-name(argument declarations)


{
declarations and statements
}
Function arguments
• arguments (parameters): a kind of input for the function blackbox
• In the function definition: formal arguments (formal parameters)
– Formal parameter: a name that is used inside the function body to refer
to its argument
• In the function call: actual arguments (actual parameters)
– The actual arguments are values are assigned to the corresponding
formal parameters.
– The actual argument can be a constant, a variable, or an even more
elaborate expression.
– The actual argument is evaluated, and its value is copied to the
corresponding formal parameter for the function.
• Because the called function works with data copied from the calling function,
the original data in the calling function is protected from whatever
manipulations the called function applies to the copies .
Example: arguments
// Function to calculate the nth triangular number
#include <stdio.h> formal argument
void calculateTriangularNumber ( int n )
{
int i, triangularNumber = 0; local variables
for ( i = 1; i <= n; ++i )
triangularNumber += i;
printf ("Triangular number %i is %i\n", n, triangularNumber);
}
int main (void)
{ actual argument
calculateTriangularNumber (10);
calculateTriangularNumber (20);
calculateTriangularNumber (50);
return 0;
}
Arguments and local variables
• Variables defined inside a function: automatic local variables
– they are automatically “created” each time the function is called
– their values are local to the function:
• The value of a local variable can only be accessed by the function in which
the variable is defined
• Its value cannot be accessed by any other function.
• If an initial value is given to a variable inside a function, that initial value is
assigned to the variable each time the function is called.
• Formal parameters: behave like local variables, private to the
function.
• Lifetime: Period of time when memory location is allocated
• Scope: Region of program text where declaration is visible
• Scope: local variables and formal parameters => only in the body of
the function
– Local variable i in function calculateTriangularNumber is different from a
variable i defined in another function (including main)
– Formal parameter n in function calculateTriangularNumber is different
from a variable n defined in another function
Automatic local variables
main calculateTriangularNumber

{ {

10 n

20 i

50 triangularNb
Example: scope of local variables
#include <stdio.h>
void f1 (float x) {
int n=6;
printf(“%f \n”, x+n);
}
int f2(void) {
float n=10;
printf(“%f \n”,n);
}
int main (void)
{
int n=5;
f1(3);
f2();
return 0;
}
Arguments are passed by copying
values !
• In a function call, the actual argument is
evaluated, and its value is copied to the
corresponding formal parameter for the
function.
– Because the called function works with data
copied from the calling function, the original
data in the calling function is protected from
whatever manipulations the called function
applies to the copies
Example: arguments
#include <stdio.h>
void gcd (int u, int v)
{
int temp;
printf ("The gcd of %i and %i is ", u, v);
while ( v != 0 ) {
temp = u % v;
u = v;
v = temp;
}
printf ("%i\n", u);
}
int main (void)
{
gcd (150, 35);
gcd (1026, 405);
gcd (83, 240);
return 0;
Example: arguments are passed by
copying values !
#include <stdio.h>
void gcd (int u, int v)
{
int temp;
printf ("The gcd of %i and %i is ", u, v);
while ( v != 0 ) { The formal
temp = u % v; parameters u and v
u = v; are assigned new
v = temp; values in the
} function
printf ("%i\n", u);
}
The actual
int main (void)
parameters x and y
{
are not changed !
int x=10,y=15;
gcd (x, y);
printf(“x=%i y=%i \n”,x,y);
return 0;
Example: arguments are passed by
copying values !
#include <stdio.h>
void multiplyBy2 (float x)
{
printf(“parameter at start: %.2f, at %p \n”,x,
&x);
x*=2;
printf(“parameter at end: %.2f, at %p \n”,x, &x);
}
int main (void)
{
float y = 7;
printf (“y before call: %.2f, at %p \n", y, &y);
multiplyBy2 (y);
printf (“y after call: %.2f, at %p \n", y, &y);
return 0;
}
Arguments by copying
main multiplyBy2

{ {

y 7 x
714
Returning function results
• A function in C can optionally return a single value
• return expression;
• The value of expression is returned to the calling function. If the type of
expression does not agree with the return type declared in the function
declaration, its value is automatically converted to the declared type before it
is returned.
• A simpler format for declaring the return statement is as follows:
• return;
• Execution of the simple return statement causes program execution to be
immediately returned to the calling function.This format can only be used to
return from a function that does not return a value.
• If execution proceeds to the end of a function and a return statement is not
encountered, it returns as if a return statement of this form had been
executed. Therefore, in such a case, no value is returned.
• If the declaration of the type returned by a function is omitted, the C compiler
assumes that the function returns an int !
Return example

void printMessage (void)


{
printf ("Programming is fun.\n");
return;
}
Example: function result
/* Function to find the greatest common divisor of two
nonnegative integer values and to return the result */
#include <stdio.h>
int gcd (int u, int v)
{
int temp;
while ( v != 0 ) {
temp = u % v;
u = v;
v = temp;
}
return u;
}
int main (void)
{
int result;
result = gcd (150, 35);
printf ("The gcd of 150 and 35 is %i\n", result);
result = gcd (1026, 405);
printf ("The gcd of 1026 and 405 is %i\n", result);
printf ("The gcd of 83 and 240 is %i\n", gcd (83, 240));
return 0;
}
Function declaration
• a function prototype—a declaration that states the return type, the number
of arguments, and the types of those arguments.
• Useful mechanism when the called function is defined after the calling
function
• The prototype of the called function is everything the compiler needs in
order to be able to compile the calling function
• In order to produce the executable program, of course that also the whole
definition of the function body is needed, but this occurs later, in the
process of linking
Example: function declaration
#include <stdio.h>
Function declaration (prototype)
void printMessage (void) ;
(has to be before the calling function)

int main (void)


{
printMessage (); Function calls
printMessage ();
return 0;
}

void printMessage (void)


{ Function definition
printf ("Programming is fun.\n"); (can be after the
} calling function)
#include explained
• #include <stdio.h>
• #include <filename> is a preprocessor directive
• Preprocessor: a first step in the C compilation process
• Preprocessor statements are identified by the pound sign # that must be the
first nonspace character of a line
• The #include directive will insert in place the contents of the specified file
• These files usually have names that end with .h (header files)
• Header files usually contain declarations and definitions that are used by
several programs
• <stdio.h> contains the declarations for the standard input output
functions printf, scanf, getchar, etc. This is why any program that
uses these functions has to include <stdio.h>
Function declaration style added in
C99 Besides the ANSI C
style for function
declaration, C99
#include <stdio.h> accepts also this
style
int main (void)
{
Function declaration
void printMessage (void) ;
(has to be before the function call
can be inside a function body)
printMessage ();
Function calls
printMessage ();
return 0;
}

void printMessage (void)


{ Function definition
printf ("Programming is fun.\n"); (can be after the
} calling function)
Examples: function declarations
In a function declaration you have to specify the argument type
inside the parentheses, and not its name.
You can optionally specify a “dummy” name for formal parameters after the type
if you want.

int gcd (int u, int v);


Or
int gcd (int, int);

void calculateTriangularNumber (int n);


Or
void calculateTriangularNumber (int);
Passing arrays as parameters
• A whole array can be one parameter in a function
• In the function declaration, you can then omit the specification of
the number of elements contained in the formal parameter array.
– The C compiler actually ignores this part of the declaration anyway; all the
compiler is concerned with is the fact that an array is expected as an
argument to the function and not how many elements are in it.
• Example: a function that returns the minimum value from an array
given as parameter
– int minimum (int values[10]);
• We must modify the function definition if a different array size is needed !
– int minimum (int values[]);
• Syntactically OK, but how will the function know the actual size of the array ?!
– int minimum (int values[], int numberOfElements);
Computing the minimum/maximum
int values[10];
int minValue, i;
minValue = values[0];
for ( i = 1; i < 10; ++i )
if ( values[i] < minValue )
minValue = values[i];

#include <limits.h>

int minValue, i;
minValue = INT_MIN;
for ( i = 0; i < 10; ++i )
if ( values[i] < minValue )
minValue = values[i];
Example: Passing arrays as
parameters
// Function to find the minimum value in an array
#include <stdio.h>
int minimum (int values[], int n) {
int minValue, i;
minValue = values[0];
for ( i = 1; i < n; ++i )
if ( values[i] < minValue )
minValue = values[i];
return minValue;
}
int main (void) {
int scores[10], i, minScore;
printf ("Enter 10 scores\n");
for ( i = 0; i < 10; ++i )
scanf ("%i", &scores[i]);
minScore = minimum (scores);
printf ("\nMinimum score is %i\n", minScore);
return 0;
}
Example: No size specified for
formal parameter array
// Function to find the minimum value in an array
#include <stdio.h>
int minimum (int values[], int numberOfElements)
{
int minValue, i;
minValue = values[0];
for ( i = 1; i < numberOfElements; ++i )
if ( values[i] < minValue )
minValue = values[i];
return minValue;
}
int main (void)
{
int array1[5] = { 157, -28, -37, 26, 10 };
int array2[7] = { 12, 45, 1, 10, 5, 3, 22 };
printf ("array1 minimum: %i\n", minimum (array1, 5));
printf ("array2 minimum: %i\n", minimum (array2, 7));
return 0;
}
Array parameters are passed by
reference !
• Parameters of non-array type: passed by copying values
• Parameters of array type: passed by reference
– the entire contents of the array is not copied into the formal
parameter array.
– the function gets passed information describing where in the
computer’s memory the original array is located.
– Any changes made to the formal parameter array by the function
are actually made to the original array passed to the function,
and not to a copy of the array.
– This change remains in effect even after the function has
completed execution and has returned to the calling routine.
Example: Array parameters are
passed by reference !
#include <stdio.h>
void multiplyBy2 (float array[], int n)
{
int i;
for ( i = 0; i < n; ++i )
array[i] *= 2;
}
int main (void)
{
float floatVals[4] = { 1.2f, -3.7f, 6.2f, 8.55f };
int i;
multiplyBy2 (floatVals, 4);
for ( i = 0; i < 4; ++i )
printf ("%.2f ", floatVals[i]);
printf ("\n");
return 0;
}
Sorting arrays
// Program to sort an array of integers
// into ascending order

#include <stdio.h>
void sort (int a[], int n)
{
int i, j, temp;
for ( i = 0; i < n - 1; ++i )
for ( j = i + 1; j < n; ++j )
if ( a[i] > a[j] ) {
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
Sorting arrays - continued
void sort (int a[], int n);

int main (void)


{
int i;
int array[16] = { 34, -5, 6, 0, 12, 100, 56, 22,
44, -3, -9, 12, 17, 22, 6, 11 };

printf ("The array before the sort:\n");


for ( i = 0; i < 16; ++i )
printf ("%i ", array[i]);
sort (array, 16);
printf ("\n\nThe array after the sort:\n");
for ( i = 0; i < 16; ++i )
printf ("%i ", array[i]);
printf ("\n");
return 0;
}
Multidimensional arrays and
functions
• When declaring a single-dimensional array as a formal parameter inside a
function, the actual dimension of the array is not needed; simply use a pair
of empty brackets to inform the C compiler that the parameter is, in fact, an
array.
• This does not totally apply in the case of multidimensional arrays. For a two-
dimensional array, the number of rows in the array can be omitted, but the
declaration must contain the number of columns in the array.

• Valid examples:
function(int array_values[100][50]);
function(int array_values[][50]);
• Invalid examples:
function(int array_values[100][]);
function(int array_values[][]);
Example: multidimensional array as
function parameter
The number of
columns must be specified !
No generic matrix display function possible !

void displayMatrix (int matrix[3][5])


{
int row, column;
for ( row = 0; row < 3; ++row) {
for ( column = 0; column < 5; ++column )
printf ("%5i", matrix[row][column]);
printf ("\n");
}
}
Example: multidimensional variable
length array as function parameter
A generic matrix display function is possible with
the variable length array feature.
The rows and columns must be listed as arguments
before the matrix itself.

void displayMatrix (int nRows, int nCols,


int matrix[nRows][nCols])
{
int row, column;
for ( row = 0; row < nRows; ++row) {
for ( column = 0; column < nCols; ++column )
printf ("%5i", matrix[row][column]);
printf ("\n");
}
}
Global variables
• A global variable declaration is made outside of any function.
• It does not belong to any particular function. Any function in the
program can then access the value of that variable and can change
its value.
• The primary use of global variables is in programs in which many
functions must access the value of the same variable. Rather than
having to pass the value of the variable to each individual function
as an argument, the function can explicitly reference the variable
instead.
• There is a drawback with this approach: Because the function
explicitly references a particular global variable, the generality of
the function is somewhat reduced !
• Global variables do have default initial values: zero
Example: global variables
#include <stdio.h>

int x;

void f1 (void) {
x++;
}

void f2 (void) {
x++;
}

int main(void) {
x=7;
f1();
f2();
printf(“x=%i \n”,x);
}
Automatic and static variables
• Automatic local variables (the default case of local vars) :
– an automatic variable disappears after the function where it is defined
completes execution, the value of that variable disappears along with it.
– the value an automatic variable has when a function finishes execution is
guaranteed not to exist the next time the function is called.
– The value of the expression is calculated and assigned to the automatic local
variable each time the function is called.
• Static local variables:
– If you place the word static in front of a variable declaration
– “something that has no movement”
– a static local variable—it does not come and go as the function is called and
returns. This implies that the value a static variable has upon leaving a
function is the same value that variable will have the next time the function is
called.
– Static variables also differ with respect to their initialization. A static, local
variable is initialized only once at the start of overall program execution—and
not each time that the function is called. Furthermore, the initial value
specified for a static variable must be a simple constant or constant
expression. Static variables also have default initial values of zero, unlike
automatic variables, which have no default initial value.
Example: Automatic and static
variables
// Program to illustrate static and automatic variables
#include <stdio.h>
void auto_static (void)
{
int autoVar = 1;
static int staticVar = 1;
printf ("automatic = %i, static = %i\n", autoVar, staticVar);
++autoVar;
++staticVar;
}
int main (void)
{
int i;
for ( i = 0; i < 5; ++i )
auto_static ();
return 0;
}
Recursive functions
• C permits a function to call itself. This process is named
recursion.
• Useful when the solution to a problem can be expressed in terms of
successively applying the same solution to subsets of the problem
• Example: factorial: recursive definition:
• n! = n * (n-1)!

factorial(n) factorial(n-1)
Example: recursive function
// Recursive function to calculate the factorial of n
unsigned long int factorial (unsigned int n)
{
unsigned long int result;
if ( n == 0 )
result = 1;
else
result = n * factorial (n - 1);
return result;
}

factorial(3)=3 * factorial(2); =6
factorial(2) = 2 * factorial(1); =2
factorial(1)= 1 * factorial(0); =1
factorial(0)= 1
Recursive function calls
• Each time any function is called in C—be it
recursive or not—the function gets its own
set of local variables and formal
n: 0
parameters with which to work !
• These local automatic variables are stored result: 1
in a memory area called stack
• Each new function call pushes a new
activation record on the stack n: 1
• This activation record contains its set of result: 1
automatic local variables
• When a function call returns, its activation
record is removed from the top of the stack n: 2

The local variable result and the result: 2


formal parameter n that exist when the
factorial function is called to calculate
the factorial of 3 are distinct from the n: 3
variable result and the parameter n
when the function is called to calculate result: 6
the factorial of 2.
Example: recursive function calls

void up_and_down(int n)
{
printf(“Start call %d: n location %p\n", n, &n);
if (n < 4)
up_and_down(n+1);
printf(“End call %d: n location %p\n", n, &n);
}

...

up_and_down(0);
Recursion pros and cons
• Tricky with recursion: programmer must make sure to get the
recursion to an end at some time !
– a function that calls itself tends to do so indefinitely unless the
programming includes a conditional test to terminate recursion.
• Recursion often can be used where loops can be used. Sometimes
the iterative solution is more obvious; sometimes the recursive
solution is more obvious.
• Recursive solutions tend to be more elegant and less efficient
than iterative solutions.
Functions - Summary
• We distinguish between Function definition, function declaration and
Function call

• Function definition general format:

returnType name ( type1 param1, type2 param2, ... )


{
variableDeclarations
programStatement
programStatement
...
return expression;
}
• The function called name is defined, which returns a value of type returnType
and has formal parameters param1, param2,... . The formal parameter param1
is declared to be of type type1, param2 is declared to be of type type2, etc.
Function Definitions - Summary
• Local variables are typically declared at the beginning of the function, but
that’s not required. They can be declared anywhere, in which case their
access is limited to statements appearing after their declaration in the
function.
• If the function does not return a value, returnType is specified as void.
• If just void is specified inside the parentheses, the function takes no
arguments.
• Declarations for single-dimensional array arguments do not have to specify
the number of elements in the array. For multidimensional arrays, the size of
each dimension except the first must be specified.
Function Declaration - Summary
• Function declaration: a prototype declaration for the
function, which has the following general format:
returnType name (type1, type2, ... );

• This tells the compiler the function’s return type, the


number of arguments it takes, and the type of each
argument (names of formal parameters are not needed
in function declaration !)
Function Calls - Summary
• A function call is a statement:
• name ( arg1, arg2, ... );
• The function called name is called and the values arg1, arg2, ... are
passed as arguments (actual parameters) to the function. If the
function takes no arguments, just the open and closed parentheses
are needed
• If you are calling a function that is defined after the call, or in
another file, a function definition has to be present before !
• A function whose return type is declared as void causes the
compiler to flag any calls to that function that try to make use of a
returned value.
• In C, all arguments to a function are passed by value; therefore,
their values cannot be changed by the function. Exception from this
rule are arrays passed as parameters, they are passed by reference
Kinds of variables - Review
Lifetime Scope

Global variable

Automatic local
variable
Static local
variable
Lecture 8
Lecture 8: Outline
• Structures [Kochan, chap 9]
– Defining and using Structures
– Functions and Structures
– Initializing Structures. Compound Literals
– Arrays of Structures
– Structures Containing Structures and/or Arrays
• More on Data Types [Kochan, chap 14]
– Enumerated Data Types
– The typedef Statement
– Data Type Conversions
The concept of structures
• Structure: a tool for grouping heterogenous elements together.
• Array: a tool for grouping homogenous elements together
• Example: storing calendar dates (day, month, year)
• Version1: using independent variables:
• int month = 9, day = 25, year = 2004;
• Using this method, you must keep track of three separate variables
for each date that you use in the program—variables that are
logically related. It would be much better if you could somehow
group these sets of three variables together. This is what the
structure in C allows you to do !
Example: structures
struct date Defines type struct date, with 3 fields of type int
{ The names of the fields are local in the context
int month; of the structure.
int day; A struct declaration defines a type: if not followed by a
int year; list of variables it reserves no storage; it merely
}; describes a template or shape of a structure.

struct date today, purchaseDate; Defines 3 variables of


type struct date

today.year = Accesses fields of a variable of


2004; type struct date
today.month = 10; A member of a particular structure is referred to
today.day = 5; in an expression by a construction of the
form structurename.member
Example: determine tomorrow’s
date (Version 1)
// Program to determine tomorrow's date
#include <stdio.h>
int main (void)
{
struct date
{
int month;
int day;
int year;
};
struct date today, tomorrow;
const int daysPerMonth[12] = { 31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31 };

printf ("Enter today's date (mm dd yyyy): ");


scanf ("%i%i%i", &today.month, &today.day, &today.year);
Example continued

if ( today.day != daysPerMonth[today.month - 1] ) {
tomorrow.day = today.day + 1;
tomorrow.month = today.month;
tomorrow.year = today.year;
}
else if ( today.month == 12 ) { // end of year
tomorrow.day = 1;
tomorrow.month = 1;
tomorrow.year = today.year + 1;
}
else { // end of month
tomorrow.day = 1;
tomorrow.month = today.month + 1;
tomorrow.year = today.year;
}
printf ("Tomorrow's date is %i/%i/%i.\n", tomorrow.month,
tomorrow.day, tomorrow.year );
return 0;
}
Operations on structures
• Legal operations on a structure are :
– copying it or assigning to it as a unit
• this includes passing arguments to functions and returning values
from functions as well.
– taking its address with &
– accessing its members.
– structures may not be compared as units !
– a structure may be initialized by a list of constant member values
Example: determine tomorrow’s
date (Version 2)
// Program to determine tomorrow's date
#include <stdio.h>
#include <stdbool.h>

struct date Defines type struct date as a global type


{
int month;
int day;
int year;
}; Declares a function that takes a
struct date as a parameter
int numberOfDays (struct date d);

int main (void)


{
struct date today, tomorrow;
printf ("Enter today's date (mm dd yyyy): ");
scanf ("%i%i%i", &today.month, &today.day, &today.year);
Example continued
if ( today.day != numberOfDays (today) ) {
tomorrow.day = today.day + 1;
tomorrow.month = today.month;
tomorrow.year = today.year;
}
else if ( today.month == 12 ) { // end of year
tomorrow.day = 1;
tomorrow.month = 1;
tomorrow.year = today.year + 1;
}
else { // end of month
tomorrow.day = 1;
tomorrow.month = today.month + 1;
tomorrow.year = today.year;
}
printf ("Tomorrow's date is %i/%i/%i.\n",tomorrow.month,
tomorrow.day, tomorrow.year);
return 0;
}
Example continued
bool isLeapYear (struct date d);

// Function to find the number of days in a month


int numberOfDays (struct date d) {
int days;
const int daysPerMonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
if ( isLeapYear (d) == true && d.month == 2 )
days = 29;
else
days = daysPerMonth[d.month - 1];
return days;
}

// Function to determine if it's a leap year


bool isLeapYear (struct date d) {
bool leapYearFlag;
if ( (d.year % 4 == 0 && d.year % 100 != 0) || d.year % 400 == 0 )
leapYearFlag = true; // It's a leap year
else
leapYearFlag = false; // Not a leap year
return leapYearFlag;
}
Example: determine tomorrow’s
date (Version 3)
// Program to determine tomorrow's date
#include <stdio.h>
#include <stdbool.h>
struct date
{
int month;
int day; Declares a function that takes a
int year; struct date as a parameter
}; and returns a struct date
struct date dateUpdate (struct date today);

int main (void){


struct date thisDay, nextDay;
printf ("Enter today's date (mm dd yyyy): ");
scanf ("%i%i%i", &thisDay.month, &thisDay.day,

&thisDay.year);
nextDay = dateUpdate (thisDay);
printf ("Tomorrow's date is %i/%i/%i.\n",nextDay.month,
nextDay.day, nextDay.year );
return 0;
Example continued
int numberOfDays (struct date d);

// Function to calculate tomorrow's date


struct date dateUpdate (struct date today) {
struct date tomorrow;
if ( today.day != numberOfDays (today) ) {
tomorrow.day = today.day + 1;
tomorrow.month = today.month;
tomorrow.year = today.year;
}
else if ( today.month == 12 ) { // end of year
tomorrow.day = 1;
tomorrow.month = 1;
tomorrow.year = today.year + 1;
}
else { // end of month
tomorrow.day = 1;
tomorrow.month = today.month + 1;
tomorrow.year = today.year;
}
return tomorrow;
}
Example: Update time by one
second
// Program to update the time by one second
#include <stdio.h>
struct time
{
int hour;
int minutes;
int seconds;
};

struct time timeUpdate (struct time now);

int main (void) {


struct time currentTime, nextTime;
printf ("Enter the time (hh:mm:ss): ");
scanf ("%i:%i:%i", &currentTime.hour, &currentTime.minutes,
&currentTime.seconds);
nextTime = timeUpdate (currentTime);
printf ("Updated time is %.2i:%.2i:%.2i\n", nextTime.hour,
nextTime.minutes, nextTime.seconds );
return 0;
}
Example continued
// Function to update the time by one second
struct time timeUpdate (struct time now) {
++now.seconds;
if ( now.seconds == 60 ) { // next minute
now.seconds = 0;
++now.minutes;
if ( now.minutes == 60 ) { // next hour
now.minutes = 0;
++now.hour;
if ( now.hour == 24 ) // midnight
now.hour = 0;
}
}
return now; Parameters of a
} struct type are
passed by copy
of value
Initializing structures. Compound
literals
struct date today = { 7, 2, 2005 };
struct time this_time = { 3, 29, 55 };
today = (struct date) { 9, 25, 2004 };
today = (struct date) { .month = 9, .day = 25, .year = 2004 };
Arrays of structures
struct time { . . . };

struct time timeUpdate (struct time now);

int main (void) {


struct time testTimes[5] =
{ { 11, 59, 59 }, { 12, 0, 0 }, { 1, 29, 59 },
{ 23, 59, 59 }, { 19, 12, 27 }};
int i;
for ( i = 0; i < 5; ++i ) {
printf ("Time is %.2i:%.2i:%.2i",
testTimes[i].hour,
testTimes[i].minutes, testTimes[i].seconds);
testTimes[i] = timeUpdate (testTimes[i]);
printf (" ...one second later it's %.2i:%.2i:%.2i\
n",
testTimes[i].hour, testTimes[i].minutes,
testTimes[i].seconds);
}
Structures containing structures
struct dateAndTime
{
struct date sdate;
struct time stime;
};

. . .

struct dateAndTime event;

event.sdate = dateUpdate (event.sdate);

event.sdate.month = 10;
Structures containing arrays
struct month
{
int numberOfDays;
char name[3];
};

struct month aMonth;

. . .

aMonth.numberOfDays = 31;
aMonth.name[0] = 'J';
aMonth.name[1] = 'a';
aMonth.name[2] = 'n';
Enumerated data type
• You can use the enumerated type to declare symbolic names to represent
integer constants.
• By using the enum keyword, you can create a new "type" and specify the
values it may have.
• Actually, enum constants are type int; therefore, they can be used wherever
you would use an int.
• The purpose of enumerated types is to enhance the readability of a
program.
• enum primaryColor { red, yellow, blue };
• enum primaryColor myColor, gregsColor;
• myColor = red;
• if ( gregsColor == yellow ) …
Enumerated data type
• The C compiler actually treats enumeration identifiers as integer constants.
Beginning with the first name in the list, the compiler assigns sequential
integer values to these names, starting with 0.
• enum month thisMonth;
• ...
• thisMonth = february;
• the value 1 is assigned to thisMonth because it is the second identifier
listed inside the enumeration list.
• If you want to have a specific integer value associated with an enumeration
identifier, the integer can be assigned to the identifier when the data type is
defined. Enumeration identifiers that subsequently appear in the list are
assigned sequential integer values beginning with the specified integer
value plus 1. For example, in the definition
• enum direction { up, down, left = 10, right };
• an enumerated data type direction is defined with the values up, down, left,
and right. The compiler assigns the value 0 to up because it appears first in
the list; 1 to down because it appears next; 10 to left because it is explicitly
assigned this value; and 11 to right because it appears immediately after left
in the list.
Example: enum
// Program to print the number of days in a month
#include <stdio.h>
int main (void)
{
enum month { january = 1, february, march, april, may,
june,july, august, september, october, november, december
};
enum month aMonth;
int days;
printf (“Enter month number: “);
scanf (“%i”, &aMonth);
Cont.
switch (aMonth ) {
case january: case march: case may: case
july:
case august: case october: case december:
days = 31; break;
case april: case june: case september: case
november:
days = 30; break;
case february:
days = 28; break;
default:
printf (“bad month number\
n”);
days = 0; break;
}
if ( days != 0 )
printf (“Number of days is %i\n”, days);
if ( amonth == february )
printf (“...or 29 if it’s a leap year\n”);
return 0;
}
The typedef statement
• C provides a capability that enables you to assign an alternate name to
a data type. This is done with a statement known as typedef.

typedef type_description type_name;

• The statement
typedef int Counter;
• defines the name Counter to be equivalent to the C data type int.
Variables can subsequently be declared to be of type Counter, as in the
following statement:
Counter j, n;
• The C compiler actually treats the declaration of the variables j and n,
shown in the preceding code, as normal integer variables.
• The main advantage of the use of the typedef in this case is in the
added readability that it lends to the definition of the variables.
• the typedef statement does not actually define a new type—only a
new type name.
The typedef statement
• In forming a typedef definition, proceed as though a normal variable
declaration were being made. Then, place the new type name where the
variable name would normally appear. Finally, in front of everything, place the
keyword typedef:
• typedef char Linebuf [81];
• defines a type called Linebuf, which is an array of 81 characters. Subsequently
declaring variables to be of type Linebuf, as in
• Linebuf text, inputLine;

typedef struct
{
int month;
int day;
int year;
} Date;

Date birthdays[100];
Data type conversions
• Expressions: Operands and operators
• Operands may be of different types; issue: how is the expression
evaluated and what is the type of the result ?

• sometimes conversions are implicitly made by the system when


expressions are evaluated !
• The C compiler adheres to strict rules when it comes to evaluating
expressions that consist of different data types.
• Essence of automatic conversion rules: convert “smaller”
type to “bigger” type

• Example: the case examined in lecture 2 was with the data types float
and int: an operation that involved a float and an int was carried out as a
floating-point operation, the integer data item being automatically
converted to floating point.

• the type cast operator can be used to explicitly dictate a conversion.


Rules for automatic conversions
1. If either operand is of type long double, the other is
converted to long double, and that is the type of the
result.
2. If either operand is of type double, the other is
converted to double, and that is the type of the result.
3. If either operand is of type float, the other is converted
to float, and that is the type of the result.
4. If either operand is of type _Bool, char, short int,
or of an enumerated data type, it is converted to int.
5. If either operand is of type long long int, the other
is converted to long long int, and that is the type of the
result.
6. If either operand is of type long int, the other is
converted to long int, and that is the type of the result.
7. If this step is reached, both operands are of type int, and
that is the type of the result.

Example: f is defined to be a float, i an int, l a long int, and s a short


int variable: evaluate expression f * i + l / s
Sign extensions
• Conversion of a signed integer to a longer integer results in
extension of the sign (0 or 1) to the left;
– This ensures that a short int having a value of –5 will also have the
value –5 when converted to a long int.
• Conversion of an unsigned integer to a longer integer results in zero
fill to the left.
Signed integer representation
• The representation of negative numbers: Most
computers represent such numbers using the two’s
complement notation.
• Using this notation, the leftmost bit represents the sign
bit. If this bit is 1, the number is negative; otherwise, the
bit is 0 and the number is positive. The remaining bits
represent the value of the number.
• The value w of an N-bit integer is given by the formula:
Two’s complement example

• N=8

• W= 11111011
• W=(-1)*27+1*26+1*25+1*24+1*23+0+1*21+1*20 =-5
Two’s complement example
• A convenient way to convert a negative number from
decimal to binary:
1. add 1 to the value
2. express the absolute value of the result in binary
3. and then “complement” all the bits; that is, change all 1s to 0s
and 0s to 1s.
• Example: convert -5 to binary:
1. First 1 is added, which gives -4;
2. Value 4 expressed in binary is 00000100
3. Complementing the bits produces 11111011.
Signed & Unsigned types
• If in an expression appear both signed and unsigned operands, signed
operands are automatically converted to unsigned
• Converting signed to unsigned:
– No change in bit representation
– Nonnegative values unchanged
– Negative values change into positive values !
– Example: int x=-5; unsigned int ux=(unsigned int) x;
printf(“%ud \n”,ux); // 4294966*62
• Conversion surprises:
int a=-5;
unsigned int b=1;

if (a>b) printf("a is bigger than b");


else if (a<b) printf("b is bigger than a");
else printf("a equals b");
Explicit conversions/casts
• Rules:
– Conversion of any value to a _Bool results in 0 if the value is zero and 1
otherwise.
– Conversion of a longer integer to a shorter one results in truncation of
the integer on the left.
– Conversion of a floating-point value to an integer results in truncation of
the decimal portion of the value. If the integer is not large enough to
contain the converted floating-point value, the result is not defined, as is
the result of converting a negative floating-point value to an unsigned
integer.
– Conversion of a longer floating-point value to a shorter one might or
might not result in rounding before the truncation occurs.
Lecture 9
Lecture 9: Outline
• Strings [Kochan, chap. 10]
– Character Arrays/ Character Strings
– Initializing Character Strings. The null string.
– Escape Characters
– Displaying Character Strings
– Inputting Character Strings
– String processing:
• Testing Strings for Equality
• Comparing Strings
• Copying Strings
– Functions in <string.h>
– String to number conversion functions
– Character Strings, Structures, and Arrays
– Example: Simple dictionary program
• Sorting the dictionary
• A better search in sorted arrays
Arrays of characters
• char word [] = { 'H', 'e', 'l', 'l', 'o', '!' };
• To print out the contents of the array word, you run through each element in
the array and display it using the %c format characters.
• To do processings of the word (copy, concatenate two words, etc) you need
to have the actual length of the character array in a separate variable !
Character strings
• A method for dealing with character arrays without having to worry about
precisely how many characters you have stored in them:
• Placing a special character at the end of every character string. In this
manner, the function can then determine for itself when it has reached the
end of a character string after it encounters this special character.
• In the C language, the special character that is used to signal the end of a
string is known as the null character and is written as '\0'.
• char word [] = { 'H', 'e', 'l', 'l', 'o', '!', '\0' };
Example: string length
// Function to count the number of characters in a string
#include <stdio.h>

int stringLength (char string[]){


int count = 0;
while ( string[count] != '\0' )
++count;
return count;
}
int main (void) {
char word1[] = { 'a', 's', 't', 'e', 'r', '\0' };
char word2[] = { 'a', 't', '\0' };
char word3[] = { 'a', 'w', 'e', '\0' };
printf ("%i %i %i\n", stringLength (word1),
stringLength (word2), stringLength (word3));
return 0;
}
Example: const strings
// Function to count the number of characters in a string
#include <stdio.h>
The function
int stringLength (const char string[]){ declares its
int count = 0; argument as a const
array of characters
while ( string[count] != '\0' ) because it is not
++count; making any changes
return count; to the array
}
int main (void) {
const char word1[] = { 'a', 's', 't', 'e', 'r', '\0' };
const char word2[] = { 'a', 't', '\0' };
const char word3[] = { 'a', 'w', 'e', '\0' };
printf ("%i %i %i\n", stringLength (word1),
stringLength (word2), stringLength (word3));
return 0;
}
Initializing character strings
• Initializing a string:
char word[] = "Hello!";
• Is equivalent with:
char word[] = { 'H', 'e', 'l', 'l', 'o', '!', '\0' };
• The null string: A character string that contains no characters other than the null
character
char empty[]= "";
char buf[100]= "";
• Initializing a very long string over several lines:
char letters[] =
{ "abcdefghijklmnopqrstuvwxyz\
ABCDEFGHIJKLMNOPQRSTUVWXYZ" };
• Adjacent strings are concatenated:
char letters[] =
{ "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" };

printf ("Programming" " in C is fun\n");


Strings vs Characters
• The string constant "x“
• The character constant 'x‘
• Differences:
1. 'x' is a basic type (char) but "x" is a derived type, an array of char

2. "x" really consists of two characters, 'x' and '\0', the null character
Escape characters
\a Audible alert • the backslash character has a
\b Backspace special significance
\f Form feed
\n Newline
• other characters can be combined
\r Carriage return with the backslash character to
\t Horizontal tab perform special functions. These
\v Vertical tab are referred to as escape
\\ Backslash characters.
\" Double quotation mark
\' Single quotation mark
\? Question mark
\nnn Octal character value nnn
\unnnn Universal character name
\Unnnnnnnn Universal character
name
\xnn Hexadecimal character value
nn
Examples: Escape characters

printf ("\aSYSTEM SHUT DOWN IN 5 MINUTES!!\n");

printf ("%i\t%i\t%i\n", a, b, c);

printf ("\\t is the horizontal tab character.\n");

printf ("\"Hello,\" he said.\n");

c = '\'';

printf("\033\"Hello\"\n");
Displaying character strings

• Displaying a string: %s
• printf ("%s\n", word);
Inputting character strings
• char string[81];
• scanf ("%s", string); // NOT recommended !
– The scanf function can be used with the %s format characters to read in a
string of characters up to a blank space, tab character, or the end of the line,
whichever occurs first
– The string terminator (null character) is appended to string
– Note that unlike previous scanf calls, in the case of reading strings, the & is
not placed before the array name !
– If you type in more than 80 consecutive characters to the preceding program
without pressing the spacebar, the tab key, or the Enter (or Return) key,
scanf overflows the character array !
• Correct use of scanf for reading strings:
• scanf ("%80s", string); // Safer version !
– If you place a number after the % in the scanf format string, this tells scanf
the maximum number of characters to read.
Example: string processing
#include <stdio.h>

void concat (char result[],


const char str1[], const char str2[]);

int main (void)


{
const char s1[] = "Test " ;
const char s2[] = "works." ;
char s3[20];
concat (s3, s1, s2);
printf ("%s\n", s3);
return 0;
}
Example: concatenate strings

// Function to concatenate two character strings


void concat (char result[], const char str1[],
const char str2[])
{
int i, j;
// copy str1 to result
for ( i = 0; str1[i] != '\0'; ++i )
result[i] = str1[i];
// copy str2 to result
for ( j = 0; str2[j] != '\0'; ++j )
result[i + j] = str2[j];
// Terminate the concatenated string with a null character
result [i + j] = '\0';
}
Testing strings for equality
bool equalStrings (const char s1[], const char s2[])
{
int i = 0;
bool areEqual;
while ( s1[i] == s2 [i] && s1[i] != '\0' && s2[i] != '\0' )
++i;
if ( s1[i] == '\0' && s2[i] == '\0' )
areEqual = true;
else
areEqual = false;
return areEqual;
}

!!! NOT: s1==s2


Alphabetically comparing strings
// Function to compare two character strings
int compareStrings (const char s1[], const char s2[])
{
int i = 0, answer;
while ( s1[i] == s2[i] && s1[i] != '\0'&& s2[i] != '\0' )
++i;
if ( s1[i] < s2[i] )
answer = -1; /* s1 < s2 */
else if ( s1[i] == s2[i] )
answer = 0; /* s1 == s2 */
else
answer = 1; /* s1 > s2 */
return answer;
}

!!! NOT: s1 < s2


!!! NOT: s1 > s2
Copying strings

void copyString(char dest[], char srs[]) {


int i;
i=0;
while ((dest[i] = srs[i]) != '\0')
i++;
}

!!! NOT: dest = srs


String functions
• The C library supplies several string-handling functions; You don’t have to
re-write them from scratch !
• ANSI C uses the <string.h> header file to provide the prototypes.
• Most frequently used functions: strlen(), strcat(), strncat(), strcmp(),
strncmp(), strcpy(), and strncpy().

• #include <string.h>
• strcat (s1, s2)
– Concatenates the character string s2 to the end of s1, placing a null
character at the end of the final string.The function also returns s1.
• strcmp (s1, s2)
– Compares strings s1 and s2 and returns a value less than zero if s1 is
less than s2, equal to zero if s1 is equal to s2, and greater than zero if s1
is greater than s2.
• strcpy (s1, s2)
– Copies the string s2 to s1, also returning s1.
• strlen (s)
– Returns the number of characters in s, excluding the null character.
String functions (cont.)
• strncat (s1, s2, n)
– Copies s2 to the end of s1 until either the null character is reached or n
characters have been copied, whichever occurs first. Returns s1.
• strncmp (s1, s2, n)
– Performs the same function as strcmp, except that at most n characters
from the strings are compared.
• strncpy (s1, s2, n)
– Copies s2 to s1 until either the null character is reached or n characters
have been copied, whichever occurs first. Returns s1.
• strchr (s, c)
– Searches the string s for the last occurrence of the character c. If found,
a pointer to the character in s is returned; otherwise, the null pointer is
returned.
• strstr (s1, s2)
– Searches the string s1 for the first occurrence of the string s2. If found,
a pointer to the start of where s2 is located inside s1 is returned;
otherwise, if s2 is not located inside s1, the null pointer is returned.
Example: String functions
#include <stdio.h>

#include <string.h> /* provides strlen() prototype */

#define PRAISE "What a super marvelous name!"

int main(void) {
char name[40];
printf("What's your name?\n");
scanf("%39s", name);
printf("Hello, %s. %s\n", name, PRAISE);
printf("Your name of %d letters occupies %d memory \n",
strlen(name), sizeof name);
return 0;
}
Example: String functions
#include <stdio.h>

#include <string.h>

int main(void) {
char string1[] = "this is";
char string2[] = "a test";
char string3[20] = "Hello, ";
char string4[] = "world!";
printf("%s\n", string3);
strcat(string3, string4);
printf("%s\n", string3);
if(strcmp(string1, string2) == 0)
printf("strings are equal\n");
else printf("strings are different\n");
return 0;
}
String to number conversions
• Storing a number as a string means storing the digit characters
• Example: the number 213 can be stored in a character string array
as the digits '2', '1', '3', '\0'. Storing 213 in numeric form means
storing it as an int.
• C requires numeric forms for numeric operations, such as addition
and comparison, but displaying numbers on your screen requires a
string form because a screen displays characters. The printf() and
scanf() functions, through their %d and other specifiers, convert
numeric forms to string forms, and vice versa.
• C also has functions whose sole purpose is to convert string forms
to numeric forms.
String to number
conversion functions
• <stdlib.h>
• atoi(s) converts string s to a type int value and returns it. The function
converts characters until it encounters something that is not part of an
integer.
• atof() converts a string to a type double value and returns it
• atol() converts a string to a type long value and returns it

// Using atoi
#include <stdio.h>
#include <stdlib.h>
int main (void) {
printf ("%i\n", atoi("245"));
printf ("%i\n", atoi("100") + 25);
printf ("%i\n", atoi("13x5"));
return 0;
}
String to number conversion
Do-it-yourself exercise
// Function to convert a string to an integer – my atoi
#include <stdio.h>
int strToInt (const char string[]) {
int i, intValue, result = 0;
for ( i = 0; string[i] >= '0' && string[i] <= '9'; ++i )
{
intValue = string[i] - '0';
result = result * 10 + intValue;
}
return result;
}
int main (void) {
printf ("%i\n", strToInt("245"));
printf ("%i\n", strToInt("100") + 25);
printf ("%i\n", strToInt("13x5"));
return 0;
}
Example: readLine

// Function to read a line of text from the terminal


void readLine (char buffer[])
{
char character;
int i = 0;
do
{
character = getchar ();
buffer[i] = character;
++i;
}
while ( character != '\n' );
buffer[i - 1] = '\0';
}
Example continued

#include <stdio.h>

void readLine (char buffer[]);

int main (void)


{
int i;
char line[81];
for ( i = 0; i < 3; ++i )
{
readLine (line);
printf ("%s\n\n", line);
}
return 0;
}
Example: array of structures
Example: a dictionary program
struct entry
{
char word[15];
char definition[50];
};

struct entry dictionary[100] =


{ { "aardvark", "a burrowing African mammal" },
{ "abyss", "a bottomless pit" },
{ "acumen", "mentally sharp; keen" },
{ "addle", "to become confused" },
{ "aerie", "a high nest" },
{ "affix", "to append; attach" },
{ "agar", "a jelly made from seaweed" },
{ "ahoy", "a nautical call of greeting" },
{ "aigrette", "an ornamental cluster of feathers" },
{ "ajar", "partially opened" } };
Example: dictionary continued
int lookup (const struct entry dictionary[],
const char search[], const int entries);

int main (void)


{
char word[10];
int entries = 10;
int entry;
printf ("Enter word: ");
scanf ("%14s", word);
entry = lookup (dictionary, word, entries);
if ( entry != -1 )
printf ("%s\n", dictionary[entry].definition);
else
printf (“The word %s is not in my dictionary.\n", word)
return 0;
}
Searching in array
#include <string.h>

// function to look up a word inside a dictionary


int lookup (const struct entry dictionary[],
const char search[],const int entries)
{
int i;
for ( i = 0; i < entries; ++i )
if ( strcmp(search, dictionary[i].word) )
return i;
return -1;
}
Binary search
• Binary Search Algorithm
• Search x in SORTED array M
• Step 1: Set low to 0, high to n – 1.
• Step 2: If low > high, x does not exist in M and the algorithm terminates.
• Step 3: Set mid to (low + high) / 2.
• Step 4: If M[mid] < x, set low to mid + 1 and go to step 2.
• Step 5: If M[mid] > x, set high to mid – 1 and go to step 2.
• Step 6: M[mid] equals x and the algorithm terminates.
Binary search
// Function to look up a word inside a dictionary
int lookup (const struct entry dictionary[],
const char search[], const int entries)
{
int low = 0;
int high = entries - 1;
int mid, result;
while ( low <= high )
{
mid = (low + high) / 2;
result = strcmp (dictionary[mid].word, search);
if ( result == -1 )
low = mid + 1;
else if ( result == 1 )
high = mid - 1;
else
return mid; /* found it */
}
return -1; /* not found */
}
Lectures 10 & 11
Outline
• Pointers
• Kernighan&Ritchie – chapter 6
• Steve Summit: Online C tutorial – chapters 10, 11
http://www.eskimo.com/~scs/cclass/notes/sx10.html
http://www.eskimo.com/~scs/cclass/notes/sx11.html
– Pointers and Addresses
– Pointers and Function Arguments
– Pointers and Arrays
– Pointer Arithmetics
– Pointers and strings
– Dynamic memory allocation
– Pointer arrays. Pointers to pointers
– Multidimensional arrays and pointers
– Structures and pointers
Pointers and addresses
• a pointer is a variable whose value is a memory address
• int count = 10;
• int *int_pointer;
• int_pointer = &count;
• The address operator has the effect of assigning to the variable
int_pointer, not the value of count, but a pointer to the variable count.
• We say that int_ptr "points to" count
• The values and the format of the numbers representing memory addresses
depend on the computer architecture and operating system. In order to have
a portable way of representing memory addresses, we need a different type
than integer !
• To print addresses: %p
Lvalues and Rvalues
• There are two “values” associated with any variable:
– An "lvalue" (left value) of a variable is the value of its address,
where it is stored in memory.
– The "rvalue" (right value) of a variable is the value stored in that
variable (at that address).
• The lvalue is the value permitted on the left side of the
assignment operator '=' (the address where the result of
evaluation of the right side will be stored).
• The rvalue is that which is on the right side of the
assignment statement
• a=a+1
Declaring pointer variables
type * variable_name;

• it is not enough to say that a variable is a pointer. You also have to


specify the type of variable to which the pointer points !
– int * p1; // p1 points to an integer
– float * p2; // p2 points to a float
• Exception: generic pointers (void *) indicate that the pointed data
type is unknown
– may be used with explicit type cast to any type (type *)
– void * p;
Indirection (dereferencing) operator *
• To reference the contents of count through the pointer variable
int_pointer, you use the indirection operator, which is the asterisk
* as an unary prefix operator. *int_pointer
• If a pointer variable p has the type t*, then the expression *p has
the type t
// Program to illustrate pointers
#include <stdio.h>
int main (void)
{
int count = 10, x;
int *int_pointer;
int_pointer = &count;
x = *int_pointer;
printf ("count = %i, x = %i\n", count, x);
return 0;
}
Example: pointers
// Program to illustrate pointers
#include <stdio.h>
int main (void)
{
int count = 10;
int *ip;
ip = &count;
printf ("count = %i, *ip = %i\n", count, *ip);
*ip=4;
printf ("count = %i, *ip = %i\n", count, *ip);
return 0;
}
Using pointer variables
• The value of a pointer in C is meaningless until it is set pointing to
something !
int *p; Severe runtime error !!! the value 4 is stored in the location to
which p points. But p, being uninitialized, has a random value,
*p = 4; so we cannot know where the 4 will be stored !
• How to set pointer values:
– Using the address operator
int *p;
int x;
p = &x;
*p = 4;
– Using directly assignements between pointer variables
int *p;
int *p1;
int x;
p1 = &x;
p = p1;
*p = 4;
NULL pointers
• Values of a pointer variable:
– Usually the value of a pointer variable is a pointer to some other variable
– Another value a pointer may have: it may be set to a null pointer
• A null pointer is a special pointer value that is known not to point anywhere.
• No other valid pointer, to any other variable, will ever compare equal to a
null pointer !
• Predefined constant NULL, defined in <stdio.h>
• Good practice: test for a null pointer before inspecting the value pointed !

#include <stdio.h>

int *ip = NULL;

if(ip != NULL) printf("%d\n", *ip);

if(ip ) printf("%d\n", *ip);


const and pointers
• With pointers, there are two things to consider:
– whether the pointer will be changed
– whether the value that the pointer points to will be changed.
• Assume the following declarations:
char c = 'X';
char *charPtr = &c;
• If the pointer variable is always set pointing to c, it can be declared as a const
pointer as follows:
char * const charPtr = &c;
*charPtr = 'Y'; // this is valid
charPtr = &d; // not valid !!!
• If the location pointed to by charPtr will not change through the pointer
variable charPtr, that can be noted with a declaration as follows:
const char *charPtr = &c;
charPtr = &d; // this is valid
*charPtr = 'Y'; // not valid !!!
Pointers and Function Arguments
• Recall that the C language passes arguments to functions by value (except
arrays)
• there is no direct way for the called function to alter a variable in the calling
function.

void swap(int x, int y) /* WRONG */


{
int temp;
temp = x;
x = y; Because of call by value,
y = temp; swap can't affect the
} arguments a and b in the
routine that called it.
swap(a,b); The function above
swaps copies of a and b.
Pointers and Function Arguments
• If it is necessary that a function alters its arguments, the caller can pass
pointers to the values to be changed
• Pointer arguments enable a function to access and change variables in the
function that called it

void swap(int *px, int *py)


/* interchange *px and *py */
{
int temp;
temp = *px;
*px = *py;
*py = temp;
}

int a=3, b=5;


swap(&a, &b);
Pointers and arrays
• In C, there is a strong relationship between pointers and arrays
• Any operation that can be achieved by array subscripting can also be done
with pointers

int a[10];

int *pa;
pa=&a[0];
Or
pa=a;

The value of a variable of type array is the address of element zero of


the array.
The name of an array is a synonym for the location of
the initial element.
Pointers and Arrays
• If pa points to a particular element of an array, then by definition pa+1 points
to the next element, pa+i points i elements after pa, and pa-i points i
elements before.
• If pa points to a[0], *(pa+1) refers to the contents of a[1], pa+i is the address
of a[i], and *(pa+i) is the contents of a[i].
• The value in a[i] can also be written as *(a+i). The address &a[i] and a+i
are also identical
• These remarks are true regardless of the type or size of the variables in the
array a !
Arrays are constant pointers

int a[10]; int a[10];


int *pa; int *pa;

pa=a; a=pa;

pa++; a++;

OK. Pointers are variables that Errors !!!


can be assigned or incremented

The name of an array is a CONSTANT having as a value the location


of the first element.
You cannot change the address where the array is stored !
An array's name is equivalent with a constant pointer
Arrays as parameters
• When an array name is passed to a function, what is
passed is the location of the first element. Within the called
function, this argument is a local variable, and so an array
name parameter is a pointer, that is, a variable containing
an address.
• As formal parameters in a function definition, T s[] and T
*s are equivalent, for any type T; The latter is preferred
because it says more explicitly that the variable is a
pointer.
• Examples:
• f(int arr[]) { ... } is equivalent with f(int *arr) { ... }
• f(char s[]) { …} is equivalent with f(char *s) { …}
Example: Arrays as parameters
void print1(int tab[], int N) { The formal parameter can be declared
int i; as array or pointer !
for (i=0; i<N; i++)
In the body of the function, the array
printf("%d ",tab[i]);
}
elements can be accessed through
void print2(int tab[],int N) { indexes or pointers !
int * ptr;
for (ptr=tab; ptr<tab+N; ptr++)
printf("%d ", *ptr);
}
void print3(int *tab,int N) {
int * ptr;
void main(void) {
for (ptr=tab; ptr<tab+N; ptr++)
printf("%d ", *ptr);
int a[5]={1,2,3,4,5};
} print1(a,5);
void print4(int *tab,int N) { print2(a,5);
int i; print3(a,5);
for (i=0; i<N; i++, tab++) print4(a,5);
printf("%d ", *tab); }
}
Example: Arrays as parameters

/* strlen: return length of string s */


int strlen(char *s)
{
int n;
for (n = 0; *s != '\0‘; s++)
n++;
return n; The actual parameter can be declared
} as array or pointer !

char array[100]="Hello, world";


char *ptr="Hello, world";

strlen(“Hello, world"); /* string constant */


strlen(array); /* char array[100]; */
strlen(ptr); /* char *ptr; */
Example: Arrays as parameters
int strlen(char *s)
{
if (*s=='\0')
return 0;
else
return 1 + strlen(++s); The recursive call gets as parameter
} the subarray starting with the
second element

It is possible to pass part of an array to a function, by passing a pointer to


the beginning of the subarray.
For example, if a is an array, f(&a[2]) and f(a+2) both pass to the
function f the address of the subarray that starts at a[2].
Pointer arithmetic
• All operations on pointers take into account the
size of the pointed type (sizeof(T)) !
• Valid pointer operations:
– Assignement between pointers of the same type
– Addition/ subtraction between a pointer and an integer
– Comparison between two pointers that point to
elements of the same array
– Subtraction between two pointers that point to
elements of the same array
– Assignment or comparison with zero (NULL)
Pointer arithmetic
• Increment/decrement: if p is a pointer to type T, p++ increases the value of
p by sizeof(T) (sizeof(T) is the amount of storage needed for an object of
type T). Similarly, p-- decreases p by sizeof(T);
T tab[N];
T * p;
int i;
p=&tab[i];
p++; // p contains the address of tab[i+1];
• Addition/subtraction with an integer: if p is a pointer to type T and n an
integer, p+n increases the value of p by n*sizeof(T). Similarly, p-n
decreases p by n*sizeof(T);

T tab[N];
T * p;
p=tab;
p=p+n; // p contains the address of tab[n].
Pointer arithmetic
• Comparison of two pointers.
• If p and q point to members of the same array, then relations like ==, !=,
<, >=, etc., work properly.
– For example, p < q is true if p points to an earlier element of the array than q
does.
• Any pointer can be meaningfully compared for equality or inequality with
zero.
• Pointer subtraction :
• if p and q point to elements of the same array, and p<q, then q-p+1 is
the number of elements from p to q inclusive.

• The behavior is undefined for arithmetic or comparisons with pointers that


do not point to members of the same array.
Example: pointer subtraction

/* strlen: return length of string s */


int strlen(char *s)
{
char *p = s;
while (*p != '\0')
p++;
return p - s;
}
Character pointers
• A string constant: "I am a string"
• is an array of characters. In the internal representation, the array is
terminated with the null character '\0' so that programs can find the end. The
length in storage is thus one more than the number of characters between
the double quotes.
• a string constant is accessed by a pointer to its first element
• char *pmessage;
• pmessage = "now is the time";
• assigns to pmessage a pointer to the character array. This is not a string
copy; only pointers are involved !
Character pointers
char amessage[] = "now is the time"; /* an array */
char *pmessage = "now is the time"; /* a pointer */

amessage now is the time\0

pmessage now is the time\0

• amessage is an array, just big enough to hold the sequence of characters


and '\0' that initializes it. Individual characters within the array may be
changed but amessage will always refer to the same storage.
• pmessage is a pointer, initialized to point to a string constant; the pointer
may subsequently be modified to point elsewhere, but the result is
undefined if you try to modify the string contents.
Precedence of operators
• *p++ increments p after fetching the character that p points to
char *p=“hello” ;
printf(“%c”,*p++); // displays
h

• *++p increments p before fetching the character that p points to

char *p=“hello” ;
printf(“%c”,*++p); // displays
e
Example: Character pointers and
functions
/* strcpy: copy t to s; array subscript version */
void strcpy(char s[], char t[])
{
int i;
i = 0;
while ((s[i] = t[i]) != '\0')
i++;
}

/* strcpy: copy t to s; pointer version */


void strcpy(char *s, char *t)
{
int i;
i = 0;
while ((*s = *t) != '\0') {
s++;
t++;
}
}
Example: Character pointers and
functions
/* strcpy: copy t to s; pointer version 2 */
void strcpy(char *s, char *t)
{
while ((*s++ = *t++) != '\0')
;
}

/* strcpy: copy t to s; pointer version 3 */


void strcpy(char *s, char *t)
{
while (*s++ = *t++)
;
}
Exercise: What is the output ?
void swap_vectors(int *a, int *b, int n) {
int *t;
t=a;
a=b;
b=t;
print_vector(a,3);
print_vector(b,3);
}
...
int a[3]={1,2,3};
int b[3]={4,5,6};
swap_vectors(a,b,3);
print_vector(a,3);
print_vector(b,3);
Exercise: different versions of
adding 2 vectors
void add_vectors1 (int a[], int b[], int r[], int n) {
int i;
for (i=0; i<n; i++)
r[i]=a[i]+b[i];
}

void add_vectors2 (int *a, int *b, int *r, int n) {


int i;
for (i=0; i<n; a++, b++, r++, i++)
*r=*a+*b;
}
Exercise: different versions of
adding 2 vectors
int a[3]={1,2,3};
int b[3]={4,5,6};
int r[3];

add_vectors1(a,b,r,3); OK, functions


print_vector(r,3); are equivalent
add_vectors2(a,b,r,3);
print_vector(r,3);
Exercise: different versions of
adding 2 vectors
int * add_vector3(int *a, int *b, int n) {
int r[3];
int i;
for (i=0; i<n; i++, a++, b++)
r[i]=*a+*b;
NO !!!
return r;
}


int a[3]={1,2,3};
BIG MISTAKE !
int b[3]={4,5,6}; The function
int * rr; returns the
rr=add_vector3(a,b,3); address of a
print_vector(rr,3); local variable !
Exercise: different versions of
adding 2 vectors
int * add_vector3(int *a, int *b, int n) {
static int r[3];
int i;
for (i=0; i<n; i++, a++, b++)
r[i]=*a+*b;
return r; Does this solve
} the problem ?

int a[3]={1,2,3};
int b[3]={4,5,6};
int * rr;
rr=add_vector3(a,b,3);
print_vector(rr,3);
Exercise: different versions of
adding 2 vectors
int * add_vector3(int *a, int *b, int n) {
static int r[3];
int i;
for (i=0; i<n; i++, a++, b++)
r[i]=*a+*b;
return r;
}
Does this solve
… the problem ?
int a[3]={1,2,3};
int b[3]={4,5,6};
int c[3]={0,1,2};
int d[3]={3,4,5};
int * rr1, *rr2;
rr1=add_vector3(a,b,3);
rr2=add_vector3(c,d,3);
print_vector(rr1,3); NO !
print_vector(rr2,3);
Dynamic memory allocation
• Variable definitions in C: the C compiler automatically allocates the
correct amount of storage (1-n memory locations) where the
variable will be stored -> this happens before the execution of the
actual program starts
• Sometimes it can be useful to dynamically allocate storage while a
program is running:
• Suppose we have a program that is designed to read in a set of
data from input into an array in memory but we don’t know how
many data items there are until the program starts execution. We
have three choices:
– Define the array to contain the maximum number of possible elements
at compile time.
– Use a variable-length array to dimension the size of the array at
runtime.
– Allocate the array dynamically using one of C’s memory allocation
routines.
malloc()
• <stdlib.h>
• void * malloc(int n);
• malloc allocates n bytes of memory and returns a pointer
to them if the allocation was succesful, NULL otherwise
• Before using the pointer returned by malloc, it has to be
checked if it is not NULL !!
• The pointer returned by malloc is of the generic type void
*; it has to be converted to a concrete pointer type
malloc() Example1
#include <stdlib.h>

char *line;
int linelen;

printf (“How long is your line ?”);


scanf(“%d”,&linelen);

line = (char *) malloc(linelen);

/* incomplete here - malloc's return value not checked */

getline(line, linelen);
malloc() Example 2
char *somestring=“how are you”;
char *copy;
...
copy = (char *) malloc(strlen(somestring) + 1);

/* incomplete -- malloc's return value not checked */

strcpy(copy, somestring);
Checking what malloc returns !
• When malloc is unable to allocate the requested memory, it returns a null
pointer. Therefore, whenever you call malloc, it's vital to check the returned
pointer before using it !

char * line = (char *) malloc(linelen); ;


if(line == NULL) {
printf("out of memory\n");
return; // exits current function
}

char * line = (char *) malloc(linelen);


if(line == NULL) {
printf("out of memory\n");
exit(1); // exits all nested function calls,
// terminates program
}
Dynamic allocation of arrays
• Dynamic allocation of an array of N elements of type
TIP:
• TIP * p;
• p= (TIP *) malloc(N*sizeof(TIP));
• Pointer p will point to a memory block big enough to hold
N elements of type TIP.
• Variable p can be used in the same way as if it was
declared:
• TIP p[N];
Example: dynamic allocation of
arrays
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int n;
int * tab;
int i;
printf("Input number of elements: \n");
scanf("%d", &n);
if ((tab=(int *)malloc(n * sizeof(int)))==NULL) {
printf(“Memory allocation error !\n");
exit(1);
}
for (i=0; i<n; i++)
scanf("%d", &tab[i]);
for (i=0; i<n; i++)
printf("%d ", tab[i]);
free(tab);
return 1;
}
Example: dynamic allocation of
character strings
void main(void)
{
char sir1[40];
char *sir2;
printf(“Enter a string: \n");
scanf("%40s", sir1);
if ((sir2=(char *)malloc(strlen(sir1)+1))==NULL) {
printf(“memory allocation error !\n");
exit(1);
}
strcpy(sir2, sir1);
printf(“The copy is: %s \n", sir2);
..........
}
Lifetime of dynamic allocated
memory
• Memory allocated with malloc lasts as long as you want it to. It does not
automatically disappear when a function returns, as automatic variables do:

void fct(void) {
int *p;
p=(int*) malloc(10*sizeof(int));
return;
}

The memory area


allocated here remains
occupied also after the
function call is ended !
p
Only the pointer
variable p accessing it
disappears.
Lifetime example
• Have a function create and return an array of values:

int * fct(void) {
int *p; YES !
p=(int*) malloc(10*sizeof(int));
// fill p with values . . .
return p;
}

int * fct(void) { NO !
int p[10];
// fill p with values . . .
return p;
}
Exercise: different versions of
adding 2 vectors
int * add_vector4(int *a, int *b, int n) {
int * r;
r=(int *) malloc(sizeof (int) * n);
if (r==NULL) exit(1);
int i;
for (i=0; i<n; i++, a++, b++)
r[i]=*a+*b;
return r;
}


int a[3]={1,2,3};
int b[3]={4,5,6};
int * rr;
rr=add_vector4(a,b,3);
print_vector(rr,3);
free()
• Dynamically allocated memory is deallocated with the free function. If p
contains a pointer previously returned by malloc, you can call
• free(p);
• which will ``give the memory back'' to the heap of memory from which
malloc requests are satisfied.
• the memory you give back by calling free() is immediately usable by other
parts of your program. (Theoretically, it may even be usable by other
programs.)
• When your program exits, any memory which it has allocated but not freed
should be automatically released by the operating system.
• Once you've freed some memory you must remember not to use it any
more. After calling free(p) it is probably the case that p still points at the
same memory. However, since we've given it back, it's now ``available,'' and
a later call to malloc might give that memory to some other part of your
program.
Structures and pointers
• Structure pointers are just like pointers to ordinary variables. The
declaration
• struct point *pp;
• says that pp is a pointer to a structure of type struct point. If pp
points to a point structure, *pp is the structure, and (*pp).x and
(*pp).y are the members.
• To use pp:
• struct point origin, *pp;
• pp = &origin;
• printf("origin is (%d,%d)\n", (*pp).x, (*pp).y);
• The parentheses are necessary in (*pp).x because the precedence
of the structure member operator . is higher then *. The expression
*pp.x means *(pp.x), which is illegal here because x is not a pointer.
Pointers to structures
• Pointers to structures are so frequently used that an alternative
notation is provided as a shorthand. If p is a pointer to a structure,
then referring to a particular member can be done by:
• p->member-of-structure
• Equivalent with (*p).member-of-structure
• printf("origin is (%d,%d)\n", pp->x, pp->y);
• Both . and -> associate from left to right, so if we have
• struct rect r, *rp = &r;
• then these four expressions are equivalent:
r.pt1.x
rp->pt1.x
(r.pt1).x
(rp->pt1).x
Precedence of operators
• The structure operators . and ->, together with () for function calls and [] for
subscripts, are at the top of the precedence hierarchy and thus bind very
tightly.
• For example, given the declaration
• struct {
• int len;
• char *str;
• } *p;
• then ++p->len increments len, not p, because the implied
parenthesization is ++(p->len) .
• Parentheses can be used to alter binding: (++p)->len increments p before
accessing len, and (p++)->len increments p afterward. (This last set of
parentheses is unnecessary.
• *p->str fetches whatever str points to;
• *p->str++ increments str after accessing whatever it points to (just like
*s++)
• (*p->str)++ increments whatever str points to
• *p++->str increments p after accessing whatever str points to.
Pointer arrays. Pointers to Pointers
• Since pointers are variables themselves,
they can be stored in arrays just as other
variables can
Pointers vs Multidimensional arrays
• int a[10][20];
• int *b[10];
• a[3][4] and b[3][4] are both syntactically legal references to an int.
• a is a true two-dimensional array: 200 int-sized locations have been
set aside, and the conventional rectangular subscript calculation 20
* row +col is used to find the element a[row,col].
• For b, however, the definition only allocates 10 pointers and does
not initialize them; initialization must be done explicitly, either
statically or with code. Assuming that each element of b does point
to a twenty-element array, then there will be 200 ints set aside, plus
ten cells for the pointers. The important advantage of the pointer
array is that the rows of the array may be of different lengths. That
is, each element of b need not point to a 20 element vector; some
may point to two elements, some to fifty, and some to none at all.
Pointers vs Multidimens arrays
• char *name[] = { "Illegal month", "Jan", "Feb", "Mar" };
• char aname[][15] = { "Illegal month", "Jan", "Feb", "Mar" };
Program design example
• a program that will read an then sort a set of text lines
into alphabetic order
• Requirements:
– Program reads a number of lines, until EOF, but not more than
MAXLINES=5000
– Each line may have a different number of characters, but not
more than MAXLEN=1000
– Program sorts lines in alphabetic order
– Program displays sorted lines
• How to approach program design problems:
– Data structures
– Algorithms
– Functions
Recall: Sorting algorithm
// sort an array of integers into ascending order

void sort (int a[], int n) {


int i, j, temp;
for ( i = 0; i < n - 1; ++i )
for ( j = i + 1; j < n; ++j )
if ( a[i] > a[j] ) {
temp = a[i];
The sorting algorithms will work,
a[i] except that now we have
= a[j];
to deal with lines}of text,a[j] = temp;
which are of different lengths,
}and which, unlike integers, can't be compared or moved
in a single operation (strcmp, strcpy).
We need a data representation that will cope efficiently
and conveniently with variable-length text lines.
Data structure: array of pointers
• Each line can be accessed by a pointer to its first character. The
pointers themselves can bee stored in an array.
• Two lines can be compared by passing their pointers to strcmp.
• When two out-of-order lines have to be exchanged, the pointers in
the pointer array are exchanged, not the text lines themselves.

#define MAXLINES 5000 /* max number of lines to be sorted */


char *lineptr[MAXLINES]; /* array of pointers to text lines */
Top-down program refinement

main
calls
calls

readlines sort writelines

1. Split problem (program) in subproblems (functions)


2. For each function:
– Functionality (what it does)
– Prototype
– Contract: how exactly does it handle input arguments, which are its
returned results and side-effects (on global variables)
Designing the functions
• Readlines:
– int readlines(char *lineptr[], int nlines);
– Argument lineptr: array will be filled with pointers to the read lines
– Argument nlines: maximum number of lines that can be read
– Return value: number of lines that has been read or -1 if an error
occured
• Writelines:
– void writelines(char *lineptr[], int nlines);
– Writes nlines elements of array lineptr
• Sort
– void sort(char *lineptr[], int nlines);
Example: main program
#include <stdio.h>
#include <string.h>

#define MAXLINES 5000 /* max #lines to be sorted */


char *lineptr[MAXLINES]; /* pointers to text lines */

int readlines(char *lineptr[], int nlines);


void writelines(char *lineptr[], int nlines);
void sort(char *lineptr[], int nlines);

int main(void) {
int nlines; /* number of input lines read */
if ((nlines = readlines(lineptr, MAXLINES)) >= 0) {
sort(lineptr, nlines);
writelines(lineptr, nlines);
return 0;
} else {
printf("error: input too big to sort\n");
return 1;
}
}
Implementing the functions
• If a function corresponds to a problem which is still
complex, split it in other subproblems (functions)
• Top-down decomposition
• Stepwise refinement
Example: decomposing readlines()
• Readlines:
– repeatedly: reads a line from stdin, allocates a buffer of the exact
line length and copies there the input, stores pointer to buffer in
current element of lineptr

• int getline(char *s, int lim);


– Reads a maximum of lim-1 characters from stdin, until \n or EOF
– Argument s must point to an array that is able to hold a
maximum of lim characters
– Returns the number of characters read
– The characters read will be stored in array s; character \n is also
included. Null character is appended.
Example: readlines() implementation
#define MAXLEN 1000 /* max length of any input line */
int getline(char *, int);

/* readlines: read input lines */


int readlines(char *lineptr[], int maxlines) {
int len, nlines;
char *p, line[MAXLEN];
nlines = 0;
while ((len = getline(line, MAXLEN)) > 0)
if (nlines >= maxlines ||
((p = (char *)malloc(len)) == NULL))
return -1;
else {
line[len-1] = '\0'; /* delete newline */
strcpy(p, line);
lineptr[nlines++] = p;
}
return nlines;
}
Example: getline

/* getline: read a line into s, return length */


int getline(char s[],int lim)
{
int c, i;
for (i=0; i < lim-1 &&
(c=getchar())!=EOF && c!='\n'; ++i)
s[i] = c;
if (c == '\n') {
s[i] = c;
++i;
}
s[i] = '\0';
return i;
}
Example: writelines

/* writelines: write output lines */


void writelines(char *lineptr[], int nlines)
{
int i;
for (i = 0; i < nlines; i++)
printf("%s\n", lineptr[i]);
}
Example: sort

void sort (char* v[], int n)


{
int i, j;
char *temp;
for ( i = 0; i < n - 1; ++i )
for ( j = i + 1; j < n; ++j )
if ( strcmp(v[i], v[j])>0 ) {
/* swaps only pointers to strings */
temp = v[i];
v[i] = v[j];
v[j] = temp;
}
}
Lecture12
Outline
• Binary representation of integer numbers
• Operations on bits
– The Bitwise AND Operator
– The Bitwise Inclusive-OR Operator
– The Bitwise Exclusive-OR Operator
– The Ones Complement Operator
– The Left Shift Operator
– The Right Shift Operator
– Binary representation of floating-point numbers
• Review: Operators: The complete table of
operator's precedence
Binary representation of
integers
• Positive integers:
0 0 0 0 0 0 0 1 0 1

most least
Sign bit significant or significant or
high-order bit low-order bit

1*2^0+0*2^1+1*2^2=5
Binary representation of
integers
• Negative integers:
1 1 1 1 1 1 1 0 1 1

most least
Sign bit significant or significant or
high-order bit low-order bit

Steps to convert a negative number from decimal to binary: Ex: -5


1. add 1 to the value: -5+1=-4
2. express the absolute value of the result in binary: 4=00000100
3. then “complement” all the bits: 11111011=-5
Steps to convert a negative number from binary to decimally: Ex: 11111011
1. complement all of the bits: 00000100
2. convert the result to decimal: 4
3. change the sign of the result, and then subtract 1: -4-1=-5
Bit operators
• & Bitwise AND
• | Bitwise Inclusive-OR
• ^ Bitwise Exclusive-OR
• ~ Ones complement
• << Left shift
• >> Right shift
• All the operators, with the exception of the ones complement
operator ~, are binary operators and as such take two operands.
• Bit operations can be performed on any type of integer value in C
—be it short, long, long long, and signed or unsigned—and on
characters, but cannot be performed on floating-point values.
Bitwise AND
b1 b2 b1&b2 int a=25;
0 0 0 int b=77;
0 1 0
printf(“%x %x %x”,a,b,a&b);
1 0 0
1 1 1

0 0 0 0 0 0 0 0 1 1 0 0 1
a=0x19
0 0 0 0 0 0 1 0 0 1 1 0 1 b=0x4d

0 0 0 0 0 0 0 0 0 1 0 0 1 a&b=0x9
Exercise: even or odd
• testing if an integer is even or odd, using bitwise operations:
• the rightmost bit of any odd integer is 1 and of any even integer
is 0.
int n;
if ( n & 1 )
printf(“odd”);
else
printf(“even”);
Bitwise Inclusive-OR (OR)
b1 b2 b1|b2 int a=25;
0 0 0 int b=77;

0 1 1 printf(“%x %x %x”,a,b,a|b);
1 0 1
1 1 1

0 0 0 0 0 0 0 0 1 1 0 0 1 a=0x19

0 0 0 0 0 0 1 0 0 1 1 0 1 b=0x4d

0 0 0 0 0 0 1 0 1 1 1 0 1 a|b=0x5d
Bitwise vs boolean !
• AND: bitwise: &, boolean: &&
• OR: bitwise: |, boolean: ||

b:%i &:%i &&:%i |:%i ||:%i \n",


a, b, a&b, a&
Bitwise Exclusive-OR (XOR)
b1 b2 b1^b2 int a=25;
0 0 0 int b=77;

0 1 1 printf(“%x %x %x”,a,b,a^b);
1 0 1
1 1 0

0 0 0 0 0 0 0 0 1 1 0 0 1
a=0x19
0 0 0 0 0 0 1 0 0 1 1 0 1 b=0x4d

0 0 0 0 0 0 1 0 1 0 1 0 0 a^b=0x54
The Ones Complement Operator

b1 ~b1
int a=25;
0 1
printf(“%x %x”,a,~a);
1 0

0 0 0 0 0 0 0 0 1 1 0 0 1 a=0x19

1 1 1 1 1 1 1 1 0 0 1 1 0 ~a=0xffffffe6
Usage: Masking bits
• A mask is a bit pattern with some bits set to on (1) and some bits to off
(0).
• Example:
• int MASK = 2; // 00000010, with only bit number 1 nonzero.
• Masking bits:
• flags = flags & MASK;
• all the bits of flags (except bit 1) are set to 0 because any bit combined
with 0 using the & operator yields 0. Bit number 1 will be left unchanged.
(If the bit is 1, 1 & 1 is 1; if the bit is 0, 0 & 1 is 0.) This process is called
"using a mask" because the zeros in the mask hide the corresponding bits
in flags.
• you can think of the 0s in the mask as being opaque and the 1s as being
transparent. The expression flags & MASK is like covering the flags bit
pattern with the mask; only the bits under MASK's 1s are visible
Usage: Turning bits on
• Turn on (set to 1) particular bits in a value while leaving the remaining bits
unchanged.
• Example: an IBM PC controls hardware through values sent to ports. To
turn on a device (i.e., the speaker), the driver program has to turn on the
1 bit while leaving the others unchanged.
• This can be done with the bitwise OR operator.
• The MASK has bit 1 set to 1, other bits 0
• int MASK = 2; // 00000010, with only bit number 1 nonzero.
• The statement
• flags = flags | MASK;
• sets bit number 1 in flags to 1 and leaves all the other bits unchanged.
This follows because any bit combined with 0 by using the | operator is
itself, and any bit combined with 1 by using the | operator is 1.
Usage: Turning bits off
• Turn off (set to 0) particular bits in a value while leaving the
remaining bits unchanged.
• Suppose you want to turn off bit 1 in the variable flags.
• The MASK has bit 1 set to 1, other bits 0
• int MASK = 2; // 00000010, with only bit number 1
nonzero.
• The statement:
• flags = flags & ~MASK;
• Because MASK is all 0s except for bit 1, ~MASK is all 1s except for
bit 1. A 1 combined with any bit using & is that bit, so the statement
leaves all the bits other than bit 1 unchanged. Also, a 0 combined
with any bit using & is 0, so bit 1 is set to 0 regardless of its original
value.
Usage: Toggling bits
• Toggling a bit means turning it off if it is on, and turning it on if it is off.
• To toggle bit 1 in flag:
• The MASK has bit 1 set to 1, other bits 0
• int MASK = 2; // 00000010, with only bit number 1 nonzero.
• flag = flag ^ MASK;
• You can use the bitwise EXCLUSIVE OR operator to toggle a bit.
• The idea is that if b is a bit setting (1 or 0), then 1 ^ b is 0 if b is 1 and is
1 if b is 0. Also 0 ^ b is b, regardless of its value.
• Therefore, if you combine a value with a mask by using ^, values
corresponding to 1s in the mask are toggled, and values corresponding to
0s in the mask are unaltered.
Usage: Checking value of a bit
• For example: does flag has bit 1 set to 1?
• you must first mask the other bits in flag so that you compare only bit 1 of
flag with MASK:
• if ((flag & MASK) == MASK)

The Left Shift Operator
•the bits contained in the
value are shifted to the left a
number of places (bits) int a=25;
•Bits that are shifted out
through the high-order bit of printf(“%x %x”,a,a<<1);
the data item are lost,
• 0s are always shifted in
through the low-order bit of
the value.shifted to the left.
Associated with this
Bit
lost 0 0 0 0 0 0 0 0 1 1 0 0 1 a : 0x19

0 0 0 0 0 0 0 1 1 0 0 1 0 a<<1 : 0x32
Exercise: multiply with 2
• Left shifting has the effect of multiplying the value that is shifted by two.
• Multiplication of a value by a power of two: left shifting the value the
appropriate number of places

int a;
scanf("%i",&a);
printf("a multiplied with 2 is %i \n",a<<1);
printf("a multiplied with 4 is %i \n",a<<2);
The Right Shift Operator
•Shifts the bits of a value to the right.
•Bits shifted out of the low-order bit of int a=25;
the value are lost.
•Right shifting an unsigned value or a printf(“%x %x”,a,a>>1);
signed positive value always results
in 0s being shifted in on the left

Bit
lost
0 0 0 0 0 0 0 0 1 1 0 0 1 a : 0x19

0 0 0 0 0 0 0 0 0 1 1 0 0 a>>1 : 0xc
Right shift of negative integers
•If the sign bit is 1, on some machines 1s are shifted in, and
on others 0s are shifted in.
•This former type of operation is known as an arithmetic right
shift, whereas the latter is known as a logical right shift.
•Never make any assumptions about whether a system
implements an arithmetic or a logical right shift. A program
that shifts signed values right might work correctly on one
system but fail on another due to this type of assumption.

Bit
lost
1 0 0 0 0 0 0 0 1 1 0 0 1

? 1 0 0 0 0 0 0 0 1 1 0 0
Example: extract groups of bits
• Example: an unsigned long value is used to represent color values, with
the low-order byte holding the red intensity, the next byte holding the green
intensity, and the third byte holding the blue intensity.
• You then want to store the intensity of each color in its own unsigned char
variable.

unsigned char BYTE_MASK = 0xff;


unsigned long color = 0x002a162f;
unsigned char blue, green, red;
red = color & BYTE_MASK;
green = (color >> 8) & BYTE_MASK;
blue = (color >> 16) & BYTE_MASK;
printf("%x %x %x\n",red, green, blue);
Exercise: getbits
• getbits(x,p,n): returns the (right adjusted) n-bit field of x that
begins at position p. We assume that bit position 0 is at the right end and that
n and p are positive values.

/* getbits: get n bits from position p */


unsigned getbits(unsigned x,int p, int n)
{
return (x>>(p+1-n))&~(~0<<n);
}

n
Exercise: printbits
• printbits(x,p,n): prints the n-bit field of x that begins at position
p. We assume that bit position 0 is at the right end and that n and p are
positive values.

void printbits(unsigned x,int p, int n)


{
int i;
unsigned mask=1<<p;
for (i=0; i<n; i++) {
if (x&mask) printf("1");
else printf("0");
mask=mask>>1;
}
}
Exercise: IEEE float
representation
• Standards: single precision / double precision
• IEEE Standard 754 Floating Point Numbers in Single precision
Layout:

31
31 30 23 22 2 1 0

sign biased exponent fraction


1 bit 8 bits 23 bits
IEEE float (cont)
• Sign: 0=positive, 1=negative
• Exponent: a bias is added to the actual exponent in order to get the stored
exponent. For IEEE single-precision floats, this value is 127
• Examples:
– actual exponent =0: biased exponent field stored =127.
– biased exponent field stored = 200: actual exponent =(200-127)= 73.
• The exponents are powers of 2 in binary !
• Mantissa: there is an assumed leading 1 in the actual mantissa that is not
stored in memory, so the mantissas are actually 24 bits, even though only 23
bits are stored in the fraction field.
• Examples:
– Stored fraction =11000…0: actual mantissa=1.11000…0(binary)= 1+1/2+1/4
• Represented value:
biased _ exp onent  127
value 2 1. fraction
IEEE float examples
• Float representation:
• 0011111111100000000000000000000
• Sign=0
• Biased exponent=01111111=127 => Actual exponent=127-127=0
• Fraction=1100000000000000000000
• Mantissa=1.f=1.11=1+1/2+1/4=1.75
• Value of number is 2^0*1.75=1.75
• Float representation:
• 0100000001100000000000000000000
• Sign=0
• Biased exponent=10000000=128 => Actual exponent=128-127=1
• Fraction=1100000000000000000000
• Mantissa=1.f=1.11=1+1/2+1/4=1.75
• Value of number is 2^1*1.75=3.5
Exercise: print bits of a float
void printbits(unsigned x,int p, int n);

int main(void)
{
float f=3.5;
unsigned int *ip=&f;

printf("\n sign: ");printbits(*ip,31,1);


printf("\n biased exponent: "); printbits(*ip,30,8);
printf("\n fraction: "); printbits(*ip,22,23);
return 1;
}
Review: Operators in C
Lecture 13
Outline
• Standard Input and Output
• Standard Input and Output (I/O)– Review & more
• Buffered/unbuffered input
• Character I/O
• Formatted I/O
• Redirecting I/O to files. Pipes

• Bibliography:
• [Kochan, chap 16.1, 16.2]
• [Kernighan&Ritche, chap 7.1, 7.2]
• [C Primer, chap 8]
Standard Input and Output
• input and output devices: such as keyboards, disk drives, printers,
screen.
• The C language itself does not have any special statements for
performing input/output (I/O) operations; all I/O operations in C
must be carried out through function calls.
• These functions are contained in the standard C library:
• #include <stdio.h>
• Advantages:
– Portability: they work in a wide variety of computer environments
– General character: they generalize to using files for I/O
• Disadvantage:
– Less performance: they don't take advantage of features peculiar to a
particular system.
Kinds of Standard I/O functions
• Character I/O
– getchar, putchar
• Formatted I/O
– scanf, printf
Character I/O example
• /* echo.c -- repeats input */
• #include <stdio.h>
• int main(void) {
• char ch;
• while ((ch = getchar() ) != ‘*’)
• putchar(ch);
• return 0;
• }
I/O streams
• C treats input and output devices the same as it treats
regular files on storage devices. In particular, the keyboard
and the display devices are treated as files opened
automatically by every C program.
• Conceptually, the C program deals with a stream instead
of directly with a file. A stream is an idealized flow of data
to which the actual input or output is mapped.
• Keyboard input is represented by a stream called stdin,
and output to the screen is represented by a stream called
stdout. The getchar(), putchar(), printf(),
and scanf() functions are all members of the standard
I/O package, and they deal with these two streams.
EOF
• One implication of I/O streams is that you can
use the same techniques with keyboard input as
you do with files.
• For example, a program reading a file needs a
way to detect the end of the file so that it knows
where to stop reading. Therefore, C input
functions come with a built-in, end-of-file
detector. Because keyboard input is treated like
a file, you should be able to use that end-of-file
detector to terminate keyboard input, too.
– CTRL-Z is EOF for keyboard input
Character I/O example + EOF
•/* echo_eof.c -- repeats input */
•#include <stdio.h>
•int main(void) {
• char ch;
• while ((ch = getchar() ) != EOF)
• putchar(ch);
• return 0;
•}
Buffered/unbuffered input
/*echo.c -- repeats input */
#include <stdio.h>
int main(void) {
char ch;
while ((ch = getchar()) != ‘*’)
putchar(ch);
return 0;
}

Suppose you type: Hi!*


What exactly does the program run look like ?
Buffered/unbuffered input
/*echo.c -- repeats input */
#include <stdio.h>
int main(void) {
char ch;
while ((ch = getchar()) != ‘*’)
putchar(ch);
return 0;
}
most systems
Suppose you type: Hi!* are line-buffered:
What does the program run look like ? input buffer is
emptied only
HHii!!* Hi!* after pressing
← OR → Hi! ENTER

If the system is If the system is


Unbuffered Buffered
From [C Primer Plus]
Buffered/unbuffered input in C
• ANSI C: <stdio.h> functions (getchar())
should be buffered
• Additional libraries may provide unbuffered input
– <conio.h> offers getche() for echoed unbuffered
input and getch() for unechoed unbuffered input
• The way of buffereing may be controled by the
operating system
– Unix: the ioctl() function (part of the Unix library
but not part of standard C) can specify the type of
input you want, and getchar() behaves accordingly
Formatted Output - printf
• The output function printf translates internal values to characters
and prints them to the standard output.

• A formal declaration of the printf function:


• int printf(const char *format,...);
• printf converts, formats, and prints its arguments on the standard
output under control of the format. It returns the number of characters
printed.

• printf is a function with variable number of arguments (this is


possible in C !): the declaration with 3 points (…) means that the
number and types of these arguments may vary. The declaration ...
can only appear at the end of an argument list.
printf
• The general format of a printf conversion specification is as
follows:
• %[flags][width][.prec][hlL]type

• type represents the conversion characters, it is a mandatory field.


• Optional fields (enclosed in brackets) are flags, width and prec,
and the type modifiers [hlL]; if they are used, they must appear in
the order shown.
References
• [Kochan] (to look up only !)
Formatted Input - scanf
• The function scanf is the input analog of printf, providing many of the same
conversion facilities in the opposite direction.
• int scanf(const char *format, ...);
• scanf reads characters from the standard input, interprets them according to
the specification in format, and stores the results through the remaining
arguments (each of which must be a pointer).
• scanf stops when it exhausts its format string, or when some input fails to
match the control specification.
• It returns as its value the number of successfully matched and assigned input
items. This can be used to decide how many items were found. On the end of
file, EOF is returned; note that this is different from 0, which means that the
next input character does not match the first specification in the format string.
• The next call to scanf resumes searching immediately after the last character
already converted.
scanf
• As with printf, scanf takes optional modifiers between the % and
the conversion character.

References
Reference [Kochan]
(to look (to!)look up only !)
up only
Some interesting scanf
conversions
scanf Examples (1)
• Whitespace characters inside a format string match an
arbitrary number of whitespace characters on the input. So,
the call
• scanf ("%i%c", &i, &c);
• with the line of text
• 29 w
• assigns the value 29 to i and a space character to c
because this is the character that appears immediately after
the characters 29 on the input.
• If the following scanf call is made instead:
• scanf ("%i %c", &i, &c);
• and the same line of text is entered, the value 29 is assigned
to i and the character 'w’ to c because the blank space in
the format string causes the scanf function to ignore any
leading whitespace characters after the characters 29 have
been read.
scanf Examples (2)
• An asterisk can be used to skip fields. If the scanf call
• scanf ("%i %5c %*f %s", &i1, text, string);
• is executed and the following line of text is typed in:
• 144abcde 736.55 (wine and cheese)
• the value 144 is stored in i1; the five characters abcde are
stored in the character array text; the floating value
736.55 is matched but not assigned; and the character
string "(wine" is stored in string, terminated by a null.
• The next call to scanf picks up where the last one
left off. So, a subsequent call such as scanf ("%s %s
%i", string2, string3, &i2); has the effect of storing
the character string "and" in string2 and the string
"cheese)" in string3 and further waits for an integer to be
typed in.
scanf Examples (3)
• The scanf call
• scanf ("%[^/]", text);
• indicates that the string to be read can consist of any
character except for a slash. Using the preceding call on the
following line of text
• (wine and cheese)/
• has the effect of storing the string "(wine and cheese)" in text
because the string is not terminated until the / is matched (which
is also the character read by scanf on the next call).
• To read an entire line from the terminal into the character array
buf, you can specify that the newline character at the end of the
line is your string terminator:
• scanf ("%[^\n]\n", buf);
• The newline character is repeated outside the brackets so that
scanf matches it and does not read it the next time it’s called.
(Remember, scanf always continues reading from the character
that terminated its last call.)
scanf Examples (4)
• When a value is read that does not match a value expected by scanf
(for example, typing in the character x when an integer is expected),
scanf does not read any further items from the input and immediately
returns. Because the function returns the number of items that
were successfully read and assigned to variables in your program,
this value can be tested to determine if any errors occurred on the
input. For example, the call
• if ( scanf ("%i %f %i", &i, &f, &l) != 3 )
• printf ("Error on input\n");
• tests to make certain that scanf successfully read and assigned three
values. If not, an appropriate message is displayed.
• Remember, the return value from scanf indicates the number of
values read and assigned, so the call
• scanf ("%i %*d %i", &i1, &i3)
• returns 2 when successful and not 3 because you are reading and
assigning two integers (skipping one in between). Note also that the
use of %n (to obtain the number of characters read so far) does not
get included in the value returned by scanf.
Redirecting I/O to a file
• Sometimes we want programs to take input from a file
instead from the keyboard or to write results in a file
instead on the screen
• Both read and write file operations can be easily
performed under many operating systems, such as Unix
and Windows, without anything special being done at all
to the program through I/O redirecting
• stdio functions in C have a general character, they work
on abstract streams
• There are also special file access mechanisms are
provided in C, but these will be discussed next semester
Redirect output
• For example, if you want to write all your program results
into a file called data.txt:
• all that you need to do under Unix or Windows, if running in a
terminal window, is to redirect the output from the program prog
into the file data.txt by executing the program with the following
command at the command prompt:
prog > data.txt
• This command instructs the system to execute the
program prog but to redirect the output normally written
to the terminal into a file called data.txt instead.
• Any values displayed by putchar or printf do not
appear on screen but are instead written into the file
called data.txt.
Redirect input
• If you want your program to read all input from a file
instead of the keyboard:
• You can have the program get its input from a file called
input.txt, for example, by redirecting the input when
the program is executed. If the program is called prog,
the following command line works:
prog < input.txt
• Any call to a function that normally reads data from your
window, such as scanf and getchar, will be made to
read its information from the file input.txt
Redirect both input and output
• Redirect both input and output
prog < input.txt > data.txt
I/O redirection example
• /* pecho.c -- repeats input
*/ • F1.txt

• #include <stdio.h>
• int main(void) { • Bla bla bla
• char ch; • Oh la la *
• while ((ch = getchar()) != • Hoo hoo hoo
‘*’)
• putchar(ch);
• return 0;
• }

What is the result of running following command ?

pecho <f1.txt >f2.txt


I/O redirection example 2
• /* pecho.c -- repeats input
*/ • F3.txt

• #include <stdio.h>
• int main(void) { • Bla bla bla
• char ch; • Oh la la
• while ((ch = getchar()) != • Hoo hoo hoo
‘*’)
• putchar(ch);
• return 0;
• }

What is the output of running following command ?

pecho <f3.txt >f4.txt


Pipes
• Pipes: putting standard output of prog directly into the standard
input of anotherprog
prog | anotherprog
Pipes example
• prog1.c • prog2.c
• #include <stdio.h> • #include <stdio.h>

• int main(void) { • int main(void) {


• char c; • char c;
• for (c='a'; c<='z'; c+ • while ((c=getchar())!=EOF)
+) • printf("*%c",c);
• putchar(c); • }
• }
What is the output of each command run ?
1. prog1
2. prog2
3. prog1 | prog2
4. prog1 > temp.txt
5. prog2 < temp.txt
Pipes example 2
• pprintf.c • pscanf.c

• #include <stdio.h> • #include <stdio.h>

• int main(void) { • int main(void) {


• int i; • int i;
• for (i=1000; • while (scanf("%d
i<=10000; i+=1000) ",&i)==1)
• printf("%d ",i); • printf("read %d \
n",i);
• }
• }
Pipe:
pprintf | pscanf
int to string string to int
Pipes example 3
• pprintf.c • prog2.c
• #include <stdio.h>
• #include <stdio.h>
• int main(void) {
• int main(void) {
• char c;
• int i; • while ((c=getchar())!
• for (i=1000; =EOF)
i<=10000; i+=1000) • printf("*
• printf("%d ",i); %c",c);
• } • }
Pipe:
pprintf | prog2
Comments on I/O redirection
• Note that I/O redirection is not actually part of the ANSI
definition of C. This means that you might find operating
systems that don’t support it. Luckily, most do.
• Special Functions for Working with Files: situations do
arise when you need more flexibility to work with files.
• For example:
• you might need to read data from two or more different files or to
write output results into several different files.
• you might need to write numerical data into a more efficient binary
file format, not as text files
• To handle these situations, special functions have been designed
expressly for working with files. These will be discussed in another
chapter

You might also like