C Structures Dynamic Memory Management Goals of this




























- Slides: 28

C Structures & Dynamic Memory Management

Goals of this Lecture • Help you learn about: • Structures and unions • Dynamic memory management • Note: • Will be covered in precepts as well • We look at them in more detail 2

Structure Variables • Structure: a collection of related data items • Difference from array • Elements of a structure (its members) could have different types. • To select a particular member, we specify its name, not its position. • Structures are often called records, and members are known as fields. 3

Declaring Structure Variables • A declaration of two structure variables struct { int number; char name[NAME_LEN+1]; int on_hand; } part 1, part 2; • Memory layout of structure members • Members are stored in the order of declaration • Assumptions: • • part 1 is located at address 2000. Integers occupy four bytes. NAME_LEN has the value 25. There are no gaps between the members. 4

Initializing Structure Variables • A structure declaration may include an initializer: struct { int number; char name[NAME_LEN+1]; int on_hand; } part 1 = {528, "Disk drive", 10}, part 2 = {914, "Printer cable", 5}; Appearance of part 1 after initialization: 5

Initializing Structure Variables • Similar rules to those for array initializers • An initializer can have fewer members • Any “leftover” members are initialized as 0 • Designated initializers (C 99) • The initializer for part 1 was {528, "Disk drive", 10} • In a designated initializer, each value would be labeled {. number = 528, . name = "Disk drive", . on_hand = 10} • Not all values need be labeled {. number = 528, "Disk drive", . on_hand = 10} • Any members that the initializer fails to account for are set to zero 6

Accessing Structure Members • ‘. ’ operator: accesses ‘member’ of structure ‘name’ . name member • Examples printf("Part number: %dn", part 1. number); printf("Part name: %sn", part 1. name); printf("Quantity on hand: %dn", part 1. on_hand); • Members of a structure are lvalues part 1. number = 258; /* changes part 1's part number */ part 1. on_hand++; /* increments part 1's quantity on hand */ • ‘. ’ takes precedence over all other operators scanf("%d", &part 1. on_hand); 7

Assignment on Structures • Assignment copies all members from part 1 to part 2: part 2 = part 1; which is the same as part 2. number = part 1. number; memcpy(part 2. name, NAME_LEN+1); part 2. onhand = part 1. onhand; • Note array member in structure assignment • An array can’t be copied in assignment in general (compile error) • But, an array embedded in a structure is copied in assignment • Programmers often use a dummy structure to exploit it struct { int a[10]; } a 1, a 2; a 1 = a 2; /* legal, since a 1 and a 2 are structures a 1. a[i] = a 2. a[i]; (0 <= i <= 9) */ 8

Notes On Structure Assignment • Structures in assignment must be of compatible types. • Structures declared at the same time (as part 1 and part 2 were) are compatible. • Structures declared using the same “structure tag” or the same type name are also compatible. • Will learn “structure tag” and typedef shortly • Except assignment, no other operations on entire structures are allowed. • == and != operators can’t be used with structures. • No big worry: such operators will produce compile errors. 9

Structure Types • Needs several structure variables that have the same members? • Ways to name a structure: • Declare a “structure tag” • Use typedef to define a type name • Structure tag: a name to identify a structure. struct part { int number; char name[NAME_LEN+1]; int on_hand; }; semicolon is necessary struct part 1, part 2, *p; p = &part 1; /* ptr init */ (*p). number or p->number part 1, part 2; /* WRONG */ “struct” is necessary 10

Declaring a Structure Tag • Tag can be combined with declaration struct part { int number; char name[NAME_LEN+1]; int on_hand; } part 1, part 2; • Structures with the same tag are compatible struct part 1 = {528, "Disk drive", 10}; struct part 2; part 2 = part 1; /* legal; both parts have the same type */ 11

Defining a Structure Type • typedef: alternative to a structure tag • Can define a new type • Not limited to structure type definition • A definition of a type named Part: typedef struct { int number; char name[NAME_LEN+1]; int on_hand; } Part; • Part can be used in the same way as built-in types: Part part 1, part 2; typedef struct tag. List{ char *key; int value; struct tag. List* next; } List; Structure tag is required to reference itself in a structure 12

