+ All Categories
Home > Documents > Chapter 3 Fundamentals of the Imperative Paradigmblk/cs3490/ch03/ch03.01.02... ·  ·...

Chapter 3 Fundamentals of the Imperative Paradigmblk/cs3490/ch03/ch03.01.02... ·  ·...

Date post: 27-May-2018
Category:
Upload: lekhuong
View: 213 times
Download: 0 times
Share this document with a friend
49
Chapter 3 Fundamentals of the Imperative Paradigm Programming Languages and Paradigms J. Fenwick, B. Kurtz, C. Norris (to be published in 2012)
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


Recommended