C++字符串函数详解

C++ 库提供了许多可以用来处理 C 字符串的函数。这些函数的功能包括:确定字符串的长度、连接两个字符串、比较两个字符串、搜索在另一个字符串内出现的一个字符串等。必须包含 cstring 头文件才能使用这些函数。

strlen 函数

strlen 函数将接收一个 C 字符串作为实参,并返回字符串的长度。这是直到(但不包括)null 终止符的字符数。例如,来看以下代码段:

char str[] = "Hello";
int length = strlen(str);

在上述代码示例中,变量 length 存储的数字值为 5。

字符串的长度不应与数组的大小混淆。请记住,传递给 strlen 的唯一信息是 C 字符串的开头。它并不知道数组在哪里结束,因此它会查找指示字符串结尾的 null 终止符。

传递 C 字符串实参

因为 C 字符串是指向 char 的指针,所以 C 字符串处理函数将釆用 char 数组或指向 char 的指针作为形参。C 字符串可以按它能釆取的以下 3 种形式中的任何一种传递给函数:
  1. 字符串常数。
  2. 存储 C 字符串的数组的名称。
  3. 保存 C 字符串地址的指针变量。

strcat 函数

C 字符串处理函数的另一个例子是 strcat。strcat 函数釆用两个字符串作为形参并连接它们,返回由第一个字符串和第二个字符串的所有字符组成的单个字符串,示例如下:
const int SIZE = 13;
char string1[SIZE] = "Hello ";
char string2 [ ] = "World!";
cout << string1 << endl;
cout << string2 << endl;
strcat(string1, string2);
cout << string1 << endl;
以上语句将产生以下输出结果:

Hello
World!
Hello World!

strcat 函数可以将 string2 的内容复制到 string1 的末尾。在本示例中,string1 在调用 strcat 之前包含有字符串 "Hello"。调用之后,它将包含字符串 "Hello World!"。图 1 显示了函数调用之前与之后两个数组的内容。

strcat 函数的作用是将 2 个字符串连接在一起
图 1 strcat 函数的作用是将 2 个字符串连接在一起

请注意 string1 中的最后一个字符(null 终止符之前)是一个空格。strcat 函数不会自动在两个连接的字符串之间插入空格,所以如果需要的话,程序员有责任确保在合适的位置加上空格。程序员还需要确保存储 string1 的数组足够大,以容纳 string1 加上 string2 再加上一个 null 终止符。

以下程序段使用 sizeof 运算符在调用 strcat 之前测试一个数组的大小:
if (sizeof(string1) >= (strlen(string1) + strlen(string2) + 1))
    strcat(string1, string2);
else
    cout << "string1 is not large enough for both strings.\n";
警告,如果保存了第一个字符串的数组其大小不足以容纳两个字符串,则 strcat 函数执行之后将导致字符串溢出数组的边界。

strcpy 函数

strcpy 函数可以用来将一个字符串复制到另一个字符串中。以下是其使用示例:
const int SIZE = 20;
char name[SIZE];
strcpy(name, "Albert Einstein");
strcpy 函数实参中的第二个 C 字符串被复制到第一个 C 字符串实参指定的地址。如果有任何内容已经存储在第一个实参所引用的位置,那么它将被覆盖,如以下程序段所示:
char string1 [ ] = "Hello ";
cout << string1 << endl;
strcpy(string1, "World!");
cout << string1;
以下是其输出结果:

Hello
World!

警告,strcpy 与 C++ 的本质一样,没有边界检查。如果第一个实参指定的数组的大小不足以容纳第二个实参指定的字符串,则第一个实参指定的数组将溢出。

比较 C 字符串

赋值和关系运算符可以处理 C++ string 类,是因为它们已被重载以使用该类。但是,正如赋值运算符不能用于分配 C 字符串一样,关系运算符 <=、<、>、>=、!= 和 == 也不能用于比较 C 字符串。

