C++Primer 3.5.1: C-style character string

  1. C-Style Character Strings
    1. C library string functions
    2. Mixing library strings and C-Style Strings

C-Style Character Strings

C-Style strings are not a type. They are a convention for how to represent and use character strings.

C-Style strings指的是一种指定如何表示和使用character strings的规定。该规定要求:

  • character strings存储在character array中;
  • null terminated。即该character array最后一个element为null character '\0'(ansii = 0)

例如,C++中的string literals就是一个C-Style string(从C中继承而来),也就是说,在C++中string literalsnull terminated。注意在这里出现了几个很容易混淆的定义,我们需要通过实际例子来辨析:

'a'  // a character 'a'
"hello, world";  // a string literal, has '\0'
char sa[] = {'h','e','l','l','o'};  // sa is a character array, no '\0'
char *p = "hello, world";  // p is a pointer to a string literal "hello, world", p points to the first element of this string literal
string s("hello, world");  // s is a string(library type)

首先,string literals指的就是一个字符串字面量,其是一个常量,存储在DS段。因为C/C++中的string literals都遵循C-Style Strings规定,因此C/C++中的string literals都是存储在一个character array中,且这个character array的最后一个元素是'\0'

其次,sa是一个charater array数组,也就是常说的字符数组(char数组)。数组中的每个element都是一个character,也就是常说的字符(char)。字符数组并不遵循C-Style strings规则,所以其并不要求最后一个元素是'\0',即并不是null terminated。但是需要注意的是,尽管sa在进行操作时会被compiler转换为一个指向首元素的指针,但是其是一个char * const的指针,即指针自身不能被修改,所以并不能给sa赋值。同理,也不能再次使用string literalssa赋值(注意这里如果使用string literalssa进行初始化是可以的)。

类似的,p是一个char类型的指针,也就是常说的char *,其指向一个string literals常量,更准确的说是指向该hello, world的首元素(即h字符)。因为string literals是一个character array,所以可以通过这个指向首元素的指针来实现subscript操作。但是需要注意的是,因为此时hello, world是一个常量,所以尽管可以通过取下标获得其中某个element,但是并不能修改这个element。更多关于char*char[]的区别可以查看here

最后,就是string类,其是library type,相应的操作符都在类中被重载。注意,在C++11标准中,明确规定了string也是null terminated,即以'\0'结尾,here

C library string functions

因为C standard library并没有重载诸如+==等操作符,所以并不能用C++中的string类中重载这些操作符对C-Style string进行操作。相反,C中提供了一系列functions来操作C-Style string。例如:

Functions Meaning
strlen(p) Returns the length of p, not couting the null
strcmp(p1, p2) Compares p1 and p2 for equality. Returns 0 if p1 == p2, a positive value if p1 > p2, a negative value if p1 < p2.
strcat(p1, p2) Appends p2 to p1. Returns p1.
strcpy(p1, p2) Copies p2 into p1. Returns p1.

其中这些函数的实参必须是指向null terminated array的指针。如果传入的指针不是指向null terminated array,那么会出现undefined的情况。例如strlen,则会不断循环直到找到null

在C++中,因为string已经重载了很多操作符,所以使用起来很方便。例如,当我们想拼接两个字符串时:

/*  c++  */
string s1("hello");
string s2("world");
string largeStr = s1 + ' ' + s2;

/*  c  */
char s1[] = "hello";
char s2[] = "world";
char largeStr[12];
strcpy(largeStr, s1);
strcat(largeStr, " "); // can't use ' ', because " " is a string literal, can be converted to pointer 
strcat(largeStr, s2);

可以看到,在C中想要实现拼接字符串非常麻烦,需要定义一个largeStr来接收拼接好的字符串;并且还需要计算好新的字符串的长度。但是在C++中如果使用string类的话则可以直接使用重载的+进行操作。

Mixing library strings and C-Style Strings

通常来说,在任何要求使用string literal的地方,我们都可以使用null-terminated array。但是反过来却不行,即我们不能在要求使用C-Style Strings的地方使用library strings

string s("hello, world");
char *str = s;  // error, can't initialize a char* from a string
const char *str = s.c_str();  // ok

但是string类中提供了一个member function来返回一个C-Style string。具体来说,c_str()函数返回一个指向一个null-terminated数组首元素的指针,其中这个数组具有与string一样的elements。换句话说,c_str()提供了一个方法来获得C-Style string,这个返回的null-terminated数组与string中的内容一样。但是需要注意的是,c_str()并不能保证一直有效,任何有可能改变s的值的操作都会使这个返回的数组失效。


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 gzrjzcx@qq.com

文章标题:C++Primer 3.5.1: C-style character string

文章字数:1.2k

本文作者:Alex Zou

发布时间:2019-12-09, 13:45:32

最后更新:2024-07-10, 03:02:36

原始链接:https://www.hellscript.cc/2019/12/09/subposts_cppPrimer/CPN-3-5-1-C-style-character-string/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

有钱的捧个钱场,没钱的借钱也捧个钱场