In C++ we can specify a string in 2 different ways. One is the old style with the string considered as an array of characters and the other as an object of type "string" that is a class defined in the STL library.
We can only store numbers inside a computer. To store characters we use a mapping . For the English language we can use the ACII mapping.
This mapping uses 1 byte to map numbers to characters. Sometimes a language like Chinese or Japanese needs more than 1 byte and in that case other mappings such as Unicode may need to be used. A character is enclosed in single digit such as 'a' and 'B' .
We have many functions for testing characters in C++ . One such function is "isupper":
Ex:
#include <iostream>#include <iomanip>using namespace std ;int main(){ char ch1 = 'a' ; char ch2 = 'A' ; //0 if false and non zero if true cout << isupper( ch1 ) << endl ; cout << isupper( ch2 ) << endl ; return 0;}
[amittal@hills strings]$ ./a.out
0
1
We can write the code for the function "isupper" ourselves .
Ex:
#include <iostream>#include <iomanip>using namespace std ;int isupper( char ch){ if( ch >= 'A' && ch <= 'Z') return 1 ; else return 0 ;}int main(){ char ch1 = 'a' ; char ch2 = 'A' ; //0 if false and non zero if true cout << isupper( ch1 ) << endl ; cout << isupper( ch2 ) << endl ; return 0;}
We wrote the function "isupper" by comparing the characters to 'A' and 'Z'. Since a character is a number we can use the Ascii chart to check if the character is uppercase.
We also have other functions such as:
isalpha Returns true (a nonzero number) if the argument is a letter of the alphabet.
Returns 0 if the argument is not a letter.
isalnum Returns true (a nonzero number) if the argument is a letter of the alphabet
or a digit. Otherwise it returns 0.
isdigit Returns true (a nonzero number) if the argument is a digit from 0 through 9.
Otherwise it returns 0.
islower Returns true (a nonzero number) if the argument is a lowercase letter.
Otherwise, it returns 0.
isprint Returns true (a nonzero number) if the argument is a printable character
(including a space). Returns 0 otherwise.
ispunct Returns true (a nonzero number) if the argument is a printable character
other than a digit, letter, or space. Returns 0 otherwise.
isupper Returns true (a nonzero number) if the argument is an uppercase letter.
Otherwise, it returns 0.
isspace Returns true (a nonzero number) if the argument is a whitespace character.
Whitespace characters are any of the following:
toupper Returns the uppercase equivalent of its argument.
tolower Returns the lowercase equivalent of its argument.
Exercise:
1) Complete the code in the function "isDigit" below
#include <iostream>#include <iomanip>using namespace std ;int isDigit( char ch){ //TO DO }int main(){ cout << isDigit( 'a' ) << endl ; cout << isDigit( '2' ) << endl ; return 0;}
Output:
$ g++ ex1.cpp ; ./a.exe
0
1
Ex:
#include <iostream>#include <iomanip>using namespace std ;int isupper( char ch){ if( ch >= 'A' && ch <= 'Z') return 1 ; else return 0 ;}char toupper( char ch ){ if( ch >= 'a' && ch <= 'z' ) { return ( ch - 'a' + 'A' ) ; } else return ch ;}int main(){ char ch1 = 'a' ; char ch2 = 'A' ; //0 if false and non zero if true cout << isupper( ch1 ) << endl ; cout << isupper( ch2 ) << endl ; return 0;
}
Exercise 10.5 from the book on page 554.
Write a loop that asks the user "Do you want to repeat the program or
quit? (R/Q)" . The loop should repeat until the user has entered an R or Q
(either uppercase or lowercase).
#include <iostream>using namespace std ;int main(){ char goAgain = ' ' ; while (toupper(goAgain) != 'R' && toupper(goAgain) != 'Q') { cout << "Do you want to repeat the program or quit? (R/Q)" ; cin >> goAgain ; } return 0;}
A C style string is an array of characters terminated by the null character as opposed to the C++ class style string that is a type and not part of a base type in C++ . The C++ string class is a class that was written after the C++ language came out and is part of the STL library. Why does the C style string need the null terminator ? Remember in C++ there is no way to get the size of an array from an array variable. We need the null terminator so that the string functions and also our own functions know when the string has ended.
A string literal is a constant string such as:
"Ccsf college is located on a hill."
String literals are stored as C style strings.
The C++ stream objects "cin" and "cout" work with both C++ and C style strings .
Ex:
#include <iostream>using namespace std ;int main(){ const int SIZE = 80; // Array size char line[SIZE]; // To hold a line of input int count = 0; // Loop counter variable cout << "Enter a city." ; cin >> line ; cout << "The city you entered is:" << line << endl ; return 0;}
Output:
[amittal@hills strings]$ ./a.out
Enter a city.Dublin
The city you entered is:Dublin
Example:
#include <iostream>using namespace std ;int main(){ const int SIZE = 80; // Array size char line[SIZE]; // To hold a line of input string line1 ; //Both C style and C++ style strings work with cin and cout cout << "Enter a city." ; cin >> line ; cout << "The city you entered is:" << line1 << endl ; cout << "Enter a city." ; cin >> line1 ; cout << "The city you entered is:" << line1 << endl ; return 0;}
C-style strings are worth learning for the following reasons:
1) When C++ first came out the "string" class had not come out at that time. Lot of the legacy C++ code might use the old C-style strings .
2) C++ library functions that only work with C-style strings.
3) Libraries still written in C such as TCP/IP calls.
There are many functions for working with C-style strings. One such function is "strlen" . The signature of "strlen" function is:
size_t strlen(const char *str)
What can be passed to the argument of "strlen" function. The below code shows how the "strlen" function can be used. The "const char *str" means the function cannot modify the contents of the string ( what the pointer points to ) . We can
assign a "char* ptr" to the "const char *str" ;
char* ptr ;
const char* str = ptr ;
The reverse cannot be done without an explicit cast. What we are stating is the "str" can be converted to a "ptr" because that will allow us to modify the values of what "str" points to .
const char* str ;
char* ptr = str ;
Using strlen:
Example:
#include <iostream>#include <cstring>using namespace std ;int main(){ char string1[] = "GeeksforGeeks" ; char* ptrStr = string1 ; cout << strlen( string1 ) << endl ; cout << strlen("GeeksforGeeks" ) << endl ; cout << strlen( ptrStr ) << endl ;}
The above code shows how "strlen" can be applied to an array, a pointer or a string literal. We can implement the function "strlen" ourselves also. We have to know when the string ends by looking for the null terminator.
#include <iostream>#include <cstring>using namespace std ;int strlen1( char* str ){ char* start = str ; while ( *(str++) ) ; return (str - start-1 ) ;}int strlen2(const char* str ){ int len = 0 ; while ( *str != 0 ) { len++ ; str++ ; } //while return (len ) ;}int main(){ char string1[] = "InClass"; cout << strlen1( string1 ) << endl ; cout << strlen2( string1 ) << endl ;}
The function "strlen1" uses the strange notation:
while ( *(str++) )
This is making use of the C++ language condition that if something is 0 then it is false. While allowed by the language this is not a good programming style. Code should be clear and easily readable. The second function "strlen2" is superior in terms of style and readability.
Using the "sizeof" call is not safe when calculating the length of the array that is holding the string. The function "sizeof" usually gives us the size of a type such as :
int x1 ;
sizeof( x1 ) ;
The above will give us 4 ( usually ) because the size of an integer is normally 4 bytes.
Ex:
#include <iostream>#include <cstring>using namespace std ;void function1( char param1[] ){ cout << sizeof( param1) << endl ;}//-------------------------------------------------int main(){ char array1[35] = { 'a' , 'f' , 'r' } ; cout << sizeof( array1 ) << endl ; function1( array1 ) ;}
//-------------------------------------------------
Output:
[amittal@hills strings]$ ./a.out
35
8
We see that in the first "sizeof" the compiler was able to determine the size of the array properly but it had help. The declaration of the array is in the same function and the compiler is able to see that. However if we pass the array name to a function and run the "sizeof" on the array variable we get a different result of 8 . The reason we get 8 is because that is the size of the pointer variable. If the function only has the array variable then there is no way for it to obtain the length of the array. It could obtain the length of the string by looking for the null character but not the array length. Why doesn't C++ have some way to store the length information. Efficiency . C++ was designed to be as fast as possible with minimum consumption of resources such as CPU and RAM.
Exercise:
What is wrong with the below code. Correct the problem.
#include <iostream>#include <cstring>using namespace std ;//-------------------------------------------------int main(){ char str1[4] = { 'w' , 'o' , 'r', 'k' } ; char str2[20] = "class" ; cout << str1 << endl ;}
Copying arrays of strings.
We cannot just assign a string array to another .
Ex:
#include <iostream>using namespace std ;int main(){ char str1[] = "First string. " ; char str2[] = "To be added " ; printf( "Address of str1:%p\n" , str1 ) ; printf( "Address of str2:%p\n" , str2 ) ; str1 = str2 ; printf( "After assignment Address of str1:%p\n" , str1 ) ; cout << str1 << endl ;}
Trying to compile the above produces:
[amittal@hills strings]$ g++ str_array1.cpp
str_array1.cpp: In function ‘int main()’:
str_array1.cpp:16:10: error: invalid array assignment
str1 = str2 ;
We must copy the characters individually . We can use the "strcpy" function to copy C-style strings.
#include <iostream>#include <stdio.h>#include <string.h>using namespace std ;int main(){ char str1[] = "First string. " ; char str2[] = "To be added." ; //Potential problem ? strcpy( str1, str2 ) ; cout << str1 << endl ;}
And writing our own strcpy function.
#include <iostream>#include <stdio.h>#include <string.h>using namespace std ;char* strcpy1( char * destination, const char * source ){ int i1=0 ; for(; i1< strlen( source ) ; i1++ ) { destination[i1] = source[i1] ; } //for destination[i1] = 0 ; return destination ;}int main(){ char str1[] = "First string. " ; char str2[] = "To be added." ; strcpy1( str1, str2 ) ; cout << str1 << endl ; return 0 ;}
Exercise
1) The "strcat" function has the following signature
char * strcat ( char * destination, const char * source );
The source string is appended to the destination string. It can be used as follows:
Ex:
#include <iostream>#include <stdio.h>#include <string.h>using namespace std ;int main(){ char str1[100] = "First string. " ; char str2[] = "To be added." ; strcat( str1, str2 ) ; cout << str1 << endl ; return 0 ;}
Write your own version of the strcat function by filling in the code below.
#include <iostream>#include <stdio.h>#include <string.h>using namespace std ;char* strcat1( char* destination, const char* source ){ return destination ;}int main(){ char str1[100] = "First string. " ; char str2[] = "To be added." ; strcat1( str1, str2 ) ; cout << str1 << endl ; return 0 ;}
Solution
#include <iostream>#include <stdio.h>#include <string.h>using namespace std ;char* strcat1( char* destination, const char* source ){ int i1=0 ; int len = strlen( destination ) ; //cout << "len:" << len << endl ; for(; i1< strlen( source ) ; i1++ ) { destination[len++] = source[i1] ; //cout << "destination:" << destination << endl ; } //for destination[len] = 0 ; return destination ;}int main(){ char str1[100] = "First string. " ; char str2[] = "To be added." ; strcat1( str1, str2 ) ; cout << str1 << endl ; return 0 ;}
Writing our own "atoi" function:
The "atoi" function converts a string to integer.
#include <iostream>#include <stdio.h>#include <string.h>#include <math.h>using namespace std ;int atoi1( char* str1 ){ int i1=0 ; int result = 0 ; int len = strlen ( str1 ) ; for(; i1< strlen( str1 ) ; i1++ ) { result = result + (str1[i1]-'0') * pow ( 10, --len ) ; } //for return result ;}int main(){ char str1[] = "125" ; cout << atoi1( str1 ) << endl ;}
The regular "atoi" will convert a string to integer. In the above we find the leftmost character and multiply it by the appropriate power of 10 .
The C++ string is a class that someone wrote using C++ class feature. It is not part of the native C++ implementation. We can rewrite our earlier program to take input from the user:
#include <iostream>#include <string>using namespace std ;int main(){ string line ; cout << "Enter a city." ; cin >> line ; cout << "The city you entered is:" << line << endl ; return 0;}
Output:
[amittal@hills strings]$ ./a.out
Enter a city.Dublin
The city you entered is:Dublin
[amittal@hills strings]$
The string type has many methods associated with it. The below example shows some of the methods being used.
Ex:
#include <iostream>#include <cstring>using namespace std ;int main(){ string movieTitle = "The" ; movieTitle.append( " Shining" ) ; cout << movieTitle << " Length is :" << movieTitle.length() << endl ; movieTitle.insert(4, 2, 'z') ; cout << movieTitle << endl ;}
Output:
[amittal@hills strings]$ ./a.out
The Shining Length is :11
The zzShining
1)
Write a file that shows how to convert a string containing a number to an integer and also how to convert an integer to a string.
2)
Complete the code in the below code.
#include <iostream>
#include <string.h>
using namespace std;
void reverse( char* str )
{
int i1 = 0 ;
int j1 = strlen( str ) ;
}
//Uses the above reverse function
//use strcpy , and strcmp function
bool isPalindrome( char* str)
{
return false ;
}
int main()
{
char str1[] = "beeb" ;
char str2[] = "car" ;
cout << str2 << endl ;
cout << reverse( str2 ) << endl ;
cout << isPalindrome( str1) << endl ;
cout << isPalindrome( str2) << endl ;
return(0) ;
}
3) Fill in the code for the missing functions:
strcmp compares 2 strings and returns 1 if they are equal and 0 if not.
strstr checks if the second argument exists in the first argument and if so then it returns that position else it returns null.
#include <iostream>#include <stdio.h>#include <string.h>using namespace std ;int strcmp( const char *str1, const char *str2 ){}char *strstr(const char *haystack, const char *needle){}int main(){ char str1[100] = "First string. " ; char str2[] = "To be added." ; char str3[] = "Testing" ; char str4[] = "ing" ; char str5[] = "Apple" ; char str6[] = "Apple" ; cout << strcmp(str4, str5 ) << endl ; cout << strcmp(str5, str6 ) << endl ; cout << "strstr: " << strstr( str3, str4 ) << endl ; cout << "strstr: " << strstr( str3, str5 ) << endl ; return 0 ;}
1)
#include <iostream>
#include <cstring>
using namespace std ;
void toString( int number1 )
{
char buffer[256] ;
//134
//
int temp = number1 ;
int powerten = 1;
while ( temp != 0 )
{
temp = temp / 10 ;
powerten = powerten * 10 ;
}
powerten = powerten / 10 ;
cout << "powerten :" << powerten << endl ;
temp = number1 ;
int i1 ;
while ( temp != 0 )
{
i1 = temp / powerten ;
cout << char(i1+'0') << " " ;
temp = temp % powerten ;
powerten = powerten / 10 ;
}
}
int atoi1( const char* str1 )
{
int powerten = 1 ;
int result = 0 ;
for( int i1= strlen( str1 ) -1 ; i1 > -1 ; i1-- )
{
result = result + (str1[i1] - '0' ) * powerten ;
powerten = powerten * 10 ;
}
return ( result ) ;
}
int main()
{
//Convert a string to an integer
char str1[] = "134" ;
int result = atoi1( str1 ) ;
cout << result << endl ;
//Convert an integer to a string
toString( 134 ) ;
}
2)
#include <iostream>
#include <string.h>
using namespace std;
void reverse( char* str )
{
int i1 = 0 ;
int j1 = strlen( str ) ;
j1-- ;
while ( i1 < j1 )
{
char temp = str[i1] ;
str[i1] = str[j1] ;
str[j1] = temp ;
i1++ ; j1-- ;
}
}
//Uses the above reverse function
bool isPalindrome( char* str)
{
char original[256] ;
strcpy( original, str) ;
reverse( str ) ;
if ( strcmp( original, str ) == 0 )
return true ;
return false ;
}
int main()
{
char str1[] = "beeb" ;
char str2[] = "car" ;
cout << str2 << endl ;
cout << reverse( str2 ) << endl ;
cout << isPalindrome( str1) << endl ;
cout << isPalindrome( str2) << endl ;
return(0) ;
}
3)
#include <iostream>#include <stdio.h>#include <string.h>using namespace std ;int strcmp( const char *str1, const char *str2 ){ if ( str1 == NULL && str2 == NULL ) return 1 ; else if ( str1 != NULL && str2 == NULL ) return 0 ; else if ( str1 == NULL && str2 != NULL ) return 0 ; int len1 = strlen ( str1 ) ; int len2 = strlen ( str2 ) ; if ( len1 != len2 ) return 0 ; for( int i1=0 ; i1 < len1 ; i1++ ) { if ( str1[i1] != str2[i1] ) return 0 ; } return 1 ;}char *strstr(const char *haystack, const char *needle){ if ( haystack == NULL || needle == NULL ) return NULL ; int len1 = strlen( haystack ) ; int len2 = strlen ( needle ) ; if ( len1 <= len2 ) return NULL ; bool match = true ; for( int i1=0 ; i1 <= (len1 - len2); i1++ ) { match = true ; for( int j1=0 ; j1 < len2 ; j1++ ) { if ( haystack[ i1+j1 ] != needle[j1] ) { match = false ; break ; } } if ( match ) return (char*)(haystack + i1) ; } //for return NULL ;}int main(){ char str1[100] = "First string. " ; char str2[] = "To be added." ; char str3[] = "Testing" ; char str4[] = "ing" ; char str5[] = "Apple" ; char str6[] = "Apple" ; cout << strcmp(str4, str5 ) << endl ; cout << strcmp(str5, str6 ) << endl ; cout << "strstr: " << strstr( str3, str4 ) << endl ; cout << "strstr: " << strstr( str3, str5 ) << endl ; return 0 ;}