[C/C++] 字符串
在 C 语言中,字符串实际上是使用空字符 \0 结尾的一维字符数组。因此,\0 是用于标记字符串的结束。
字符串常量
// str是一个指针,初始化为一个字符串常量,str实际上是const char *,不能修改
// str和str2的地址是一样的,指向同一块地址
char * str = "hello world";
char * str2 = "hello world";
如果需要修改字符串,则需要使用字符数组
字符数组
一维字符数组
char str[] = "hello";
char str2[STR_LEN + 1] = "hello";
char str3[] = {'h', 'e', 'l', 'l', 'o'}; // 这种情况的数组没有办法当作字符串使用,因为没有'\0'
char str4[] = {'h', 'e', 'l', 'l', 'o', '\0'};
printf("%lu, %lu\n", sizeof(str) / sizeof(char), strlen(str)); // 6, 5
printf("%lu, %lu\n", sizeof(str2) / sizeof(char), strlen(str2)); // 6, 5
printf("%lu, %lu\n", sizeof(str3) / sizeof(char), strlen(str3)); // 5, 10 这个10是因为遇到str4的'\0'
printf("%lu, %lu\n", sizeof(str4) / sizeof(char), strlen(str4)); // 6, 5
二维字符数组
// 下面两种写法存储方式大有不同,一个是二维数组,一个是指针数组,存储空间不同
// week[0]相当于char*
char *week[] = {"Monday", "Tuesday", " Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
char week2[][10] = {"Monday", "Tuesday", " Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
printf("sizeof(week1) %lu\n", sizeof(week)); // 70
printf("sizeof(week2) %lu\n", sizeof(week2)); // 56
// 动态申请字符串数组空间
char *week3[7]; // 7表示数组有7个元素
for (int i = 0; i < 7; i++) {
week3[i] = (char *) malloc(10 * sizeof(char)); // 10 表示每个元素申请10个char空间
}
输入输出
char str1[20];
scanf("%s", str1); // 遇到空白符 或者制表符 会截断输入 scanf不安全,会越界
//scanf("%19s", str1); // 遇到空白符 或者制表符 会截断输入 安全的方式
printf("str1: %s\n", str1);
char str2[100];
fgets(str2, 20, stdin); /*从输入流stdin即输入缓冲区中读取20个字符到字符数组str中,包含空格*/
puts(str2);
常见错误
// 以为char * 是字符串类型,定义了一个变量就可以直接使用,由于没有对string初始化,不一定每次都出错
char *string;
scanf("%s",string);
// 空字符串
char buffer[100] = ""; // 空字符串 长度100,buffer[0]='\0'
char buffer1[] = ""; // 这个数组的长度只有1!buffer1无法存放字符串
API库函数
在C语言中所有的字符串都当作数组来处理,不能用运算符进行赋值和比较,相关操作的头文件是<string.h>
strlen
库函数 size_t strlen(const char *str) 计算字符串 str 的长度,不包含结尾的0。
char line[] = "hello";
printf("strlen(hello)=%lu\n", strlen(line)); // 5
printf("sizeof(hello)=%lu\n", sizeof(line)); // 6
⚠️ 此处有一个坑,strlen
函数返回值是size_t
无符号类型。因此不能对返回值进行算数运算比较,例如:
// 下面两行代码不等价,无符号数减无符号数不可能出现负数
if(strlen(x) >= strlen(y)){}
if(strlen(x) - strlen(y) >= 0){}
自定义strlen函数
size_t my_strlen(const char *s) {
int cnt = 0;
while (*s++ != '\0') {
// while (s[cnt] != '\0') {
cnt++;
}
return cnt;
}
strcmp/strncmp
进行比较(字典序),根据str1[index]和str2[index] ASCII的差值返回一个小于、等于、大于0的值
⚠️ 如果想只比较前K个字符的大小,则使用strncmp函数
char s1[] = "abc";
char s2[] = "bbc";
char s3[] = "abc";
char s4[] = "abc ";
printf("%d\n", strcmp(s1, s2)); // -1
printf("%d\n", strcmp(s1, s3)); // 0
printf("%d\n", strcmp(s1, s4)); // -32
自定义实现strcmp函数
#include <assert.h>
int my_strcmp(const char *s1, const char *s2) {
assert(s1 && s2);
while (*s1 == *s2) {
if (*s1 == '\0')
return 0;
s1++;
s2++;
}
if (*s1 > *s2) {
return *s1 - *s2;
}
if (*s1 < *s2) {
return *s1 - *s2;
}
}
strcpy/strncpy
库函数
char *strcpy(char *dest, const char *src)
把 src 所指向的字符串复制到 dest,它的返回值是dst
- 如果是字符串常量,无需strcpy,直接赋值即可
char *s = "title";
char *t;
s = t;
- 如果是字符数组,需要用到memcpy,不能直接赋值,以下用法是错误的
char str1[10], str2[10];
str1 = "abc"; // wrong
str2 = str1; // wrong
char str[10] = "abc";
- 示例
#include <stdlib.h>
#include <string.h>
char *dst = (char *)malloc(strlen(src) + 1);
strcpy(dst, src);
自定义实现strcpy函数
char *my_strcpy(char *dst, const char *src) {
if ((dst == NULL) || (src == NULL))
return NULL;
char *ret = dst;
while ((*dst++ = *src++) != '\0');
return ret;
}
⚠️ 目标数组dest不够大,而源src字符串的长度又太长,可能会造成缓冲溢出的情况
可以采用安全的函数strncpy(char *dest, const char *src, size_t n)
。第三个参数表示复制的字符数, 通常使用方式如下
strncpy(dest, src, sizeof(dest)-1);
dest[sizeof(dest) - 1] = '\0';
strcat/strncat
库函数 char *strcat(char *dest, const char *src)
把 src 所指向的字符串追加到 dest 所指向的字符串的结尾
⚠️如果目标数组dest不够大,而源src字符串的长度又太长,可能会造成缓冲溢出的情况
可以采用安全的函数strncat(char *dest, const char *src, size_t n)
,第三个参数表示复制的字符数, 通常使用方式如下
strncat(dest, src, sizeof(dest)- strlen(dest) - 1);
字符串搜索函数
在字符串中找字符 strchr(str, int c) / strrchr(str, int c)
在参数 str 所指向的字符串中搜索第一次/最后一次出现字符 c(一个无符号字符)的位置
char s[] = "hello";
char *p = strchr(s, 'l');
printf("%s %ld\n", p, p - s + 1); // llo 3
return 0;
字符串中找字符串 strstr(const char *s1, const char *s2) / strcasestr(const char *s1, const char *s2)
其他函数 strbrk/strstr/strspn/strsok/tolower/toupper
C++
C++ 提供了以下两种类型的字符串表示形式:
- 完全兼容C 风格字符串
#include<cstring>
- C++ 引入
string
类类型
C++ 中的 String 类
#include <iostream>
#include <string>
using namespace std;
int main () {
string str1 = "runoob";
string str2 = "google";
string str3;
int len ;
// 复制 str1 到 str3
str3 = str1;
cout << "str3 : " << str3 << endl;
// 连接 str1 和 str2
str3 = str1 + str2;
cout << "str1 + str2 : " << str3 << endl;
// 连接后,str3 的总长度
len = str3.size();
cout << "str3.size() : " << len << endl;
return 0;
}