You are on page 1of 19

Answers to Exercises

Chapter 1
Chapter 2
Chapter 3
Chapter 4
Chapter 5
Chapter 6
Chapter 7
Chapter 1
Exercise 1.2
#include <stdio.h>
#include <stdlib.h>

main(){
int this_number, divisor, not_prime;
int last_prime;

this_number = 3;
last_prime = 3;

printf("1, 3 is a prime pair\n");

while(this_number < 10000){


divisor = this_number / 2;
not_prime = 0;
while(divisor > 1){
if(this_number % divisor == 0){
not_prime = 1;
divisor = 0;
}
else
divisor = divisor-1;
}

if(not_prime == 0){
if(this_number == last_prime+2)
printf("%d, %d is a prime pair\n",
last_prime, this_number);
last_prime = this_number;
}
this_number = this_number + 1;
}
exit(EXIT_SUCCESS);
}

Exercise 1.3
#include <stdio.h>
#include <stdlib.h>

main(){
printf("Type in a string: ");
printf("The value was: %d\n", getnum());
exit(EXIT_SUCCESS);
}

getnum(){
int c, value;;

value = 0;
c = getchar();
while(c != '\n'){
value = 10*value + c - '0';
c = getchar();
}
return (value);
}

Exercise 1.4
#include <stdio.h>
#include <stdlib.h>

/* array size */
#define NUMBER 10

main(){
int arr[NUMBER], count, lo, hi;

count = 0;
while(count < NUMBER){
printf("Type in a string: ");
arr[count] = getnum();
count = count+1;
}
lo = 0;
while(lo < NUMBER-1){
hi = lo+1;
while(hi < NUMBER){
int tmp;
if(arr[lo] > arr[hi]){
tmp = arr[lo];
arr[lo] = arr[hi];
arr[hi] = tmp;
}
hi = hi + 1;
}
lo = lo + 1;
}
/* now print them */
count = 0;
while(count < NUMBER){
printf("%d\n", arr[count]);
count = count+1;
}
exit(EXIT_SUCCESS);
}

getnum(){
int c, value;;

value = 0;
c = getchar();
while(c != '\n'){
value = 10*value + c - '0';
c = getchar();
}
return (value);
}

Exercise 1.5
#include <stdio.h>
#include <stdlib.h>

/*
* To print an int in binary, hex, decimal,
* we build an array of characters and print it out
* in order.
* The values are found least significant digit first,
* and printed most significant digit first.
*/
#define NDIG 32 /* assume max no. of digits */

int getnum(void);

main(){
int val, i, count;
char chars[NDIG];

i = getnum();

/* print in binary */
val = i;
count = 0;
do{
chars[count] = val % 2;
val = val / 2;
count = count + 1;
}while(val);
count = count - 1; /* just incremented above */

while(count >= 0){


printf("%d", chars[count]);
count = count - 1;
}
printf("\n");

/* print in decimal */
val = i;
count = 0;
do{
chars[count] = val % 10;
val = val / 10;
count = count + 1;
}while(val);
count = count - 1; /* just incremented above */

while(count >= 0){


printf("%d", chars[count]);
count = count - 1;
}
printf("\n");
/* print in hex */
val = i;
count = 0;
do{
chars[count] = val % 16;
val = val / 16;
count = count + 1;
}while(val);
count = count - 1; /* just incremented above */

while(count >= 0){


if(chars[count] < 10)
printf("%d", chars[count]);
else{
/* assume 'A' - 'F' consecutive */
chars[count] = chars[count]-10+'A';
printf("%c", chars[count]);
}
count = count - 1;
}
printf("\n");
exit(EXIT_SUCCESS);
}

getnum(){
int c, value;;

value = 0;
c = getchar();
while(c != '\n'){
value = 10*value + c - '0';
c = getchar();
}
return (value);
}
Training | Contact
Skip to page content Skip to section menu Skip to site-wide navigation About Us |
Training | Consultancy | Software | Publications | Open Source | Support | Open Standards
| FAQ | Jobs
Site Style Info
Publications > The C Book > Answers > Chapter 2

