Folder101   Home Notes Quiz Assigns Info  
Forum Forum
101 Home 101
 
  C++ Level 2

Working with Strings and Characters

Introduction

String & Character Functions

strlen()

strncpy()

tolower() atoi()

strcpy()

strcmp()

toupper() atof()

Validating User Input

ASCII Code

Character & String Input

Numerical Input

Combined Input

Extension Work


  Introduction

As described in the Arrays tutorial, a string is simply a character array, ending with a null character. You have seen how to declare and initialize strings. Now you need to learn how to work with strings - finding the length of a string, copying one string, comparing strings and converting strings to numbers.

Knowing the basics of string manipulation will enable you to create simple validation routines, allowing you to check user input for appropriateness and enabling you to increase the robustness of your code.


   String & Character Functions

There are many functions that enable you to manipulate strings. The C standard library has a varied set of pre-defined string and character handling functions and C++ inherits most of these. Among the many functions provided, here are some that are commonly used:-

  • strlen - returns the length of a string
  • strcpy - for copying one string into another
  • strcmp - for comparing one string into another
  • tolower - returns the equivalent of a character in lowercase
  • toupper - returns the equivalent of a character in uppercase
  • atoi - If the string contains an integer value, this integer value is returned
  • atof - If the string contains an floating point value, this value is returned as a double

      strlen

The strlen() function returns the length of a null terminated string. The null character is not counted. The header file for strlen() is string.h.

Here is an example:-

cout << strlen("hello");

This should print out 5 to the standard output. Try it.

 
#include <iostream.h>
#include <string.h>
void main()
{
   cout <<
strlen("hello") << endl;
}

      strcpy  

The strcpy() function copies the contents of one string into another string. If the string being copied is larger than the string buffer it is being copied into, then strcpy() would write past the end of the string buffer, which would give undesirable consequences. The header file for strcpy() is string.h.

Here is an example:-

char strBuffer[80];
strcpy(strBuffer, "hello");

This should copy the string "hello" into the strbuffer character array. Try it.

 
#include <iostream.h>
#include <string.h>
void main()
{
   char strBuffer[80];
   strcpy(strBuffer, "hello");
   cout <<
strBuffer << endl;
}

What do you think would happen if the code were changed to this?

char strBuffer[2];

      strncpy  

The strncpy() function is similar to the strcpy() function. It also copies the contents of the second string into the first string. The difference is you have to specify a third parameter, the maximum number of characters to copy. This helps ensure you don't write past the end of the string buffer. Here is an example:-

int maxChars = 80;
char strBuffer[maxChars];
strncpy(strBuffer, "hello", maxChars);

Try it.

 
#include <iostream.h>
#include <string.h>
void main()
{
   const
int maxChars = 80;
   char strBuffer[maxChars];
   strncpy(strBuffer, "hello", maxChars);
   cout <<
strBuffer << endl;
}

What happens if you change the code to this?

strncpy(strBuffer, "hello", 0);

or

strncpy(strBuffer, "hello", 2);

      strcmp  

The strcmp() function compares two strings. It returns a 0 if the two strings are the same. If the strings are not the same, it returns a number greater or less than 0. The header file for strcmp() is string.h.

Here is an example:-

strcmp("Hello", "hello");

In this case, the return value would be non zero, indicating the strings are not equal.

Here is an example of a password verification routine:-

 
#include <iostream.h>
#include <string.h>
int password()
{
   
char s[80];
   
cout << "Enter your password" << endl;
   
cin >> s;
   if (strcmp(s, "opensesame")) {
      cout << "invalid password" << endl;
      return 0;
   }
   return 1;

}

Note: Don't forget to call the password routine from main() and include the prototype near the top of your code or in your own header file.

      tolower  

The tolower() function returns the lowercase equivalent of a character. If the character supplied to tolower() is a letter, then the equivalent is returned as lowercase. If the character is not a letter then it is returned unchanged. The header file for tolower() is ctype.h or stdlib.h.

Here is an example:-

tolower('A');

This should return the character 'a'; Try it.

 
#include <iostream.h>
#include <stdlib.h>
void main()
{
  cout << tolower('A') << endl;
}

In your earlier password verification routine, you may have noticed that the password is case sensitive. In other words, the user input had to match the password exactly - all lower case in the example given. If the user entered "Opensesame" instead of "opensesame" the routine declared it as an invalid password. You could change this routine so it was case insensitive by using the tolower function.

Try it. I don't think I need to give you any code for this - too easy.

       toupper  

The toupper() function returns the uppercase equivalent of a character. If the character supplied to toupper() is a letter, then the equivalent is returned as uppercase. If the character is not a letter then it is returned unchanged. The header file for toupper() is ctype.h or stdlib.h.

Here is an example:-

toupper('a');

This should return the character 'A'; Try it.

 
#include <iostream.h>
#include <stdlib.h>
void main()
{
  cout << toupper('a') << endl;
}

     atoi  

