使用字符串总结

         在C语言中,字符串表示为字符的数组。字符串中的最后一个字符是空字符(’\0’),这样,操作字符串的代码就知道在哪里结束,官方将这个空字符定义为NUL。C++包含一些来自C语言的字符串操作函数,它们在<cstring>头文件中定义。通常,这些函数直接操作内存分配。C++提供了一个得到极大改善的字符串概念,并作为标准库的一部分提供了这个字符串的实现。在C++中,std::string是一个类(实际上是basic_string模板类的一个实例),这个类支持<cstring>中提供的许多功能,还能自动管理内存分配。本篇博文就以使用字符串为话题展开,总结我们常用的字符串类型,希望对大家有一点帮助。

 

C风格字符串

         前面说过,C风格字符串就是以’\0’为结束标志的字符串,实际是以数组的形式来存储的。下面我们用几个C字符串函数举几个栗子吧!

#define_CRT_SECURE_NO_WARNINGS  //关闭安全性检测

#include<iostream>

#include<string>

#include<cassert>

#include<cstring>

#include<cstdio>

 

usingnamespacestd;

 

//字符串拷贝函数的内部实现

char *Mystrcpy(char *strDest,const char *strSrc)

{

    //检验参数的合法性

    assert(NULL  !=  strDest &&  NULL  !=  strSrc);

 

    //保存目标字符串的起始位置,以便最后返回

    char *strAddr  =  strDest;

 

    //完成拷贝操作

    while'\0'  !=  (*strDest++  =  *strSrc++) )

    {

        NULL;

    }

 

    //返回目标字符串的起始位置

    return strAddr;

}

 

int main()

{

   

    const char *str  =  "C风格字符串";

    size_t size  =  strlen(str);

 

    //str[0]= 'K';  /*编译器会捕捉到任何写入只读内存的企图*/

 

    //size大小为11strlen计算的是实际字符串的大小,不包括字符串结束标志'\0'

    printf("The length of \"%s\" is %d\n", str,size);

 

    //为保证pStr能保存str中内容,必须在size的基础上加1,以便有位置来存储字符串结束标志'\0'

    char *pStr  =  new char[size+ 1];

 

    //使用C字符串函数完成字符串拷贝

    strcpy(pStr,str);

    printf("The content of pStr is \"%s\"\n",pStr);

 

    //释放动态申请内存

    delete[] pStr;

    //将指针变量置空,避免野指针

    pStr  = nullptr;

 

    pStr  = newchar[20];

    //使用自定义函数完成字符串拷贝操作

    Mystrcpy(pStr,"Hello ");

    //strcat字符串拼接,从pStr的结束标志'\0'处开始拼接str(包括str'\0'

    strcat(pStr,str);

    printf("The content of pStr is \"%s\"\n",pStr);

 

    //释放动态申请内存

    delete[] pStr;

    //将指针变量置空,避免野指针

    pStr  = nullptr;

 

    return 0;

}

 

