8.3. Safe Additions to Strings

As mentioned in Dangers of Buffer overflows, adding textual data to a string is dangerous. It is not very difficult to work with strings safely, but it does require extra effort and needs topics that we covered toward the end of the course. In particular, dynamic memory allocation, data structures, and file input / output need to be used along with the functions from The string library.

A library of functions is helpful. There are actually several open source string libraries for C. This article compares some popular string processing libraries. Many of these libraries are quite large and go well beyond safely adding data to strings. So to keep things simple, I wrote a modest set of functions to avoid string buffer overflows and truncations. The code is in the textstring.h file, which can be added to your code with an include statement.

#include "textstring.h"

Declare a pointer to a data structure along with a starting string length as follows:

txtstr *str;

str = tstr_new(LINESIZE);

Then use functions defined below to store data to str in various ways. To avoid conflicts with your name space, all functions in the library begin with tstr_. To access the string to print it or any other char * string operations, use either:

char *ptr = tstr_str(str);
- or -
char *ptr = str->string;

The tstr_str function resets the string to the beginning, which impacts future string appending functions.

To avoid memory leaks when finished with a string, especially in a function other than main, use:

tstr_free(str);
tstr_new

Allocate an new txtstr with a given size:

txtstr *tstr_new(int);

str = tstr_new(200);
tstr_ReadLine

Same as String Example - ReadLine, except the lines go to a txtstr * data structure. Read a txtstr line from a file:

bool tstr_ReadLine(txtstr *, FILE *);

// str is a new line from the file on each loop iteration.
// End of file is reached when false is returned.
while( tstr_ReadLine(str, fileptr) )
tstr_sprintf

Safe sprintf() into a txtstr. New string starts at the beginning of the str->string. Formatting is the same as the standard printf and sprintf functions. Multiple data variables may be referenced:

int tstr_sprintf(txtstr *, const char *, ...);

tstr_sprintf(str, "V = %lf, and a string\n", V, str2);
tstr_strappend

Formatted append a char * string to an existing txtstr. Note, the format string may contain text, but only one string is added. Only tstr_sprintf has the formatting functionality of sprintf:

int tstr_strappend(txtstr *str, const char *fmt, char *s2);

tstr_strappend(str, "adding a string: %s\n", s2)
tstr_append

Formatted append txtstr to existing txtstr. This function is like tstr_strappend except the string to add is in a txtstr * data structure, not a char * string:

int tstr_append(txtstr *str1, const char *fmt, txtstr *str2);
tstr_cat

Safe strcat of txtstr``s. Contents of ``s2 is added to the end of s1:

void tstr_cat(txtstr *s1, txtstr *s2);
tstr_strcat

Safe strcat for a char * string:

void tstr_strcat(txtstr *str, char *s2);
tstr_cpy

Safe strcpy of txtstr. s2 is copied to s1:

void tstr_cpy(txtstr *s1, txtstr *s2);
tstr_strcpy::

Safe copy of char * string into a txtstr. The s2 string is copied to the s1 data structure:

void tstr_strcpy(txtstr *s, char *);
tstr_str::

Return string for printing or other use and reset so string is empty:

char *tstr_str(txtstr *str);

printf("%s\n", tstr_str(str));
tstr_reset::

Reset the txtstr so that the string is empty. Future appends go the beginning of the string:

void tstr_reset(txtstr *);
tstr_free

Free the memory held by a txtstr. It is important to remember this to avoid memory leaks:

void tstr_free(txtstr *str);

Here is the include file that may be downloaded. Testing and example code is also available for download.