The atoi() function returns the integer equivalent of a value held in a string. If the string supplied to atoi() contains an integer value, then that value is returned. If the string does not contain an integer value then the return value is either undefined or in some implementations, a zero is returned. The header file for atoi() is stdlib.h.

Here is an example:-

atoi("1234");

This should return the integer 1234. Try it.

 
#include <iostream.h>
#include <stdlib.h>
void main()
{
  cout << atoi("1234") << endl;
}

Why would you need to convert a string value to a number value? When the user enters a number, you are in fact getting that input as a character or string and not a number. You may want to carry out some mathematics on that data. Here is an example:-

 

#include <iostream.h>
#include <stdlib.h>

void sum()
{
  char num1[80];
  char num2[80];
  int sum;
  cout <<
"Enter a number" << endl;
  cin >>
num1;
  cout <<
"Enter another number" << endl;
  cin >>
num2;
  sum = atoi(num1) + atoi(num2);
  cout << "The sum of the numbers is " << sum << endl;
}

Note: Don't forget to call the sum routine from main() and include the prototype near the top of your code or in your own header file.

     atof  

The atof() function returns the floating point equivalent of a value held in a string. If the string supplied to atof() contains a floating point value, then that value is returned. If the string does not contain a floating point value then the return value is either undefined or in some implementations, a zero is returned. The header file for atof() is stdlib.h.

Here is an example:-

atof("1.234");

This should return the integer 1.234. Try it.

 
#include <iostream.h>
#include <stdlib.h>
void main()
{
  cout << atof("1.234") << endl;
}

You have now learned some basic string and character functions. The next task is to apply this knowledge to validating user input.


 Validating User Input

Consider all the programs you have written so far. They nearly all require user input. In all the examples given so far, it is assumed the user will input the appropriate data types when asked to do so. The sum() routine that you created earlier expected the user to enter two different numbers. I expect your program works just fine if the user enters a number when you ask for one, but it behaves strangely or crashes if the user enters letters.

When writing a program, it is best to assume that a user will never use your program as expected. In other words, assume that whenever user input is required you may get inappropriate input. It is your job to validate input and make your programs robust and bullet-proof; able to handle whatever a user throws at it.

A bulletproof program is one that can handle anything that comes up at runtime, including bizarre user input.

Now, let's think about the types of user input you could you have.

When a user presses a key such as 'a' on the keyboard, they are inputting a character datatype. When a user presses something like a '1' on the keyboard, that '1' they are inputting is still a character datatype and not a numerical 1.

So, your program may...

  • expect a character or string input

  • expect a numerical input (really keyboard characters '0' ... '9')

  • expect a combined character and numerical input

In all cases, we are really getting character datatypes from the keyboard. So, before looking at each of these types of input, we are going to look at the ASCII character set, which is a way of representing keyboard characters.

      ASCII Code

Computers store characters as digital data. If a keyboard character is pressed, then a code representing the character is sent to the CPU. The set of character codes representing keyboard and other characters is called the 8-bit ASCII code.

There are 256 different codes representing 256 different characters in the ASCII set.

For example:-

  • the letter A is represented by the code 01000001, which in base 10 is 65

  • the letter B is represented by the code 01000010, which in base 10 is 66

More character codes are shown in the picture below.

You can look at the 7-bit set of character codes if you like.

Some useful codes to memorize are:-

  • digit '0' = 48
  • digit '9' = 57
  • 'A' = 65
  • 'Z' = 90
  • 'a' = 97
  • 'z' = 122

Note: digit '0' is 48, digit '1' is 49, etc. so you can figure the code for any other digit.

Also, 'A' is 65, 'B' is 66, etc. so you can figure out the code for any uppercase letter, too.

Finally, 'a' is 97, 'b' is 98, etc. so you can figure out the code for any lowercase letter, too.

The code below prints out the codes for the characters'A' to 'Z'

 

int codes()
{
   // output the ASCII values of A..Z
   for (int i = 'A'; i <= 'Z'; i++)
      cout << "The ASCII value of " << (char) i << " is " << i << endl;
}

or you could print out the whole of the ASCII set.

 

int printASCII()
{
   // output the ASCII set
   for (int i = 0; i <= 255; i++)
      cout << "The ASCII code " << i << " is the character " << (char) i << endl;
}

Now let's look more closely at the type of user input you program might require:-

  • character or string input

  • numerical input (really keyboard characters '0' ... '9')

  • combined character and numerical input

      Character or String Input

Suppose a program requires the user to enter a character or a string. In many cases, it may not matter exactly what the user enters - their name for example. Your program will not care in this case what combination of characters a user entered - it is their choice what name to enter.

However, suppose your program requires a particular character to be entered. Consider the code below. This routine asks the user if they want to repeat a test. It expects an input in the form of Y or y or N or n. The return value depends on the users choice. A Y or y returns a 0. A N or n returns a 1 and anything else returns a 2.

 

