字符串基础知识总结

有几种不同类型的字符串: c风格字符串(包括字符串字面常量和指向以空字符结尾的字符数组的指针),string类型(类类型)

c风格字符串

  • c风格字符串必须符合某种编码(如ASCII),并且除了字符串的末尾之外,字符串里面不能包含空字符(空字符是字符结束的标志).这些限制使得c风格字符串只能保存文本数据,而不能保存二进制数据(如图片,音频等)

  • c风格字符串不保存自身长度,要获取一个c字符串的长度,需要遍历整个字符串,直到遇到代表字符串结尾的空字符为止,这个操作的时间复杂度为O(n)(n是字符串长度).

  • c字符串容易造成缓冲区溢出

    • 如使用strcat函数将src字符串中的内容拼接到字符串的末尾时,

      1
      char *strcat(char* dest, const char* src)

      由于c字符串不记录自身的长度,所以strcat假定用户在执行这个函数时,已经为dest分配了足够多的内存,可以容纳src字符串中的所有内容,但是万一这个假设不成立就会造成缓冲区溢出.

  • c字符串修改字符串长度时需要进行内存重分配;内存重分配涉及复杂的算法,而且可能需要执行系统调用,通常来说比较耗时.

字符串,字符数组相关API

  • c标准库string函数, 共有4个函数
    • strlen(p), strcmp(p1, p2), strcat(p1, p2), strcpy(p1, p2)
    • 传入此类函数的指针必须指向以空字符结尾的数组
      不能使用strlen函数求”使用列表初始化的字符数组的长度,因此列表初始化的字符数组不以空字符结尾
    • strlen计算c风格字符串的长度时,c风格字符串末尾的空字符不计算在内
  • strcpy(char* dest, const char*src)
    • 把src所指向的字符串复制到dest,包括结尾处的空字符
    • 如果目标数组dest的内存空间比src的内存空间小,会出现缓冲区溢出
  • strcmp(const char* str1, const char* str2)
1
2
3
4
5
6
7
8
9
10
11
12
void testCharArray3() {
cout << "strlen(\"danam\"): " << strlen("danam") << endl;

// 允许使用以空字符结尾的字符数组类初始化string对象或为string对象赋值
string s("danam");
cout << "s:" << s << " s.size():" << s.size() << endl;

char c[] = "nice";
cout << "strlen(c): " << strlen(c) << " c:" << c << endl;
string s1(c);
cout << "s1.size():" << s1.size() << " s1:" << s1 << endl;
}

运行结果

1
2
3
4
strlen("danam"): 5
s:danam s.size():5
strlen(c): 4 c:nice
s1.size():4 s1:nice

memset和memstcpy fill

  • memset
    • 头文件string.h(c++头文件cstring)
    • memset可以对数组中每个元素赋以相同的值.但是因为memset按字节赋值,即对每个字节赋相同的值,一般只用来填充char型数组(char类型占一个字节),如果填充int数组最好只在要对数组赋值0或-1时使用memset.
    • memset函数的格式为:memset(数组名,值,sizeof(数组名))
    • 与fill相比,memset执行速度较快.
  • fill
    • 头文件algorithm
    • fill()函数可以将数组或者容器中的某一段区间赋为某个相同的值.和memset不同,这里的赋值可以是数组类型对应范围的任意值.
    • fill函数格式:
      • fill(arr, arr+n, 0) (其中arr为指向数组首元素的指针,arr+n为指向数组尾元素的指针, 0为要赋的值) 
      • fill(vec.begin(), vec.end(), 0) (vec.begin()和vec.end()为迭代器表示的范围)