【共读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));
}

原文地址:https://www.cnblogs.com/ChattyKu/p/9470365.html

时间: 2024-08-27 21:19:34

【共读Primer】19.<3.5> 数组-C风格字符串 Page109的相关文章

【共读Primer】20.&lt;3.6&gt; 多维数组 Page112

C++中的多位数组,严格来说是数组的数组. int ia[3][4]; //大小为3的数组,每个元素是含有4个整数的数组 // 大小为10的数组,每个元素都是大小为20的数组, // 这些数组的元素是含有30个整数的数组 int arr[10][20][30] = {0}; // 将所有元素初始化为 0 初始化多维数组 int ia1[3][4] = { {0,1,2,3}, {4,5,6,7}, {8,9,10,11} }; // 以下语句等价于上面的初始化 int ia2[3][4] = {

【共读Primer】8.&lt;2.1&gt; 基本内置类型(2) Page32

虽然C++中的类型是强制声明的,但是这并不意味着不同类型之间不可以进行一些计算或赋值. 我们来看下面的一组代码 1 #include <iostream> 2 3 int main() 4 { 5 bool b = 42; 6 int i = b; 7 double pi = i; 8 unsigned char c = -1; 9 signed char c2 = 256; 10 std::cout << "bool b =" << b 11 &l

【共读Primer】35.&lt;5.2&gt;语句作用域 Page155

在if .switch. while 和for语句的控制结构内定义的变量只在其结构内部可见,超出结构范围将变为未定义. 1 #include <iostream> 2 #include <vector> 3 4 using std::cout; 5 using std::endl; 6 7 std::vector<int> v = {1,2,3,4,5,6,7,8,9}; 8 9 10 int get_num() 11 { 12 return 1; 13 } 14 15

【共读Primer】58.[6.5]参数匹配 Page217

一般来说函数的选择是比较明确的事情,因为有着参数类型和参数数量的标准. 但是如果将类型转换和默认参数都加入到重载函数中,这个过程就变的复杂起来. 来看看一下代码: void f(); void f(int); void f(int ,int); void f(double, double = 3.14); 在函数的选择过程中分为两步: 1. 找到当前作用域可见的所有名称相同的函数 2. 找到参数数量相等且类型相同或可转换的函数 f(5.6); // 调用 void f(double, doubl

【共读Primer】3.&lt;1.3&gt;注释简介 Page8

C++的注释有两种 1.  双斜杠开始到本行结束 (//) 2. 斜杠星开始 星斜杠结束 (/*)(*/) 1 #include <iostream> // 标准库中输入输出流的库名称 2 /* 3 * 简单主函数: 4 * 读取两个数,求它们的和 5 */ 6 int main() 7 { 8 std::cout << "Enter two numbers:" << std::endl;// 输出一个提示信息的字符串,并在结尾换行 9 int v1

【共读Primer】10.&lt;2.3&gt; 复合类型 Page45

C++的复合类型 引用和指针 引用就像是类型的别名 int ival = 1024; int &refVal = ival; // int &refVal2 ; // 报错:引用必须被初始化 int &refVal1 = ival, &refVal2 = ival, &refVal3 = refVal1, Val4=ival; // refVal1/refVal2/refVal3都是引用,其中refVal3用另一个引用进行初始化 // Val4是一个int它并不是引

【共读Primer】27.&lt;4.7&gt;条件运算符 Page134

条件表达式,判断第一个表达式的真假,如果为真,返回冒号左侧的结果,如果为假返回冒号右侧的结果 (a> b ?  a : b) string finalgrade = (grade < 60) ? "fail" : "pass"; // 如果grade小于60则返回fail,否则返回pass 条件运算符的嵌套 // 如果grade值90以上,返回"high pass" ,否则看是否小于60,小于则返回fail,大于等于则返回pass f

【共读Primer】26.&lt;4.6&gt;成员访问运算符 Page133

成员访问运算符: . 点运算符 -> 箭头运算符 string s1="a string", *p = &s1; auto n = s1.size(); // 运行string对象s1的size成员 n = (*p).size(); // 运行p所知对象的size成员 n = p->size(); // 等价于(*p).size() 因为皆因用运算符的优先级低于点运算符,所以执行解引用运算的子表达式两端必须加括号. 如果不加括号则含义会不同 // 含义是:运行p的s

【共读Primer】46.[6.3]参数传递--main函数处理参数 Page196

前面所讲到的main函数都是空参数列表的. 相信大家都见过启动程序带的参数,那么这些参数时如何传递进去的. 现在我们来看一下main函数声明的完整形式 int main(int argc, char **argv) { for (int i = 0; i < argc; ++i) { std::cout << "command param " << i << " is :"<< argv[i] <<