[关闭]
@rg070836rg 2015-08-16T15:09:36.000000Z 字数 3878 阅读 1766

字符串

data_structure


一、从字符串谈起

本文主要讨论C串与string类的区别。
在谈区别前,首先提下,字符串是显示生活中绝大多数数据的存储形式,几乎任何数据,都能以字符串的方式存储。所以字符串是很重要的。在平常的数据处理中,有可能会处理大量的字符串。

1.1、c语言中的字符串

在c中,并没有提供string类,C语言中有一个string.h的头文件,这个头文件里面声明的函数,是用来对字符串的处理,而c语言的字符串——就是用char数组存储的,所以,显而易见,string.h的一系列函数,也是针对char数组的操作。

1.2、c++中的字符串

很明显,由于有缺点,所以在c++中,引入了标准函数库的string类,这是一个封装了大多数我们所需要的任何对于字符串需要操作的类,而且很重要的一点,用这个类,不必担心内存的一系列问题,方便程度极其高,也由于这个原因,操作的效率不如char数组。

那么,本文会对这两者进行深入的探究。在对比之前,我们先分别介绍下c串和string类。

二、C串

c语言中,字符串是以字符数组存储的,也是其唯一的存储方式,比如我要定义一个hello world的字符串,需要这样做:
char string[12] = "hello wolrd";
字符串是以'\0'结尾的,所以12位的char数组,只能存11个字符,

2.1、C串初始化

既然讲到了初始化,这边归纳下,c串有哪些初始化方式,及他们的区别和使用场景。

大概看了下,有这几种初始化方式:

  1. char a[12]="hello world";
  2. char b[]="hello world";
  3. char *c="hello world";
  4. char d[]={'h','e','l','l','o',' ','w','o','r','l','d'};

前三种是比较正常的赋值方式,c课本还举了第四种,但经测试,是有问题的。

经过测试:

  1. cout<<strlen(a)<<endl;
  2. cout<<strlen(b)<<endl;
  3. cout<<strlen(c)<<endl;

不难发现这三个字符串的长度都是10,那么他们的区别在哪里呢?

我们一个个的解释:


首先, char a[12]="hello world";

编译的时候,编译器会把"hello world"变成"hello world/0"存储在目标文件的某个位置(字符串都是属于全局的,在编译的时候就已经分配了内存了,只有程序退出的时候才会被销毁),编译程序会在内存中留出连续12个字节的区域,把第一个字节地址赋给a,同时把字符串的内容一个字符一个字符地复制到a所指的内存区域,因此定义字符串数组时,其元素个数至少应该比字符串的长度多1。


第二种 char b[]="hello world";

这个和第一种的区别是,是由编译器求得元素个数,然后执行方式和第一种一样。


最后一种,char *c="hello world";
"hello world"是一个字符串常量他存储在常量存储区,只能用一个指针指向它却不允许改变,所以经常在那些不需要修改字符串的地方用,比如文件名的传递。
这边就是,c指向该常量地址。


同时要注意一点:数组可以自动转型成指针,指针不能转成数组,字符串等价于字符数组,而不等于字符指针。


在此,我认为,三种方式的区别的根本在于,前两种,是原版的复制品,是把字符串的内容,拷贝到自身的空间里面去;最后一种,仅仅是指向了它。还有,字符数组可以弱化成指针,反过来却不可以。


最后还要提示下自己,字符串的初始化只有这几种,绝对不能,出现如下的低级错误:char a[10];a="hi!",若没有随定义初始化,可以用提供的strcpy函数来进行后来的赋值。


2.2、string.h中提供的一些函数的问题

这块的函数,非常之不安全,因为在编译的时候,不会对数组的大小做检查,一不小心就会数组越界,导致程序紊乱奔溃。所以这一块对程序员的要求很高,要求程序员能够明白自己所用的空间到底够不够。下面举个错误的例子。

  1. char a[]="hello";
  2. char b[]="world";
  3. strcat(a,b);

这段代码,在编译的时候绝对不会报错,而运行的时候,程序会奔溃。
如图:
此处输入图片的描述
如果程序比较长,而且使用字符串函数比较多的话,程序查错十分麻烦,十分之不安全。
对此,微软公司对C/C++语言的扩展,生成了安全CRT(C Runtime Library = C运行时间库)函数。
下面网页连接到微软MSDN

这边具体的一些string.h中的函数会贴在最后

2.3、CRT 中的安全功能

上面既然提到了安全CRT函数,这边就简单的介绍下:

