C风格字符串

尽管C++支持C风格字符串,但在C++程序中最好还是不要使用它们。这是因为C风格字符串不仅使用起来不太方便,而且极易引发程序漏洞,是诸多安全问题的根本原因。

字符串字面值是一种通用结构的实例,这种结构即是C++由C继承而来的C风格字符串。C风格字符串不是一种类型,而是为了表达和使用字符串而形成的一种约定俗成的写法。按此习惯书写的字符串存放在字符数组中并以空字符串结束。以空字符结束的意思是在字符串最后一个字符后面跟着一个空字符(‘\0‘)。一般利用指针来操作这些字符串。

C标准库String函数

下表列出了C语言标准库提供的一组函数,这些函数可用于操作C风格字符串,它们定义在出string头文件中,出string是C语言头文件string.h的C++版本。

C风格字符串的函数

strlen(p)      返回p的长度,空字符不计算在内

strcmp(p1,p2)         比较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;  //严重错误:ca没有以空字符结束

此例中,ca虽然也是一个字符数组但他不是以空字符作为结束的,因此上述程序将产生未定义的结果。strlen函数将有可能沿着ca在内存中的位置不断向前寻找,直到遇到空字符才停下来。

比较字符串

比较两个C风格字符串的方法和之前学习过的比较标准库string对象的方法大相径庭。比较标准库string对象的时候,用的是普通的关系运算符和相等性运算符:

string s1="A string example";

string s2="A different string";

if(s1<S2)  //false:s2小于s1

如果把这些运算符用着两个C风格字符串上,实际比较的将是指针而非字符串本身:

const char ca1[]="A string example";

const char ca2[]="A different string";

if(ca1<ca2)   //未定义的:试图比较两个无关地址

谨记之前介绍过的,当使用数组的时候其实真正用的是指向数组首元素的指针。因此,上面的if条件实际上比较的是两个const char*的值。这两个指针指向的并非同一个对象,所以将得到未定义的结果。

要想比较两个C风格字符串需要调用strcmp函数,此时比较的就不再是指针了。如果两个字符串相等,strcmp返回0,如果前面的字符串较大,返回正值;如果后面的字符串较大,返回负值:

if(strcmp(ca1,ca2)<0)  //和两个string对象的比较s1<s2效果一样

目标字符串的大小由调用者指定

连接或拷贝C风格字符串也与标准库string对象的同类操作差别很大。例如,要想把刚刚定义的那两个string对象s1和s2连接起来,可以直接携程下面的形式:

//将largeStr初始化成s1,一个空格和s2的连接

string largeStr=s1+“ ”+s2;

同样的操作如果放到ca1和ca2这两个数组身上就会产生错误了。表达式ca1+ca2试图将两个指针相加,显然这样的操作没什么意义,也肯定是非法的。

正确的方法是使用strcat函数和strcpy函数。不过要想使用这两个函数,还必须提供一个用于存放结果字符串的数组,该数组必须足够大以便容纳下结果字符串及末尾的空字符。下面的代码虽然很常见,但是充满了安全风险,极易引发严重错误:

//如果我们计算错了largeStr的大小将引发严重错误

strcpy(largeStr,ca1);  //把ca1拷贝给largeStr

strcat(largeStr," ");  //在largeStr的末尾加上一个空格

strcat(largeStr,ca2);  //把ca2连接到largeStr后面

混用string对象和C风格字符串

允许使用字符串字面值来初始化string对象:

string s("Hello World!");  //s的内容是Hello World

更一般的情况是,任何出现字符串字面值的地方都可以用以空字符结束的字符数组来替代:

  • 允许使用以空字符结束的字符数组来初始化string对象或为string对象赋值。
  • 在string对象的加法运算中允许使用以空字符结束的字符数组作为其中一个运算对象(不是两个运算对象都是):在string对象的复合赋值运算中允许使用以空字符数组作为右侧的运算对象。

上述性质反过来就不成立了:如果程序的某处需要一个C风格字符串,无法直接用string对象来代替它。例如,不能用string对象直接初始化指向字符的指针。为了完成该功能,string专门提供了一个名为c_str的成员函数:

char *str=s;//错误:不能用string对象初始化char*

const char *str=s.c_str();  //正确

顾名思义,c_str函数的返回值是一个C 风格的字符串。也就是说,函数的返回结果是一个指针,该指针指向一个以空字符结束的字符数组,而这个数组所存的数据恰好与那个string对象的一样。结果指针的类型是const char*,从而确保我们不会改变字符数组的内容。

我们无法保证c_str函数返回的数组一直有效,事实上,如果后续的操作改变了s的值就可能让之前返回的数组失去效用。

使用数组初始化vector对象

前面介绍过不允许使用一个数组为另一个内置类型的数组赋初始值,也不允许使用vector对象初始化数组。相反的,允许使用数组类初始化vector对象。要实现这一目的,只需指明要拷贝区域的首元素地址和尾后元素地址就可以了:

int int_arr[]={0,1,2,3,4,5};

//ivec有6个元素,分别是int_arr中对应元素的副本

