Most expensive game to develop: GTA IV - $100,000,000

Oct 2, 2009

Arrays and Strings - Part 2/2

Previously we talked about arrays and the way it works. A few information back there and once you had understood, we'll be able to talk now about strings.

Strings

Strings are a sequence of characters (char). Useful to provide or store information in the user-program interaction, like saving the user's name or sending an error message. And in C++ we have two ways to deal with them. One is called C-style string way and the other is based on the string class library (new in C++). Let's talk about the old-fashioned way.

-> C-style string

String, as said before, is a sequence of chars. And how can we store a sequence? Yes, with arrays. But the string has one interesting feature. The last element of a string is the null character, symbolized as "\0" and it sets the end of a string. Also, it defines if the array is a string or not. You have to add this null character if you define a sequence of chars and want it to be a string. Otherwise, it'll be just a char array. But creating a string with double quotes (" ") already add the null character for you.

char myName[] = "kamikkaze"; // correct, string created!
char myName[] = {'k','a','m','i','k','k','a','z','e'.'\0'}; // correct, it's a string
char yourName[] = {'u','s','e','r'}; // also correct, but not a string

By not defining the array size, it leaves the compiler calculated it for you, it's good when you want create a constant string. This is the didatic part of strings. Now let's see how they work when we use them.

In C++ we have cin and cout for reading and printing data. Check the examples:

cout << "Helo Mars!"; // we're printing a string

char myName[] = "kamikkaze";
cout << myName;
  // here we're also printing a string. But why we don't use the brackets here? This is related how the array's name and the cin/cout objects work inside and I'll explain it later

char youName[20]; // we have to define the maximum array size - always counting the null character!
cout << "Type your name:" << endl;
cin >> youName;
cout << Your name is " << youName << endl;



Simple examples. At the last one, I defined the size of the array. This is because I didn't specified what elements it'll stored so the compiler couldn't save a space in the memory to allocate them. When doing it, we take the risk to waste memory if the entire array isn't fulfilled. The way to bypass such wasting is doing dynamic allocation but I'll not going further into this subject now.

Now, you may find an error when you type more than one word in the last example above. If you write your full name and you press ENTER just the first name you wrote will be stored at the array. Why did that happen? As you know, the last character of a string is the null character. But the cin command reads whitespaces - like SPACE and TAB, as it's a null character and the rest of the name you wrote is gonna wait in the input queue. So the next cin command will read the rest of the name, no matter what you asked the user to do. See the example :

#include < iostream >
#define size 50
#define hnum 10
using namespace std;

void main(){
    char myName[size];
    char height[hnum];
    cout << "Type your name: " << endl;
    cin >> myName;
    cout << "Now type your height: " << endl;
    cin >> height;
    cout << "Your name is " << myName << " and your height is " << height << endl;
}


Output:

Type your name:
kamikkaze theMighty
Now type your height:
Your name is kamikkaze and your height is theMighty



There are some ways to avoid this. In C++ we have the cin.get(array_name,array_size) and cin.getline(array_name,array_size) functions.

The cin.getline takes two parameters. One is the name of the array that will store the string; and the other is the size of that array. What getline do is read all the characters, including whitespaces and replace the ENTER (newline character) you had typed at the end with the null character. So, as it's name says, it gets the line you're typing at and store in the array.

The cin.get function takes the same parameters and do almost the same things as cin.getline. The catch here is that this function puts the newline character (ENTER) in the input queue. It means, the next input order will read the ENTER from the queue and messing with your program. A way to overcome it is to add a cin.get() after (each) cin.get you use, to discard the ENTER from the queue. A not so pretty solution, I agree.

Now two major problems you might find using these function:
1-> empty line --> This problem just happens with cin.get function. If it tries to read an empty line, a failbit situation occurs, blocking the input queue. This means, no more data will be read in your program. To solve this problem just use cin.clear() :)

2-> many characters, few space --> When the string is bigger then the array size, both function leave the remaining chars in the input queue, but getline() sets a failbit and block incoming input.

Also we have strings related functions, They are strcmp(), strlen() and strcpy():

strcmp(string1, string2) -> this function compares two strings. Returns an integer value: 0 if they are equal; >0 if the first char that doesn't match has a greater value in string1 than in string2; <0 if the first char that doesn't match has a lower value in string1 than in string2. Note: values are based in the ASCII table;

strlen(string_name) -> determines the lenght of a string. It doesn't count the null character;

strcpy(string_destination, string_source) -> copy the string_source into the string_destination;

Note: You may have to use #include < string.h > to use these function for strings.

-> String Class

The C++ provide us with this new class. Instead of creating an array, now, for making a string, we just have to use the string object. See the example:

#include < string > // make the class available

string myName = "kamikkaze"; // string initialized!

Now we use the string type. We don't have to specify the size for the string, the class do it for us and in addition, it also resize it if any changes is make. But the notation of array still exists. You can acess any position like myName[2] or myName[0].

With string as object, operations like concatenation and assignment turn out to be easy. Unlike the char array, string class allows us to do this:

string str1 = "Hello";
string str2;
str1 = str2; // YES, WE CAN do it


And joining two or more arrays couldn't be easier now:

string str1 = "Hello";
string str2 = "World";
string str3;
str3 = str1 + str2; // valid operation :)
str1 += str2; // also valid operation (str1 = str1 + str2)


Along the cin.strlen() and cin.getline() functions, the string class provides us the string_name.size() and getline(input,string_name):

string Name = "World";
int lenght = World.size();
// x = 5

string name;
cout << "Enter your name: ";
getline (cin,name);
// as the string class already set the necessary size our string, unlike the cin.getline() function, we just have to enter the input source and the name of the string.

The string class has more features and I don't intent to write the entire documentation here. My goal was to point the most visible facilities the usage of this method when working with strings but it's up to you decide what is good for your program.


Note 2: < string.h > is different from < string > ! The first is for strings operations used in C-style strings ; and the second is for the class string !!


That's it. A simple introduction of arrays and strings in C++. In games, both of these subjects are used with thousands of other functions in the middle of a endless code page. But I always find interesting and useful, as a programmer, to know how functions, variables, etc work in the memory, when I compile and so. It's a lovely world of abstraction when you deal with a little more complex thing like pointers and OOP...So much pain :)
...ok cya XD