安全CRT(C Runtime Library = C运行时间库)函数,是微软公司对C/C++语言的扩展。它在原来函数名后添加了“_s”后缀;一般返回出错代码;并将原来的函数返回值,作为一个参数,添加到函数输入参数列表的最后;对带缓冲区参数的函数,还添加了表示缓冲区大小的输入参数,以防止内存溢出。

例如,strcpy 函数不能调用字符串复制它是否为其目标缓冲区太大的。 但是,它的安全副本,strcpy_s,将缓冲区大小作为参数,因此,它可以确定是否发生缓冲区溢出。 如果使用 strcpy_s 将字符放到一个十六进制字符缓冲区,这是在部分中有错误;strcpy_s 不可以更正错误,但是,它可以检测错误和通过调用的参数无效处理程序会通知您。


2.4、总结

c串的使用很不方便,同时还有安全性的问题。
所以建议,在使用c串的同时,一定要注意对字符串处理的,一定要有长度来限制!

三、c++ string类

由于c串的一系列不方便的,不安全的缺陷,c++抛弃了char数组,产生了标准程序库的string类,这个类里面集成的函数,足够满足我们近乎所有对字符串的需求。
同样,我们从构造函数开始说起

3.1、构造方法

构造很方便,字符串的构造函数创建一个新字符串,包括:

  • 无参
  • 以length为长度的ch的拷贝(即length个ch)
  • 以str为初值 (长度任意),
  • 以index为索引开始的子串,长度为length, 或者
  • 以从start到end的元素为初值.
    即:
  1. string str;
  2. string str1( 5, 'c' );
  3. string str2( "Now is the time..." );
  4. string str3( str2, 11, 4 );

3.2、操作方法

由于string类重写了许多运算符,还预设了很多函数,所以用起来十分方便,而且无需再担心空间与安全问题。

具体的一些函数,会在最后贴出,以供查阅。

四、其他

在这里,我想谈下c++string与c串的转换,有的时候,可能需要用到转换,一般会是在传文件名,不需要修改串内容的时候会用到,

这边,string类提供了string.c_str的函数,返回当前字符串的首字符地址。但是,c_str函数的返回值是const char*的,不能直接赋值给char*,所以就需要我们进行相应的操作转化。

  1. string str="a";
  2. const char *ss=str.c_str();

而反过来,很方便:

  1. char a[]="hello";
  2. string str=a;

附录A:C串功能函数

这边附上另外一篇文档的链接:【C语言字符串操作】
其实c++api上都有,这边挑选几个复制过来:

  1. strcat
  2. 语法:
  3. #include <string.h>
  4. char *strcat( char *str1, const char *str2 );
  5. 功能:函数将字符串str2 连接到str1的末端,并返回指针str1. 例如:
  6. printf( "Enter your name: " );
  7. scanf( "%s", name );
  8. title = strcat( name, " the Great" );
  9. printf( "Hello, %s\n", title );
  1. strchr
  2. 语法:
  3. #include <string.h>
  4. char *strchr( const char *str, int ch );
  5. 功能:函数返回一个指向str ch 首次出现的位置,当没有在str 中找ch到返回NULL
  1. strcmp
  2. 语法:
  3. #include <string.h>
  4. int strcmp( const char *str1, const char *str2 );
  5. 功能:比较字符串str1 and str2, 返回值如下:
  6. 返回值
  7. 解释
  8. less than 0 str1 is less than str2
  9. equal to 0 str1 is equal to str2
  10. greater than 0 str1 is greater than str2
  11. 例如:
  12. printf( "Enter your name: " );
  13. scanf( "%s", name );
  14. if( strcmp( name, "Mary" ) == 0 )
  15. printf( "Hello, Dr. Mary!\n" );
  1. strcpy
  2. 语法:
  3. #include <string.h>
  4. char *strcpy( char *to, const char *from );
  5. 功能:复制字符串from 中的字符到字符串to,包括空值结束符。返回值为指针to
  1. strlen
  2. 语法:
  3. #include <string.h>
  4. size_t strlen( char *str );
  5. 功能:函数返回字符串str 的长度( 即空值结束符之前字符数目)。
  1. strstr
  2. 语法:
  3. #include <string.h>
  4. char *strstr( const char *str1, const char *str2 );
  5. 功能:函数返回一个指针,它指向字符串str2 首次出现于字符串str1中的位置,如果没有找到,返回NULL

附录B:string类常用函数

这边附上另外一篇文档的链接:【string字符串操作】

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注