int validateYesNo()
{


   char YesNo[80];

   cout << "Would you like to repeat the test? Y/N" << endl;
   cin >> YesNo;

   //check for a Y
   if (toupper(YesNo[0]) == 'Y') return 0;

   //check for a N
   else if (toupper(YesNo[0]) == 'N') return 1;

   else return 2;

}

Note: Don't forget to call the validateYesNo() routine from main() and include the prototype near the top of your code or in your own header file. Also, include stdlib.h.

Try running the code. You can call this routine from main like so -

cout << validateYesNo();

Then you will see the return value for the function.

Now try changing the code:-

if (toupper(YesNo[0]) == 'Y')

to

if (toupper(YesNo[0]) == 89)

Run your program. What do you expect the return value to be?

You should get a return value of 0 if you enter a Y or a y. This is because the ASCII code for Y is 89.

Checking a character input through comparing with ASCII codes can be quite useful.

       Numerical Input

It is simple to test if a character entered by the user is a digit; you can use the isdigit() function. If the character supplied to isdigit() is a digit, the return value is nonzero. If the character is not a digit then zero will be returned. The header file for isdigit() is ctype.h.

isdigit(ch)… // ch is a char variable

For example:-

isdigit('1')

would return a nonzero. Whereas,

isdigit('a')

would return a zero.

Suppose you had to write a program that gets the users age. What types of input could there be? Numbers such as 5, 21, 100 are all valid, but input such as abc, 12z, would be invalid. Now, using cin() to get the input will return a string. However, you cannot use any of the string functions such as strcmp() to check the input because you don't know what to compare the input to.

One way of checking the string is to check each character in the string. This is what the code below does. It checks that each character in the string is a digit.

 

void getage()
{

   char ch[80];
   int valid = 0;

   cout << "Enter your age" << endl;
   cin >> ch;

   for (int i = 0; i < (int) strlen(ch); i++){

      if (isdigit(ch[i])) valid = 1;
      else valid = 0;
   }

   if (valid)
      cout << "Your said your age is " << ch << endl;
   else
      cout << "Invalid input " << endl;

}

Note: Don't forget to call the getage() routine from main() and include the prototype near the top of your code or in your own header file. Also, include ctype.h.

Suppose you had to write a program that gets a number between 0 and 9. Instead of using isdigit(), to check the input, you could check using ASCII code. This is what the code below does.

Notice that the code first checks the length of the user input. This is in case the user enters something like 5w. If I did not check the string length, then my program might accept 5w as valid because it would just compare the first character 5 with a digit.

 

void getSingleDigit()
{

   char ch[80];
   int valid = 0;

   cout << "Enter a number from 0 to 9" << endl;
   cin >> ch;

  //check to see if user entered a single character  
  If (strlen(ch) > 1) {
      cout << "Invalid input " << endl;
      return;
   }

     //check to see if user entered a digit  
      if (ch[0] >= 48 && ch[0] <= 57 ) valid = 1;
      else valid = 0;

   if (valid)
      cout << "Your entered " << ch << endl;
   else
      cout << "Invalid input " << endl;

}

Note: Don't forget to call the getSingleDigit routine from main() and include the prototype near the top of your code or in your own header file. Remember, the strlen() function requires the string.h header.

     Combined Character & numerical Input

It is simple to test if a character entered by the user is an alphanumeric character; i.e. a letter or digit. You can use the isalnum() function. If the character supplied to isalnum() is a letter or digit, the return value is nonzero. If the character is not a digit or letter, a zero will be returned. The header file for isalnum() is ctype.h.

isalnum(ch)… // ch is a char variable

For example:-

isalnum('b') or isalnum('1')

would return a nonzero. Whereas,

isalnum('$') or isalnum('+'')

would return a zero.

Suppose you had to write a program that gets the users postcode. What types of input could there be? Input such as sw3olp and se204yy are valid, but input such as *&9 would be invalid. Now, using cin() to get the input will return a string. However, you cannot use any of the string functions such as strcmp() because you don't know what to compare the input to.

One way of checking the string is to check each character in the string. This is what the code below does. It checks that each character in the string is an alphanumeric character.

 

void postcode()
{

   char ch[80];
   int valid = 0;

   cout << "Enter your postcode" << endl;
   cin >> ch;

   for (int i = 0; i < (int) strlen(ch); i++){

      if (isalnum(ch[i])) valid = 1;
      else valid = 0;
   }

   if (valid)
      cout << "Your said your postcode is " << ch << endl;
   else
      cout << "Invalid input " << endl;

}

Note: Don't forget to call the postcode() routine from main() and include the prototype near the top of your code or in your own header file. Also, include ctype.h.


 Extension Work

Carry out the following exercise:-

  1. Start step6 of the practice assignment 3

That it!
Now try the quiz questions