详解C与C++中操作字符串方法的不同
2016-10-05 20:12
381 查看
灵感来源于前些天无意编写的一个小程序,下面是稍微修改过的代码:
这里发生了一个很有趣的现象,我把这段程序分别用VS2013内置的编译器和它的debug版本进行编译运行,出现了两个截然不同的结果:前者显示“equal”,后者显示“not equal”。其中原因我们先按下不表,下文会提到。
这里我们主要关注的是程序的本意应该是比较两个字符串内容是否相等,但是在c语言中像上述程序那样写,却不是比较两个字符串指针指向的具体内容,而是直接对两个字符串指针地址进行比较。因此,在c语言中要比较字符串内容,需要用到
然而,在c++中,对字符串的比较却不必这么麻烦,c++标准库中定义了一个string类型来处理字符串,因此要实现上述程序的比较功能,只需像下面这样:
从上述例子可以看出c与c++在操作字符串上的区别,究其原因,是因为字符串在c语言中是以字符形式存入一个数组中,如
好了,文章写到这里,我们再来看一下文章开头提到的“有趣”的现象-为什么不同的编译器编译相同的程序会得到不同的结果呢?
这是因为好的编译器,会把相同的常量字符串仅仅存一份拷贝,各个指针都指向这个拷贝,所以文章开头的程序会出现比较两个指向相同的“char”字符串的指针时打印“equal”的结果。但是有的编译器会存放多份拷贝,也就是说即使编译器检测到两个指针指向的常量字符串相同,编译器仍然会给两个指针分配不同的地址,当然这种编译器不能算是好的编译器,至少在这一点的处理上就可能会大大浪费存储空间。
既然有了上面的基础,那么我们再来看一下下面这个”加强版”的程序:
猜一下程序运行的结果?
哈哈,程序运行的结果是:
当然,上面的结果是基于我说的“好”的编译器的基础上的,要不然,可能运行结果就应该是空了。至于为什么同样是C风格的字符串,为什么指针型的比较能相等而数组型的却不可以呢?答案其实很简单。
在定义一个数组时,编译器是在栈里为数组分配了一段内存,返回的是指向数组首元素的指针,如本程序中就应该是指向c的指针;而在定义一个指向常量的指针时,在这里是指向”char”这个字符串常量的内存首地址,所以二者地址一般是不同的,自然比较的结果就不相等了。
#include<stdio.h> int main() { char *str1="char"; char *str2="char"; if(str1==str2) printf("equal.\n"); else printf("not equal.\n"); return 0; }
这里发生了一个很有趣的现象,我把这段程序分别用VS2013内置的编译器和它的debug版本进行编译运行,出现了两个截然不同的结果:前者显示“equal”,后者显示“not equal”。其中原因我们先按下不表,下文会提到。
这里我们主要关注的是程序的本意应该是比较两个字符串内容是否相等,但是在c语言中像上述程序那样写,却不是比较两个字符串指针指向的具体内容,而是直接对两个字符串指针地址进行比较。因此,在c语言中要比较字符串内容,需要用到
<string.h>头文件中量身打造的字符串函数,在此处应该用到的是strcmp()函数。
#inlcude<stdio.h> #incldue<string.h> int main() { char *str1="char"; char *str2="char"; if(strcmp(str1,str2)==0) printf("equal.\n"); else printf("not equal.\n"); return 0; }
然而,在c++中,对字符串的比较却不必这么麻烦,c++标准库中定义了一个string类型来处理字符串,因此要实现上述程序的比较功能,只需像下面这样:
#include<iostream> #include<string> using namespace std; int main() { string str1="char"; string str2="char"; if(str1==str2) cout<<"equal"<<endl; else cout<<"not equal"<<endl; return 0; }
从上述例子可以看出c与c++在操作字符串上的区别,究其原因,是因为字符串在c语言中是以字符形式存入一个数组中,如
char[]="hello"其实是
char[]={'h','e','l','l','o','\0'},因此直接对字符串比较其实比较的是指针地址;而在c++中,string是一个类型,在STL(c++标准库)中定义了string类型的“==”操作符的重载版本,因此能够直接对两个string型变量进行比较其内容。下面是摘取的string类型中关于“==”的部分源码:
template<class _Elem,class _Traits,class _Alloc> inline bool operator== ( const basic_string<_Elem, _Traits, _Alloc>& _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right) { // test for string equality return (_Left.compare(_Right) == 0); }
int compare(const _Myt& _Right) const _NOEXCEPT { // compare [0, _Mysize) with _Right return (compare(0, this->_Mysize, _Right._Myptr(), _Right.size())); }
const value_type *_Myptr() const { // determine current pointer to buffer for nonmutable string return (this->_BUF_SIZE <= this->_Myres ? _STD addressof(*this->_Bx._Ptr) : this->_Bx._Buf); }
int compare(size_type _Off, size_type _N0, const _Elem *_Ptr, size_type _Count) const { // compare [_Off, _Off + _N0) with [_Ptr, _Ptr + _Count) #if _ITERATOR_DEBUG_LEVEL == 2 if (_Count != 0) _DEBUG_POINTER(_Ptr); #endif /* _ITERATOR_DEBUG_LEVEL == 2 */ if (this->_Mysize < _Off) _Xran(); // _Off off end if (this->_Mysize - _Off < _N0) _N0 = this->_Mysize - _Off; // trim _N0 to size size_type _Ans = _Traits::compare(this->_Myptr() + _Off, _Ptr, _N0 < _Count ? _N0 : _Count); return (_Ans != 0 ? (int)_Ans : _N0 < _Count ? -1 : _N0 == _Count ? 0 : +1); }
好了,文章写到这里,我们再来看一下文章开头提到的“有趣”的现象-为什么不同的编译器编译相同的程序会得到不同的结果呢?
这是因为好的编译器,会把相同的常量字符串仅仅存一份拷贝,各个指针都指向这个拷贝,所以文章开头的程序会出现比较两个指向相同的“char”字符串的指针时打印“equal”的结果。但是有的编译器会存放多份拷贝,也就是说即使编译器检测到两个指针指向的常量字符串相同,编译器仍然会给两个指针分配不同的地址,当然这种编译器不能算是好的编译器,至少在这一点的处理上就可能会大大浪费存储空间。
既然有了上面的基础,那么我们再来看一下下面这个”加强版”的程序:
#include<stdio.h> int main() { char *str1="char"; char *str2="char"; char str3[]="char"; if(str1==str2) printf("1 equal to 2\n"); if(str1==str3) printf("1 equal to 3\n"); if(str2==str3) printf("2 equal to 3\n"); return 0; }
猜一下程序运行的结果?
哈哈,程序运行的结果是:
1 equal to 2
当然,上面的结果是基于我说的“好”的编译器的基础上的,要不然,可能运行结果就应该是空了。至于为什么同样是C风格的字符串,为什么指针型的比较能相等而数组型的却不可以呢?答案其实很简单。
在定义一个数组时,编译器是在栈里为数组分配了一段内存,返回的是指向数组首元素的指针,如本程序中就应该是指向c的指针;而在定义一个指向常量的指针时,在这里是指向”char”这个字符串常量的内存首地址,所以二者地址一般是不同的,自然比较的结果就不相等了。
相关文章推荐
- Visual C++.NET中的字符串转换方法(ZT)
- Visual C++.NET中的字符串转换方法
- JAVA与C++::关于JNI中文字符串操作问题总结
- 《Windows Via C/C++》边学习,边翻译(四)操作字符和字符串-3
- 对字符串的操作的一些方法
- Visual C++.NET中 字符串转换方法[2]
- 《Windows Via C/C++》边学习,边翻译(六)操作字符和字符串-5
- 再谈两种不同字符串比较方法的性能对比
- C++中几种不同交换两个数的方法
- C++操作字符串
- delphi中实现用字符串表示并操作控件的方法。
- JAVA与C++::关于JNI中文字符串操作问题总结
- visual c++.net中的字符串转换方法
- 字符与字符串操作——Windows via C/C++
- 两种不同字符串比较方法的性能对比
- Visual C++.NET中 字符串转换方法(转载)
- C++ 字符串操作经验集(转)
- C#优化字符串操作(6)--把123456789转换为12-345-6789的3种方法
- Oracle多行记录字符串综合操作几种方法
- 谈c++ 和 c#关于字符串和其它类型的相加操作