【共读Primer】19.<3.5> 数组-C风格字符串 Page109
C风格的字符串是指以空字符‘\0’结尾的一个字符串。
这种字符串虽然在C++中兼容,但是极易引起内存安全问题,所以不建议使用。
但是作为一个语言特性,我们应该了解它,这样才能在碰到的时候做到心中有数。
3.5.4 C标准库string函数
这里所说的string函数并不是std::string的函数,而是在C的标准库中,对C风格字符串进行操作的一些全局函数。
strlen(p); //计算p的长度,不计入空字符结尾 strcmp(p1, p2); // 比较两个字符串p1和p2是否相等,相等返回0,p1>p2返回正值, p1<p2返回负值 strcat(p1, p2); // 将p2附加到p1后,返回p1 strcpy(p1, p2); // 将p2拷贝给p1, 返回p1
观察以上函数,它们正常运行的基础条件是在结尾有一个'\0'的空字符,如果这个条件没有达到
,那么对于上述的任何一个函数来说结果都将是灾难性的。
对于下面的两行代码来说,返回的结果将是一个未知的值,因为ca这个字符串并没有以空为结尾。
char ca[] = {'C', '+', '+'}; cout << strlen(ca) << endl;
比较字符串
在C风格的字符串进行比较的时候我们需要使用到strcmp函数来进行比较,而不是直接使用逻辑判断符号进行比较
// 使用C++的string类型进行比较 string s1 = "A string example"; string s2 = "A different string"; if (s1 < s2) // false: s2 小于 s1 { cout << "s1 < s2" << endl; } else { cout << "s1 > s2" << endl; } // 直接使用C风格的字符串进行比较 const char ca1[] = "A string example"; const char ca2[] = "A different string"; // if ( ca1 < ca2 ) // 这样的比较结果是未定义的,因为比较的内容是两个指针的值 if (strcmp(ca1, ca2)) // 这样的写法才会使结果与string对象的比较相同。 { cout << "s1 < s2" << endl; } else { cout << "s1 > s2" << endl; }
拼接字符串
我们在对C风格的字符串进行拼接的时候需要使用到如下的方法。
string largeStr = s1 + " " + s2; // 这种以加号的连等来拼接的方式不适用于C风格的字符串 // char ca3 = ca1 + " " + ca2; // 这个表达式是错误的 // 针对C风格的字符串我们需要使用一下的方式来拼接 strcpy(largeStr, ca1); // 把 ca1拷贝给largeStr strcat(largeStr, " "); // 把largeStr的末尾加上一个空格 strcat(largeStr, ca2); // 把 ca2连接到largeStr后面
但是一个潜在的问题是largeStr所需要的控件是不容易准确估计的,而一旦代码发生改变,这个问题很可能被忽略,因为并不是每次都会出问题。
这将会成为程序运行的一个潜在风险
3.5.5 与旧代码的接口
这里的一些操作是,可以使用C风格字符串初始化string或对它进行赋值,在使用在加法操作中,允许使用C风格的字符串进行操作,但必须保证有string的出现。
string s("Hello World"); // s 使用C风格字符串进行初始化 // char *Cstr = s; // 这个等式是不成立的 const char *str = s.c_str(); // 将 string的对象内容返回为一个C风格的字符串
char Cstr[30] = {0};
stpcpy(Cstr, s.c_str());
而在上述代码的最后一行中,我们无法保证c_str()的返回值一直有效,更安全的做法是对返回的C风格字符串进行拷贝。
// 使用数组来进行vector的初始化, begin和end两个函数是C++11特性 int int_arr[] = {0,1,2,3,4,5}; vector<int> ivec(begin(int_arr), end(int_arr));
虽然以上代码是正确的,但是非常不建议使用,因为对指针的操作总是存在一定的危险性。
以下是所有代码,可编译的版本,大家可自行编译执行或修改来查看变化。
#include <iostream> #include <string> #include <vector> using std::cout; using std::endl; using std::string; using std::vector; using std::begin; using std::end; int main() { char p[] = "Hello World!"; char p1[] = "Hello World!p1"; char p2[] = "Hello World!p2"; strlen(p); //计算p的长度,不计入空字符结尾 strcmp(p1, p2); // 比较两个字符串p1和p2是否相等,相等返回0,p1>p2返回正值, p1<p2返回负值 strcat(p1, p2); // 将p2附加到p1后,返回p1 strcpy(p1, p2); // 将p2拷贝给p1, 返回p1 char ca[] = {'C', '+', '+'}; cout << strlen(ca) << endl; // 使用C++的string类型进行比较 string s1 = "A string example"; string s2 = "A different string"; if (s1 < s2) // false: s2 小于 s1 { cout << "s1 < s2" << endl; } else { cout << "s1 > s2" << endl; } // 直接使用C风格的字符串进行比较 const char ca1[] = "A string example"; const char ca2[] = "A different string"; // if ( ca1 < ca2 ) // 这样的比较结果是未定义的,因为比较的内容是两个指针的值 if (strcmp(ca1, ca2)) // 这样的写法才会使结果与string对象的比较相同。 { cout << "s1 < s2" << endl; } else { cout << "s1 > s2" << endl; } string largeStr = s1 + " " + s2; // 这种以加号的连等来拼接的方式不适用于C风格的字符串 // char ca3 = ca1 + " " + ca2; // 这个表达式是错误的 // 针对C风格的字符串我们需要使用一下的方式来拼接 char largeCStr[30] = {0}; strcpy(largeCStr, ca1); // 把 ca1拷贝给largeStr strcat(largeCStr, " "); // 把largeStr的末尾加上一个空格 strcat(largeCStr, ca2); // 把 ca2连接到largeStr后面 string s("Hello World"); // s 使用C风格字符串进行初始化 // char *Cstr = s; // 这个等式是不成立的 const char *str = s.c_str(); // 将 string的对象内容返回为一个C风格的字符串 char Cstr[30] = {0}; strcpy(Cstr, s.c_str()); // 使用数组来进行vector的初始化, begin和end两个函数是C++11特性 int int_arr[] = {0,1,2,3,4,5}; vector<int> ivec(begin(int_arr), end(int_arr)); }
上一篇: 过了个搞笑的母亲节
下一篇: C++实现递归版二分搜索算法