这是因为与 C 字符串一起使用时,这些运算符会比较存储 C 字符串的地址,而不是比较构成 C 字符串的字符的实际序列。下面的程序显示了尝试使用相等运算符比较C字符串的错误结果。
// This program illustrates that you cannot compare C-strings with relational operators. Although it
// appears to test the strings for equality, that is not what happens.
#include <iostream>
using namespace std;

int main()
{
    // Two arrays for holding two strings
    const int LENGTH = 40;
    char firststring[LENGTH], secondstring[LENGTH];
    // Read two strings
    cout << "Enter a string: ";
    cin.getline(firststring, LENGTH);
    cout << "Enter another string: ";
    cin.getline(secondstring, LENGTH);
    // Attempt to compare the two strings using ==
    if (firststring == secondstring)
        cout << "You entered the same string twice.\n"
    else
        cout << "The strings are not the same.\n";
    return 0;
}
程序输出结果:

Enter a string: Alfonso
Enter another string: Alfonso
The strings are not the same.

此程序中,虽然输入的两个字符串完全相同,但输出的结果总是报告它们不相等,原因就在于以下表达式:

firststring == secondstring

在 if 语句中的这个表达式比较的其实是两个数组的内存地址,而不是比较存储在这些地址中的字符串。由于这些地址是不同的,所以比较会产生错误的结果。事实上,在 C++ 中,即使是像下面这样一模一样的字符串在比较时也通常会产生错误的结果。

"abc" == "abc"

这是因为大多数编译器并不检查以前是否遇到过字符串常数,而是将两个字符串存储在不同的内存地址,然后编译器会比较两个不同的地址,最后给出的结果当然是 false。

strcmp 函数

要正确地比较 C 字符串,应该使用库函数 strcmp。该函数以两个 C 字符串作为形参,并返回一个整数,表示两个字符串相互比较的结果。其原型如下:

int strcmp(char *string1, char *string2);

该原型表示函数将釆用两个 C 字符串作为形参(前面讲过,char* 是 C 字符串的类型)并返回一个整数结果。结果的值是根据以下约定设置的:
  • 如果两个字符串的每个字符都相等,则结果为 0。
  • 如果 string1 以字母顺序排在 string2 之前,则结果为负数。
  • 如果 string1 以字母顺序排在 string2 之后,则结果为正值。

以下是使用 strcmp 确定两个字符串是否相等的示例:
if (strcmp(stringl, string2) == 0)
    cout << "The strings are equal";
else
    cout << "The strings are not equal";
下面的程序使用了 strcmp 函数比较两个 C 字符串,它可以获得正确的比较结果:
// This program correctly tests two C-strings for
// equality with the strcmp function.
#include <iostream>
#include <cstring>
using namespace std;

int main()
{
    // Two arrays for two strings
    const int LENGTH = 40;
    char firststring[LENGTH], secondstring[LENGTH];
    // Read two strings
    cout << "Enter a string: ";
    cin.getline(firststring, LENGTH);
    cout << "Enter another string:";
    cin.getline(secondstring, LENGTH);
    // Compare the strings for equality with strcmp
    if (strcmp(firststring, secondstring) == 0)
        cout << "You entered the same string twice. \n";
    else
        cout << "The strings are not the same.\n";
    return 0;
}
程序输出结果:

Enter a string: https://www.xinbaoku.com
Enter another string:https://www.xinbaoku.com
You entered the same string twice.

当比较字符串时,函数 strcmp 是区分大小写的。如果用户在此程序中输入 "Dog" 和 "dog",则程序将报告它们不一样。一些编译器提供执行不区分大小写比较的非标准版本的 strcmp。除了字符的大小写被忽略之外,这些函数与 strcmp —样工作。

下面程序是关于如何使用 strcmp 的一个更实用的例子。它要求用户输入希望购买的计算机设备的编号。设备编号中包含数字、字母和连字符,所以它必须作为字符串存储。一旦用户输入了设备编号,程序将显示其价格。
// This program uses strcmp to compare the string entered by the user with the valid part numbers.
#include <iostream>
#include <cstring>
#include <iomanip>
using namespace std;