Chapter 2
Exercise 2.1

Trigraphs are used when the input device used, or the host system's native character set,
do not support enough distinct characters for the full C language.

Exercise 2.2

Trigraphs would not be used in a system that has enough distinct characters to allocate a
separate one to each of the C language symbols. For maximum portability, one might see
a trigraph representation of a C program being distributed, on the grounds that most
systems which do not use ASCII will be able to read ASCII coded data and translate it
into their native codeset. A Standard C compiler could then compile such a program
directly.

Exercise 2.3

White space characters are not equivalent to each other inside strings and character
constants. Newline is special to the preprocessor.

Exercise 2.4

To continue a long line. Especially in systems that have an upper limit on physical line
length.

Exercise 2.5

They become joined.

Exercise 2.6

Because the */ which apparently terminates the inner comment actually terminates the
outer comment.
Exercise 2.7

31 characters for internal variables, six for external variables. The six character names
must not rely on distinction between upper and lower case, either.

Exercise 2.8

A declaration introduces a name and a type for something. It does not necessarily reserve
any storage.

Exercise 2.9

A definition is a declaration that also reserves storage.

Exercise 2.10

It is always the case that the largest range of values can be held in a long double, although
it may not actually be any different from one of the smaller floating point types.

Exercise 2.11

The same answer holds true for the type with the greatest precision: long double. C does
not permit the language implementor to use the same number of bits for, say, double and
long double, then to allocate more bits for precision in one type and more for range in the
other.

Exercise 2.12

There can never be problems assigning a shorter floating point type to a longer one.

Exercise 2.13

Assigning a longer floating type to a shorter one can result in overflow and undefined
behaviour.

Exercise 2.14

Undefined behaviour is completely unpredictable. Anything may happen. Often, nothing


seems to happen except that erroneous arithmetic values are produced.

Exercise 2.15
a. Signed int (by the integral promotions).
b. This cannot be predicted without knowing about the implementation. If an int
can hold all of the values of an unsigned char the result will be int, again by
the integral promotions. Otherwise, it will have to be unsigned int.
c. Unsigned int.
d. Long.
e. Unsigned long.
f. Long.
g. Float.
h. Float.
i. Long double.

Exercise 2.16
a. i1 % i2
b. i1 % (int)f1
c. If either operand is negative, the sign is implementation defined, otherwise it is
positive. This means that, even if both operands are negative, you can't predict the
sign.
d. Twounary negate, binary subtract.
e. i1 &= 0xf;
f. i1 |= 0xf;
g. i1 &= ~0xf;
h. i1 = ((i2 >> 4) & 0xf) | ((i2 & 0xf) << 4);
i. The result is unpredictable. You must never use the same variable more than once
in an expression if the expression changes its value.

