|
|
The story behind the String component illustrates our pragmatic approach to C++ Standard Components. We based our decision to provide a String component on (1) the knowledge that almost every C program manipulates strings and (2) an AT&T Bell Laboratories internal study showing that string manipulation errors account for a large percentage of the programming errors made by their C programmers. Both assumptions are probably just as valid in your environment.
Consider the following true story from a real computer networking project. Assume machine contains a machine name, such as "nj/garage/edsel", service contains a service name, such as "authorize", and we want to assign to a third variable, dialstring, the result of concatenating machine and service with an intervening dot (the result would be "nj/garage/edsel.authorize" for the illustrative values). Here is the code for Release 1 of the system:
#include <string.h> char *machine, *service; char dialstring[32]; ... strcpy(dialstring, machine); strcat(dialstring, "."); strcat(dialstring, service);A user crashed Release 1 by using a dialstring longer than 32 characters. Release 2 contained the fix:
#include <string.h> char *machine, *service; char dialstring[100]; ... if (strlen(machine)+strlen(service)+1>100)error(); strcpy(dialstring, machine); strcat(dialstring, "."); strcat(dialstring, service);A user crashed Release 2 by using a dialstring longer than 100 characters (it's just as well - if it had been exactly 100 characters, it would have crashed anyway). In Release 3, they tried doing it dynamically:
#include <string.h> #include <malloc.h> char *machine, *service; char *dialstring; ... dialstring = malloc(strlen(machine)+strlen(service)+1); strcpy(dialstring, machine); strcat(dialstring, "."); strcat(dialstring, service);Release 3 crashed at random times in random places, apparently unrelated to this code. An extensive debugging effort finally uncovered the problem - the amount of memory allocated is short by one byte (for the null character). Here is Release 4:
#include <string.h> #include <malloc.h> char *machine, *service; char *dialstring; ... dialstring = malloc(strlen(machine)+strlen(service)+2); strcpy(dialstring, machine); strcat(dialstring, "."); strcat(dialstring, service);Release 4 worked fine in system test. In the field, though, it was run on a machine with a very small memory, and crashed when malloc() returned zero. Here's Release 5:
#include <string.h> #include <malloc.h> char *machine, *service; char *dialstring; ... dialstring = malloc(strlen(machine)+strlen(service)+2); if (dialstring == 0) error(); strcpy(dialstring, machine); strcat(dialstring, "."); strcat(dialstring, service);Release 5 no longer crashed. However, it gradually ate up all available memory after it had been running for long enough. Another debugging effort traced the problem to its source, and the fix was put in for Release 6:
#include <string.h> #include <malloc.h> char *machine, *service; char *dialstring; ... dialstring = malloc(strlen(machine)+strlen(service)+2); if (dialstring == 0) error(); strcpy(dialstring, machine); strcat(dialstring, "."); strcat(dialstring, service); ... free(dialstring);