CSC 211 Data Structures Lecture 6 Dr Iftikhar

  • Slides: 97
Download presentation
CSC 211 Data Structures Lecture 6 Dr. Iftikhar Azim Niaz ianiaz@comsats. edu. pk 1

CSC 211 Data Structures Lecture 6 Dr. Iftikhar Azim Niaz ianiaz@comsats. edu. pk 1

Last Lecture Summary I n n Concept of Pointer operators q n n Pointer

Last Lecture Summary I n n Concept of Pointer operators q n n Pointer Arithmetic Pointer and functions q q n Address and Indirection Pass by Value Pass by Reference Pointer and Arrays 2

Objectives Overview n n n Dynamic Memory Management with Pointers Structures Unions Strings Multidimensional

Objectives Overview n n n Dynamic Memory Management with Pointers Structures Unions Strings Multidimensional Arrays 3

Dynamic Memory Allocation In C and C++, three types of memory are used by

Dynamic Memory Allocation In C and C++, three types of memory are used by programs: n Static memory - where global and static variables live n Heap memory dynamically allocated at execution time n - "managed" memory accessed using pointers Stack memory - used by automatic variables 4

3 Kinds of Program Data n STATIC DATA: Allocated at compiler time n DYNAMIC

3 Kinds of Program Data n STATIC DATA: Allocated at compiler time n DYNAMIC DATA: explicitly allocated and deallocated during program execution by C++ instructions written by programmer using operators new and delete n AUTOMATIC DATA: automatically created at function entry, resides in activation frame of the function, and is destroyed when returning from function 5

Dynamic Memory Allocation Diagram 6

Dynamic Memory Allocation Diagram 6

Allocation of Memory n n n Static Allocation: Allocation of memory space at compile

Allocation of Memory n n n Static Allocation: Allocation of memory space at compile time. Dynamic Allocation: Allocation of memory space at run time. Dynamic allocation is useful when q q q arrays need to be created whose extent is not known until run time complex structures of unknown size and/or shape need to be constructed as the program runs objects need to be created and the constructor arguments are not known until run time 7

Overview of memory management n Stack-allocated memory q q q When a function is

Overview of memory management n Stack-allocated memory q q q When a function is called, memory is allocated for all of its parameters and local variables. Each active function call has memory on the stack (with the current function call on top) g() When a function call terminates, the memory is deallocated (“freed up”) g() n Ex: main() calls f(), f() calls g() recursively calls g() f() main() 8

Overview of memory management n Heap-allocated memory q This is used for persistent data,

Overview of memory management n Heap-allocated memory q This is used for persistent data, that must survive beyond the lifetime of a function call n n q q global variables dynamically allocated memory – C statements can create new heap data (similar to new in Java/C++) Heap memory is allocated in a more complex way than stack memory Like stack-allocated memory, the underlying system determines where to get more memory – the programmer doesn’t have to search for free memory space! 9

