ENCM 339 Fall 2017 Tutorial for Week 8 for section T01 Steve Norman, PhD, PEng Electrical & Computer Engineering Schulich School of Engineering University of Calgary 2 November, 2017
ENCM 339 T01 Tutorial 2 Nov 2017 slide 2/12 Today s tutorial malloc and free. A C struct type for managing dynamically allocated strings. Note: Online copies of ENCM 339 Fall 2017 section T01 tutorials can be found by following links starting at people.ucalgary.ca/~norman
ENCM 339 T01 Tutorial 2 Nov 2017 slide 3/12 Exercise 1 For the program on the next slide... Draw a diagram for point (1). (To save time, let s leave out details of static storage.) Draw a diagram for point (2). (Again, let s leave out details of static storage.) Identify two unsafe and defective uses of the variable p. Describe the output of the program as precisely as possible. (Assume that the calls to malloc succeed.)
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(void) { char *p, *q; p = malloc(4); // (1) strcpy(p, "foo"); q = malloc(8); strcpy(q, p); free(p); q[3] = t ; q[4] = \0 ; // (2) printf("<%s><%s>\n", q, p); p[0] = x ; free(q); return 0;
ENCM 339 T01 Tutorial 2 Nov 2017 slide 5/12 A C type for dynamically allocated strings Using statically or automatically allocated arrays of chars to hold strings has many disadvantages. One disadvantage is that it s difficult to build up strings by concatenating strings together or by appending characters one at a time eventually, the array may be completely full, with no more room for more characters. The next slide shows a header file called dastring.h, with a type that could be used for dynamically allocated string objects.
ENCM 339 T01 Tutorial 2 Nov 2017 slide 6/12 struct d_a_s { int len; // length of C string int cap; // size of array char *arr; // pointer to element 0 ; typedef struct d_a_s dastring; We ll use these rules for dastring objects... Empty strings will have len == 0 and cap == 0, and arr will point to a statically allocated string of length 0. Non-empty strings will have arr point to element 0 of a dynamically-allocated array of size cap. The array will contain a null-terminated string of length len. (So, clearly, len < cap must be true.)
ENCM 339 T01 Tutorial 2 Nov 2017 slide 7/12 Exercise 2: Bad initialization Which of the initializations below comply with the rules for dastring objects and which ones don t? #include "dastring.h" int main(void) { dastring x = {0, 0, ""; dastring y = {4, 5, "quux"; dastring z; //... more code... return 0;
ENCM 339 T01 Tutorial 2 Nov 2017 slide 8/12 Exercise 3: Better initialization Function interface: void das_init(dastring *das, const char *s); // REQUIRES: das points to an unitialized object. // s points to the start of a C string. // PROMISES: *das has been initialized by copying // the C string. Example use: int main(void) { dastring x; das_init(&x, ""); dastring y; das_init(&y, "quux"); //... code that uses x and y... return 0; Let s write a definition for das_init.
ENCM 339 T01 Tutorial 2 Nov 2017 slide 9/12 Exercise 4: Appending characters one at a time Let s consider a function called push_back, which appends a single character to the string managed by a dastring object... int main(void) { dastring x; das_init(&x, ""); push_back(&x, a ); push_back(&x, b ); push_back(&x, c ); push_back(&x, d ); printf("%s\n", x.arr); return 0; The output should be... abcd
ENCM 339 T01 Tutorial 2 Nov 2017 slide 10/12 It s not efficient to copy all of a string from one array to another every time a character is appended. When a bigger array is needed, it makes sense to allocate more than enough space, so that some future push_back operations can succeed without having to allocate new memory and copy a lot of characters. This approach is taken in the code on the next slide. For the main function shown on the previous slide, let s make diagrams for each time point one in push_back is reached.
ENCM 339 T01 Tutorial 2 Nov 2017 slide 11/12 void push_back(dastring *das, int c) { if (das->len == 0) { das->len = 0; das->cap = 4; das->arr = malloc(4); else if (das->len + 1 == das->cap) { das->cap = 2 * das->cap; char *old = das->arr; das->arr = malloc(das->cap); strcpy(das->arr, old); free(old); das->arr[das->len] = c; das->len += 1; // point one das->arr[das->len] = \0 ;
ENCM 339 T01 Tutorial 2 Nov 2017 slide 12/12 Remark C lacks features needed to make a type like dastring convenient for programmers. Using dastring correctly is awkward, and using it incorrrectly in all sorts of ways is unfortunately quite easy. Class types in C++ have the kinds of features needed for programmers to create new types that are as convenient to use as built-in types. (These exercises were orginally designed mostly to give students practice with malloc and free, but also partly to provide an introduction to C++ class types. Section 01 of ENCM 339 in Fall 2017 won t cover C++ at all.)