Section 7 - CStrings Revealed

decorative pastry

3A.7.1  CStrings (REVIEW)

This section is a rather dry review of the functions that can be used to manipulate the primitive CStrings (i.e. arrays of chars). Some of you have had these functions and can skip this material. The reason we study CStrings is that they are very low-level objects and have very little overhead associated with them. This means that using CStrings to manipulate character data

  1. is very fast, and
  2. gives the programmer surgical control over memory

This is used in advanced real-time game and simulation programs in which speed and tight control are desirable.  For most programs we will continue to use s-c strings. This week I want to introduce the CStrings to give you some practice with this interesting and historical data type.

You already know that a CString is a more primitive kind of character string that is not a class, but a simple array of chars.

char name[80];

It is usually initialized like so (but, remember, this is not the same as a s-c string assignment.)

char name[] = "Cherries";

This places the eight letters of the word "Cherries" in locations name[0],...name[7], and a null in name[8].

As with any array, we can access an individual character of a CString anywhere in the program using brackets:

name[0] = 'H';
name[1] = 'i';
name[2] = '\0';  // must null-terminate if we use manual notation

And the shortcut function strcpy() can be used instead of above:

strcpy(name, "Hi");

However, you absolutely cannot do this with CStrings:

name = "Hi"; // error!

3A.7.2 Displaying CStrings

CStrings can be displayed just as easily as other data in C++:

int main()
{
  char greetings[100] = "Hello World!";  // '\0' put in
  // for us by compiler.
  cout << greetings << endl;
  return 0;
}

3A.7.3 Receiving and Displaying Strings

Here is an example which shows the recommended way to receive a line of text from the user into a CString:

#include <iostream>
#include <cstring>
using namespace std;

int main()
{
  char user[80];
  int n;

  cout << "Please enter your first name: ";
  cin.getline(user, sizeof(user)-1, '\n');

  n = strlen(user);
  cout << "\nHello " << user << ".  How does it feel to have"
  " a name that\nhas " << n << " letters in it?\n";

  cout << "\n(That's just a rhetorical question.)\n";
  return 0;
}

And the run:

Please enter your first name: Michael

Hello Michael.  How does it feel to have a name that
has 7 letters in it?

(That's just a rhetorical question.)
Press any key to continue . . .

3A.7.4 Useful CString Functions

The above example contained one of the many built-in C++ functions that operate on CStrings, namely strlen().  strlen() returns the length of the string (not including the null terminator). Here are some other CString functions.

COPYING CSTRINGS

strcpy() copies one string into another. (NOTE: You cannot use = to copy CStrings!).

char first[] = "Gunter", temp[40];

strcpy(temp, first);    // copies "Gunter" into temp
strcpy(first, "Grass"); // replaces "Gunter" with "Grass"

Strncpy(), takes a third argument - the maximum number of characters to move. This is safer than strcpy() which will merrily copy characters past the end of the destination array if the second string is longer than the first.  Use the sizeof() operator which tells us the size of the destination array, and subtract 1 to allow for the impending null terminator:

strncpy(dest,"Big Trouble in Hacker City", sizeof(dest)-1);
dest[ sizeof(dest)-1 ] = '\0';

COMPARING TWO CSTRINGS

Use the strcmp() function to compare two CStrings to see if they are equal:

if ( !strcmp( str1, str2) )
{
// do this if they are equal
}
else
{
// do this if they are NOT equal
}

This is not a typo: !strcmp() is true if they are equal, while strcmp() is true if they are not equal.

strcmp() is more useful than just testing for equality.  If the int result it returns is negative, then str1 comes before str2 in alphabetical ordering, and if the returned value is positive, str1 comes after str2.

LOOKING FOR SUBSTRINGS

If you want to find out if and where a (usually smaller) CString (or string literal) is inside a (usually larger) CString (or string literal) do this:

char *p;
p = strstr(larger, smaller);

Notice that p is a char pointer, and when the strstr() function returns, it will be pointing to the first occurrence of the CString smaller, inside the CString larger. If the CString smaller doesn't occur at all, then p will be NULL, or 0.

CONVERTING A CSTRING  TO A DOUBLE OR INT

The method you learned for s-c strings,  will also work for CStrings:

istringstream(stringNum1) >> num1;

You have to #include <sstream> to use istringstream.

Another method for converting CStrings to numbers is through use of the functions atof() for floats/doubles and atol() for ints/longs.  For example,

char stringNum[20] = "2.5";
double dblNum;

dblNum = atof(stringNum);

atof() and atol() do not require inclusion of <sstream>.

CONVERTING  A DOUBLE OR INT  TO A CSTRING

This is no great solution for this direction.  You must use a "deprecated" method called sprintf() as follows:

char stringNum[20];
double dblNum = -1.233;
long lngNum = 54234;

sprintf(stringNum, "%lf", dblNum);
cout << stringNum << endl;

sprintf(stringNum, "%ld", lngNum);
cout << stringNum << endl;

Note that you use the format conversions symbols %lf for double and %ld for long.  There are other format conversion symbols that you can look up for detailed control of conversion to CStrings.