字符数组&字符串

定义&初始化

char str[] = {'a', 'b', 'c', 'd'};

char str[] = "abcd";

==注意:字符串包含最后\0终止符,所以其实有五个元素==

因此字符串不完全等于字符数组, 终止字符可以直接用ASCII码值0来表示,字符形式需要用\0来表示

如果再字符串中想定义双引号需要加\表示转义 char str[] = "abc\"";否则遇到引号会认为字符结束了

因此字符串其实就等价于有终止字符的字符数组

字符串实际上是字符数组的首地址,因此字符串变量可以被看作是一个指向字符的指针。当我们对字符串变量进行加法或减法运算时,实际上是在进行指针运算

输入/输出

可以用循环输入 for(int i = 0;i < n;i ++) cin >> str[i];

但一般不会告诉你有几个字符,所以用scanf("%s", str);cin >> str;直接输入整个字符串是更好的选择

==注意会带终止字符,占用地址更大==

  • 输出是会一直挨个遍历直到遇到了终止符,如果没有可能会输出乱码

  • 普通输入会以空格分隔 例如 abc def

    则读取到的字符串是abc

    可以使用cin.getline(str, 10);//第一个参数是字符数组,第二个参数是最大输入的字符个数

    或者stdio.h中的fgets(str, 10, stdin);//第三个参数表示从哪输入,stdin表示终端

<string.h>中的常用函数

strlen获取字符串长度

int len = strlen(str)此长度并非数组长度而是以结束字符结尾的长度

strcpy 复制字符串

strcpy(dst, src)将第二个字符串复制到第一个字符数组

要确保字符数组有足够的长度可以容纳归第二个字符串

==只会复制终止符前面的内容==

strcat拼接

strcat(a,b)将第二个字符串复制到第一个字符串的末尾,相当于两个字符串连接,同样需要确保内存大小

strcmp比较大小

int order = strcmp(a,b);比较两个字符串的字典序大小,返回其比较顺序

1
2
3
order < 0 		// a < b
order == 0 // a == b
order > 0 // a > b

strstr

char *c = strstr(a,b); 判断字符串a是否包含字符串b,返回的结果是a中首次出现b的地址,类型为char *c (指针类型)

如果用结果减去a,即int index = c - a;则会返回下标;如果找不到b会返回NULL(NULL 等价于 0)

直接判断结果可以知道a是否包含b

strtok 分隔字符串

将第一个字符串以第二个字符串中出现的字符进行分隔

找到第一个非分隔符的位置返回地址,如果没有则返回NULL,同时将这个地址之后的第一个分隔符转化为终止符

1
2
3
char str[] = "= one + two * (three / four)";
char delimiter[] = "=+*/() "; //设定分隔值
char* token = strtok(str, delimiter);

输出token,则可以得到字符串one

并且strtok是比较特殊的函数,它在调用时会记录上一次分隔的位置,再次调用时,第一个参数只需要传入NULL,可通过下述代码,token会指向这些位置

通过while循环,提取原字符串的one two three four

1
2
3
4
5
while(token){
cout << token << endl;
if(token == NUll) break;
token = strtok(NULL, delimiter);
}

memset & memcpy

对内存进行操作,由于字符的内存恰好是1byte,故也可以看作是对字符进行操作

memset(arr, ch, sizeof(arr));

  • 第一个参数是内存的起始地址
  • 第二个参数是设置的值,字符型(-128到127)
  • 第三个参数是内存的长度

代表将内存中从这个字符数组开始,对应长度的内存都赋值为第二个参数

当然其他类型的数组也可以用memset

但是,比如int占4个字节,如果赋值为1,对应的二进制是由四个值为1的字节组成的,即在内存中以4个00000001组成,其结果是一个大整数(但是0和-1没有问题,因为内存中0的二进制都是0来表示,-1都是1来表示)

memcpy 将一段内存从一个位置复制到另一个位置

memcpy(dst, src, sizeof(src));

  • 第一个参数代表目标地址
  • 第二个参数代表被复制的地址
  • 第三个参数代表要复制的内存长度

用途:比如数组无法直接用等于号赋值,所以如果想对数组进行赋值,就可以直接用memcpy

<stdlib.h>中的常见函数

==将字符串转化成数值==

atoi & atoll & atof

  • a代表ASCII码表
  • i, f, ll分别对应int,float类型,long long类型 (注意是代表float类型而不是转换成float,实际转化成double)

通过这些函数可以将字符串转化成对应类型的数值