Nested Arrays and Structures • Structures and arrays can be combined without restriction. struct person_name { char first[FIRST_NAME_LEN+1]; char middle_initial; char last[LAST_NAME_LEN+1]; }; struct student { struct person_name; int id, age; char sex; } student 1, student 2; Structure can have a structure member Can access a nested structure member strcpy(student 1. name. first, "Fred"); Array of structures struct student st[100]; st[83. age = 19; st[83]. name. first[0] = ‘ ’; 13

Initializing an Array of Structures struct dialing_code { char *country; int code; }; const struct dialing_code country_codes[] = {{"Argentina", 54}, {"Bangladesh", 880}, {"Brazil", 55}, {"Burma (Myanmar)", 95}, {"China", 86}, {"Colombia", 57}, {"Congo, Dem. Rep. of", 243}, {"Egypt", 20}, {"Ethiopia", 251}, {"France", 33}, {"Germany", 49}, {"India", 91}, {"Italy", 39}, {"Japan", 81}, {"Mexico", 52}, {"Nigeria", 234}, {"Pakistan", 92}, {"Philippines", 63}, {"South Africa", 27}, {"South Korea", 82}, {"Spain", 34}, {"Sudan", 249}, {"Thailand", 66}, {"Turkey", 90}, {"Ukraine", 380}, {"United Kingdom", 44}, {"United States", 1}, {"Vietnam", 84}}; • Often useful to define a constant table • Note that inner braces are optional 14

Union • Identical to a structure except that • the compiler allocates only enough space for the largest of the members, which is shared by other members • Assigning a new value to one member alters the values of the other members as well. struct { int i; double d; } s; union { int i; double d; } u; • s’s members take up different memory space • u’s members share the same memory space 15

Unions • Member access is identical to that of structures u. i = 82; u. d = 74. 8; • Changing one member changes other members • Initialization requires a value for the first member • Or you can use a designated initializer union { int i; double d; } u = {0}; union { int i; double d; } u = {. d = 10. 0}; • Why you need unions? • Saving space (e. g. , only one member is used at any time) • Mixed data structure (e. g. , array of elements where each element can either be int or double) 16

Dynamic Memory Management

Dynamic Storage Allocation • C’s built-in data types are in fixed size • Even arrays and structures are in fixed size at program start • A program often needs to allocate memory dynamically • The ability to allocate storage during program execution • e. g. , storage needs may scale to input size • C’s dynamic memory allocation functions malloc—Allocates a block of memory but doesn’t initialize it. calloc—Allocates a block of memory and clears it. realloc—Resizes a previously allocated block of memory. • #include <stdlib. h> • These functions return a value of type void * (a “generic” pointer). • If a memory allocation function can’t locate a memory block of the requested size, it returns a null pointer. (NULL or 0) 18

Null Pointers p = malloc(10000); if (p == NULL) { /* allocation failed; take appropriate action */ } • NULL is a macro defined in various library headers • #define NULL ((void *)0) • Represents the null pointer • Often combine the call of malloc with the NULL test: if ((p = malloc(10000)) == NULL) { /* allocation failed; take appropriate action */ } 19

Using malloc to Allocate Memory void *malloc(size_t size); • Prototype for the malloc • Allocates a block of size bytes and returns a pointer to it. • size_t is an unsigned integer typedefined in the library. p = (char *)malloc(n + 1); • Allocates a string of n characters • p is char * variable • +1 for the null character strcpy(p, “abc”); • The first four chars in array • ‘a’, ‘b’, ‘c’, ‘ ’ 20

Using malloc to Allocate Storage for an Array int *a; a = malloc(n * sizeof(int)); • Allocates an array of n integers • n is determined at program execution • sizeof operator is often used to calculate the size of int for (i = 0; i < n; i++) a[i] = 0; • Once allocated, a can be used like an array • Thanks to the relationship between pointers and arrays • Of course, you can use pointer arithmetic instead of subscripting. 21

The calloc Function void *calloc(size_t nmemb, size_t size); • Prototype for calloc: • Allocates an array with nmemb elements where each element is size bytes long (nmemb x size bytes). • Returns a null pointer if the space isn’t available • Initializes allocated memory by setting all bits to 0 a = calloc(n, sizeof(int)); struct point { int x, y; } *p; p = calloc(1, sizeof(struct point)); • Allocates n-integer array • Allocates an item of any type with first argument=1 22

The realloc Function void *realloc(void *ptr, size_t size); • Prototype for realloc: • Resize a dynamically allocated array • ptr must point to a memory block obtained by a previous call of malloc, calloc, or realloc. • size represents the new size of the block, which may be larger or smaller than the original size. • Properties of realloc: • When memory expanding, realloc doesn’t initialize the newly -added bytes • When realloc returns NULL, the old block is unchanged • If ptr == NULL, it behaves like malloc. • If size == 0, it frees the memory block. 23

The realloc Function • We expect realloc to be reasonably efficient: • When reducing the size, realloc should shrink the block “in place. ” • realloc always attempts to expand a block without moving it. • realloc could move the memory block • If it can’t enlarge ptr in place, it allocates a new block elsewhere, then copy the contents of the old block into it. • In that case, the return pointer != ptr • Make sure to update all pointers to the memory block in case it has been moved by realloc 24

Danger in Dynamic Memory Allocation • Obtain dynamic memory blocks from a storage pool known as the heap. • Calling alloc functions too often, or asking for large blocks of memory can exhaust the heap, causing them to return NULL. • What’s worse, a program may allocate blocks of memory and then lose track of them, thereby wasting space. • Example p = malloc(…); q = malloc(…); p = q; The first block can’t be used nor freed “garbage” 25

Deallocating Storage • Garbage: a block of memory that’s no longer accessible • A program that leaves garbage behind has a memory leak. • Some languages provide a garbage collector • Java automatically locates and recycles garbage, but C doesn’t. • Why? C is efficiency-oriented (garbage collection is slow) • Each C program should recycle its own garbages • By calling the free function to release unneeded memory void free(void *ptr); • Prototype for free: • free will be passed a pointer to an unneeded memory block p = malloc(…); q = malloc(…); free(p); p = q; 26

The “Dangling Pointer” Problem char *p = malloc(4); . . . free(p); . . . strcpy(p, "abc"); /*** WRONG ***/ • Illegal to access p after freeing p • free(p) deallocates p’s memory but does not change p itself • A pointer that is no longer allocated is called a dangling pointer. • Modifying the memory that p points to is a serious error. • Hard to keep track of dangling pointers • Several pointers may point to the same block of memory. • When the block is freed, all the pointers are left dangling. 27

Summary • Structures and Unions • Allows heterogeneous data items (cf. arrays) • Structure tag or typedef can be used for specifying the same struct variables • Dynamic memory management • Allocates variable-sized space on run-time • De-allocation is the programmer’s responsibility: be careful about dangling pointers 28