int main()
{
    // Price of items
    const double A_PRICE = 49.0, B_PRICE = 69.95;
    // Character array for part number
    const int PART_LENGTH = 8;
    char partNum[PART_LENGTH];
    // Instruct the user to enter a part number
    cout << "The computer part numbers are: \n";
    cout << "\tBlu-ray Disk Drive, part number S147-29A\n";
    cout << "\tWireless Router, part number S147-29B\n";
    cout << "Enter the part number of the item you\n";
    cout << "wish to purchase: ";
    // Read a part number of at most 8 characters
    cin >> setw(9);
    cin >> partNum;
    // Determine what user entered using strcmp and print its price
    cout << showpoint << fixed << setprecision(2);
    if (strcmp(partNum, "S147-29A") == 0)
        cout << "The price is $" << A_PRICE << endl;
    else if (strcmp(partNum, "S147-29B") == 0)
        cout << "The price is $" << B_PRICE << endl;
    else
        cout << partNum << " is not a valid part number.\n";
    return 0;
}
程序输出结果:

The computer part numbers are:
        Blu-ray Disk Drive, part number S147-29A
        Wireless Router, part number S147-29B
Enter the part number of the item you
wish to purchase: S147-29A
The price is $49.00

结合使用 ! 运算符与 strcmp

在测试字符串是否相等时,有些程序员更倾向于结合使用逻辑非运算符(!)和 strcmp。由于 0 在逻辑上被认为是 false,所以 !运算符可以将该值转换为 true。当两个字符串相同时,表达式 strcmp(string1, string2) 将返回 true;当两个字符串不同时,则返回 false。

以下两个语句在执行时具有完全相同的效果:
if(strcmp(str1, str2)==0)
    cout << "equal";
if(!strcmp(str1, str2))
    cout << "equal";

排序字符串

由于 strcmp 可以返回两个正在比较的字符串的有关字母顺序的信息,因此可用于对 C 字符串列表进行排序。

下面的程序就是一个简单的例子,它要求用户输入两个名字,然后按字母升序排列。
// This program uses the return value of strcmp to alphabetically sort two strings entered by the user.
#include <iostream>
#include <cstring>
using namespace std;

int main()
{
    // Two arrays to hold two strings
    const int NAME—LENGTH = 30;
    char name1[NAME_LENGTH], name2[NAME_LENGTH];
    //Read two strings
    cout << "Enter a name (last name first):";
    cin.getline(namel, NAME_LENGTH);
    cout << "Enter another name: ”;
    cin.getline(name2, NAME_LENGTH);
    // Print the two strings in alphabetical order
    cout << "Here are the names sorted alphabetically: \n";
    if (strcmp(name1, name2) < 0)
        cout << name1 << end1 << name2 << endl;
    else if (strcmp(name1, name2) > 0)
        cout << name2 << end1 << name1 << endl;
    else
        cout << "You entered the same name twice! \n";
    return 0;
}
程序输出结果:

Enter a name (last name first):Smith,Riched
Enter another name: Jones,John
Here are the names sorted alphabetically:
Jones,John
Smith,Riched

表 1 总结了本节讨论的字符串处理函数(所有列出的函数都需要 cstring 头文件)。

表 1 C 字符串常用函数
函 数 描 述
strlen 接收一个 C 字符串作为实参。返回 C 字符串的长度(不包括 null 终止符)。
用法示例:len = strlen(name);
strcat 接收两个 C 字符串作为实参。该函数将第二个字符串的内容附加到第一个 C 字符串 (第一个字符串被改变,第二个字符串保持不变)。
用法示例:strcat(string1, string2);
strcpy 接收两个 C 字符串作为实参。该函数将第二个 C 字符串复制到第一个 C 字符串。第 二个 C 字符串保持不变。
用法示例:strcpy(string1, string2);
strcmp 接收两个 C 字符串实参。如果 string1 和 string2 相同,则该函数返回 0;如果 string2 按字母顺序大于 string1,则返回负数;如果 string2 按字母顺序小于 string1,则返回 一个正数。
用法示例:if (strcmp(string1, string2))