程序运行结果

        注意到程序第一行的宏定义了吗?相信大家在编写程序时,使用到C库函数时,在编译时经常会报如下警告,这可能会令有“NO ERROR,NO WARNING”编程习惯的小伙伴很不爽。

         看到这张图是不是有一种似曾相识的感觉呢!这主要是因为C库函数关于字符串的操作函数都是不安全的,它们的安全性都有程序猿们来负责,这无疑是给程序猿增添了很多的麻烦,特别是处理一些内存溢出的问题。上面的警告是因为编译器的安全检查导致的,这似乎是程序员们的福音。如果你习惯了使用C库函数,又觉得这些WARNING令你很不爽,你可以尝试博主的做法(在源文件的第一行加上”#define_CRT_SECURE_NO_WARNINGS”来关闭编译器的安全性检查)。如果你还是觉有点不舒服,那么你可以尝试在所有有警告的函数后面加上“_s”,如strcpy_s。 “s”是safe的简写,这些函数都是做过安全处理的,大家放心使用就可以了。这就是C风格字符串的内容,下面让我们进入C++字符串吧!

 

C++字符串

         为了理解C++string类的必要性,我们先来看看C风格字符串的优势和劣势吧

优势:

①很简单,底层使用了基本的字符类型和数组结构

②量级轻,如果使用得当,只会占用所需内存

③很低级,因为可以按操作原始内存的方式轻松操作和复制字符串

④能够很好地被C程序猿所理解

劣势:

①为了模拟字符串数据类型,需要付出很多努力

②使用难度大,而且很容易产生难以找到的内存bug

③没有使用C++面向对象的特性

④要求程序猿了解底层的实现形式

         尽管string是一个类,但是可以把string当做内建类型来使用。事实上,把string想象成简单类型更容易发挥string的作用。通过运算符的重载,C++的string使用起来比C风格字符串容易得多。下面我们就写个简单的程序用一下C++string吧!

#include<iostream>

#include<string>

 

using namespace std;

 

int main()

{

    string str1 = "C++string";

 

    //operator=完成拷贝功能,相当于C库函数中的strcpy,操作是不是简单多啦

    string str2 = str1;

    cout<<"The content of str2 is "<<"\""<< str2 << "\""<< endl;

 

    str1 = "Hello ";

    //operater+operator+=都可以完成字符串拼接功能

    str1 += str2;//str1 = str1 + str2;

    cout << "The content of str1 is " << "\"" <<  str1  <<  "\"" <<  endl;

 

    //为了达到兼容的目的,还可以使用c_str()方法获得一个表示C风格字符串的const字符指针

    const char *pStr  =  str1.c_str();

    cout << "The content of pStr is " << "\"" <<  pStr  <<  "\"" <<  endl;

 

    //将字符串转换为数值

    string str3 = "100";

    int value = 0;

    value  = stoi(str3,NULL, 8);

    cout<<"value is "<< value << endl;

 

    //将数值转换为字符串

    value = 12345;

    str3 = to_string(value);

    cout << "The content of str3 is " << "\"" <<  str3  <<  "\"" <<  endl;

 

    return0;

}

 

程序运行结果

        前面说过,在C++中,std::string是一个类(实际上是basic_string模板类的一个实例),这个类支持<cstring>中提供的许多功能,还能自动管理内存分配。string类在std名称空间的<string>头文件中定义。当string操作需要扩展string时,string类能够自动处理内存需求,因此不再会出现内存溢出的情况了。string重载了“+”和“+=”运算符,方便字符串之间的拼接;重载了“==”、“!=”、“<”、“<=”、“>”、“>=”运算符,方便字符串之间的比较;重载了“=”运算符,方便字符串之间的拷贝;……

         为了达到兼容的目的,还可以用于string类的c_str()方法获得一个表示C风格字符串的const字符指针。不过,一旦string执行了任何内存重分配或string对象的销毁操作,这个返回的const指针就失效了。永远不要从函数中返回在基于堆栈的string上调用c_str()的结果。

 

std::string字面量

        源程序中的字符串字面量通常解释为constchar*。在字符串后面加上“s”可以把字符串字面量解释为std::string(这是C++14新特性)。如:

auto str = “std::string字面量”s;

         注意,有可能你的编译器不支持上述操作,因为std::string字面量是C++14新特性,只有支持C++14新特性的编译器才支持上述定义哦。

 

原始字符串字面量

         原始字符串字面量(raw string literal)是可以横跨多行代码的字符串字面量,不需要转义嵌入的双引号,像“\t”“\n”等转义序列不再按照转义序列的方式来处理了,而是按照普通文件的方式来处理。

#include<iostream>

#include<string>

 

using namespace std;

 

int main()

{

   

    //原始字符串字面量(raw string literal)是可以横跨多行代码的字符串字面量

    string str = R"( '\n \t

 "原始字符串字面量\v" ' )";

 

    //普通字符串字面量需要借助"\"来实现可以横跨多行代码的字符串字面量

    string str1 = "hello \

                  world\n";

 

    cout << "The content of str is " << "\"" <<  str  <<  "\"" <<  endl;

    cout << "The content of str1 is " << "\"" <<  str1  <<  "\"" <<  endl;

 

    //str= R"( "()" )";  /*原始字符串字面量中不能包含“"(”“)"”*/

 

    str = R"+( "()" )+";/*修改后就可以包含“"(”“)"”*/

    cout << "The content of str is " << "\"" <<  str  <<  "\"" <<  endl;

   

    return0;

}

 

程序运行结果

         注意,原始字符串字面量(rawstring literal)是可以横跨多行代码的字符串字面量,而普通字符串字面量需要借助“\”来实现可以横跨多行代码的字符串字面量。在原始字符串字面量中,不需要转义嵌入的双引号,像“\t”“\n”等转义序列不再按照转义序列的方式来处理了,而是按照普通文件的方式来处理。

         如果需嵌入“"(”和“)"”,则需要使用扩展的原始字符串字面量语法,如下所示:

         R”d-char-sequence(r-char-sequence)d-char-sequence”

         r-char-sequence是实际的原始字符串。d-char-sequence是可选的分隔符序列,原始字符串首尾的分隔符序列应该一致。分隔符序列最多能有16个字符。应该选择未出现在原始字符串字面量中的序列作为分隔符序列。

         上面的程序中:

          str = R"("()" )";

改为:str = R"+("()" )+";// d-char-sequence为“ + ”,r-char-sequence为“ ”()” ”

      在操作数据库查询字符串和正则表达式等字符串时,原始字符串字面量可以令程序的编写更加方便。

非标准字符串

         许多C++程序猿都不使用C++风格的字符串,有这么几个原因:一是一些程序猿不是不知道有C++string类型,而是因为它并不总是C++规范的一部分。二是一些程序猿发现,C++string没有提供他们需要的行为,所有开发了自己的字符串类型。也许最常见的原因是,开发框架和操作系统有自己的表达字符串的方式。例如Microsoft MFC中的CString类,它常常用于兼容或解决遗留的问题。在C++开始项目时,提前确定团队如何表示字符串是非常重要的。

         如果你想进一步了解CString的用法,请查阅MSDN。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值