例如cout << atoi("123") << endl;

字符串要是合法的数值,不然得到的结果是0. 例如cout << atof("abc") << endl;

<ctype.h>中的常见函数

==用于判断字符的类型== (具体如下图)

ctype

isprint

判断是否是可打印字符

isspace

判断是否是空格

isgraph

判断是否是可绘制字符

ispunct

判断是否是标点符号

isalnum

判断字符串中的字符是否都是字母或数字

isdigit

判断是否是数字

isalpha

判断是否是字母

isupper

判断是否是大写字母

islower

判断是否是小写字母

toupper & tolower

返回字母的大写或者小写形式

string

定义&初始化

引入头文件 include <string>

  • 初始可直接用字符串string str1 = "012345";

  • 或者使用另一个字符串 string str2 = str1;

  • 也可以像vector一样用长度加字符来初始化string str3(6, '#');

  • 也可以用括号代替等于号 string str4(str1); 或者 string str5("012345");

  • 利用format构造字符串形如:

    format("{0}.zip/{0}/{1}/{1}.cpp", id, problem)

这种用括号进行初始化的方式叫做构造函数

1
2
3
4
5
6
7
8
//用括号的好处在于可用添加更多的参数
//如果第一个参数是string类型,可以额外跟两个参数
string str6(str1, 2); //代表从第几个字符开始,使用多少个字符初始化
string str7(str1, 2, 2);
//如果第一个参数是字符串类型,可以跟一个参数
string str8("012345", 2); //代表使用多少个字符初始化
string str8({48, '1', '2'}); //列表初始化
string str10(str1.begin() + 1, str1.end() - 1); //迭代器初始胡

输入/输出

输入输出可以直接当一个普通变量来进行

  • 使用cin >> str;也是根据空格分格;

  • 如果想要输入整行,需要使用getline(cin, str);

  • 同时也可以使用范围循环来遍历string的每个字符

    for (char& c: str) {};

比起C语言的字符串简单了很多,不需要考虑终止符,非常的直观清晰

string所支持的运算&函数

==stringvector很像,但string不属于容器==

支持的运算符

  • = 赋值运算
  • <=> 比较运算
  • [ ] 下标访问运算
  • + 加法运算,字符串的拼接
  • += 直接将字符串加到末尾

支持的函数

访问

  • at —> 带范围检测的下标访问

  • front —> 获取第一个字符

  • back —> 获取最后一个字符

  • c_str —> 返回C语言字符

    比如printf("%s", str.c_str());

迭代器

  • begin —> 起始迭代器
  • end —> 末尾迭代器

容量

  • empty —> 判断是否为空
  • size —> 获取字符个数
  • length —> 获取字符个数

修改

  • clear —> 清空字符串

  • resize —> 改变大小

  • push_back —> 将字符插入末尾

  • pop_back —> 移除末尾字符

  • insert —> 插入字符(串)

    ==除了可以使用迭代器表示位置外,还可以直接用下标表示==

    例如"abc"插入后str.insert(1, "def");得到字符串"abcdef"

  • erase —> 删除子串

    str.erase(one, two);同样可以用下标来表示

    第一个参数表示开始删除的位置,第二个参数表示删除的个数;如果第二个参数不填则默认删除之后所有的元素

  • append —> 将字符串插入末尾

  • replace —> 替换一段字串

    str.replace(1,2,"xyz");

    参数分别表示开始的位置,结束的位置,插入的元素(同样可以用下标表示位置)

操作

  • find —> 寻找字串首次出现的位置

    对于字符串"This is island";

    int pos = str.find("is");返回第一次出现的下标

    还可以指定从哪个下标开始查找 int pos = str.find("is", 3);

    如果找不到会返回string::npos(string的一个特殊值,代表没有找到,属于unsigned long long类型,具体值是无符号整数的最大值,因为内存中全是1,所以也等于有符号的-1;所以有些代码会直接判断find的值是否为-1,来表示是否找到,和使用string::npos来判断等价)

  • substr —> 返回指定子串

    string sub = str.substr(2,3);根据开始下标(第一个参数)和返回长度(第二个参数)来返回一个子串,如果不填第二个参数,则返回开始下标到结尾子串

  • starts_with —> 前缀判断

    ends_with —> 后缀判断

    bool res = str.starts_with("hel");

其他普通函数

  • stoi —> 将string转成数值(同样有stollstod的版本)
  • to_string —> 将数值转成string
  • format构造函数 —> string str = format("d = {:.0f}", d);