Test Your C Skills - Errata

Test Your C Skills is a very popular book in India written by Yashwant Kanetkar. It contains questions and answers (most of which are objective type) to test the reader’s C skills. This is one of the books that almost every engineering student in India reads while preparing for interviews and selection tests in companies. That is because many companies in India pick up questions from this book to test candidate’s skills in their selection process.

Unfortunately, this book contains loads of non-standard, and misinformation about the C langauge. It deals with codes that are specific to 16bit Turbo C compiler (which is out-dated and broken). More than 40 % of the book deals with non-standard code. Many of the code snippets in book invoke undefined behavior, but the author goes on to give his own explanations to those codes. This instills students with bad and non-portable coding practices.

Contacting the author and publisher hasn’t helped so far.  They don’t seem to bother as long as their book sells.

This page is intended to make the readers aware of the errors in this nasty book. The following are just a few of the errors out of the book. There are at least 10 times more errors than what I am listing here.

In all the code snippets given in the book:

  1. The standard headers are included using double quotes ("stdio.h"), which should only be used for user-defined headers. For standard headers, < and > delimiters should be used.

 

  1. The last output statement is not ended with a ‘\n’, thus there is no guarantee that complete output is displayed after execution.

 

  1. There is no mention of return type for main function, relying on the default int type. Though it is acceptable for older standards of C, its not valid with the current C standard (C99), which requires functions to have explicit return type to be mentioned. And there is no return statement given in the main function.

 

Questions & answers from the book:

 

Q1.0

What would be the output of the following program?

main()

{

char far *s1,*s2;

printf("%d %d",sizeof(s1),sizeof(s2));

}

 

His answer:

4 2

 

Erratum:

1. size of pointer type can vary from implementation to implementation.

2. far is not a standard keyword/type qualifier.

3. sizeof doesn't return integer, it returns a value of type size_t.  So using %d will cause undefined behaviour. [This mistake repeats in all the code snippets in the book where sizeof value is printed].

 

 

Q1.28

What do you mean by scope of a variable? What are the 4 different types of scopes that a variable can have?

 

His answer:

Scope indicates the region over which the variable's declaration has an effect. The four kinds of scopes are: file, function, block and prototype.

 

Erratum:

There are only three relevant scopes for variables: file, block, and prototype scope. There is no function scope for variables.

 

Q6.3

What would be the output of the following program?

 

#define SQR(x) ( x * x )

main()

{

int a, b=3;

a= SQR( b+2 );

printf("%d", a);

}

 

His answer:

11

Because, on preprocessing the expression becomes a= (3 +2 * 2+ 3)

 

Erratum:

On preprocessing, it becomes: (b + 2 * b + 2), not (3 +2 * 2+ 3).  Preprocessor will not replace with value of object, but just makes text replacements.  And the expression he gives (3 +2 * 2+ 3) would yield the value 10, not 11.

 

Q7.7

What would be the output of the following program assuming that the array begins at location 1002?

 

main()

{

int a[3][4]={

1,2,3,4,

5,6,7,8,

9,10,11,12};

printf("\n%u%u%u",a[0]+1,*(a[0]+1),*(a[0]+1),*(*(a+0)+1));

}

 

Erratum:

This code gives undefined output as %u is not the format specifier for pointer, %p is the only format specifier that can be used for pointers (portably).

[This mistake repeats in all codes snippets in the book where pointer value is printed].

 

Q8.16

Can two different huge pointers contain two different addresses but refer the same location in memory?

 

Erratum:

huge is not a standard C qualifier. Moreover, it was only used in 16 bit compilers, which are obsolete these days. The "Section 8-More about pointers" is filled with questions and discussions on far and huge pointers, which are non-standard.

 

Q8.8

What would be the output of the following program?

 

#include "stdio.h"

main()

{

      printf("%d %d",sizeof(NULL),sizeof(""));

}

 

His answer:

2 1

 

Erratum:

Size of NULL is implementation specific. It may yield the size of any integer types or of pointer type.

 

Q11.11

What would be the output of the following program?

 

main()

{

      struct emp

{

      char *n;

      int age;

      };

struct emp e1 ={ “Dravid”, 23 };

struct emp e2= e1;

strupr(e2.n);

printf(“\n%s”,e1.n);

}

 

His Answer:

DRAVID

 

When a structure is assigned, passed, or returned, the copying is done monolithically. This means that the copies of any pointer fields will point to the same place as the original. In other words, anything pointed to is not copied. Hence, on changing the name through e2.n, it automatically el.n.

 

Erratum:

The function call strupr(e2.n); tries to modify the string literal “Dravid”, which may not be modifiable. If the implementation stores the string literals in read-only location, the behavior is undefined.

 

Q12.4

Point out the error, if any in the following program.

 

#include “stdio.h”

main()

{

      unsigned char;

      FILE *fp;

 

      fp=fopen(“trial”,”r”);

      while( (ch = getc(fp) ) != EOF )

            printf(“%c”,ch);

     

      fclose(fp);

}

 

His answer:

EOF has been defined as #define EOF –1 in the file “stdio.h” and an

unsigned char ranges from 0 to 255 hence when EOF is read from

the file it cannot be accommodated in ch. Solution is to declare ch as an int.

 

Erratum:

EOF need not always be defined with the value –1. EOF may be defined with any other negative integer value.

 

 

Q12.11

Point out the error in the following program.

 

#include"stdio.h"

main()

{

char ch;

int i;

scanf("%c",&i);

scanf("%d",&ch);

printf("%c%d",ch,i);

}

 

His answer:

You would not get a chance to supply a character for second scanf() statement. Solution is to precede the second scanf() with the following statement:

fflush(stdin);

This would flush out the enter hit for the previous scanf() to be flushed out from the input stream, i.e. keyboard.

 

Erratum:

1. fflush is meant for output and update streams. Using it for input stream causes undefined behaviour.

2. In the scanf statement,  %c is used for integer i, and %d for character ch, this may write more than one byte to the char variable ch, causing undefined behaviour.

 

Q17.11

How many bytes would be allocated by the following code?

 

#include “alloc.h”

#define MAXROW 3

#define MAXCOL 4

main()

{

      int (*p)[MAXCOL][MAXROW];

      p=(int(*)[MAXROW][MAXCOL]) malloc(sizeof (*p));

}

 

His answer:

14 bytes.

 

Erratum:

  1. The number of bytes allocated is dependent on size of int, which may vary from implementation to implementation. And it would allocate at-least 24 bytes as each int occupies at-least 2 bytes.
  2. The cast for malloc return value is unnecessarily as it returns a value of type void*. [This kind of cast repeats everywhere in the book where malloc statement is used.]

 

 

Q17.29

How much maximum memory can we allocate in a single call to malloc()?

 

His answer:

64 KB.

 

Erratum:

The amount of memory that could be allocated though malloc() in a single call is purely dependant on platform and implementation. His answer is applicable only for the 16Bit DOS environments where 64 KB was the limit.

 

Q20.9

How would you use the function memmove()?

 

His answer:

#include "mem.h"

#include "alloc.h"

main()

{

.../*Code showing different calls to memmove*/

}

 

Erratum:

Both the headers mem.h and alloc.h are not part of C standard.

memmove function is available in the standard header <string.h>.