技术交流QQ群:1027579432,欢迎你的加入!
1.Cpp中的字符串
- C++提供了以下两种类型的字符串表示形式:
- C风格字符串
- C++引入的string类类型
1.1 C风格字符串
- C风格的字符串起源于C语言,并在C++中继续得到支持。字符串实际上是使用null字符'\0'终止的一维字符数组。因此,一个以null结尾的字符串,包含了组成字符串的字符。
- 下面的声明和初始化创建了一个"Hello"字符串。由于在数组的末尾存储了空字符,所以字符数组的大小比单词"Hello"的字符数多一个。
char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
- 依据数组初始化规则,可以把上面的语句写成以下语句:
char greeting[] = {'H', 'e', 'l', 'l', 'o', '\0'};
-
以下是C/C++中定义的字符串的内存表示:
- 其实,不需要把null字符放在字符串常量的末尾。C++编译器会在初始化数组时,自动把'\0'放在字符串的末尾,如下面的例子:
#include "iostream" using namespace std; int main(){ char greeting[6] = {'H', 'e', 'l', 'l', 'o'}; cout << "greeting: " << greeting << endl; return 0; }
-
C++中有大量的函数用来操作以null结尾的字符串,见下表:
// 字符串中的常见函数: char str1[11] = "hello"; char str2[11] = "world"; char str3[11]; int len, result; // 复制str1到str3 strcpy(str3, str1); cout << "strcpy(str1, str3):" << str3 << endl; // 连接str1和str2 strcat(str1, str2); cout << "strcat(str1, str2):" << str1 << endl; // 连接后,str1的总长度 len = strlen(str1); cout << "strlen(str1):" << len << endl; // str1与str2比较 result = strcmp(str1, str2); cout << "strcmp(str1, str2):" << result << endl;
1.2 C++中的字符串
- C++标准库提供了string类类型,支持上述所有的操作,另外还增加了其他更多的功能,见下面的实例:
#include "string" // Cpp中的字符串 string s1 = "abandon"; string s2 = "banana"; string s3; // 复制s1到s3 s3 = s1; cout << "s3:" << s3 << endl; // 连接s1和s2 s3 = s1 + s2; cout << "s1 + s2:" << s3 << endl; // 连接后的s3总长度 int len1, result1; len1 = s3.size(); cout << "s3.size():" << len1 << endl; // 比较s1和s2 result1 = s1 > s2; cout << "s1 > s2:" << result1 << endl;
2.字符串中的细节知识
- string类提供了一系列针对字符串的操作,比如:
- append() -- 在字符串的末尾添加字符
- find() -- 在字符串中查找字符串
- insert() -- 插入字符
- length() -- 返回字符串的长度
- replace() -- 替换字符串
- substr() -- 返回某个子字符串
// 4 string类中的其他函数 string name = "Curry"; cout << "The length of string is:" << name.length() << endl; // 拼接 name.append("Coder"); cout << "name:" << name << endl; // 删除 int pos; pos = name.find("Coder"); // 查找Coder在字符串中的位置 cout << "pos = " << pos << endl; name.replace(pos, 4, ""); // 从位置pos开始,后面的连续4个字符都将被替换为空格 cout << "name = " << name << endl; // 找子串 int first = name.find_first_of("r"); // 从头找到字符r的位置 int last = name.find_last_of("r"); // 从尾部找字符的位置 cout << name.substr(first + 1, last - first -1) << endl; // 提取两个r之间的字符子串
- C++中输入的方式很多,下面介绍与C语言中getchar()类似的函数cin.getline()函数,cin.getline()是在输入一段字符完成后开始读取数据(注意,是输入完成后,以Enter为结束标志)
// 5 cin.getline()函数 char X[N]; cin.getline(X,N); int a = 0, b = 0; for (int i=0; i < N;i++){ if (X[i] == '#') // #是结尾标志 break; if (X[i] >= '0' && X[i] <= '9') // 统计数字个数 a++; if ((X[i] >= 'a' && X[i] <= 'z') || (X[i] >= 'A' && X[i] <= 'Z')) // 统计字母个数 b++; } cout << "a = " << a << " b = " << b << endl;
- 字符串与vector
- 字符串常量与标准库string不是同一种类型
string s("hello"); cout << "s.size() = " << s.size() << endl; // 正确 // cout << "hello".size() << endl; 错误 cout << s + "world" << endl; // 正确 // cout << "hello" + "world" << endl; 错误
-
strlen、sizeof与size()求字符串长度的区别:
cout << strlen("123") << endl; //返回 3 cout << sizeof("123") << endl; //返回 4 string s = "123"; cout << s.size() << endl; //返回 3
-
sizeof和strlen区分:
- sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型。该类型保证能容纳实现所建立的最大对象的字节大小。
- sizeof是运算符,strlen是函数
- sizeof可以用类型做参数,如sizeof(int),strlen只能用char*做参数,且必须是以'\0'结尾的。sizeof还可以用函数做参数,如short f(); cout << sizeof(f());
- 数组做sizeof的参数不退化,传递给strlen就退化为指针了
- 大部分编译程序在编译的时候就把sizeof计算过了,是类型或是变量的长度,这就是 sizeof(x)可以用来定义数组维数的原因。
char str[20] = "0123456789"; int a = strlen(str); 10 int b = sizeof(str); 20
- strlen的结果要在运行的时候才能计算出来,是用来计算字符串的长度,不是类型占内存的大小
- sizeof后如果是类型必须加括弧,如果是变量名可以不加括弧。这是因为sizeof是个操作符不是个函数
- 当适用一个结构类型或变量时,sizeof返回实际的大小;当适用一静态地空间数组,sizeof 返回全部数组的尺寸;sizeof操作符不能返回动态地被分派了的数组或外部的数组的尺寸。
- 字符数组可以用数组名来输出数组内容,而普通数组不行
- 原因:因为char型数组中的每一个元素都是1个字节,所以每一个字符之间的地址都是+1的,是连续的。所以当cou 输出时读到字符数组中的 '\0'便停止输出; 而int数组每个元素占4个字节,所以数组中每个元素地址的间隔是4,但其实它也是连续的,出现乱码是因没找到结束符。
int aa[10] = {1, 2, 3, 4, 6, 7}; char bb[6] = {'h', 'a', 'a', 'p', 'y', '\0'}; char cc[] = "happy"; cout << aa << endl; cout << bb << endl; cout << cc << endl;
- 原因:因为char型数组中的每一个元素都是1个字节,所以每一个字符之间的地址都是+1的,是连续的。所以当cou 输出时读到字符数组中的 '\0'便停止输出; 而int数组每个元素占4个字节,所以数组中每个元素地址的间隔是4,但其实它也是连续的,出现乱码是因没找到结束符。
- 字符串常量与标准库string不是同一种类型
- char数组的几种表示方法
- C风格
char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'}; char greeting[] = {'H', 'e', 'l', 'l', 'o', '\0'};
- C++风格
- string类
- char*:指向字符串的指针,指向字符串的首个字母
- const char*(常量指针):指向的是一个const char类型,不能通过当前的指针对字符串的内容作修改
- char * const(指针常量):指针是一个常量,不能修改指针
- char []:与char*有很多的相同点,代表字符数组,可以对应一个字符串;如char * a = "string1"; char b[] = "string2"; a是一个指向char类型的字符串的指针;b是一个字符数组
- char *与char[]的不同:a是变量,指向可以改变;b是常量,是该字符数组的首地址,其值不能改变
- C风格
3.注意的地方1
#include <iostream>
using namespace std;
int main(){
// str1与str2是两个字符串数组,我们会为它们分配长度为12字节的空间,因为是两个初始地址不同的数组,故str1!=str2
char str1[] = "hello world";
char str2[] = "hello world";
if(str1 == str2)
cout << "str1与str2相同\n";
else
cout << "str1与str2不同\n";
// str3 与 str4是两个指针,无须为它们分配内存来存储字符串的内容,只需要把它们指向"hello world"在内存中的地址就可以了。
// 由于"hello world"是字符串常量,它在内存中只有一个拷贝,因此str3与str4指向同一个地址
char *str3 = "hello world";
char *str4 = "hello world";
if(str3 == str4)
cout << "str3与str4相同\n";
else
cout << "str3与str4不同\n";
return 0;
}
4.注意的地方2
#include <iostream>
#include <cstring>
using namespace std;
// 数组中注意的点
int GetSize(char *data){
return sizeof(data);
}
int GetSize1(char data[]){
return sizeof(data);
}
int GetSize2(int* data){
return sizeof(data);
}
int GetSize3(int data[]){
return sizeof(data);
}
int main(){
char* ch1 = "abcdefghijk";
int size11 = sizeof(ch1);
char* ch11 = ch1;
int size12 = sizeof(ch11);
int size13 = GetSize(ch1);
int size14 = GetSize1(ch1);
/*---------------------------------------------------------------*/
char ch2[] = "abcdefghijk";
int size21 = sizeof(ch2);
char* ch21 = ch2;
int size22 = sizeof(ch21);
int size23 = GetSize(ch2);
int size24 = GetSize1(ch2);
/*---------------------------------------------------------------*/
int data[] = {1, 2, 3, 4, 5};
int size31 = sizeof(data);
int* data11 = data;
int size32 = sizeof(data11);
int size33 = GetSize2(data);
int size34 = GetSize3(data);
/*---------------------------------------------------------------*/
cout << "size11 = " << size11 << endl;
cout << "size12 = " << size12 << endl;
cout << "size13 = " << size13 << endl;
cout << "size14 = " << size14 << endl;
/*---------------------------------------------------------------*/
cout << "size21 = " << size21 << endl;
cout << "size22 = " << size22 << endl;
cout << "size23 = " << size23 << endl;
cout << "size24 = " << size24 << endl;
/*---------------------------------------------------------------*/
cout << "size31 = " << size31 << endl;
cout << "size32 = " << size32 << endl;
cout << "size33 = " << size33 << endl;
cout << "size34 = " << size34 << endl;
return 0;
}