Here are some example declarations of character variables initialized by character literals. Notice that literal characters are bracketed by single quotes and that char is the name of the type of all characters:
An appropriate integer can be converted into the character it represents. For example, the statement:
Control characters represent special keys such as the return key, etc. They have special literal representations that use the backslash character:
int isupper(int);
int islower(int);
int isdigit(int);
int isspace(int);
int iscntrl(int);
int ispunct(int);
int isalnum(int);
int toupper(int);
int tolower(int);
int main()
{
while(true)
{
cout << "Enter a character (<Ctrl>c to quit): ";
char response = cin.get();
cout << "int(" << response << ") = " << int(response)
<< '\n';
cin.sync(); // flush '\n'
}
return 0;
}}
A C string variable is simply an array of characters. To allow C strings of varying sizes, these arrays are often allocated in the heap:
Programmers should use C++ strings (see below) instead of C strings, because C strings don't check for out-of-range indices, and they don't allocate and deallocate memory for themselves. Instead, these jobs are left to the programmer.
There are several places where C strings are still used in C++. One example are command line arguments. The DOS console always passes the entire command line, including the command name, to main() as an array of C strings (i.e. an array of arrays of chars). The console also passes the length of this array to main().
test.cpp (A simple expression evaluator)
int main(int argc, char* argv[])
{
if (argc != 4)
{
cerr << "usage: " << argv[0] << " NUMBER OPERATOR NUMBER\n";
exit(1);
}
double num1 = atof(argv[1]);
double num2 = atof(argv[3]);
double num = 0;
// result stored here
char op = argv[2][0];
switch (op)
{
case '+': num = num1 + num2; break;
case '*': num = num1 * num2; break;
case '-': num = num1 - num2; break;
case '/': num = num1 / num2; break;
case 'e': num = pow(num1, num2); break; // DOS won't allow ^
default:
cerr << "unrecognized operator: " << op << '\n';
return 1;
} // switch
cout << "result
= " << num << '\n';
return 0;
}
Notice that although the executable is renamed, the new name is used in the error message:
D:>eval 22 + 15
result = 37
D:>eval 3.2 * 7
result = 22.4
D:>eval 15 / 3
result = 5
D:>eval 15 - 5
result = 10
D:>eval 2 e 5
result = 32
D:>eval 23
usage: eval NUMBER OPERATOR
NUMBER
D:>eval 6 # 2
unrecognized operator: #
D:>
The basic_string template is similar to the vector vector template with some additional string-type members. A char_traits structure contains information about encoding, comparing, inputting, and outputting the underlying "characters". The string type is the char instance of basic_string:
The boldface text demonstrates the most important string operations:
#include "str_utils.h"
#include <iostream>
#include <string>
using namespace std;
int main()
{
// converting C
strings to strings
string s1("California"),
s2, s3;
s2 = "Nevada";
// converting strings
to C strings
printf("%s\n\n",
s1.c_str());
cout << "s3 empty? = " << s3.empty() << "\n\n";
// assigning
copies strings
s3 = s2;
cout << "s2
= " << s2 << '\n';
cout << "s3
= " << s3 << '\n';
s3[0] = 'n';
cout << "s2
= " << s2 << '\n';
cout << "s3
= " << s3 << "\n\n";
// strings can
grow
s3 = "Nevada is
in the USA";
cout << s3
<< "\n\n";
// 3 ways to traverse a string
for(int i
= 0; i < s1.size(); i++)
cout << s1[i] << ' ';
cout << '\n';
// at() does index
bounds checking
for(i = 0; i <
s2.length(); i++)
cout << s2.at(i) << ' ';
cout << '\n';
string::iterator
p;
for(p = s1.begin();
p != s1.end(); p++)
cout << *p << ' ';
cout << "\n\n";
// error handling
try
{
cout << s1.at(500); // index too big!
}
catch(out_of_range
e)
{
cerr << e.what() << "\n\n";
}
// comparing strings
cout << s1
<< " == " << s2 << " = " << (s1 == s2) <<
'\n';
cout << s1
<< " != " << s2 << " = " << (s1 != s2) <<
'\n';
cout << s1
<< " <= " << s2 << " = " << (s1 <= s2)
<< "\n\n";
// concatonation
cout << s1
+ ' ' + "is next to" + ' ' + s2 << "\n\n";
// finding substrings
int pos = s1.find("for");
s3 = s1.substr(pos,
3); // 3 chars beyond pos
cout << s3
<< '\n';
s3 = s1.substr(pos,
string::npos); // tail of s1
cout << s3
<< "\n\n";
// replacing
substrings
s3 = s1;
s3.replace(pos,
3, "XXXXX");
cout << s3
<< "\n\n";
// stats
cout <<
"s1's max size = " << s1.max_size() << '\n';
cout << "s1's
capacity = " << s1.capacity() << '\n';
cout << "s1's
size = " << s1.size() << "\n\n";
// erasing substrings
s1.erase(pos,
3);
cout << s1
<< '\n';
cout << "s1's
max size = " << s1.max_size() << '\n';
cout << "s1's
capacity = " << s1.capacity() << '\n';
cout << "s1's
size = " << s1.size() << "\n\n";
// string I/O
cout << "Enter
3 strings seperated by white space: ";
cin >> s1 >>
s2 >> s3;
cout << "\nYou
entered: " << s1 << ' ' << s2 << ' ' << s3
<< '\n';
s1 = reverse(s2);
cout << s1
<< '\n';
if (palindrome(s3))
cout << "s3 is a palindrome!\n";
return 0;
}
These are just some sample string manipulation functions. The first one demonstrates string recursion. (I had some difficulty passing strings by value in VC++.)
bool palindrome(const string&
s)
{
return s == reverse(s);
}
s3 empty? = 1
s2 = Nevada
s3 = Nevada
s2 = Nevada
s3 = nevada
Nevada is in the USA
C a l i f o r n i a
N e v a d a
C a l i f o r n i a
invalid string position
California == Nevada = 0
California != Nevada = 1
California <= Nevada = 1
California is next to Nevada
for
fornia
CaliXXXXXnia
s1's max size = 4294967293
s1's capacity = 31
s1's size = 10
Calinia
s1's max size = 4294967293
s1's capacity = 31
s1's size = 7
Enter 3 strings seperated by white space: shoe crab rotator
You entered: shoe crab rotator
barc
s3 is a palindrome!
Safe strings, also known as smart strings, encapsulate C strings (also known as dumb strings). An implementation follows. It is entirely for instructional purposes. Programmers should use the string class from the standard C++ library, instead. The code in boldface shows how popular C string functions from the standard C library are used (see above).
string.h
class String
{
public:
String(char* s =
0);
String(const String&
s) { copy(s); }
~String() { free();
}
String& operator=(String&
s);
String& operator=(char*
s)
{
*this = String(s);
return *this;
}
char& operator[](int i);
bool operator==(const
String s) const
{
return (strcmp(str, s.str) == 0);
}
bool operator!=(const
String s) const
{
return (strcmp(str, s.str) != 0);
}
bool operator<(const
String s) const
{
return (strcmp(str, s.str) < 0);
}
bool operator>(const
String s) const
{
return (strcmp(str, s.str) > 0);
}
friend ostream&
operator<<(ostream& os, const String& s);
friend istream&
operator>>(istream& is, String& s);
friend String operator+(const
String& s1, const String& s2);
friend String operator+(const
String& s1, char * s2);
friend String operator+(const
String& s1, char c2);
bool empty() const
{ return length == 0; }
int getLength()
const { return length; }
char* getStr()
{ return str; }
operator char*()
const { return str; } // automatic conversion
// etc.
private:
int length; // string length
char* str; // the encapsulated C string
void copy(const String& s); // must use pass-by-ref
void free() { if (str) delete[] str; }
};
String::String(char* s /* = 0
*/)
{
if (s == 0)
{
str = 0;
length = 0;
}
else
{
length = strlen(s);
str = new char[length + 1];
strcpy(str, s);
}
}
String& String::operator=(String&
s)
{
if (&s != this)
{
free();
copy(s);
}
return *this;
}
char& String::operator[](int
i)
{
if (i < 0 ||
length <= i)
error("index out of range");
return str[i];
}
void String::copy(const String&
s)
{
length = s.length;
str = new char[length
+ 1];
strcpy(str,
s.str);
}
String operator+(const String&
s1, const String& s2)
{
char* s = new char[s1.length
+ s2.length + 1];
strcpy(s, s1.str);
strcat(s, s2.str);
return String(s);
}
String operator+(const String&
s1, char * s2)
{
char* s = new char[s1.length
+ strlen(s2) + 1];
strcpy(s, s1.str);
strcat(s, s2);
return String(s);
}
String operator+(const String&
s1, char c2)
{
char* s = new char[s1.length
+ 2];
strcpy(s, s1.str);
s[s1.length] =
c2;
s[s1.length + 1]
= 0;
return String(s);
}
ostream& operator<<(ostream&
os, const String& s)
{
os << s.str;
return os;
}
istream& operator>>(istream&
is, String& s)
{
char buffer[80];
// is 80 enough?
is.get(buffer,
80);
is.sync(); // flush
is.buffer
s = buffer;
return is;
}
int main()
{
String s1("California"),
s2(s1), s3;
cout << s1
<< '\n';
cout << s2
<< '\n';
s2 = "Nevada";
cout << s2
<< "\n\n";
cout << "s3.empty() = " << s3.empty() << "\n";
cout << "enter
a string: ";
cin >> s3;
cout << s3
<< "\n\n";
for(int i = 0; i
< s1.getLength(); i++)
cout << s1[i] << ' ';
cout << "\n\n";
s3 = s2;
cout << s3
<< "\n\n";
s3 = s1 + ' ' +
"is next to" + ' ' + s2;
cout << s3
<< "\n\n";
cout << s1
<< " == " << s2 << " = " << (s1 == s2) <<
'\n';
cout << s1
<< " != " << s2 << " = " << (s1 != s2) <<
'\n';
cout << s1
<< " < " << s2 << " = " << (s1 < s2) <<
'\n';
cout << s1
<< " > " << s2 << " = " << (s1 > s2) << "\n\n";
// Strings automatically convert
to C strings!
cout << "strlen("
<< s1<< ") = " << strlen(s1) << '\n';
return 0;
}
s3.empty() = 1
enter a string: Oregon
Oregon
C a l i f o r n i a
Nevada
California is next to Nevada
California == Nevada = 0
California != Nevada = 1
California < Nevada = 1
California > Nevada = 0
strlen(California) = 10