String handling Comparison



Typical string handling code in C. (Followed by example of using libmib astrings.)

Code like this, although easy
and simple to write, is unsafe.

char buf[256];
char *pszExtraPath = ";/usr/local/bin";

strcpy(buf,getenv("PATH")); /* oops! could overrun! */
strcat(buf,pszExtraPath); /* Could overrun as well! */

printf("Checking...%s\n",buf); /* Some printfs overrun too! */

This safe code can cause truncation. It is a clumsy retrofit. Because of the strncpy vs strncat non-terminating behavior (always can't quite remember which does what), it is a bit messy as we calculate what space is left, and adjust to make sure we don't walk one character passed the end. This code is safe, but truncates to avoid buffer overrun.

char buf[256];
char *pszExtraPath = ";/usr/local/bin";

strncpy(buf,getenv("PATH"),sizeof(buf)-1); /* Could truncate */
buf[sizeof(buf)-1] = '\0';
if (strlen(buf) < sizeof(buf)-1) { /* Still have some room */
	strncat(buf,pszExtraPath,sizeof(buf)-strlen(buf)-1 ); /* Could truncate */
}

printf("Checking...%s\n",buf); /* Some printfs overrun too! */

Some feel the only "correct" way is to use dynamically allocated strings, which can look like the following verbose code. This code is safe, and correct.

char *psz;
char *pszExtraPath = ";/usr/local/bin";

/* Calculate all the space needed, so don't have to realloc. */
psz = malloc(strlen(getenv("PATH")+strlen(pszExtraPath)+1));
if (!psz) /* malloc error */ exit(-1);

/* We got all the space, so just do it. */
strcpy(psz,getenv("PATH"));
strcat(psz,pszExtraPath);

/* printf isn't safe either, we split up
	printf("Checking...%s\n",psz);
*/
printf("Checking...");fputs(psz,stdout);printf("\n");
free(psz);
Some code uses a structure or a C++ class to implement "smarter" strings, at the cost of a bit of extra storage overhead, and having to use a structure member to access the actual pointer. This code is safe. This example uses a qmail-type method.


char *pszExtraPath = ";/usr/local/bin";
typedef struct {
    char *s;
    int len;
} stralloc;
stralloc sa = {NULL}; /* Have to initialize the .s member to NULL */

if (!stralloc_copys(&sa,getenv("PATH"))) /* error */ exit(-1);
if (!stralloc_cats(&sa,pszExtraPath)) /* error */ exit(-1);
/* printf isn't safe either, we split up
    printf("Checking...%s\n",sa.s);
*/
printf("Checking...");fputs(sa.s,stdout);printf("\n");
free(sa.s);


Use the Mib Software astring functions and benefit from dynamically allocated strings with much simpler code. This code is safe, and often requires only slight modifications to existing sources.
   char *pasz = 0;      /* Must initialize to 0 */
	char *paszOut = 0;
	char *pszExtraPath = ";/usr/local/bin";

	if (!astrcpy(&pasz,getenv("PATH"))) /* malloc error */ exit(-1);
	if (!astrcat(&pasz,pszExtraPath)) /* malloc error */ exit(-1);
	
	/* Finally, a "limitless" printf! we can use */
	asprintf(&paszOut,"Checking...%s\n",pasz);fputs(paszOut,stdout);

	astrfree(&pasz); /* Can use free(pasz) also. */
	astrfree(&paszOut);

Although you still have to remember to free() to prevent memory leaks, there is no additional local variable overhead. The value is still used as a char *, and is compatible with most of the other string.h calls, (strlen, strchr, etc.) Along with "limitless" asprintf and afgets (included) it just got a lot easier to implement and retrofit "overrun-safe" character buffer code.

The astring license is intended to meet the "open source" definition 1.0, allowing commercial and non-commercial use free of charge.

More Detailed Topics
Example: an "fgrep-like" filter using astrings easily handles unlimited line lengths in a small amount of code.

Overview and Related Topics
Up to: Libmib Allocated String Functions
Up to: Libmib: Character String Processing
Up to: Libmib


This Libmib documentation may not be distributed. Copyright 1998, Forrest J. Cavalier III
Mib Software
High Reuse Software Development