chapter 3 fundamentals of the imperative paradigmblk/cs3490/ch03/ch03.01.02... · ·...
TRANSCRIPT
Chapter 3 Fundamentals of the Imperative Paradigm
Programming Languages and Paradigms
J. Fenwick, B. Kurtz, C. Norris
(to be published in 2012)
Introduction • In this chapter you will learn about
– The characteristics of imperative programming languages
– Details about programming in C
– How C answers some fundamental questions about programming language design
– A brief look at some other imperative languages
• In the case study at the end of the chapter you will be asked to write an interpreter for Wren Intermediate Code using C
The Emergence of Imperative Languages • Based on the von Neumann architecture
– The computer memory hold data values and
– Instructions that operate on the data
– Instructions may involve data movement, arithmetic or logical operations, or control instructions
– The name imperative implies a sequence of commands that result in the machine changing state in some way
• The first high level imperative language was Fortran
– John Backus at IBM headed the development team; the original design started in 1954
– Fortran I was released in 1957 and Fortran II in 1958
– Subsequent versions: Fortran IV, Fortran 77, Fortran 90
General Characteristics • Variables that model memory locations
• Assignment statements equivalent to one or more data movement or operation instructions
• Procedure (subroutine) calls equivalent to an underlying jump to subroutine instructions
• Conditional (Selection) commands such as if and switch implemented with conditional and unconditional branch instructions
• Iterative commands such as while and for implemented with conditional and unconditional branch instructions
History of C • Original development, 1969-1973
– Dennis Ritchie at Bell Telephone Laboratories
– The languages was used to implement the UNIX operating system, but C itself is not tied to any OS
– C is standardized by ANSI (American National Standards Institute)
– C programs tend to be smaller and faster than implementations in other languages
– The syntax of C is the basis of several object-oriented languages (C++, Java, C#)
C Preprocessor • Header files (.h)
– Header files commonly contain forward declarations of classes, subroutines, variables, and other identifiers
– Using header files provides a certain degree of information hiding
– Header files are included using #include “ <file name> ”
• Implementation files (.c)
– Provides the full implementation of methods defined in the .h file
– Can contain helper methods not visible in the .h file
An Example /* greet.h header file */
void greet(void);
/* greet.c source file */
#include <stdio.h>
void greet(void){
printf("Hello Jay\n");
}
/* main.c source file */
#include "greet.h"
int main(void){
greet();
}
Other Directives • Here are some other directives
– #define is often used to define constants or flags; #undef undoes a previous definition
– #ifndef and #ifdef are used to check the status of a flag
– #if, #elif, #endif set up alternative actions
• A very short example
#ifdef __unix__
# include <unistd.h>
#elif defined _WIN32
# include <windows.h>
#endif
Base Data Types char single byte in length; capable of holding one character
int integer whose size is the natural size of integers on the target architecture
float single precision floating point
double double precision floating point
#include <stdio.h>
int main(void){
printf("%ld\n", sizeof(char));
printf("%ld\n", sizeof(short int));
printf("%ld\n", sizeof(int));
printf("%ld\n", sizeof(long int));
printf("%ld\n", sizeof(float));
printf("%ld\n", sizeof(double));
printf("%ld\n", sizeof(long double));
}
• The results for a 64-bit architecture are shown to the right
1 2 4 8 4 8 16
Other Data Types • Signed vs unsigned
– A byte can specify 28 = 256 values
– Unsigned: 0 to 255, signed: -128 to 127
• char literals are specified by single quotes, ch=‘a’;
• Constants
– Specified by the const keyword
– Assignment to a const variable causes a compile error
• No boolean type
– An int is normally used where 0 is false and any nonzero value is true
– Logical boolean operators are &&, ||, and !
C Pointer Types • Close to von Neumann architecture; pointers hold
explicit memory addresses
• Explicit memory locations are not used in Java; references are used
• An example int * iPointToInts;
int pointToMe = 4;
iPointToInts = &pointToMe;
pointToMe = 3;
*iPointToInts = 3;
Aliasing
int * iPointToIntsToo;
iPointToInts = &pointToMe;
iPointToIntsToo = &pointToMe;
*iPointToInts = 9;
printf("%d, %d\n", *iPointToIntsToo, pointToMe);
//outputs 9, 9
• Consider the following example
• Give three ways the value 9 can be changed to the value 8
Test Your Understanding #include <stdio.h>
int main(void){
int * pointer;
int pointee;
pointee = 5;
pointer = &pointee;
*pointer = *pointer + 2;
printf("%d\n", pointee);
printf("%d\n", *pointer);
pointee = pointee - 1;
printf("%d\n", pointee);
printf("%d\n", *pointer);
}
What is output by this program?
Using a pointer to void
void * iCanPointToAnything;
char letter;
int number;
iCanPointToAnything = &letter;
iCanPointToAnything = &number;
*(char *)iCanPointToAnything = 'A';
• Normal pointers enforce type checking
• A void pointer can point to any type
• When dereferencing a void pointer
– A cast must be used to indicate the type of the data
– It also implies the number of bytes to use
• Example
Pointer Arithmetic • Pointer arithmetic is a two edged sword: it provides
opportunities to write very compact code but often that code is cryptic and hard to maintain
• Some attitudes towards pointer arithmetic
– It can be very powerful and some people love it
– It can be accidentally misused and lead to some long debugging sessions
– My personal opinion: avoid whenever possible
Test Your Understanding #include <stdio.h>
int main(void){
char letters[10] = {'a', 'h', 'g', 't', 'r', 'e'};
char * pointer = &letters[2];
printf("%c\n", *pointer);
printf("%c\n", *(pointer + 2));
pointer = pointer + 3;
printf("%c\n", *pointer);
pointer = &letters[1];
pointer--;
printf("%c\n", *pointer);
printf("%c\n", *(pointer + 3));
}
What is output by this program?
C Strings • What is a C String?
– There is no String object like in OO languages
– A C string is an array of characters that must be terminated with the null character.
– If the null is missing, the string will go on forever
• Example
– this statement creates a 6 byte C string consisting of the ASCII characters: ‘h’, ‘e’, ‘l’, ‘l’, ‘o’, ‘\0’.
char * string = "hello";
C Arrays int list[10];
int * ptr;
ptr = list;
ptr++;
ptr = &list[1];
int newList[20];
ptr = newList;
list++; // each of these will result in a compile error
list = &list[1];
int newList[10];
list = newList;
Test Your Understanding Which statements would generate a warning or error?
int * numberPointers[3];
int * pointer;
int number;
a) number = pointer;
b) *pointer = number;
c) pointer = numberPointers[1];
d) pointer = numberPointers;
e) numberPointers[2] = number;
f) numberPointers[2] = &number;
g) numberPointers[2] = pointer;
C Structures • A struct is used to group related data struct Person{
char first[20];
char last[20];
int DOB;
int gender;
}; //note the semicolon after the closing brace
struct Person paul;
• The data can be of different types, as seen above
An alternative definition is struct Person{ << same as above >> } paul;
Assigning Fields of a struct • As seen below, the integer fields for year of birth
(DOB) and gender can be assigned directly using the dot notation and assignment
• The first and last names use the strncpy method when the n is the number of characters, 20 in this case
strncpy(paul.first, "Paul", 20);
strncpy(paul.last, "McCartney", 20);
paul.DOB = 1942;
paul.gender = 1;
Using typedef • Structs are commonly used to define new types
using a typedef typedef struct {
char first[20];
char last[20];
int DOB;
int gender;
} Person;
• With a named type it is easy to create any array of that type Person class[SIZE];
Test Your Understanding Person class[SIZE]; where SIZE is a const int previously declared and initialized. Which of the
following snippets of code would print out the DOB field of each Person in the class array? int i; Person * pointer; a) for (i = 0; i < SIZE; i++) printf("%d\n", class[i].DOB); b) for (i = 0; i < SIZE; i++) printf("%d\n", class.DOB[i]); c) for (pointer = class, i = 0; i < SIZE; i++, pointer++) printf("%d\n", (*pointer).DOB); d) for (pointer = *class, i = 0; i < SIZE; i++, pointer++) printf("%d\n", (*pointer).DOB);
Dynamic Memory Allocation
int * grades;
int i;
grades = (int *) malloc(sizeof(int) * SIZE);
for (i = 0; i < SIZE; i++)
grades[i] = 0;
• Complementary to the malloc function is the free function: free(grades);
• Unlike languages that provide automatic garbage collection such as Java, the C programming language puts the burden of garbage collection on the programmer.
Test Your Understanding
Variable Type sptr structType * *sptr (*sptr).intPointer sptr->intPointer &number s.letter s *sptr->intPointer
typedef struct {
int * intPointer;
char letter;
} structType;
structType s;
structType * sptr;
int number;
Control Structures • These should be familiar to you since C++, Java, and
C# share similar control structures with C
• One difference is the lack of a boolean type in C so this strange looking code is legal while (num){
//do something
num--;
}
• We will examine control structures in more detail later in this chapter
Test Your Understanding • The following code uses a break to exit an infinite
loop int result = 2;
while (1) {
result = result * result;
if (result > 100) break;
}
• What is the final value of result?
The main function • Two commonly used formats int main(void);
or
int main(int argc, char * argv[]);
• Explanation
– The int is the exit status (0 is normal and nonzero usually indicates an error condition)
– The argc parameter is a count of the number of command line arguments.
– The argv parameter is an array of C strings that are the command line arguments.
An Example #include <stdio.h>
int main(int argc, char *argv[]) {
int i;
printf("%d\n",argc);
for (i = 0; i < argc; i++)
printf("%s\n",argv[i]);
return 0;
}
%commandargs –b 1 cat 4 commandargs -b 1 cat
Defining functions in C
returnType functionName(parameterList) {
variable declarations;
statements;
}
• Some important features
– The return type is any valid type including null
– The local variable declarations are not visible outside of the function
– The parameters are passed by value; this can lead to some common errors as seen in the next slides
An Increment Function – first attempt
#include <stdio.h>
void increment(int number); int main() {
int num = 3;
increment(num);
printf("%d\n", num);
}
void increment(int number) {
number = number + 1;
}
• What will be printed?
A Quick Fix
#include <stdio.h>
void increment(int number); int main() {
int num = 3;
num = increment(num);
printf("%d\n", num);
}
void increment(int number) {
number = number + 1;
}
A Better Fix
#include <stdio.h>
void increment(int number); int main() {
int num = 3;
increment(&num);
printf("%d\n", num);
}
void increment(int number) {
//dereference the pointer to change num in main
(*number)++;
}
Test Your Understanding • What is printed by this program? #include <stdio.h>
int postIncrement(int * number);
int main(void){
int num = 3;
int anotherNum;
anotherNum = postIncrement(&num);
printf("%d %d\n", num, anotherNum);
}
int postIncrement(int *number){
int tmp = *number;
(*number)++;
return tmp;
}
Passing Structs as Parameters • Consider the Person type shown previously
– If pass by value is used void printPerson(Person person) the parameter size is 48 bytes
– If pass by pointer is used void printPerson(Person * personPtr) the parameter size is 8 bytes on a 64-bit machine
• Assuming the struct is passed as a pointer, how would the data be printed?
Answer void printPerson(Person * personPtr){
printf("%s %s:\n",
personPtr->first,
personPtr->last);
printf("\tyear of birth: %d\n",
personPtr->DOB);
printf("\tgender: %s\n",
(personPtr->gender == 1?
"male" : "female"));
}
• A simplified notation
– (* personPtr).first can be replaced with
– personPtr->first
Arrays are Passed as Pointers • What is printed by #include <stdio.h>
void increment(int numbers[], int size);
int main(void){
const int SIZE = 3; int numbers[SIZE];
int i;
for (i = 0; i < SIZE; i++)
numbers[i] = i;
increment(numbers, SIZE);
for (i = 0; i < SIZE; i++)
printf("%d ",numbers[i]);
}
void increment(int numbers[], int size){
int i;
for (i = 0; i < size; i++)
numbers[i]++;
}
Test Your Understanding • What will be printed by the following #include <stdio.h>
void increment(int number);
int main(void) {
const int SIZE = 3;
int i, numbers[SIZE];
for (i = 0; i < SIZE; i++)
numbers[i] = i;
increment(numbers[0]);
for (i = 0; i < SIZE; i++)
printf("%d\n", numbers[i]);
}
void increment(int number){
number++;
}
Equivalence of Arrays and Pointers • A pointer version of the previous program #include <stdio.h>
void increment(int *numPtr, int size);
int main(void){
const int SIZE = 3;
int numbers[SIZE];
int i;
for (i = 0; i < SIZE; i++)
numbers[i] = i;
increment(numbers, SIZE);
for (i = 0; i < SIZE; i++)
printf("%d ",numbers[i]);
}
void increment(int *numPtr, int size){
int i;
for (i = 0; i < size; i++)
numPtr[i]++;
}
Input and Output in C • Using stdio.h
– Steam-based I/O that comes in two flavors
• Text-based I/O with lines terminated by new line
• Binary- based I/O using raw, uninterpreted bytes
– Commonly used functions: getchar, putchar, scanf, printf
• Here is a simple echo program #include <stdio.h>
int main(void) {
int c;
while ((c = getchar()) != EOF){
putchar(c);
}
}
printf
Specifier Produces Modifiers Examples d or i Decimal output number to indicate width
+ to force sign to be displayed (space) display space if not negative - to left justify within field 0 to left pad with zeros .number to indicate minimum width h argument is a short int l argument is a long int
%d, %3d %+d, %+3d % d, % 3d %-3d, %-+3d %03d, %+03d %.3d, %+.3d %hd. %+.2hd %ld, %3ld
u Unsigned decimal Same as %d, %i; however + is invalid %u, %-3u, %03u, %.3u o Unsigned octal number to indicate width
- to left justify within field 0 to left pad with zeros .number to indicate minimum width h argument is a short int l argument is a long int # causes value to be preceded by 0
%o, %3o %-3o %03o %.3o, %-.3o %ho, %.2ho %hl, %-.4hl %#o, %#0.2o
x, X Hexadecimal in upper case (X) or lower case (x)
number to indicate width - to left justify within field 0 to left pad with zeros .number to indicate minimum width h argument is a short int l argument is a long int # causes value to be preceded by 0x or 0X
%x, %X, %3x %-3x, %-3X %03x %.4x, %-.4x %hx, %.2hx %lx, %-.4lx %#x, %#-.4x
• You have already seen code like printf("%d, %d\n ",3, 72); This will print “3, 72”
More Specifiers Specifier Produces Modifiers Examples
c character number to indicate width - to left justify within field
%c, %3c %-3c
s string number to indicate width - to left justify within field
%s, %3s %-3s
e, E Scientific notation using e or E
number to indicate width + to force sign to be displayed (space) display space if not negative - to left justify within field .number to indicate minimum width 0 to left pad with zeros
%e, %E, %20E %+20E %- 20E, % -9E %-+20E %.20E %+020E
f Decimal floating point number to indicate width + to force sign to be displayed (space) display space if not negative - to left justify within field 0 to left pad with zeros .number to indicate number of digits after decimal point
%f, %15f %+f, %+15f % f, % 15f %-15f, %+-15f %020f %10.2f, %+10.2f
% %% outputs a single %
scanf • Two examples
int num1, num2, count;
char let;
count = scanf("%d %c %d", &num1, &let, &num2);
and char word1[20];
char word2[20];
int count;
count = scanf("%s %s", word1, word2);
(* notice no & before word1/2 since they are arrays *)
• Buffer overflow problem
– Bounds are not checked so if more than 20 characters this will overflow neighboring memory; the following code limits the read to 20 characters max
– count = scanf("%20s %20s", word1, word2);
fopen • The general format:
fopen(<<file name>>, <<access mode>>)
• The file name is a string; access options are • “r” – opens file for reading
• “w” – opens file for writing; create file if it does not exist, otherwise discard contents
• “r+” – opens file for reading and writing
• “w+” – opens file for reading and writing; create file if it does not already exist,
• otherwise discard contents
• “a” – opens file for writing (appending to); create file if it does not already exist
• “a+” – opens file for writing (appending to); create file if it does not already exist
Example Program #include <stdio.h>
#include <stdlib.h>
void printAndExit(char * msg);
int main(int argc, char * argv[]) {
FILE * infp;
const int size = 80;
char line[size];
int num;
if (argc < 2) printAndExit("Usage: a.out <infile>");
if ((infp = fopen(argv[1], "r")) == NULL)
printAndExit("File open failed");
fscanf(infp, "%80s %d", line, &num);
printf("%s %d\n", line, num);
}
void printAndExit(char * msg) {
printf("%s\n", msg);
exit(0);
}
A Second Example int main(int argc, char * argv[]){
FILE * infp;
FILE * outfp;
const int size = 80;
char line[80];
if (argc < 3)
printAndExit("Usage: a.out <infile> <outfile>");
if ((infp = fopen(argv[1], "r")) == NULL)
printAndExit("File open for read failed");
if ((outfp = fopen(argv[2], "w")) == NULL)
printAndExit("File open failed");
while (!feof(infp)) {
fgets(line, size, infp);
fprintf(outfp, "%s", line);
}
}
Second Example, Version 2 int main(int argc, char * argv[]) {
FILE * infp;
FILE * outfp;
const int size = 80;
int c;
if (argc < 3)
printAndExit("Usage: a.out <infile> <outfile>");
if ((infp = fopen(argv[1], "r")) == NULL)
printAndExit("File open for read failed");
if ((outfp = fopen(argv[2], "w")) == NULL)
printAndExit("File open failed");
while ((c = fgetc(infp)) != EOF) {
fputc(c, outfp);
}
}
Test Your Understanding Assuming the file words.txt contains the following three lines of input, what is the output of the program? hello student
how
are you
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE * infp;
const int SIZE = 10;
char input[SIZE];
if ((infp = fopen("words.txt", "r")) == NULL) exit(0);
while (fscanf(infp, "%10s", input) > 0)
printf("%10s\n", input);
}
ANSI C Libraries
Header Functionality
<ctype.h> Functions that operate on character data such as isalpha, isdigit, isspace, isxdigit, isalnum
<math.h> Math functions such as sin, cos, tan, log, pow, floor, ceil
<stdio.h> Functions to support input and output
<stdlib.h> Functions that make calls to operating system such as exit, malloc, and conversion functions such as atoi
<string.h> Functions that operator on strings such as strcpy, strcat, strcmp
• Some of the most commonly used libraries are
• Specifying access to the math library gcc program.c –lm