Main

Blog (RSS)

Code listings from Mastering C Pointers

Most of the following code examples are taken from the second edition, but the formatting has been changed to match the first edition. The first edition has consistent code formatting whereas the second is a mess. However, the second edition makes an effort to use ANSI C and is more relatable. The first edition uses K&R style function declarations and rarely includes headers.

I tried out all these programs using Borland Turbo C 2.01 running on DOSBox.

#include <stdio.h>
void main(void)
{

     char *a;

     a = "ANGULAR";

     *a = 66;            /* writing to potentially const data */

     printf("%s\n", a);

}

In the first edition, this claims it will print BANGULAR. It’s changed to BNGULAR in the second edition. He writes to string constants in many programs in the book (which happens to work on MS-DOS).

#include <string.h>
#include <stdlib.h>
void main(void)
{

     char *a, b[256];

     gets(b);                  /* yikes */

     a = malloc(strlen(b));    /* wrong size */

     strcpy(a, b);

}

In the text after this example he claims that the strlen returns the number of characters “including the NULL” (sic). Uhm, no. (Later in the book he ends up changing his mind.)

#include <stdlib.h>
#include <stdio.h>
void main(void)
{

     int *x, y;

     if ((x = malloc(400)) == NULL) {      /* when sizeof() is a burden */
          printf("Out of memory\n");
          exit(0);
     }
     else
          for (y = 0; y <= 198; ++x)    /* ??? */
               *(x + y) = 88;

}

This program will end up writing 88 well past the end of the allocated space—and will probably die with a segmentation fault at some point. It’s also regularly how he uses malloc: with raw numbers of bytes.

The loop is a work of raw, unpracticed performance art. It assumes an int is two bytes and even if the index variable was used correctly, it wouldn’t initialize the last element.

When I tried this program it just kept going. After a while, I killed it.

#include <stdio.h>
int square(int i);
void main(void)
{

     int x, y;

     x = 8;
     y = 11;

     x = square(x);
     y = square(y);

     printf("%d  %d\n", x, y);

}
int square(int a)
{

     return(a * a);

}

In this example he calls the square function "useless". His next version is this.

int square(int a, int *b)
{

     *b = *b * *b;
     return(a * a);

}

And then this.

void square(int *a, int *b)
{

     *a *= *a;
     *b *= *b;

}

The reasoning behind this (d)evolution is ludicrous: “The example of a function returning a value, supposedly for assignment to another variable in the calling program, and changing the the value of another calling program variable is not especially unique, although it does not follow a typical function programming pattern.” (p. 100 in second edition). The final version is, supposedly, typical.

Basically, he’s trying to demonstrate how you “return” multiple values from a C function. But how is square at all a reasonable candidate? The first version was actually the best since you could abstract out any logic that deals with overflow.

(By the way, he considers getting rid of a function call an important optimization. Function calls waste time, don’t ya know.)

#include <stdio.h>
void newprint(char *, int);
void main(void)
{

     int x, y;

     x = 17;
     y = 134;

     newprint("%d  %d", x, y);   /* Wrong number of arguments */

}
newprint(char *str, int args)     /* Different signature */
{

     int *ptr;

     ptr = &args;

     printf("%s\n%d\n%d\n", str, *ptr, *(ptr + 1));     /* WTF */

}

I consider this the worst and most interesting program in the book because it demonstrates a complete lack of understanding—really, why the hell don’t you just look up the ellipsis (...) argument?—but it still stumbles its way to success. This version doesn’t compile. Obviously. It’s proof that the author didn’t make any effort to test what he wrote.

However, it will work with the code from the first edition, which follows.

main()
{

     int x, y;

     x = 17;

     y = 134;

     newprint("%d  %d", x, y);

}
newprint(str, args)
char *str;
int args;
{

     int *ptr;

     ptr = &args;

     printf("%s\n%d\n%d\n", str, *ptr, *(ptr + 1));

}

This compiled with Turbo C and printed all the arguments passed. GCC 7 with -std=c89 also compiled it (with warnings) but printed some random stuff (surprise!) for *(ptr + 1).

The only way you should be describing a program like this is to demonstrate some low-level implementation detail and warn that it’s really a bad idea. But that’s not what Traister does. He counsels that this is how C handles function calls.

union test {              /* code before includes */
      int x;              /* is really bad style */
      float y;
      double z;
};
#include <stdio.h>
#include <stdlib.h>
void main(void)
{

     union test *ptr;

     if ((ptr = malloc(sizeof(union test))) == NULL)
          exit(0);

     printf("%d\n", sizeof(union test));

     ptr->x = 19;                   /* These are all pointless */
     ptr->y = 131.334;              /* but are done in all */
     ptr->z = 9.9879;               /* examples with unions */

}

Not only is this bad style, but even for an example it’s just dumb.

#include <stdio.h>
#include <string.h>
void main(void)
{

     char a[20], *b, **c;

     strcpy(a, "Capacitor");

     b = a;
     c = b;                        /* Nope */

     printf("%s  %c\n", *c, **c);  /* No idea what will happen */

}

This code is the same in both editions. It adds fuel to the fire that he didn’t test anything because it’s obviously wrong. But this will compile in Turbo C without any warnings. (GCC 7 will compile it with warnings.) He claims it will print Capacitor and C. It almost certainly won’t.

(In the second edition copy I have, someone wrote in the book trying to follow the logic, such as it is.)

#include <stdio.h>
#include <string.h>
void main(void)
{

     char *b, c[10];
     int x, *a;

     strcpy(c, "Goodbye");

     b = "HELLO";
     a = &b;         /* Ugh */
     x = &c[0];      /* Because int == pointer, amirite? */
     *a = x;         /* High five! */

     printf("%s\n", b);
}

This prints Goodbye. It should print, I am a negligent textbook author.

June 25, 2018

Send comments to wozniak.ca with the local part being comment

Last modified 2018-06-25