CSCI 1730 Midterm Test Answers Summer 2009 1 : 1 2 3 4 5 2 (a) : /* The stringlength() function returns the number of characters in s. */ int stringlength(char *s) { if (s == NULL) return 0; int i = 0; while ( s[i] != '\0' ) i++; return i; } 2 (b) : The stringlength( ) function should not alter the input string, so this modification will help by enabling the compiler to fail and issue an error message if the function's code accidently attempts to change the input string. in the calling function. This makes no difference in implementing the function. The modification has no disadvantages. 2 (c) : This modification has no effect on the calling function, as the value of s is passed by value, so can't be modified by stringlength( ) in any case. For the implementation the difference is trivial; the implementation code can't redirect its local copy of s to point at some other string, something which would be poor coding practice anyway. There really are no significant advantages or disadvantages to this second modification, but in practice it wouldn't be employed because it is useless and could only cause confusion to someone who is maintaining the code. 3 : A typedef creates an alias for an exisiting type, so it doesn't create a new type. It can be useful in clarifying code, as in the typedef for a signal handling function which makes the protype for signal( ) understandable. It also allows the creation of types such as pid_t, which aid in writing portable systems code because only the typedefs in a header need be changed when the type itself needs to be updated due to longer word lengths and the like on newer computing platforms. 4(a) : the DIR structure containing information on the current working directory. 4(b) : a directory entry (dirent structure) for some file in the current working directory. 4(c) : writes to STDOUT the file names of all files (of any sort) in the current working directory. 5(a) : only if an error causes the call to fail, in which case -1 is returned. 5(b) : it replaces the code, data, stack, and heap of the calling process completely so as to execute "cmnd" from its starting point in main( ). 5(c) : it serves to terminate the argument list for "cmnd", which in this case is empty (no arguments). 6(a) : defines a signal handler fo use with (c); it wakes the process up from the pause( ) by returning, but does nothing else. 6(b) : sets an alarm, which will raise SIGALRM after nsecs seconds. 6(c) : pauses the process until a signal is received. Since the handler from (a) was installed before (b) to handle SIGALRM, if that's the next signal received then the process will resume when the handler returns (instead of terminating, which is the default disposition of SIGALRM.) 6(d) : turns off the alarm timer and returns the number of unused seconds on the alarm (in case the timer is tripped early by some other signal.) 6(e) : The code is that of Fig. 10.7 of the UNIX text; its deficiencies are discussed on pages 314--315. Briefly, those are A, B, and C below. A. It erases any existing alarm; it should save and restore any unused seconds on an existing alarm. B. It may alter the disposition of SIGALRM; it should save and restore that disposition. C. There is a race condition between (b) and (c), since the alarm could go off before pause( ) is reached, causing the process to hang indefinitely. This is hard to fix completely. One can use setjmp and longjmp, but this creates other possible problems with signal handling. The only complete solution is to implement the sleep function using the POSIX reliable signal functions. 7(a) : checks to see if process is child, in which case (b)--(e) will be executed. 7(b) : closes unused write end of pipe. 7(c) : keeps executing as long as there is a character in the pipe to be read. 7(d) : writes one character from the read buffer to standard output. 7(e) : closes the read end of the pipe. 7(f) : if process is not child, it is parent, and (g)--(j) will be executed. 7(g) : closes unused read end of pipe. 7(h) : writes command line string to pipe. 7(i) : closes the write end of the pipe. 7(j) : waits for child to terminate. 7(k) : we see the following; Mystery program! > Note there is no prompt until after a.out has terminated, since it is running in the foreground. The characters 'Mystery program!' are taken by the shell to be a single string consisting of all the characters between the ' marks, with ! not given its special shell meaning due to those ' marks. That string is written to the pipe by the parent in a single command, then read by the child from the pipe and written to standard output one character at a time. When the parent closes the write end of the pipe, the pipe returns 0 to the child, so then a line return is written to the screen (where standard output appears by default). The prompt thus appears on the next line after the parent terminates.