TOC PREV NEXT

Solutions to sample quiz questions


Solutions to questions for "Fundamentals" quiz

  1. Suppose that an integer variable n contains the value 80. Fill in the blanks in the printf statement below so that it produces the output
		80% usually
		means "excellent"
printf statement:
		printf (" _____ ", n);
Solution: "%d%% usually\nmeans \"excellent\". The % must be quoted with another %, not a backslash.
  1. Consider the program segment
		int k;
		k = getchar ( );
		printf ("%d", k);
What gets printed if the user types a 2, then hits return?
Solution: Not a 2, but the decimal value of the ASCII character '2'.
  1. The following program is intended to compute 5! = 120, but it prints 24 instead. What's wrong with it?
	int main ( ) {
		int theNum, total;
		total = 1;
		theNum = 5;
		while (theNum > 1) {
			total *= --theNum;
		}
		printf ("%d", total);
		return 0;
	}
Solution: The decrement -- should follow theNum, not precede it.
  1. What would be the effect of substituting !(theNum = 1) for the while condition theNum > 1 in the main program of exercise 3?
Solution: The expression theNum = 1 is an assignment, not a comparison. Its value is the value assigned, namely 1. The value of ! 1 is false, since 1 is a true value. When a while loop's condition evaluates to false, the loop is exited; thus the loop is never executed, and the value 1 is printed.
  1. Fill in the blanks in the code below to convert the while loop in exercise 3 to an equivalent for loop.
	int main ( ) {
		int theNum, total;
		total = 1;
		for ( ____ ; _____ ; _____ ) {
			total *= theNum;
		}
		printf ("%d", total);
		return 0;
	}