vector<int> ivec(begin(int_arr),end(int_arr));

在上述代码中,用于创建ivec的两个指针实际上指明了用来初始化的值在数组int_arr中的位置,其中第二个指针应指向待拷贝区域尾元素的下一个位置。此例中,使用标准库函数begin和end来分别计算int_arr的首指针和尾后指针,在最后的结果中,ivec将包含6个元素,它们的次序和值都与数组int_arr完全一样。

C风格字符串,布布扣,bubuko.com

时间: 2024-12-24 04:06:56

C风格字符串的相关文章

c风格字符串,字符串字面值,c++字符串

C风格字符串:本质上就是以空字符null为结束符的数组 可以简单的理解为:有'\0'的是c风格字符串,无'\0'的是普通字符数组 字符串字面值:是一串常量字符,字符串字面值常量用双引号括起来的零个或多个字符表示. C++字符串:通俗而言是string类,为和c语言兼容,C++中所有的字符串字面值都由编译器自动在末尾添加一个空字符.(实际上在c++中,string最好直接理解为一个基本类型,相关操作都封装在string类中,避免使用char *出错) 由下面的代码可以看出: int main()

C风格字符串和C++ string 对象赋值操作的性能比较

<<C++ Primer>> 第四版 Exercise Section 4.3.1 部分Exercise 4.2.9 习题如下: 在自己本机执行如下程序,记录程序执行时间: 1 #include "stdafx.h" 2 #include <iostream> 3 #include <string> 4 #include <vector> 5 #include <ctime> 6 7 using namespace

string字符串转C风格字符串 进而转换为数字

要求如题 头文件stdlib.h中有一个函数atof() 可以将字符串转化为双精度浮点数(double) double atof(const char *nptr); 此字符串为C风格字符串,因此需要将string转化为C风格字符串 此时可用到一个函数c_str() const char *c_str() 参考资料: string中c_str().data().copy(p,n)函数的用法 在使用c_str()时遇到了一个问题–此函数的返回值为const char * 因为是const数据类型,

删除 C 风格字符串中间的 &#39;*&#39;(不用库函数)

char* removeMiddleStar(char *str) { if (!str) return str; char *p = str; for(; *p == '*'; ++p); char *q = p; while(*++q != '\0'); while(*--q == '*'); for (char *k = p; *k != '\0'; ++k) if ((k < q && *k != '*') || k >= q) *p++ = *k; *p = '\0'

【C++ Primer每日一刷之八】之八 C 风格字符串

4.3 C 风格字符串 尽管 C++ 支持 C 风格字符串,但不应该在 C++ 程序中使用这个类型.C 风格字符串常常带来许多错误,是导致大量安全问题的根源. 在前面我们第一次使用了字符串字面值,并了解字符串字面值的类型是字符常量的数组,现在可以更明确地认识到:字符串字面值的类型就是const char 类型的数组.C++ 从 C 语言继承下来的一种通用结构是C 风格字符串,而字符串字面值就是该类型的实例.实际上,C 风格字符串既不能确切地归结为 C 语言的类型,也不能归结为 C++ 语言的类型

CareerCup之1.2C风格字符串翻转

[题目] 原文: Write code to reverse a C-Style String. (C-String means that "abcd" is represented as five characters, including the null character.) 译文: 写代码翻转一个C风格的字符串.(C风格的意思是"abcd"需要用5个字符来表示,包含末尾的 结束字符) [分析] 这是一道经典的面试题目,虽然看似简单,但仍然有陷阱.唯一的陷阱

动态数组、C风格字符串、字符串字面值

动态数组 每一个程序在执行时都占用一块可用的内存空间,用于存放动态分配的对象,此内存空间称为程序的自由存储区(free store)或堆(heap).C语言使用malloc和free在堆中分配存储空间,而C++语言则使用new和delete表达式实现相同的功能. 动态分配数组时,如果数组元素具有类类型,将使用该类的默认构造函数实现初始化:如果数组元素是内置类型,则无初始化: string *psa = new string[10]; //array of 10 empty strings int

C风格字符串与C++风格字符串

C风格字符串与C++风格字符串 C风格字符串:对字符串进行操作的 C 函数定义在头文件<cstring>中: 1. 字符串定义:char* result: 2. 字符串的最后一个字符是null字符('\0'),可以通过这个字符确定字符串的结尾. 3. strlen()返回的是字符串的大小:因此,分配空间的时候,需要比字符串的实际空间大1. e.g. char* copyString(const char* inString) { char *result = new char[strlen(i

C++ 标准头文件与C头文件区别与联系以及C风格字符串

1.cstdlib是C++里面的一个常用头文件, 等价于C中的<stdlib.h>. 2.一般一个带".h" 扩展名的库文件,比如iostream.h.这是延续C语言的,为了兼容C.在新标准的库中都有一个 不带".h"扩展名的相对应,区别除了后者好多改进之处,还有一点就是后者的东西都放进了"std"名字空间中. 但是 string.h有点特别,问题在于C++要兼容C的标准库,C的标准库里也有一个名字叫做"string.h&q