Note: void * denotes a generic pointer type Allocating new heap memory void *malloc(size_t

Note: void * denotes a generic pointer type Allocating new heap memory void *malloc(size_t size); n Allocate a block of size bytes, return a pointer to the block (NULL if unable to allocate block) void *calloc(size_t num_elements, size_t element_size); n Allocate a block of num_elements * initialize every byte to zero, return pointer to the block (NULL if unable to allocate block) element_size bytes, 10

Allocating new heap memory void *realloc(void *ptr, size_t new_size); n Given a previously allocated

Allocating new heap memory void *realloc(void *ptr, size_t new_size); n Given a previously allocated block starting at ptr, q q change the block size to new_size, return pointer to resized block n n If block size is increased, contents of old block may be copied to a completely different region In this case, the pointer returned will be different from the ptr argument, and ptr will no longer point to a valid memory region n If ptr is NULL, realloc is identical to malloc n Note: may need to cast return value of malloc/calloc/realloc: char *p = (char *) malloc(BUFFER_SIZE); 11

Deallocating heap memory void free(void *pointer); n Given a pointer to previously allocated memory,

Deallocating heap memory void free(void *pointer); n Given a pointer to previously allocated memory, q n put the region back in the heap of unallocated memory Note: easy to forget to free memory when no longer needed. . . q q q especially if you’re used to a language with “garbage collection” like Java This is the source of the notorious “memory leak” problem Difficult to trace – the program will run fine for some time, until suddenly there is no more memory! 12

Checking for successful allocation n n Call to malloc might fail to allocate memory,

Checking for successful allocation n n Call to malloc might fail to allocate memory, if there’s not enough available Easy to forget this check, annoying to have to do it every time malloc is called. . . Garbage inserted into source code if programmer uses malloc n solution: #define malloc DON’T CALL malloc DIRECTLY! #define MALLOC(num, type) (type *)alloc((num)*sizeof(type)) extern void *alloc(size_t size); Use MALLOC instead. . . Scales memory region appropriately (Note use of parameters in #define) Also, calls “safe” alloc function 13

Checking for successful allocation n implementation of alloc: #undef malloc void *alloc(size_t size) {

Checking for successful allocation n implementation of alloc: #undef malloc void *alloc(size_t size) { void *new_mem; new_mem = malloc(size); if (new_mem == NULL) exit(1); return new_mem; } n Nice solution – as long as “terminate the program” is always the right response 14

Memory errors n Using memory that you have not initialized n Using memory that

Memory errors n Using memory that you have not initialized n Using memory that you do not own n Using more memory than you have allocated n Using faulty heap memory management 15

Using memory that you have not n initialized Uninitialized memory read n Uninitialized memory

Using memory that you have not n initialized Uninitialized memory read n Uninitialized memory copy q not necessarily critical – unless a memory read follows void foo(int *pi) { int j; *pi = j; /* UMC: j is uninitialized, copied into *pi */ } void bar() { int i=10; foo(&i); printf("i = %dn", i); /* UMR: Using i, which is now junk value */ } 16

Using memory that you don’t own n n Null pointer read/write Zero page read/write

Using memory that you don’t own n n Null pointer read/write Zero page read/write typedef struct node { struct node* next; int val; } Node; What if head is NULL? int find. Last. Node. Value(Node* head) { while (head->next != NULL) { /* Expect NPR */ head = head->next; } return head->val; /* Expect ZPR */ } 17

Using memory that you don’t own n Invalid pointer read/write q Pointer to memory

Using memory that you don’t own n Invalid pointer read/write q Pointer to memory that hasn’t been allocated to program void gen. IPR() { int *ipr = (int *) malloc(4 * sizeof(int)); int i, j; i = *(ipr - 1000); j = *(ipr + 1000); /* Expect IPR */ free(ipr); } void gen. IPW() { int *ipw = (int *) malloc(5 * sizeof(int)); *(ipw - 1000) = 0; *(ipw + 1000) = 0; /* Expect IPW */ free(ipw); } 18

Using memory that you don’t own n Common error in 64 -bit applications: q

Using memory that you don’t own n Common error in 64 -bit applications: q q ints are 4 bytes but pointers are 8 bytes If prototype of malloc() not provided, return value will be cast to a 4 -byte int Four bytes will be lopped off this value – resulting in an invalid pointer value /*Forgot to #include <malloc. h>, <stdlib. h> in a 64 -bit application*/ void illegal. Pointer() { int *pi = (int*) malloc(4 * sizeof(int)); pi[0] = 10; /* Expect IPW */ printf("Array value = %dn", pi[0]); /* Expect IPR */ } 19

Using memory that you don’t own n Free memory read/write Access of memory that

Using memory that you don’t own n Free memory read/write Access of memory that has been freed earlier int* init_array(int *ptr, int new_size) { ptr = (int*) realloc(ptr, new_size*sizeof(int)); memset(ptr, 0, new_size*sizeof(int)); return ptr; Remember: realloc may move entire block } int* fill_fibonacci(int *fib, int size) { int i; /* oops, forgot: fib = */ init_array(fib, size); /* fib[0] = 0; */ fib[1] = 1; for (i=2; i<size; i++) What if array is moved fib[i] = fib[i-1] + fib[i-2]; to new location? return fib; } q 20

Using memory that you don’t own n Beyond stack read/write char *append(const char* s

Using memory that you don’t own n Beyond stack read/write char *append(const char* s 1, const char *s 2) { const int MAXSIZE = 128; char result[128]; result is a local array name – int i=0, j=0; stack memory allocated for (j=0; i<MAXSIZE-1 && j<strlen(s 1); i++, j++) { result[i] = s 1[j]; } for (j=0; i<MAXSIZE-1 && j<strlen(s 2); i++, j++) { result[i] = s 2[j]; } result[++i] = ''; return result; Function returns pointer to stack } memory – won’t be valid after function returns 21

Using memory that you haven’t n allocated Array bound read/write void gen. ABRand. ABW()

Using memory that you haven’t n allocated Array bound read/write void gen. ABRand. ABW() { const char *name = “Safety Critical"; char *str = (char*) malloc(10); strncpy(str, name, 10); str[11] = ''; /* Expect ABW */ printf("%sn", str); /* Expect ABR */ } 22

Faulty heap management n Memory leak int *pi; void foo() { pi = (int*)

Faulty heap management n Memory leak int *pi; void foo() { pi = (int*) malloc(8*sizeof(int)); /* Allocate memory for pi */ /* Oops, leaked the old memory pointed to by pi */ … free(pi); /* foo() is done with pi, so free it */ } void main() { pi = (int*) malloc(4*sizeof(int)); /* Expect MLK: foo leaks it */ foo(); } 23

Faulty heap management n Potential memory leak q q no pointer to the beginning

Faulty heap management n Potential memory leak q q no pointer to the beginning of a block not necessarily critical – block beginning may still be reachable via pointer arithmetic int *plk = NULL; void gen. PLK() { plk = (int *) malloc(2 * sizeof(int)); /* Expect PLK as pointer variable is incremented past beginning of block */ plk++; } 24

Faulty heap management n n Freeing non-heap memory Freeing unallocated memory void gen. FNH()

Faulty heap management n n Freeing non-heap memory Freeing unallocated memory void gen. FNH() { int fnh = 0; free(&fnh); /* Expect FNH: freeing stack memory */ } void gen. FUM() { int *fum = (int *) malloc(4 * sizeof(int)); free(fum+1); /* Expect FUM: fum+1 points to middle of a block */ free(fum); /* Expect FUM: freeing already freed memory */ } 25

Definition — The Heap n A region of memory provided by most operating systems

Definition — The Heap n A region of memory provided by most operating systems for allocating storage not in Last in, First out discipline n n n Must be explicitly allocated and released May be accessed only with pointers n n I. e. , not a stack Remember, an array is equivalent to a pointer Many hazards to the C programmer 26

Static Data Allocation 0 x. FFFF stack (dynamically allocated) This is Th e Hea

Static Data Allocation 0 x. FFFF stack (dynamically allocated) This is Th e Hea p. address space SP heap (dynamically allocated) static data 0 x 0000 program code (text) PC 27

Allocating Memory in The Heap n See <stdlib. h> void *malloc(size_t size); void free(void

Allocating Memory in The Heap n See <stdlib. h> void *malloc(size_t size); void free(void *ptr); void *calloc(size_t nmemb, size_t size); void *realloc(void *ptr, size_t size); n malloc() — allocates size bytes of memory from the heap and returns a pointer to it. n n NULL pointer if allocation fails for any reason free() — returns the chunk of memory pointed to by ptr n Must have been allocated by malloc or calloc 28

Allocating Memory in The Heap n See <stdlib. h> void *malloc(size_t size); void free(void

Allocating Memory in The Heap n See <stdlib. h> void *malloc(size_t size); void free(void *ptr); void *calloc(size_t nmemb, size_t size); void *realloc(void *ptr, size_t size); n malloc() — allocates size bytes of memory from r big /o d n a the heap and returns a pointer to it. er ult t a n f i n po n NULL pointer if allocation fails for any reason tatio d a en or if b m g Se err pointed to n free() — returns the chunk of memory e tim by ptr n Must have been allocated by malloc or calloc 29

Allocating Memory in The Heap n See <stdlib. h> void *malloc(size_t size); void free(void

Allocating Memory in The Heap n See <stdlib. h> void *malloc(size_t size); void free(void *ptr); void *calloc(size_t nmemb, size_t size); void *realloc(void *ptr, size_t size); k n u h n malloc() — allocates size bytes of memory ffrom c o or e z i ) s ( the heap and returns a pointer to it. knows lloc ) ma ( n NULL pointer if allocation fails for any reason y e b fre ocated ) n free() — returns the chunk of memory all loc(pointed to cal by ptr n Must have been allocated by malloc or calloc 30

Notes n n calloc() is just a variant of malloc() is analogous to new

Notes n n calloc() is just a variant of malloc() is analogous to new in C++ and Java n n new in C++ actually calls malloc() free() is analogous to delete in C++ n n delete in C++ actually calls free() Java does not have delete — uses garbage collection to recover memory no longer in use 31

Typical usage of malloc() and free() char *get. Text. From. Somewhere(…); int main(){ char

Typical usage of malloc() and free() char *get. Text. From. Somewhere(…); int main(){ char * txt; …; txt = get. Text. From. Somewhere(…); …; printf("The text returned is %s. ", txt); free(txt); } 32

Typical usage of malloc() and free() char * get. Text. From. Somewhere(…){ get. Text.

Typical usage of malloc() and free() char * get. Text. From. Somewhere(…){ get. Text. F char *t; rom. Somew here() creates a n. . . ew t = malloc(string. Length); malloc() string using. . . return t; } int main(){ char * txt; …; txt = get. Text. From. Somewhere(…); …; printf("The text returned is %s. ", txt); free(txt); } 33

Typical usage of malloc() and free() char * get. Text. From. Somewhere(…){ char *t;

Typical usage of malloc() and free() char * get. Text. From. Somewhere(…){ char *t; . . . t = malloc(string. Length); . . . return t; } to d e n g assi ion s i t ct tex n o u t f r g te Poin t in callin tx int main(){ char * txt; …; txt = get. Text. From. Somewhere(…); …; printf("The text returned is %s. ", txt); free(txt); } 34

Usage of malloc() and free() char *get. Text(…){ char *t; . . . t

Usage of malloc() and free() char *get. Text(…){ char *t; . . . t = malloc(string. Length); . . . return t; } r to e b m me e r t d to s e t u n i m ) po ( e n g a i r ma sto e h t free t x by t int main(){ char * txt; …; txt = get. Text(…); …; printf("The text returned is %s. ", txt); free(txt); } 35

Definition – Memory Leak n The steady loss of available memory due to forgetting

Definition – Memory Leak n The steady loss of available memory due to forgetting to free() everything that was malloc’ed. n n Bug-a-boo of most large C and C++ programs If you “forget” the value of a pointer to a piece of malloc’ed memory, there is no way to find it again! n Killing the program frees all memory! 36

Dynamic Memory Allocation in C++ n n n In C, functions such as malloc()

Dynamic Memory Allocation in C++ n n n In C, functions such as malloc() are used to dynamically allocate memory from the Heap. In C++, this is accomplished using the new and delete operators new is used to allocate memory during execution time q q returns a pointer to the address where the object is to be stored always returns a pointer to the type that follows the new 37

Operator new Syntax new Data. Type [Int. Expression] n If memory is available, in

Operator new Syntax new Data. Type [Int. Expression] n If memory is available, in an area called the heap (or free store) new allocates the requested object or array, and returns a pointer to (address of ) the memory allocated. n Otherwise, program terminates with error message. n The dynamically allocated object exists until the delete operator destroys it. 38

Operator new 2000 char* ptr; ? ? ? 5000 ptr = new char; *ptr

Operator new 2000 char* ptr; ? ? ? 5000 ptr = new char; *ptr = ‘B’; 5000 ‘B’ cout << *ptr; NOTE: Dynamic data has no variable name 39

The NULL Pointer n n n There is a pointer constant called the “null

The NULL Pointer n n n There is a pointer constant called the “null pointer” denoted by NULL But NULL is not memory address 0. NOTE: It is an error to dereference a pointer whose value is NULL. Such an error may cause your program to crash, or behave erratically. It is the programmer’s job to check for this. while (ptr != NULL) { . . . // ok to use *ptr here } 40

Operator delete Syntax delete Pointer delete [ ] n n n Pointer The object

Operator delete Syntax delete Pointer delete [ ] n n n Pointer The object or array currently pointed to by Pointer is deallocated, and the value of Pointer is undefined. The memory is returned to the free store. Good idea to set the pointer to the released memory to NULL Square brackets are used with delete to deallocate a dynamically allocated array. 41

Operator delete 2000 char* ptr; 5000 ? ? ? ptr = new char; *ptr

Operator delete 2000 char* ptr; 5000 ? ? ? ptr = new char; *ptr = ‘B’; cout << *ptr; 5000 ‘B’ NOTE: delete deallocates the memory pointed to by ptr delete ptr; 42

Example char *ptr ; ptr = new char[ 5 ]; ptr 3000 ? ?

Example char *ptr ; ptr = new char[ 5 ]; ptr 3000 ? ? ? NULL 6000 ? ? ? strcpy( ptr, “Bye” ); ptr[ 0 ] = ‘u’; delete [] ptr; ptr = NULL; 6000 ‘B’ ‘y’ ‘e’ ‘’ ‘u’ // deallocates the array pointed to by ptr // ptr itself is not deallocated // the value of ptr becomes undefined 43

Memory leaks n When you dynamically create objects, you can access them through the

Memory leaks n When you dynamically create objects, you can access them through the pointer which is assigned by the new operator n Reassigning a pointer without deleting the memory it pointed to previously is called a memory leak It results in loss of available memory space n 44

Memory leak example int *ptr 1 = new int; int *ptr 2 = new

Memory leak example int *ptr 1 = new int; int *ptr 2 = new int; *ptr 1 = 8; *ptr 2 = 5; ptr 2 = ptr 1; ptr 1 8 ptr 2 5 ptr 1 8 How to avoid? ptr 2 5 45

Inaccessible object n n An inaccessible object is an unnamed object that was created

Inaccessible object n n An inaccessible object is an unnamed object that was created by operator new and which a programmer has left without a pointer to it. It is a logical error and causes memory leaks. 46

Dangling Pointer n n It is a pointer that points to dynamic memory that

Dangling Pointer n n It is a pointer that points to dynamic memory that has been deallocated. The result of dereferencing a dangling pointer is unpredictable. 47

Dangling Pointer example int *ptr 1 = new int; int *ptr 2; *ptr 1

Dangling Pointer example int *ptr 1 = new int; int *ptr 2; *ptr 1 = 8; ptr 2 = ptr 1; delete ptr 1; ptr 1 8 ptr 2 ptr 1 How to avoid? ptr 2 48

Dynamic Arrays n n n You would like to use an array data structure

Dynamic Arrays n n n You would like to use an array data structure but you do not know the size of the array at compile time. You find out when the program executes that you need an integer array of size n=20. Allocate an array using the new operator: int* y = new int[20]; // or int* y = new int[n] y[0] = 10; y[1] = 15; // use is the same 49

Dynamic Arrays n n n ‘y’ is a lvalue; it is a pointer that

Dynamic Arrays n n n ‘y’ is a lvalue; it is a pointer that holds the address of 20 consecutive cells in memory. It can be assigned a value. The new operator returns as address that is stored in y. We can write: y = &x[0]; y = x; // x can appear on the right // y gets the address of the // first cell of the x array 50

Dynamic Arrays n We must free the memory we got using the new operator

Dynamic Arrays n We must free the memory we got using the new operator once we are done with the y array. delete[ ] y; n We would not do this to the x array because we did not use new to create it. 51

Structures n Collections of related variables (aggregates) under one name q n n Can

Structures n Collections of related variables (aggregates) under one name q n n Can contain variables of different data types Commonly used to define records to be stored in files Combined with pointers, can create linked lists, stacks, queues, and trees 52

Structure Definitions n Example struct card { char *face; char *suit; }; n n

Structure Definitions n Example struct card { char *face; char *suit; }; n n n struct introduces the definition for structure card is the structure name and is used to declare variables of the structure type card contains two members of type char * q These members are face and suit 53

Structure Definitions n struct information q q q A struct cannot contain an instance

Structure Definitions n struct information q q q A struct cannot contain an instance of itself Can contain a member that is a pointer to the same structure type A structure definition does not reserve space in memory n n Instead creates a new data type used to declare structure variables Declarations q Declared like other variables: card one. Card, deck[ 52 ], *c. Ptr; q Can use a comma separated list: struct card { char *face; char *suit; } one. Card, deck[ 52 ], *c. Ptr; 54

Structure Definitions n Valid Operations q q Assigning a structure to a structure of

Structure Definitions n Valid Operations q q Assigning a structure to a structure of the same type Taking the address (&) of a structure Accessing the members of a structure Using the sizeof operator to determine the size of a structure 55

Initializing Structures n Initializer lists q Example: card one. Card = { "Three", "Hearts"

Initializing Structures n Initializer lists q Example: card one. Card = { "Three", "Hearts" }; n Assignment statements q Example: card three. Hearts = one. Card; q Could also declare and initialize three. Hearts as follows: card three. Hearts; three. Hearts. face = “Three”; three. Hearts. suit = “Hearts”; 56

Accessing Members of Structures n Accessing structure members q Dot operator (. ) used

Accessing Members of Structures n Accessing structure members q Dot operator (. ) used with structure variables card my. Card; printf( "%s", my. Card. suit ); q Arrow operator (->) used with pointers to structure variables card *my. Card. Ptr = &my. Card; printf( "%s", my. Card. Ptr->suit ); q my. Card. Ptr->suit is equivalent to ( *my. Card. Ptr ). suit 57

Using Structures With Functions n Passing structures to functions q Pass entire structure n

Using Structures With Functions n Passing structures to functions q Pass entire structure n q n Both pass call by value To pass structures call-by-reference q q n Or, pass individual members Pass its address Pass reference to it To pass arrays call-by-value q q Create a structure with the array as a member Pass the structure 58

typedef n Creates synonyms (aliases) for previously defined data types Use typedef to create

typedef n Creates synonyms (aliases) for previously defined data types Use typedef to create shorter type names n Example: n typedef struct Card *Card. Ptr; n n Defines a new type name Card. Ptr as a synonym for type struct Card * typedef does not create a new data type q Only creates an alias 59

Example using Structures n High-Performance Card-shuffling and Dealing Simulation n Pseudocode: q q Create

Example using Structures n High-Performance Card-shuffling and Dealing Simulation n Pseudocode: q q Create an array of card structures Put cards in the deck Shuffle the deck Deal the cards 60

1 2 3 4 5 6 7 8 9 10 11 12 13 14

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 /* Fig. 10. 3: fig 10_03. c The card shuffling and dealing program using structures */ #include <stdio. h> #include <stdlib. h> #include <time. h> struct card { const char *face; const char *suit; }; typedef struct card Card; void fill. Deck( Card * const, const char *[], const char *[] ); void shuffle( Card * const ); void deal( const Card * const ); int main() { Card deck[ 52 ]; const char *face[] = { "Ace", "Deuce", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Jack", "Queen", "King"}; const char *suit[] = { "Hearts", "Diamonds", "Clubs", "Spades"}; srand( time( NULL ) ); 1. Load headers 1. 1 Define struct 1. 2 Function prototypes 1. 3 Initialize deck[] and face[] 1. 4 Initialize suit[]

31 32 33 34 35 36 37 38 39 40 41 42 43 44

31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 fill. Deck( deck, face, suit ); shuffle( deck ); deal( deck ); return 0; } 2. Randomize void fill. Deck( Card * const w. Deck, const char * w. Face[], 2. fill. Deck const char * w. Suit[] ) { Put all 52 cards in the deck. int i; face and suit determined by for ( i = 0; i <= 51; i++ ) { w. Deck[ i ]. face = w. Face[ i % 13 ]; w. Deck[ i ]. suit = w. Suit[ i / 13 ]; } } remainder (modulus). 2. 1 shuffle 2. 2 deal 3. Function definitions void shuffle( Card * const w. Deck ) { int i, j; Card temp; for ( i = 0; i <= 51; i++ ) { j = rand() % 52; temp = w. Deck[ i ]; w. Deck[ i ] = w. Deck[ j ]; w. Deck[ j ] = temp; } } Select random number between 0 and 51. Swap element i with that element.

61 62 void deal( const Card * const w. Deck ) 63 { 64

61 62 void deal( const Card * const w. Deck ) 63 { 64 int i; 65 66 for ( i = 0; i <= 51; i++ ) 67 printf( "%5 s of %-8 s%c", w. Deck[ i ]. face, 68 w. Deck[ i ]. suit, 69 ( i + 1 ) % 2 ? 't' : 'n' ); 70 } Cycle through array and print out data. 3. Function definitions

Eight of Diamonds Ace of Hearts Eight of Clubs Five of Spades Seven of

Eight of Diamonds Ace of Hearts Eight of Clubs Five of Spades Seven of Hearts Deuce of Diamonds Ace of Clubs Ten of Diamonds Deuce of Spades Six of Diamonds Seven of Spades Deuce of Clubs Jack of Clubs Ten of Spades King of Hearts Jack of Diamonds Three of Hearts Three of Diamonds Three of Clubs Nine of Clubs Ten of Hearts Deuce of Hearts Ten of Clubs Seven of Diamonds Six of Clubs Queen of Spades Six of Hearts Three of Spades Nine of Diamonds Ace of Diamonds Jack of Spades Five of Clubs King of Diamonds Seven of Clubs Nine of Spades Four of Hearts Six of Spades Eight of Spades Queen of Diamonds Five of Diamonds Ace of Spades Nine of Hearts King of Clubs Five of Hearts King of Spades Four of Diamonds Queen of Hearts Eight of Hearts Four of Spades Jack of Hearts Four of Clubs Queen of Clubs Program Output

C structures: aggregate, yet scalar n aggregate in that they hold multiple data items

C structures: aggregate, yet scalar n aggregate in that they hold multiple data items at one time q q n named members hold data items of various types like the notion of class/field in C or C++ – but without the data hiding features scalar in that C treats each structure as a unit q q q as opposed to the “array” approach: a pointer to a collection of members in memory entire structures (not just pointers to structures) may be passed as function arguments, assigned to variables, etc. Interestingly, they cannot be compared using == (rationale: too inefficient) 65

Structure declarations n Combined variable and type declaration struct tag {member-list} variable-list; n Any

Structure declarations n Combined variable and type declaration struct tag {member-list} variable-list; n Any one of the three portions can be omitted struct {int a, b; char *p; } x, y; q q /* omit tag */ variables x, y declared with members as described: int members a, b and char pointer p. x and y have same type, but differ from all others – even if there is another declaration: struct {int a, b; char *p; } z; /* z has different type from x, y */ 66

Structure declarations struct S {int a, b; char *p; }; n /* omit variables

Structure declarations struct S {int a, b; char *p; }; n /* omit variables */ No variables are declared, but there is now a type struct S that can be referred to later struct S z; q /* omit members */ Given an earlier declaration of struct S, this declares a variable of that typedef struct {int a, b; char *p; } S; /* omit both tag and variables */ q This creates a simple type name S (more convenient than struct S) 67

Recursively defined structures n n Obviously, you can’t have a structure that contains an

Recursively defined structures n n Obviously, you can’t have a structure that contains an instance of itself as a member – such a data item would be infinitely large But within a structure you can refer to structures of the same type, via pointers struct TREENODE { char *label; struct TREENODE *leftchild, *rightchild; } 68

Recursively defined structures n When two structures refer to each other, one must be

Recursively defined structures n When two structures refer to each other, one must be declared in incomplete (prototype) fashion struct HUMAN; struct PET { char name[NAME_LIMIT]; char species[NAME_LIMIT]; struct HUMAN *owner; } fido = {″Fido″, ″Canis lupus familiaris″}; struct HUMAN { char name[NAME_LIMIT]; We can’t initialize the owner struct PET pets[PET_LIMIT]; member at this point, } sam = {″Sam″, {fido}}; since it hasn’t been declared yet 69

Member access n Direct access operator s. m q subscript and dot operators have

Member access n Direct access operator s. m q subscript and dot operators have same precedence and associate left-to-right, so we don’t need parentheses for sam. pets[0]. species n Indirect access s->m: equivalent to (*s). m Dereference a pointer to a structure, then return a member of that structure q Dot operator has higher precedence than indirection operator , so parentheses are needed in (*s). m (*fido. owner). name or fido. owner->name q . evaluated first: access owner member * evaluated next: dereference pointer to HUMAN . and -> have equal precedence and associate left-to-right 70

Memory layout struct COST { int amount; char currency_type[2]; } struct PART { char

Memory layout struct COST { int amount; char currency_type[2]; } struct PART { char id[2]; struct COST cost; int num_avail; } layout of struct PART: currency_type id amount num_avail cost Here, the system uses 4 -byte alignment of integers, so amount and num_avail must be aligned Four bytes wasted for each structure! 71

Memory layout A better alternative (from a space perspective): struct COST { int amount;

Memory layout A better alternative (from a space perspective): struct COST { int amount; char currency_type; } struct PART { struct COST cost; char id[2]; int num_avail; } currency_type amount id num_avail cost 72

Structures as function arguments n Structures are scalars, so they can be returned and

Structures as function arguments n Structures are scalars, so they can be returned and passed as arguments – just like ints, chars struct BIG changestruct(struct BIG s); q q n Call by value: temporary copy of structure is created Caution: passing large structures is inefficient – involves a lot of copying avoid by passing a pointer to the structure instead: void changestruct(struct BIG *s); n What if the struct argument is read-only? q Safe approach: use const void changestruct(struct BIG const *s); 73

Unions n n n Memory that contains a variety of objects over time Only

Unions n n n Memory that contains a variety of objects over time Only contains one data member at a time Members of a union share space Conserves storage Only the last data member defined can be accessed union declarations q Same as struct union Number { int x; float y; }; Union my. Object; 74

Unions n Storage q q n size of union is the size of its

Unions n Storage q q n size of union is the size of its largest member avoid unions with widely varying member sizes; for the larger data types, consider using pointers instead Initialization q Union may only be initialized to a value appropriate for the type of its first member 75

Unions n Like structures, but every member occupies the same region of memory! q

Unions n Like structures, but every member occupies the same region of memory! q q Structures: members are “and”ed together: “name and species and owner” Unions: members are “xor”ed together union VALUE { float f; int i; char *s; }; /* either a float xor an int xor a string */ 76

Unions n n Up to programmer to determine how to interpret a union (i.

Unions n n Up to programmer to determine how to interpret a union (i. e. which member to access) Often used in conjunction with a “type” variable that indicates how to interpret the union value enum TYPE { INT, FLOAT, STRING }; struct VARIABLE { Access type to determine enum TYPE type; how to interpret value union VALUE value; }; 77

Valid Union Operators n n Assignment to union of same type: = Taking address:

Valid Union Operators n n Assignment to union of same type: = Taking address: & Accessing union members: . Accessing members using pointers: -> 78

1 /* Fig. 10. 5: fig 10_05. c 2 An example of a union

1 /* Fig. 10. 5: fig 10_05. c 2 An example of a union */ 3 4 5 6 7 #include <stdio. h> 8 9 }; union number { int x; double y; 10 11 12 13 14 15 16 17 int main() { union number value; value. x = 100; printf( "%sn%s%dn%s%fnn", "Put a value in the integer member", "and print both members. ", 18 19 20 21 22 23 24 25 26 "int: ", value. x, "double: n", value. y ); value. y = 100. 0; printf( "%sn%s%dn%s%fn", "Put a value in the floating member", "and print both members. ", "int: ", value. x, "double: n", value. y ); 27 return 0; 28 } 1. Define union 1. 1 Initialize variables 2. Set variables 3. Print

Put a value in the integer member and print both members. int: 100 double:

Put a value in the integer member and print both members. int: 100 double: -9255959211743313600000000000000000000000 Put a value in the floating member and print both members. int: 0 double: 100. 000000 Program Output

Strings n n n Arrays of characters End with a null byte ('�') String

Strings n n n Arrays of characters End with a null byte ('') String literals implicitly provide the null terminator: "hello" becomes: 'h' 'e' 'l' 'o' '' 81

Strings in C n Definition: – A string is a character array ending in

Strings in C n Definition: – A string is a character array ending in '' — i. e. , q q q n char s[256]; char t[] = "This is an initialized string!"; char *u = "This is another string!"; String constants are in double quotes n n n May contain any characters Including " and ' — String constants may not span lines n However, they may be concatenated — e. g. , "Hello, " "World!n" is the same as "Hello, World!n" 82

Strings in C (continued) n Let q n char *u = "This is another

Strings in C (continued) n Let q n char *u = "This is another string!"; Then q u[0] == 'T' u[1] == 'h' u[2] == 'i' … u[21] == 'g' u[22] == '!' u[23] == '' 83

Support for Strings in C n Most string manipulation is done through functions in

Support for Strings in C n Most string manipulation is done through functions in <string. h> n String functions depend upon final '' n n So you don’t have to count the characters! Examples: – q q q int strlen(char *s) – returns length of string n Excluding final '' char* strcpy(char *s, char *ct) – Copies string ct to string s, return s must be big enough to hold contents of ct n ct may be smaller than s See K&R pp. 105 -106 for various implementations 84

Support for Strings in C (continued) n Examples (continued): – q int strcmp(char *s,

Support for Strings in C (continued) n Examples (continued): – q int strcmp(char *s, char *t) n lexically compares s and t, returns <0 if s < t, >0 if s > t, zero if s and t are identical q q char* strcat(char *s, char *ct) n n n D&D § 8. 6, K&R p. 106 Concatenates string ct to onto end of string s, returns s s must be big enough to hold contents of both strings! Other string functions q q strchr(), strspn(), strcspn() strpbrk(), strstr(), strtok(), … K&R pp. 249 -250; D&D § 8. 6 85

Character Handling Library <ctype. h> 86

Character Handling Library <ctype. h> 86

String Conversion Functions in C n See <stdlib. h> double atof(const char *s) int

String Conversion Functions in C n See <stdlib. h> double atof(const char *s) int atoi(const char *s) long atol(const char *s) double strtod(const char *s, char **endp) long strtol(const char *s, char **endp, int base) unsigned long strtoul(const char *s, char **endp, int base) 87

Dilemma n Question: – q q q n If strings are arrays of characters,

Dilemma n Question: – q q q n If strings are arrays of characters, … and if arrays cannot be returned from functions, … how can we manipulate variable length strings and pass them around our programs? Answer: – q Use storage allocated in The Heap! 88

C-Style Multidimensional Arrays Most high level languages support arrays with more than one dimension.

C-Style Multidimensional Arrays Most high level languages support arrays with more than one dimension. 2 D arrays are useful when data has to be arranged in tabular form. Higher dimensional arrays appropriate when several characteristics associated with data. Example: A table of test scores for several different students on several different tests. For storage and processing, use a two-dimensional array. 89

Declaring Two-Dimensional Arrays Standard form of declaration: element_type array_name[NUM_ROWS][NUM_COLUMNS]; Example: const int NUM_ROWS =

Declaring Two-Dimensional Arrays Standard form of declaration: element_type array_name[NUM_ROWS][NUM_COLUMNS]; Example: const int NUM_ROWS = 30, NUM_COLUMNS = 4; [0] [[1] [2] [3] [0] [1] [2] [3] [29] . . . double scores. Table[NUM_ROWS][NUM_COLUMNS]; Initialization List the initial values in braces, row by row; May use internal braces for each row to improve readability. Example: double rates[2][3] = {{0. 50, 0. 55, 0. 53}, // first row {0. 63, 0. 58, 0. 55}}; // second row 90

 Processing Two-Dimensional Arrays Remember: Rows (and) columns are numbered from zero!! Use doubly-indexed

Processing Two-Dimensional Arrays Remember: Rows (and) columns are numbered from zero!! Use doubly-indexed variables: scores. Table[2][3] is the entry in row 2 and column 3 row index column index Counting from 0 nested loops to vary the two indices, most often in a rowwise manner. 91

Higher-Dimensional Arrays The methods for 2 D arrays extend in the obvious way to

Higher-Dimensional Arrays The methods for 2 D arrays extend in the obvious way to 3 D arrays. Example: To store and process a table of test scores for several different students on several different tests for several different semesters const int SEMS = 10, STUDENTS = 30, TESTS = 4; typedef double Three. Dim. Array[SEMS][STUDENTS][TESTS]; Three. Dim. Array grade. Book; grade. Book[4][2][3] is the score of 4 th semester for student 2 on test 3 // number of semesters, students and tests all counted from zero!! 92

Arrays of Arrays [0] [[1] [2] [3] [0] [1] [2] [3] double scores. Table[30][4];

Arrays of Arrays [0] [[1] [2] [3] [0] [1] [2] [3] double scores. Table[30][4]; [29] . . . Declares scores. Table to be a one-dimensional array containing 30 elements, each of which is a one-dimensional array of 4 real numbers; tha scores. Table is a one-dimensional array of rows , each of which has 4 real values. We could declare it as typedef double Row. Of. Table[4]; [0] [[1] [2] [3] [1] [2] Row. Of. Table scores. Table[30]; [3] [29] . . . 93

In any case: scores. Table[i] is the i-th row of the table scores. Table[i][j]

In any case: scores. Table[i] is the i-th row of the table scores. Table[i][j] should be thought of as (scores. Table[i])[j] that is, as finding the j-th element of scores. Table[i]. Address Translation: The array-of-arrays structure of multidimensional arrays explains address translation. Suppose the base address of scores. Table is 0 x 12348: scores. Table[10][4 ] scores. Table[10] ® 0 x 12348 + 10*(sizeof Row. Of. Table) = 0 x 12348 + 10 * (4 * 8) [0] [1] [9] [10] scores. Table[10][3 ® base(scores. Table[10]) + 3*(sizeof double) ] = 0 x 12348 + 10 * (4 * 8) + 3 * 8 = 0 x 124 a 0 In general, an n-dimensional array can be viewed (recursively) as a one-dimensional array whose elements are (n - 1)-dimensional arrays. . . . [3] 94

Implementing multidimensional arrays More complicated than one dimensional arrays. Memory is organized as a

Implementing multidimensional arrays More complicated than one dimensional arrays. Memory is organized as a sequence of memory locations, and is thus 1 D How to use a 1 D structure to store a MD structure? A E I B F J C G K D H L A character requires a single byte Compiler instructed to reserve 12 consecutive bytes Two ways to store consecutively i. e. rowwise and columnwise. 95

Implementing multidimensional arrays A E I B F J C G K D H

Implementing multidimensional arrays A E I B F J C G K D H L B F J Row. Wise A B C D E F G H I J K L C G K D H L Column. Wise A E I B A F E J I C G K D H L B F J C G K D H L 96

Summary n Dynamic Memory Management with Pointers q q n n malloc() calloc() free()

Summary n Dynamic Memory Management with Pointers q q n n malloc() calloc() free() new and delete operators realloc() Structures Unions Strings Multidimensional Arrays 97