Solution: for (theNum=5; theNum>1; --theNum) {
  1. Write down the values for all variables appearing in each statement.
		int main ( ) {
			int x, y, z;
			float a, b;
			x = 3;  y = 5.3;  z = 2;	x ____	y ____	z ____
			a = 2.5; b = 3.14;		a ____	b ____
	/*1*/		x += y + a * z-b;		x ____
	/*2*/		a = b / (x%y + z)		a ____
			z += (x == y);			z ____
	/*3*/ 		x == (a = b);			x ____
			return 0;
		}
Solution
		x = 3;  y = 5.3;  z = 2;	x=3  y=5  z=2
		a = 2.5; b = 3.14;		a=2.50  b=3.14
	/*1*/	x += y + a * z-b;		x=9
	/*2*/	a = b / (x%y + z)		a=0.523333
		z += (x == y);			z=2
	/*3*/	x == (a = b);			x=9
Where do you need parentheses to have x assigned a value of 14 in the statement labeled /*1*/? What then is the new value of a in the statement labeled /*2*/? What is the new value of x in the statement labeled /*3*/?
Solution: Parentheses should go around the y+a. There is no change to a in the statement labeled /*2*/, and x retains the value 14 in the statement labeled /*3*/.
  1. Predict the output of the following program. Hint: only three lines get printed. (This is somewhat more complicated than any of the actual quiz questions.)
	int main ( ) {
		char c;
		for (c='a'; c<'g'; ++c) {
			switch (c) {
				case 'a':	c += 2;
				case 'c':	c += 1;
				case 'g':	++c;
						printf ("%c\n" , c-- );
				default:	++c;
			}
			printf ("*** %c\n" , c);
		}
		return 0;
	}
Solution: The program prints the following:
	e
	*** e
	*** g 

Solutions to questions for the "Functions and argument pointers" quiz

  1. What is the output of the following program segment?
		c = 'a';
		putchar (c);
		putchar (F(c));
		putchar (c);
Assume that the function F has been defined as follows:
		char F (char c) {
			c = 'f';
			return (c);
		}
Solution: The three characters "afa" get printed. The variable c in the calling code is copied into the local variable c in F; the assignment to c in F thus does not affect anything in the calling code.
  1. Modify the code from exercise 1 so that, on return from the F function, the variable c in the calling code contains the character 'f'.
Solution: F's parameter must now be an address so that the change can affect a variable outside the function. Four changes are necessary:
	c = 'a';
	putchar (c);
	putchar (F(&c));	/* first change: insert ampersand */
	putchar (c);
		...
	char F (char *c) {	/* second change: insert asterisk */
		*c = 'f';	/* third change: insert asterisk */
		return (*c);	/* fourth change: insert asterisk */
	}
  1. Write a function AllDone that, given a string as argument, returns a true value if the string is "exit" and returns false otherwise.
Two solutions:
int AllDone (char s[]) {
	if (strcmp(s,"exit") == 0) {
		return 1;
	} else {
		return 0;
	}
}
int AllDone (char s[]) {
	return !(strcmp(s,"exit"));
}

  1. Write a function GetWordAndValue that prompts the user for a string and an integer and returns both to the calling program. Assume that the caller has already provided space in memory for all the characters of the word.
Solution
	void GetWordAndValue (char word[], int *value) {
		printf ("Type a word: ");
		scanf ("%s", word);
		printf ("Type an integer: ");
		scanf ("%d", value); /* note that value is already a pointer */
	}
  1. Write a main program that calls GetWordAndValue and echoes the values returned.
Solution
	#include <stdio.h>
	int main ( ) {
		char word[20];
		int k;
		GetWordAndValue (word, &k);
		printf ("word is '%s', k is %d\n", word, k);
		return 0;
	}

Solutions to questions for "Arrays, Structures, and Files" quiz

  1. Fill in the blanks in the program below so it prints the contents of the file whose name is provided by the user.
	#include <stdio.h>
	int main ( ) {
		char fileName[32];
		char c;
		FILE *inFile;
		printf ("File name? ");
		gets (fileName);
		__________________ ;
		if ( _____________ ) {
			fprintf (stderr, "File doesn't exist!\n");
			exit (1);
		};
		while ( _______________ ) {	/* get a char if not done */
			fprintf ( __________ );	/* print it */
		}
		return 0;
	}
Solution: The following code goes in the blanks:
	inFile = fopen (fileName, "r") ;
	if (inFile == NULL) {
		fprintf (stderr, "File doesn't exist!\n");
		exit (1);
	};
	while ((c=getc(inFile))!=EOF) {     /* done? */
		fprintf (stdout, "%c", c);       /* print it */
  1. Define a struct to represent dates. The struct members should be a string representing the month, an integer representing the date in the month, and another integer representing the year. Then define the type Date to be synonymous with the struct definition, and define an array dateList of five dates.
Solution
	struct date {
		char month[10];	/* September is the longest month name. */
		int dateInMonth;
		int year;
	};		/* Don't forget the semicolon! */
	
	typedef struct date Date;
	Date dateList[5];
  1. Fill in the blank in the code below so that it moves each element of the values array to the immediately subsequent position in the array. The loop should discard the last value in the array. Thus if the array contained the values 1, 2, 3, 4, and 5 before the loop, it should contain the values 1, 1, 2, 3, and 4 after the loop.
	int values[5];
		...
	for ( _____________________________ ) {
		values[k] = values[k-1];
	}
Solution: for (k=4; k>0; k--) { ... Recall that subscripts of a five-element array run from 0 to 4.
  1. Modify the definition of the values array in exercise 3 so that it also initializes the array to contain the values 1, 2, 3, 4, 5.
Solution: int values[5] = {1, 2, 3, 4, 5} or int values[ ] = {1, 2, 3, 4, 5}.
  1. Write a function HasZeroDiagonal that, given a 5-by-5 integer array, returns 1 if all the elements on the main array diagonal are zero and returns 0 otherwise.
Solution
	int HasZeroDiagonal (int a[][]) {
		int k, result;
		result = 1;
		for (k=0; k<5; k++) {
			result = result && (a[k][k] == 0);
		}
		return result;
	}

Solutions to questions for "General use of pointers" quiz

  1. (Exercise 5.3 in K&R) Rewrite the strcat function given below, which uses array indexing, to use pointers instead.
		void strcat (char s[], char t[]) {
			int i, j;
			i = j = 0;
			while (s[i] != '\0') {
				i++;
			}
			while ((s[i++] = t[j++]) != '\0') {
			}
		}
Solution:
	void strcat (char *s, char *t) {
		while (*s != '\0') {
			s++;
		}
		while ((*(s++) = *(t++)) != '\0') {
		}
	}

A more understandable way to code both versions would be to move the incrementing into the loop body:

	while ((s[i] = t[j]) != '\0') {
		i++;
		j++;
	}
	while ((*s = *t) != '\0') {
		s++;
		t++;
	}
  1. Consider the following function, intended to return a string typed by the user to the caller.
		char* WordInput ( ) {
			char word[20];
			printf ("Type a word: ");
			scanf ("%s", word);
			return word;
		}
What's wrong with the function? Does replacing its second line by
		char* word;
fix the problem?
Solution: The problem with the function is that the twenty characters of memory allocated for the word array, like the storage allocated for any local variable, is released when the WordInput function exits. The return word statement returns only the pointer, not the characters pointed to, and this pointer after exit from WordInput basically points into the phantom zone. Replacing the array definition by the definition of a pointer is even worse. It allocates space for the pointer, but no space at all for the characters of the string!
  1. What is the meaning of the following declaration?
		char* a, b;
Solution: The variable a is declared as a pointer to a char and the variable b is declared as a char. The asterisk doesn't "distribute" over the variables. It's for this reason that we generally use one declaration per variable.
  1. Which of the following would cause compile-time or run-time problems? Please explain. Also give the type of the right-hand side of each assignment statement, and draw a diagram for each legal assignment to the pointer variable px.
		float x, *px, a[5];
		x = *px;		/* 1 */
		*px = x;		/* 2 */
		px = &x;		/* 3 */
		&x = px;		/* 4 */
		&(x+1) = x;		/* 5 */
		&(x)+1 = x;		/* 6 */
		*(&(x+1)) = x;		/* 7 */
		*(&(x)+1) = x;		/* 8 */
		x = a;			/* 9 */
		x = a[0];		/* 10 */
		x = *(a[1]);		/* 11 */
		x = (*a)[2];		/* 12 */
		x = a[3+1];		/* 13 */
		x = a[3]+1;		/* 14 */
		x = &((a[3])+1);	/* 15 */
		x = &(a[3])+1;		/* 16 */
		x = *(&(a[3])+1);	/* 17 */
		px = a;			/* 18 */
		px = a[0];		/* 19 */
		px = &(a[4]);		/* 20 */
Solution: #4-7, #9, #11-12, #15-16, and #19 cause compile-time errors. #8 probably causes a run-time problem. Accessing through any pointer will cause a run-time problem if the corresponding storage has not been allocated.
	x = *px;	/* both floats */
	*px = x;	/* ditto */
	px = &x;	/* both pointers to floats */
	&x = px;	/* illegal; stores into a constant */
	&(x+1) = x;	/* illegal like #4 */
	&(x)+1 = x;	/* illegal like #4 */
	*(&(x+1)) = x;	/* &(x+1) is illegal */
	*(&(x)+1) = x;	/* stores into the variable after x! */
	x = a;		/* illegal; x is float, a is pointer to float */
	x = a[0];	/* both floats */
	x = *(a[1]);	/* illegal; a[1] is float, not pointer */
	x = (*a)[2];	/* illegal; (*a) is a[0] which is float */
	x = a[3+1];	/* both floats */
	x = a[3]+1;	/* both floats */
	x = &((a[3])+1);	/* illegal like #5 */
	x = &(a[3])+1;	/* illegal: rhs is the address of a[4] */
	x = *(&(a[3])+1);	/* same as x = a[4] */
	px = a;		/* both addresses of floats */
	px = a[0];	/* illegal; px is pointer to float, a[0] is float */
	px = &(a[4]);	/* both addresses of floats */
Diagrams for assignments to px:
#3


#18


#20


Solutions to questions for "Linked structures" quiz

  1. What's the difference between the use of "." and the use of "->" in referring to a field of a structure?
Solution: p->member is the same as (*p).member . p must therefore be declared as a pointer to a struct.
  1. Declare a type named ListPtrType that's a pointer to a struct, each instance of which contains an integer info member and a next member that's a pointer to an instance of the struct type.
Solution
	struct listNode {
		int info;
		struct listNode *next;
	};
	typedef struct listNode *ListPtrType;
  1. Write a function that returns a pointer to a newly-created node of the structure type you just declared. Use sizeof and calloc to allocate the space for the new node.
Solution
	ListPtrType newNodePtr ( ) {
		return ((ListPtrType) calloc (1, sizeof(struct listNode)));
	}
  1. Given the following declarations
    		struct tnode {
    			char *word;
    			struct tnode *left, *right;
    		};
    		typedef struct tnode TREENODE, *TREEPTR;
    		TREEPTR tree;
    		TREENODE node;
    
    indicate which of the following are legal expressions; for legal expressions, also indicate the type of the expression.
    1. node->word[2]
    2. node.word[2]
    3. tree->left->word
    4. *(tree->left)
    5. *tree->left
    6. tree->*left
Solution: (a) is illegal, since node is a structure variable, not a pointer to a structure. (b) is of type char, assuming that there are at least three characters in the word. (c) is a pointer to a char, assuming tree is non-null. (d) is a struct tnode if tree is non-null. (e) is the same as (d) since the precedence of " ->" is higher than that of "*". (f) is illegal.
  1. What does *p++ mean?
Solution: It's the same as *(p++). The value of the expression is whatever p points to. A side effect of the expression is that p is incremented (the expression value is whatever p pointed to before being incremented). This is idiomatic but obnoxiously concise C usage.
  1. Page 115 of K&R contains the following program to print the argument list.
		int main (int argc, char *argv[]) {
			while (--argc > 0) {
				printf ("%s%s", *++argv, (argc > 1) ? " " : "");
			}
			printf ("\n");
			return 0;
		}
Modify this program to print the arguments on separate lines, and to omit duplicate arguments from the argument list. If, for instance, the program is run with the command line
		a.out a b a c
the output should be

		a
		b
		c
Solution
	#include <strings.h>
	
	#define TRUE 1
	#define FALSE 0
	typedef int boolean;
	
	/* this program prints out all unique command line arguments */
	boolean not_dup (char *arg, char ** argv);
	int main (int argc, char **argv) {
		int i; char **arg;
		for (i = 1, arg = argv+1; i<argc; i++, arg++) {
			/* Loop through arguments */
			/* (ignore the first, which is a cmd, not an argument) */
			if (not_dup(*arg, argv)) {	/* print unique args */
				puts(*arg);
			}
		}
		return 0;
	}
	
	/* "Walk" down the list of arguments until arg matches the item */
	/* in argv. If the pointer to that item is the same as arg, then there  */
	/* aren't any duplicates before the item itself. */
	boolean not_dup(char *arg, char ** argv) {
		char **arg_item;
		for (arg_item = argv+1; *arg_item < arg ; arg_item++) {
			/* Check all items before arg */
			if (strcmp(*arg_item, arg) == 0) {		/* and compare */
				return(FALSE);	/* return false if match is found */
			}
		}
		return(TRUE);	/* If no dups found then this item must be unique */
	}

TOC PREV NEXT