[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;
}
posted @ 2023-04-03 09:05  __Helios  阅读(58)  评论(0编辑  收藏  举报