浅谈C++的string类型

一,C语言的字符串

在C语言里,对字符串的处理一项都是一件比较痛苦的事情,因为通常在实现字符串的操作的时候都会用到最不容易驾驭的类型——指针。

比如下面这个例子:

//example 1:

char str[12] = "Hello";

char *p = str;

*p = ''h''; //改变第一个字母

 

//example 2:

char *ptr = "Hello";

*ptr = ''h''; //错误

 

第一个字符串时用数组开辟的,它是可以改变的变量。而第二个字符串则是一个常量,也就是字面值。ptr只是指向它的指针而已,而不能改变指向的内容。

看两者的汇编即可明了:

char p[] = "Hello";
004114B8 mov         eax,dword ptr [string "Hello" (4166FCh)]
004114BD mov         dword ptr [ebp-10h],eax
004114C0 mov         cx,word ptr ds:[416700h]
004114C7 mov         word ptr [ebp-0Ch],cx

char *ptr = "Hello";
004114CB mov         dword ptr [ebp-1Ch],offset string "Hello" (4166FCh)

可见用数组和用指针是完全不相同的。

要想通过指针来改变常量是错误,正确的写法应该是用const指针。

const char *ptr = "Hello";

 

 

二,初识string类

正是因为C风格字符串(以空字符结尾的字符数组)太过复杂难于掌握,不适合大程序的开发,所以C++标准库定义了一种string类,定义在头文件<string>。注意<string.h>和<cstring>都是错误的,这两个头文件主要定义C风格字符串操作的一些方法,譬如strlen(), strcpy()等。第一个是C的头文件格式,而第二个是C++风格的头文件,但是和<string.h>是一样的,它的目的是为了和C兼容。

看下面例子:

//example 3:

string str("world");   //可以用C风格字符串初始化

string words = "Hello";

string greet = words;

string join = greet + words; //可以像基本类型一样操作

 

但是如果试图把string类型的对象直接赋给C风格的字符串的话,编译器会报错的。

string var = "**";

char *ptr = var; //error!

 

但是实际应用中这个问题也难以避免,很多时候我们还是需要将string类型的转化为char*来实现自定义的操作,C++标准库也为了和之前用C写的程序兼容,于是可以用string的c_str()函数。

string var = "**";

char *ptr = var.c_str(); //还不能被编译

 

但是c_str()为了防止意外地修改string对象,返回的是const指针,所以上面这段代码是不能被编译的。正确的应该是用const指针。

string var = "**";

const char *p = var.c_str(); //Correct!

 

这个c_str()方法在C++IO流操作上也被广泛应用。

在打开文件时,如果要指定文件名,可以用C风格的字符串。如果用到string类型的字符串作为文件名时,就必须调用c_str()方法将其转换为一个C风格字符串。

//example 4:

string   filename; //定义文件名称

cin >> filename;

ifstream.open(filename.c_str()); //要使用C风格字符串

 

三, 深入了解string类

对string有一定了解以后,我们可以来了解C++标准库定义的一系列丰富的字符串操作,当然都是基于string类型。从某一种程度上来说,string就是一种字符容器。

标准库为string定义了很多方法,包括构造、插入(insert)、替换(assign和replace)、比较(compare)、查找(find)、删除(erase)、连接(append)以及对子串的操作(substr)。而每一种操作都有很多种重载。

比如插入,除了包括标准容器的插入方式以外,string类本身还有一些特有的插入方法。

//example 5:

//与标准容器相同的插入操作:

str.insert(iter, value) //在迭代器iter之前插入value, 返回新元素的迭代器

str.insert(iter, n, value); //在迭代器iter之前插入n个value,返回void

str.insert(iter, begin, end); //在迭代器iter之前插入迭代器begin和end标记范围内的元素,返回void

//string类特有的插入方法:

str.insert(pos, n, ch); //在下标为pos的字符之前插入n个字符ch

str.insert(pos, str2); //在下标为pos的字符之前插入string类型的对象str2的副本

str.insert(pos1, str2, pos2, len); //在下标为pos1的z字符之前插入string类型str2中从下表为pos2开始的len个字符

str.insert(pos, cp); //在下标为pos的字符前插入字符指针cp指向的C风格字符串的副本

 

总之string是一种非常灵活的字符串类型,标准库让我们可以忽略内存管理和具体实现方式,我们只需要关注其接口就好。并且初学者在使用字符串的时候也应尽量使用这种类型,而不是C风格的字符串。

当然,无C语言学习经历的人可以例外。

 

 

参阅书籍:

<C++ Primer 4th>Stanley Lippman

<The C++ Programming Language> Bjarne Stroustrup>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值