Exercise 2.17
a. (c = (( u * f) + 2.6L);
b. (int = ((float) + long double);
c. (int = (long double));
d. (int);

Note: the integral promotion of char to int might be to unsigned int,


depending on the implementation.

e. (u += (((--f) / u) % 3));
f. (unsigned += ((float / unsigned) % int));
g. (unsigned += (float % int));
h. (unsigned += float);
i. (unsigned);
j. (i <<= (u * (- (++f))));
k. (int <<= (unsigned * (- float)));
l. (int <<= (unsigned * float));
m. (int <<= float);
n. (int);

The rules for the shift operators state the right-hand operand is always converted
to int. However, this does not affect the result, whose type is always determined
by the type of the left-hand operand. This is doubly so for the current example,
since an assignment operator is being used.

o. (u = (((i + 3) + 4) + 3.1));
The rules state that the subexpressions involving + can be arbitrarily regrouped, as
long as no type changes would be introduced. The types are:

(unsigned = (((int + int) + int) + double))

so the leftmost two additions can be regrouped. Working from the left:

(unsigned = ((int + int) + double));


(unsigned = (int + double));
(unsigned = double);
(unsigned);
p. (u = (((3.1 + i) + 3 ) + 4));

See the comments above on regrouping.

(unsigned = (((double + int) + int) + int));

The two rightmost additions can be regrouped.

(unsigned = ((double + int) + int));


(unsigned = (double + int));
(unsigned = double);
(unsigned);
q. (c = ((i << (- (--f))) & 0xf));
r. (char = ((int << (- (--float))) & int ));
s. (char = ((int << (- float)) & int ));
t. (char = ((int << float) & int));
u. (char = (int & int));
v. (char);
Chapter 3
Exercise 3.1

They all give an int result with a value of 1 for true and 0 for false.

Exercise 3.2

They all give an int result with a value of 1 for true and 0 for false.

Exercise 3.3

They guarantee an order of evaluation: left to right, and stop as soon as the overall result
can be determined.

Exercise 3.4

Break can be used to turn a switch statement into a set of exclusive choices of action.

Exercise 3.5

Continue has no special meaning in a switch statement, but only to an outer do, while
or for statement.

Exercise 3.6

Inside a while statement, the use of continue may cause the update of the loop control
variable to be missed. It is, of course, the responsibility of the programmer to get this
right.

Exercise 3.7

Because the scope of a label doesn't extend outside the function that it lives in, you can't
use goto to jump from one function to another. Using the longjmp library routine,
described in Chapter 9, a form of function-to-function jump is supported, but not a
completely general one.
Exercise 4.1
#include <stdio.h>
#include <stdlib.h>

main(){
int i, abs_val(int);;

for(i = -10; i <= 10; i++)


printf("abs of %d is %d\n", i, abs_val(i));
exit(EXIT_SUCCESS);
}

int
abs_val(int x){

if(x < 0)
return(-x);
return(x);
}

Exercise 4.2

There are two files that form the answer to this exercise. This is the first.

#include <stdio.h>
#include <stdlib.h>

int curr_line(void), curr_col(void);


void output(char);

main(){
printf("line %d\n", curr_line());
printf("column %d\n", curr_col());

output('a');
printf("column %d\n", curr_col());

output('\n');
printf("line %d\n", curr_line());
printf("column %d\n", curr_col());
exit(EXIT_SUCCESS);
}

The second file contains the functions and static variables.

#include <stdio.h>

int curr_line(void), curr_col(void);


void output(char);

static int lineno=1, colno=1;

int
curr_line(void){
return(lineno);
}

int
curr_col(void){
return(colno);
}

void
output(char a){
putchar(a);
colno++;
if(a == '\n'){
colno = 1;
lineno++;
}
}

Exercise 4.3

The recursive function:

#include <stdio.h>
#include <stdlib.h>

void recur(void);

main(){
recur();
exit(EXIT_SUCCESS);
}

void
recur(void){
static ntimes;

ntimes++;
if(ntimes < 100)
recur();
printf("%d\n", ntimes);
ntimes--;
}

Exercise 4.4

And finally, the largest of all of the answers.

#include <stdio.h>
#include <stdlib.h>

#define PI 3.141592
#define INCREMENT (PI/20)
#define DELTA .0001
double sine(double), cosine(double);
static unsigned int fact(unsigned int n);
static double pow(double x, unsigned int n);

main(){
double arg = 0;

for(arg = 0; arg <= PI; arg += INCREMENT){


printf("value %f\tsine %f\tcosine %f\n", arg, sine(arg),
cosine(arg));
}
exit(EXIT_SUCCESS);
}

static unsigned int


fact(unsigned int n){
unsigned int answer;

answer = 1;
while(n > 1)
answer *= n--;

return(answer);
}

static double
pow(double x, unsigned int n){
double answer;

answer = 1;
while(n){
answer *= x;
n--;
}
return(answer);
}

double
sine(double x){
double difference, thisval, lastval;
unsigned int term;
int sign;

sign = -1;
term = 3;

thisval = x;
do{
lastval = thisval;
thisval = lastval + pow(x, term)/fact(term) * sign;
term += 2;
sign = -sign;
difference = thisval - lastval;
if(difference < 0)
difference = -difference;
}while(difference > DELTA && term < 16);
return(thisval);
}

double
cosine(double x){
double difference, thisval, lastval;
unsigned int term;
int sign;

sign = -1;
term = 2;

thisval = 1;
do{
lastval = thisval;
thisval = lastval + pow(x, term)/fact(term) * sign;
term += 2;
sign = -sign;
difference = thisval - lastval;
if(difference < 0)
difference = -difference;
}while(difference > DELTA && term < 16);

return(thisval);
}
Chapter 5
Exercise 5.1

0-9.

Exercise 5.2

Nothing. It is guaranteed to be a valid address and can be used to check a pointer against
the end of the array.

Exercise 5.3

Only when they point into the same array, or to the same object.

Exercise 5.4

It can safely be used to hold the value of a pointer to any sort of object.

Exercise 5.5
a. int
b. st_eq(const char *s1, const char * s2){
c.
d. while(*s1 && *s2 && (*s1 == *s2)){
e. s1++; s2++;
f. }
g.
h. return(*s1-*s2);
i. }
j. const char *
k. find_c(char c, const char *cp){
l.
m. while(*cp && *cp != c)
n. cp++;
o. if(*cp)
p. return(cp);
q.
r. return(0);
s. }
t. const char *
u. sub_st(const char *target, const char *sample){
v.
w. /*
x. * Try for a substring starting with
y. * each character in sample.
z. */
aa. while(*sample){
bb. const char *targ_p, *sample_p;
cc.
dd. targ_p = target;
ee. sample_p = sample;
ff. /* string compare */
gg. while(*targ_p && *sample_p && (*targ_p == *sample_p)){
hh. targ_p++; sample_p++;
ii. }
jj. /*
kk. * If at end of target, have substring!
ll. */
mm. if(*targ_p == 0)
nn. return(sample);
oo. /* otherwise try next place */
pp. sample++;
qq. }
rr. return(0); /* no match */
ss. }

Exercise 5.6

No answer can be given.


Chapter 6
Exercise 6.1
struct {
int a,b;
};

Exercise 6.2

Without a tag or any variables defined, the structure declaration is of little use. It cannot
be referred to later.

Exercise 6.3
struct int_struc{
int a,b;
}x,y;

Exercise 6.4
struct int_struc z;

Exercise 6.5
p = &z;
p->a = 0;

Exercise 6.6

Explicitly, for example

struct x;

or implicitly,

struct x *p;

when no outer declaration exists.

Exercise 6.7

It is not treated as a pointer, but as a short-hand way of initializing the individual array
elements.

Exercise 6.8

Nothing unusual at all, the string is treated as a literal constant of type const char *.
Exercise 6.9

Yes. It is easier!
Training | Contact
Skip to page content Skip to section menu Skip to site-wide navigation About Us |
Training | Consultancy | Software | Publications | Open Source | Support | Open Standards
| FAQ | Jobs
Site Style Info
Publications > The C Book > Answers > Chapter 7

Chapter 7
Exercise 7.1
#define MAXLEN 100

Exercise 7.2

In expressions, there may be precedence problems. A safer definition would be


#define VALUE (100+MAXLEN).

Exercise 7.3
#define REM(a,b) ((a)%(b))

Exercise 7.4
#define REM(a,b) ((long)(a)%(long)(b))

Exercise 7.5

It generally signifies a library header file.

Exercise 7.6

It generally signifies a private header file.

Exercise 7.7

By using the conditional compilation directives. Examples are shown in the text.

Exercise 7.8

It uses long int in place of int and unsigned long int, in place of unsigned int using the
arithmetic environment provided by the translator, not the target. It must provide at least
the ranges described in <limits.h>.

You might also like