csc 211 data structures lecture 6
DESCRIPTION
CSC 211 Data Structures Lecture 6. Dr. Iftikhar Azim Niaz [email protected]. 1. Last Lecture Summary I. Concept of Pointer Pointer operators Address and Indirection Pointer Arithmetic Pointer and functions Pass by Value Pass by Reference Pointer and Arrays. 2. Objectives Overview. - PowerPoint PPT PresentationTRANSCRIPT
2
Last Lecture Summary I Concept of Pointer Pointer operators
Address and Indirection Pointer Arithmetic Pointer and functions
Pass by Value Pass by Reference
Pointer and Arrays
2
3
Objectives Overview Dynamic Memory Management with Pointers Structures Unions Strings Multidimensional Arrays
4
Dynamic Memory Allocation
Static memory - where global and static variables live
Heap memory - dynamically allocated at execution time- "managed" memory accessed using pointers
Stack memory - used by automatic variables
In C and C++, three types of memory are used by programs:
5
3 Kinds of Program Data STATIC DATA: Allocated at compiler time
DYNAMIC DATA: explicitly allocated and deallocated during program execution by C++ instructions written by programmer using operators new and delete
AUTOMATIC DATA: automatically created at function entry, resides in activation frame of the function, and is destroyed when returning from function
6
Dynamic Memory Allocation Diagram
s ta tic da ta
S tack
H eap
Run-tim
e allocatedm
emory
Com
pile-time
allocatedm
emory
P rog ramcode
H igh -end
Low -end
7
Allocation of Memory Static Allocation: Allocation of memory space at
compile time. Dynamic Allocation: Allocation of memory
space at run time. Dynamic allocation is useful when
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
8
Overview of memory management Stack-allocated memory 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) When a function call terminates,
the memory is deallocated (“freed up”)
Ex: main() calls f(),f() calls g()g() recursively calls g() main()
f()
g()
g()
9
Overview of memory management Heap-allocated memory This is used for persistent data, that must survive
beyond the lifetime of a function call 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!
10
Allocating new heap memoryvoid *malloc(size_t size); 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); Allocate a block of num_elements * element_size bytes,
initialize every byte to zero,return pointer to the block(NULL if unable to allocate block)
Note: void * denotes a generic pointer type
11
Allocating new heap memoryvoid *realloc(void *ptr, size_t new_size); Given a previously allocated block starting at ptr,
change the block size to new_size, return pointer to resized block
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
If ptr is NULL, realloc is identical to malloc
Note: may need to cast return value of malloc/calloc/realloc:
char *p = (char *) malloc(BUFFER_SIZE);
12
Deallocating heap memoryvoid free(void *pointer); Given a pointer to previously allocated memory,
put the region back in the heap of unallocated memory Note: easy to forget to free memory when no
longer needed... 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!
13
Checking for successful allocation 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...
solution:#define mallocDON’T CALL malloc DIRECTLY!#define MALLOC(num,type) (type *)alloc((num)*sizeof(type))extern void *alloc(size_t size);
Garbage inserted into source code if programmer uses malloc
Use MALLOC instead...Scales memory region appropriately
(Note use of parameters in #define)Also, calls “safe” alloc function
14
Checking for successful allocation 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;} Nice solution – as long as “terminate the
program” is always the right response
15
Memory errors Using memory that you have not initialized
Using memory that you do not own
Using more memory than you have allocated
Using faulty heap memory management
16
Using memory that you have not initialized Uninitialized memory read Uninitialized memory copy
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 = %d\n", i);/* UMR: Using i, which is now junk value */
}
17
Using memory that you don’t own Null pointer read/write
Zero page read/write
typedef struct node {struct node* next;int val;
} Node;
int findLastNodeValue(Node* head) {while (head->next != NULL) { /* Expect NPR */head = head->next;}return head->val; /* Expect ZPR */
}
What if head is NULL?
18
Using memory that you don’t own Invalid pointer read/write
Pointer to memory that hasn’t been allocated to program
void genIPR() {int *ipr = (int *) malloc(4 * sizeof(int));int i, j;i = *(ipr - 1000); j = *(ipr + 1000); /* Expect IPR */free(ipr);
}
void genIPW() {int *ipw = (int *) malloc(5 * sizeof(int));*(ipw - 1000) = 0; *(ipw + 1000) = 0; /* Expect IPW */free(ipw);
}
19
Using memory that you don’t own Common error in 64-bit applications: 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
/*Forgot to #include <malloc.h>, <stdlib.h> in a 64-bit application*/void illegalPointer() {
int *pi = (int*) malloc(4 * sizeof(int));pi[0] = 10; /* Expect IPW */printf("Array value = %d\n", pi[0]); /* Expect IPR */
}
Four bytes will be lopped off this value – resulting in an invalid pointer value
20
Using memory that you don’t own 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;
}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++)fib[i] = fib[i-1] + fib[i-2];return fib;
}
What if array is moved to new location?
Remember: realloc may move entire block
21
Using memory that you don’t own Beyond stack read/write
char *append(const char* s1, const char *s2) {const int MAXSIZE = 128;char result[128];int i=0, j=0;for (j=0; i<MAXSIZE-1 && j<strlen(s1); i++,j++) {result[i] = s1[j];}for (j=0; i<MAXSIZE-1 && j<strlen(s2); i++,j++) {result[i] = s2[j];}result[++i] = '\0';return result;
}
Function returns pointer to stack memory – won’t be valid after
function returns
result is a local array name –stack memory allocated
22
Using memory that you haven’t allocated Array bound read/write
void genABRandABW() {const char *name = “Safety Critical";char *str = (char*) malloc(10);strncpy(str, name, 10);str[11] = '\0'; /* Expect ABW */printf("%s\n", str); /* Expect ABR */
}
23
Faulty heap management 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();
}
24
Faulty heap management Potential memory leak
no pointer to the beginning of a block not necessarily critical – block beginning may still be reachable via
pointer arithmetic
int *plk = NULL;void genPLK() {
plk = (int *) malloc(2 * sizeof(int)); /* Expect PLK as pointer variable is incremented
past beginning of block */plk++;
}
25
Faulty heap management Freeing non-heap memory Freeing unallocated memoryvoid genFNH() {
int fnh = 0;free(&fnh); /* Expect FNH: freeing stack memory */
}void genFUM() {
int *fum = (int *) malloc(4 * sizeof(int));free(fum+1); /* Expect FUM: fum+1 points to middle of a block */free(fum);free(fum); /* Expect FUM: freeing already freed memory */
}
26
Definition — The Heap A region of memory provided by most operating
systems for allocating storage not in Last in, First out discipline
I.e., not a stack
Must be explicitly allocated and released May be accessed only with pointers
Remember, an array is equivalent to a pointer
Many hazards to the C programmer
27
Static Data Allocation
0x00000000
0xFFFFFFFF
address space
program code(text)
static data
heap(dynamically allocated)
stack(dynamically allocated)
PC
SPThis is The Heap.
28
Allocating Memory in The Heap 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);
malloc() — allocates size bytes of memory from the heap and returns a pointer to it.
NULL pointer if allocation fails for any reason free() — returns the chunk of memory pointed to
by ptr Must have been allocated by malloc or calloc
29
Allocating Memory in The Heap 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);
malloc() — allocates size bytes of memory from the heap and returns a pointer to it.
NULL pointer if allocation fails for any reason free() — returns the chunk of memory pointed to
by ptr Must have been allocated by malloc or calloc
Segmentation fault and/or big-
time error if bad pointer
30
Allocating Memory in The Heap 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);
malloc() — allocates size bytes of memory from the heap and returns a pointer to it.
NULL pointer if allocation fails for any reason free() — returns the chunk of memory pointed to
by ptr Must have been allocated by malloc or calloc
free() knows size
of chunk
allocated by malloc(
) or
calloc()
31
Notes calloc() is just a variant of malloc() malloc() is analogous to new in C++ and
Java new in C++ actually calls malloc()
free() is analogous to delete in C++ delete in C++ actually calls free() Java does not have delete — uses garbage collection to
recover memory no longer in use
32
Typical usage of malloc() and free()char *getTextFromSomewhere(…);
int main(){char * txt;…;txt = getTextFromSomewhere(…);…;printf("The text returned is %s.", txt);free(txt);
}
33
Typical usage of malloc() and free()char * getTextFromSomewhere(…){
char *t;...t = malloc(stringLength);...return t;
}
int main(){char * txt;…;txt = getTextFromSomewhere(…);…;printf("The text returned is %s.", txt);free(txt);
}
getTextFromSomewhere() creates a new string using malloc()
34
Typical usage of malloc() and free()char * getTextFromSomewhere(…){
char *t;...t = malloc(stringLength);...return t;
}
int main(){char * txt;…;txt = getTextFromSomewhere(…);…;printf("The text returned is %s.", txt);free(txt);
}
Pointer to text is assigned to
txt in calling function
35
Usage of malloc() and free()char *getText(…){
char *t;...t = malloc(stringLength);...return t;
}
int main(){char * txt;…;txt = getText(…);…;printf("The text returned is %s.", txt);free(txt);
}
main() must remember to
free the storage pointed to
by txt
36
Definition – Memory Leak The steady loss of available memory due to
forgetting to free() everything that was malloc’ed.
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!
Killing the program frees all memory!
37
Dynamic Memory Allocation in C++ 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 returns a pointer to the address where the object is
to be stored always returns a pointer to the type that follows the
new
38
Operator new Syntaxnew DataType
new DataType [IntExpression]
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.
Otherwise, program terminates with error message.
The dynamically allocated object exists until the delete operator destroys it.
39
Operator new
char* ptr;
ptr = new char;
*ptr = ‘B’;
cout << *ptr;
NOTE: Dynamic data has no variable name
2000
???
ptr
5000
5000‘B’
40
The NULL Pointer 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 }
41
Operator delete Syntax delete Pointer
delete [ ] 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.
42
Operator delete
char* ptr;
ptr = new char;
*ptr = ‘B’;
cout << *ptr;
delete ptr;
5000
5000‘B’
2000
ptr
???
NOTE: delete deallocates the memory pointed to by ptr
43
Example char *ptr ;
ptr = new char[ 5 ];
strcpy( ptr, “Bye” );
ptr[ 0 ] = ‘u’;
delete [] ptr;
ptr = NULL;
‘B’ ‘y’ ‘e’ ‘\0’‘u’
ptr3000
???
6000
6000???NULL
// deallocates the array pointed to by ptr// ptr itself is not deallocated// the value of ptr becomes undefined
44
Memory leaks When you dynamically create objects, you can
access them through the pointer which is assigned by the new operator
Reassigning a pointer without deleting the memory it pointed to previously is called a memory leak
It results in loss of available memory space
45
Memory leak example
int *ptr1 = new int;int *ptr2 = new int;*ptr1 = 8;*ptr2 = 5;
ptr18
5ptr2
ptr18
5ptr2
ptr2 = ptr1;
How to avoid?
46
Inaccessible object 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.
47
Dangling Pointer It is a pointer that points to dynamic memory
that has been deallocated. The result of dereferencing a dangling pointer
is unpredictable.
48
Dangling Pointer example
int *ptr1 = new int;int *ptr2;*ptr1 = 8;ptr2 = ptr1;
ptr18
ptr2
delete ptr1;
ptr1
ptr2How to avoid?
49
Dynamic Arrays 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
50
Dynamic Arrays ‘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
51
Dynamic Arrays We must free the memory we got using the
new operator once we are done with the y array.
delete[ ] y;
We would not do this to the x array because we did not use new to create it.
52
Structures Collections of related variables (aggregates)
under one name 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
53
Structure Definitions Example
struct card { char *face; char *suit;
}; struct introduces the definition for structure
card card is the structure name and is used to
declare variables of the structure type card contains two members of type char *
These members are face and suit
54
Structure Definitions struct information
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
Instead creates a new data type used to declare structure variables
Declarations Declared like other variables:
card oneCard, deck[ 52 ], *cPtr; Can use a comma separated list:
struct card { char *face; char *suit;} oneCard, deck[ 52 ], *cPtr;
55
Structure Definitions Valid Operations
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
56
Initializing Structures Initializer lists
Example:card oneCard = { "Three", "Hearts" };
Assignment statements Example:
card threeHearts = oneCard; Could also declare and initialize threeHearts as
follows:card threeHearts;threeHearts.face = “Three”;threeHearts.suit = “Hearts”;
57
Accessing Members of Structures Accessing structure members Dot operator (.) used with structure variablescard myCard;printf( "%s", myCard.suit );
Arrow operator (->) used with pointers to structure variablescard *myCardPtr = &myCard;printf( "%s", myCardPtr->suit );
myCardPtr->suit is equivalent to( *myCardPtr ).suit
58
Using Structures With Functions Passing structures to functions Pass entire structure
Or, pass individual members Both pass call by value
To pass structures call-by-reference Pass its address Pass reference to it
To pass arrays call-by-value Create a structure with the array as a member Pass the structure
59
typedef Creates synonyms (aliases) for previously
defined data types Use typedef to create shorter type names Example:
typedef struct Card *CardPtr; Defines a new type name CardPtr as a
synonym for type struct Card * typedef does not create a new data type
Only creates an alias
60
Example using Structures High-Performance Card-shuffling and
Dealing Simulation Pseudocode:
Create an array of card structures Put cards in the deck Shuffle the deck Deal the cards
1. Load headers
1.1 Define struct
1.2 Function prototypes
1.3 Initialize deck[] and face[]
1.4 Initialize suit[]
1 /* Fig. 10.3: fig10_03.c2 The card shuffling and dealing program using structures */3 #include <stdio.h>4 #include <stdlib.h>5 #include <time.h>67 struct card { 8 const char *face;9 const char *suit;10 };1112 typedef struct card Card;1314 void fillDeck( Card * const, const char *[], 15 const char *[] );16 void shuffle( Card * const );17 void deal( const Card * const );1819 int main()20 { 21 Card deck[ 52 ];22 const char *face[] = { "Ace", "Deuce", "Three", 23 "Four", "Five",24 "Six", "Seven", "Eight", 25 "Nine", "Ten",26 "Jack", "Queen", "King"};27 const char *suit[] = { "Hearts", "Diamonds", 28 "Clubs", "Spades"};2930 srand( time( NULL ) );
2. Randomize
2. fillDeck
2.1 shuffle
2.2 deal
3. Function definitions
3132 fillDeck( deck, face, suit );33 shuffle( deck );34 deal( deck );35 return 0;36 }3738 void fillDeck( Card * const wDeck, const char * wFace[], 39 const char * wSuit[] )40 { 41 int i;4243 for ( i = 0; i <= 51; i++ ) { 44 wDeck[ i ].face = wFace[ i % 13 ];45 wDeck[ i ].suit = wSuit[ i / 13 ];46 }47 }4849 void shuffle( Card * const wDeck )50 { 51 int i, j;52 Card temp;5354 for ( i = 0; i <= 51; i++ ) { 55 j = rand() % 52;56 temp = wDeck[ i ];57 wDeck[ i ] = wDeck[ j ];58 wDeck[ j ] = temp;59 }60 }
Put all 52 cards in the deck. face and suit determined by remainder (modulus).
Select random number between 0 and 51. Swap element i with that element.
3. Function definitions
6162 void deal( const Card * const wDeck )63 { 64 int i;6566 for ( i = 0; i <= 51; i++ )67 printf( "%5s of %-8s%c", wDeck[ i ].face, 68 wDeck[ i ].suit,69 ( i + 1 ) % 2 ? '\t' : '\n' );70 }
Cycle through array and print out data.
Program OutputEight of Diamonds Ace of HeartsEight of Clubs Five of SpadesSeven of Hearts Deuce of Diamonds Ace of Clubs Ten of DiamondsDeuce of Spades Six of DiamondsSeven of Spades Deuce of Clubs Jack of Clubs Ten of Spades King of Hearts Jack of DiamondsThree of Hearts Three of DiamondsThree 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 SpadesQueen of Diamonds Five of Diamonds Ace of Spades Nine of Hearts King of Clubs Five of Hearts King of Spades Four of DiamondsQueen of Hearts Eight of Hearts Four of Spades Jack of Hearts Four of Clubs Queen of Clubs
65
C structures: aggregate, yet scalar aggregate in that they hold multiple data items at one time 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
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)
66
Structure declarations Combined variable and type declarationstruct tag {member-list} variable-list; Any one of the three portions can be omitted
struct {int a, b; char *p;} x, y; /* 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 */
67
Structure declarationsstruct S {int a, b; char *p;}; /* omit variables */ No variables are declared, but there is now a
type struct S that can be referred to later
struct S z; /* omit members */ Given an earlier declaration of struct S, this
declares a variable of that type
typedef struct {int a, b; char *p;} S; /* omit both tag and variables */
This creates a simple type name S(more convenient than struct S)
68
Recursively defined structures 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;}
69
Recursively defined structures 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]; struct PET pets[PET_LIMIT];} sam = {″Sam″, {fido}};
We can’t initialize the owner member at this point,
since it hasn’t been declared yet
70
Direct access operator s.m subscript and dot operators have same precedence and
associate left-to-right, so we don’t need parentheses for sam.pets[0].species
Indirect access s->m: equivalent to (*s).m Dereference a pointer to a structure, then return a
member of that structure Dot operator has higher precedence than indirection
operator , so parentheses are needed in (*s).m(*fido.owner).name or fido.owner->name
Member access
. evaluated first: access owner member* evaluated next: dereference pointer to HUMAN
. and -> have equal precedence and associate left-to-right
71
struct COST { int amount; char currency_type[2]; }struct PART { char id[2]; struct COST cost; int num_avail; }layout of struct PART:
Here, the system uses 4-byte alignment of integers,so amount and num_avail must be alignedFour bytes wasted for each structure!
Memory layout
id amount num_avail
cost
currency_type
72
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;}
Memory layout
idamount num_avail
cost
currency_type
73
Structures as function arguments Structures are scalars, so they can be returned and passed as arguments – just like ints, chars
struct BIG changestruct(struct BIG s); 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); What if the struct argument is read-only?
Safe approach: use constvoid changestruct(struct BIG const *s);
74
Unions 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
Same as structunion Number { int x; float y;};Union myObject;
75
Unions Storage
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 Union may only be initialized to a value appropriate
for the type of its first member
76
Unions Like structures, but every member occupies
the same region of memory! 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 */
77
Unions 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 { enum TYPE type; union VALUE value;};
Access type to determine how to interpret value
78
Valid Union Operators Assignment to union of same type: = Taking address: & Accessing union members: . Accessing members using pointers: ->
1. Define union
1.1 Initialize variables
2. Set variables
3. Print
1 /* Fig. 10.5: fig10_05.c2 An example of a union */3 #include <stdio.h>45 union number { 6 int x;7 double y;8 };910 int main()11 { 12 union number value;13 14 value.x = 100;15 printf( "%s\n%s\n%s%d\n%s%f\n\n",16 "Put a value in the integer member",17 "and print both members.",18 "int: ", value.x, 19 "double:\n", value.y );20 21 value.y = 100.0;22 printf( "%s\n%s\n%s%d\n%s%f\n",23 "Put a value in the floating member",24 "and print both members.",25 "int: ", value.x, 26 "double:\n", value.y );27 return 0;28 }
Program Output
Put a value in the integer memberand print both members.int: 100double:-92559592117433136000000000000000000000000000000000000000000000.00000 Put a value in the floating memberand print both members.int: 0double:100.000000
81
Strings Arrays of characters End with a null byte ('\0') String literals implicitly provide
the null terminator:"hello" becomes: 'h' 'e' 'l' 'l' 'o' '\0'
82
Strings in C Definition:– A string is a character array ending
in '\0' — i.e., char s[256]; char t[] = "This is an initialized string!"; char *u = "This is another string!";
String constants are in double quotes May contain any characters Including \" and \' —
String constants may not span lines However, they may be concatenated — e.g., "Hello, " "World!\n" is the same as "Hello, World!\n"
83
Strings in C (continued) Let
char *u = "This is another string!"; Then
u[0] == 'T'u[1] == 'h'u[2] == 'i'…u[21] == 'g'u[22] == '!'u[23] == '\0'
84
Support for Strings in C Most string manipulation is done through functions
in <string.h>
String functions depend upon final '\0' So you don’t have to count the characters!
Examples:– int strlen(char *s) – returns length of string
Excluding final '\0' char* strcpy(char *s, char *ct) – Copies string ct to
string s, return s s must be big enough to hold contents of ct ct may be smaller than s
See K&R pp. 105-106 for various implementations
85
Support for Strings in C (continued) Examples (continued):– int strcmp(char *s, char *t)
lexically compares s and t, returns <0 if s < t, >0 ifs > t, zero if s and t are identical D&D §8.6, K&R p. 106
char* strcat(char *s, char *ct) 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 strchr(), strrchr(), strspn(), strcspn() strpbrk(), strstr(), strtok(), …
K&R pp. 249-250; D&D §8.6
86
Character Handling Library <ctype.h>
Prototype Description
int isdigit( int c ) Returns true if c is a digit and false otherwise.
int isalpha( int c ) Returns true if c is a letter and false otherwise. int isalnum( int c ) Returns true if c is a digit or a letter and false otherwise. int isxdigit( int c ) Returns true if c is a hexadecimal digit character and false otherwise. int islower( int c ) Returns true if c is a lowercase letter and false otherwise. int isupper( int c ) Returns true if c is an uppercase letter; false otherwise. int tolower( int c ) If c is an uppercase letter, tolower returns c as a lowercase letter. Otherwise, tolower
returns the argument unchanged. int toupper( int c ) If c is a lowercase letter, toupper returns c as an uppercase letter. Otherwise, toupper
returns the argument unchanged. int isspace( int c ) Returns true if c is a white-space character—newline ('\n'), space (' '), form feed
('\f'), carriage return ('\r'), horizontal tab ('\t'), or vertical tab ('\v')—and false otherwise
int iscntrl( int c ) Returns true if c is a control character and false otherwise. int ispunct( int c ) Returns true if c is a printing character other than a space, a digit, or a letter and false
otherwise. int isprint( int c ) Returns true value if c is a printing character including space (' ') and false
otherwise. int isgraph( int c ) Returns true if c is a printing character other than space (' ') and false otherwise.
87
String Conversion Functions in C 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)
88
Dilemma Question:–
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:– Use storage allocated in The Heap!
89
C-Style Multidimensional ArraysMost high level languages support arrays with more than one
dimension.
2D arrays are useful when data has to be arranged in tabular form.
Higher dimensional arrays appropriate when several characteristics associated with data.
Test 1 Test 2 Test 3 Test 4Student 1 99.0 93.5 89.0 91.0Student 2 66.0 68.0 84.5 82.0Student 3 88.5 78.5 70.0 65.0
: : : : :: : : : :
Student-n 100.0 99.5 100.0 99.0
For storage and processing, use a two-dimensional array.
Example: A table of test scores for several different students on
several different tests.
90
Declaring Two-Dimensional ArraysStandard form of declaration:element_type array_name[NUM_ROWS][NUM_COLUMNS];
Example:const int NUM_ROWS = 30,
NUM_COLUMNS = 4;
double scoresTable[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
...
[0][1][2][3]
[29]
[0] [[1] [2] [3]
91
Processing Two-Dimensional Arrays
Remember: Rows (and) columns are numbered from zero!!
Use doubly-indexed variables:scoresTable[2][3] is the entry in row 2 and column 3
row index column index
Use nested loops to vary the two indices, most often in a rowwise manner.
Counting from 0
92
Higher-Dimensional ArraysThe methods for 2D arrays extend in the obvious way to 3D 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 ThreeDimArray[SEMS][STUDENTS][TESTS];ThreeDimArray gradeBook;
gradeBook[4][2][3] is the score of 4th semester for student 2 on test 3
// number of semesters, students and tests all counted from zero!!
93
Arrays of Arrays
double scoresTable[30][4];
Declares scoresTable to be a one-dimensional array containing 30 elements, each of which is a one-dimensional array of 4 real numbers; that is, scoresTable is a one-dimensional array of rows , each of which has 4 real values. We could declare it as
typedef double RowOfTable[4];
RowOfTable scoresTable[30];
...
[0][1][2][3]
[29]
[0] [[1] [2] [3]
...
[0] [[1] [2] [3][0][1][2][3]
[29]
94
scoresTable[i] is the i-th row of the table
Address Translation:The array-of-arrays structure of multidimensional arrays explains address translation. Suppose the base address of scoresTable is 0x12348:
scoresTable[10] 0x12348 + 10*(sizeof RowOfTable)
In general, an n-dimensional array can be viewed (recursively) as a one-dimensional array whose elements are (n - 1)-dimensional arrays.
In any case:
scoresTable[i][j] should be thought of as (scoresTable[i])[j] that is, as finding the j-th element of scoresTable[i].
®
scoresTable[10][3] ® base(scoresTable[10]) + 3*(sizeof double)
scoresTable[10][4]
...
...[3]
[0] [1]
[9][10]
...
= 0x12348 + 10 * (4 * 8) + 3 * 8 = 0x124a0
= 0x12348 + 10 * (4 * 8)
95
Implementing multidimensional arraysMore complicated than one dimensional arrays.
Memory is organized as a sequence of memory locations, and is thus 1D
How to use a 1D structure to store a MD structure?A B C DE F G HI J K L
A character requires a single byte
Compiler instructed to reserve 12 consecutive bytes
Two ways to store consecutively i.e. rowwise and columnwise.
96
Implementing multidimensional arraysA B C DE F G HI J K L
RowWiseABCDEFGHIJKL
ColumnWiseAEIBFJCGKDHL
A B C DE F G HI J K L
A B C DE F G HI J K L
97
Summary Dynamic Memory Management with Pointers
malloc() calloc() free() realloc() new and delete operators
Structures Unions Strings Multidimensional Arrays