文章目录
1. C/C++ 字符串概述
1.1 字符串常量
格式要求:
采用英文双引号包含的所有内容,C/C++ 语言规定,字符串常量都存在一个 ‘\0’ 结尾
特点:
字符串常量是常量,意味着它们在程序执行期间不能被修改。
在内存的【数据区】,在程序中存储字符串是存储的字符串所处内存的空间首地址,用
char *
存储对应的首地址。"ABCDEFG" 占用字节为 8 个字节!!!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
printf("字符串占用字节数: %ld\n", sizeof("ABCDEFG"));
/*
str 可以存储字符串常量在内存【数据区】的空间首地址
同时也是当前字符串下标为 0 的元素空间首地址。
*/
char * str = "1234567890";
printf("str : %s\n", str);
printf("%p\n", "1234567890");
printf("&str[5] : %s\n", &str[5]);
printf("*str : %c\n", *str);
printf("str[5] : %c\n", str[5]);
printf("\"1234567890\"[5] : %c\n", "1234567890"[5]);
return 0;
}
1.2 字符数组
格式要求:
字符数组是一组按顺序存储的字符,使用字符数组可以存储字符串。
例如:
char strArray[] = {'H', 'e', 'l', 'l', 'o', '\0'};
或者char strArray[] = "Hello";
。特点:字符数组是可变的,可以在程序执行期间修改其中的元素
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
char arr1[4] = {'a', 'b', 'c', '\0'};
/*
arr1 数组名数据类型为 char * 是当前字符数组空间首地址,同时也是
数组中下标为 0 的元素空间首地址。
可以将一个符合 C/C++ 规范的字符数组当做一个字符串【变量】操作。
C/C++ 规范要求末尾必须有 \0
*/
printf("arr1 = %s\n", arr1);
printf("arr1 = %p\n", arr1);
printf("arr1[1] = %c\n", arr1[1]);
arr1[1] = 'P';
printf("arr1 = %s\n", arr1);
char *str = "ABC";
str[1] = 'p'; // 段错误!!!字符串常量无法修改
printf("str = %s\n", str);
return 0;
}
2. 字符串函数
【注意】
- 字符串是一个常量,数据内容无法修改,地址无法修改
- 字符串函数操作请注意【内存空间问题】
- 字符串函数,注意其返回值类型
2.1 拷贝赋值功能相关函数(覆盖)
2.1.1 strcpy
格式
char * strcpy(char * dest, const char * src)
作用
将
src
指向得字符串内容,拷贝到dest
字符数据空间中。
2.1.2 strncpy
格式
char *strncpy(char *dest, const char *src, size_t n)
作用
将
src
指向得字符串内容,拷贝到dest
字符数据空间中,最多复制n
个字符
2.1.3 memcpy
格式
void *memcpy(void *dest, const void *src, size_t n)
作用
从
src
复制n
个字符到dest
中。
2.1.4 memmove
格式
void * memmove(void * dest, const void *src, size_t n)
作用
从
src
复制n
个字符到dest
的函数。
2.1.5 memset
格式
void * memset(void * str, int c, size_t n)
作用
复制字符
c
(一个无符号字符)到参数str
所指向的字符串的前n
个字符。
2.1.6 注意小点
src
可以是字符串常量,也可以是字符数组dest
必须是可以存储字符数据的内存空间,一般是字符数组或者动态申请内存字符空间,而且空间要求足够使用。- 返回值是
dest
对应的空间地址。- 拷贝函数使用时,如果指定的
n
个字节数不包含src
字符串的最后一位'\0'
时,需要手动添加'\0'
来截断字符串,否则dest
字符串会继续有后续的数据内容memcpy
和memmove
功能和strncpy
一致,memmove
可以更好的保护拷贝源数据src
【墙裂推荐】使用memmove
,不会导致内存数据丢失
2.1.7 【函数区别】
- 用途
memcmp
: 通常用于比较两个内存区域的字节,不仅仅局限于字符串。strncmp
: 主要用于比较字符串的前 n 个字符。- 参数:
memcmp
: 接受三个参数,分别是两个内存区域的起始地址和要比较的字节数。strncmp
: 接受三个参数,分别是两个字符串的起始地址和要比较的字符数。- 返回值:
memcmp
: 返回一个整数,如果两个内存区域相等,则返回0;如果第一个不等于第二个,返回第一个不等于第二个的字节的差值。strncmp
: 返回一个整数,如果两个字符串相等,则返回0;如果第一个不等于第二个,返回第一个不等于第二个字符的 ASCII 码差值。- 比较方式:
memcmp
: 按字节比较,不考虑字符的含义。strncmp
: 按字符比较,可以根据字符的字典序进行比较。- 比较长度:
memcmp
: 需要明确指定要比较的字节数,没有考虑字符串的长度。strncmp
: 需要明确指定要比较的字符数,但会在达到指定字符数或遇到字符串结束符 ‘\0’ 时停止比较。
strcnpy
用于复制字符串,但相比于strcpy
, 它可以指定要复制的最大字符数,避免缓冲区溢出。他会复制指定数量字符,或者直到遇到字符串结束符'\0'
memcpy
用于复制任何内存块的内容,不局限于字符串- 字符串结束符
strncpy
会在达到指定的复制字符数或遇到src
字符串的结束符'\0'
时停止memcpy
不关心内存块中是否包含结束符,它只是简单地按字节进行复制- 补零操作
strncpy
在达到指定的字符数之前,如果遇到src
字符串的结束符,会用零填充剩余空间,以确保目标字符串总长度为指定值memcpy
不会自动在目标内存块的末尾添加零使用场景取决于需求。如果需要比较两个字节数组,不考虑其是否为字符串,使用
memcmp
。如果明确在比较字符串,且希望控制比较的字符数,使用strncmp
。
2.2 追加功能相关函数
2.2.1 strcat
格式
char * strcat(char * dest, const char * src)
作用
把
src
所指向的字符串追加到dest
所指向的字符串的结尾
2.2.2 strncat
格式
char * strncat(char * dest, const char * src, size_t n)
作用
把
src
所指向的字符串追加到dest
所指向的字符串结尾,直到n
字符长度或者'\0'
为止、
2.2.3 注意小点
- 字符串末尾标记
'\0'
- 返回值数据类型为
char *
,返回内容是dest
对应的空间地址dest
必须有对应内存空间- 返回值是
dest
对应的空间地址。
2.3 比较功能相关函数
2.3.1 strcmp
格式
int strcmp(const char * str1, const char * str2)
作用
把
str1
所指向的字符串和str2
所指向的字符串进行比较。
2.3.2 strncmp
格式
int strncmp(const char * str1, const char * str2, size_t n)
作用
把
str1
和str2
进行比较,最多比较的是前n
个字符。
2.3.3 memcmp
格式
int memcmp(const void * str1, const void * str2, size_t n)
作用
把
str1
和str2
的前n
个字节进行比较。
2.3.4 注意小点
- 如果返回值 < 0,则表示 str1 小于 str2。
- 如果返回值 > 0,则表示 str1 大于 str2。
- 如果返回值 = 0,则表示 str1 等于 str2。
- memcmp 使用时比较的是字节
2.3.5 【函数区别】
- 用途:
memcmp
: 通常用于比较两个内存区域的字节,不仅仅局限于字符串。strncmp
: 主要用于比较字符串的前 n 个字符。- 参数:
memcmp
: 接受三个参数,分别是两个内存区域的起始地址和要比较的字节数。strncmp
: 接受三个参数,分别是两个字符串的起始地址和要比较的字符数。- 返回值:
memcmp
: 返回一个整数,如果两个内存区域相等,则返回0;如果第一个不等于第二个,返回第一个不等于第二个的字节的差值。strncmp
: 返回一个整数,如果两个字符串相等,则返回0;如果第一个不等于第二个,返回第一个不等于第二个字符的 ASCII 码差值。- 比较方式:
memcmp
: 按字节比较,不考虑字符的含义。strncmp
: 按字符比较。- 比较长度:
memcmp
: 需要明确指定要比较的字节数,没有考虑字符串的长度。strncmp
: 需要明确指定要比较的字符数,但会在达到指定字符数或遇到字符串结束符 ‘\0’ 时停止比较。使用场景取决于需求。如果需要比较两个字节数组,不考虑其是否为字符串,更倾向于使用
memcmp
。如果明确在比较字符串,且希望控制比较的字符数,更倾向于使用strncmp
。
2.4 找目标字符或者字符串功能相关函数
2.4.1 strchr
格式
char * strchr(const char * str, int c)
作用
在参数 str 所指向的字符串中搜索第一次出现字符 c(一个无符号字符)的位置。
2.4.2 strrchr
格式
char * strrchr(const char * str, int c)
作用
在参数 str 所指向的字符串中搜索最后一次出现字符 c(一个无符号字符)的位置。
2.4.3 memchr
格式
void *memchr(const void * str, int c, size_t n)
作用
在参数 str 所指向的字符串的前 n 个字节中搜索第一次出现字符 c(一个无符号字符)的位置。
2.4.4 strstr
格式
char * strstr(const char * haystack, const char * needle)
作用
在字符串 haystack 中查找第一次出现字符串 needle(不包含空结束字符)的位置。
2.4.5 注意小点
strchr
strrchr
strstr
函数成功找到时,返回一个目标字符c
的位置的指针,如果未找到返回一个空指针NULL
【扩展】在
C
语言中,strchr
函数的参数c
被声明为int
类型而不是char
类型的原因与函数的设计和历史原因有关。
返回值的灵活性:
strchr函数的返回类型是
char *
,即一个字符指针。返回指向字符的指针时,可以使用NULL
表示未找到字符,而不使用一个特定的字符值(比如-1
)。如果c
被声明为char
,则无法用NULL
表示未找到。兼容性:
在
C
语言的早期版本中,EOF
被定义为-1
,而不是char
类型的字符。如果c
被声明为char
,则可能会导致类型不匹配的问题。将c
声明为int
可以确保与EOF
的比较正常工作。字符扩展:
char
类型在一些系统中可能是有符号的, 而在另一些系统中可能是无符号的。使用int
可以确保适应所有字符,包括unsigned char
的情况。虽然在实际使用中,通常将c
视为字符,但将其声明为int
是为了保证更好的兼容性和一致性。
2.5 计算字符串长度函数
2.5.1 strlen
格式
size_t strlen(const char * str)
作用
计算字符串长度,直到空结束字符,但不包括空结束字符。
2.6 截取字符函数
2.6.1 strtok
格式
char *strtok(char *str, const char *delim)
作用
分解字符串
str
为一组字符串,delim
为分隔符。
3. 字符串相关函数例子
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
// 字符串常量,字符串常量无法修改
char *str = "1234567890";
// 字符串打印
printf("str : %s\n", str);
// 字符串首地址
printf("str : %p\n", str);
// 从第五个字符开始打印
printf("&str[4] : %s\n", &str[4]); // &str[4] : 567890
// 下标为 0 的字符
printf(" *str : %c\n", *str); // *str : 1
// 下标为 4 对应的字符
printf("str[4] : %c\n", str[4]); // str[4] : 5
// "1234567890"这个字符串中下标为 5 的字符
printf("\"1234567890\"[5] : %c\n", "1234567890"[5]); // "1234567890"[5] : 6
// 字符数组
char arr[20] = {'a', 'b', 'c', '\0'};
printf("---------------------\n");
/*
字符串拷贝函数
格式:
char *strcpy(char *dest, const char *src);
将 src 指向的字符串内容,拷贝到 dest 字符数据空间中
char *strncpy(char *dest, const char *src, size_t n);
将 src 指向的字符串内容,拷贝到 dest 字符数据空间中,最多复制 n 个字符
void * memcpy(void * dest, const void *src, size_t n);
从 src 复制 n 个字符到 dest。
void * memmove(void *dest, const void *src, size_t n);
另一个用于从 src 复制 n 个字符到 dest 的函数。
要求:
1. src 可以是字符串常量,也可以是字符数组
2. dest 必须是可以存储字符数据的内存空间,一般是字符数组或者
动态申请内存字符空间,而且要求空间足够使用
*/
strcpy(arr, str);
printf("arr = %s\n", arr); // 打印结果为 arr = 1234567890
printf("---------------------\n");
strncpy(arr, "abcd", 3);
// strncpy 在使用时需要手动添加字符串结束符,以确保目标字符串的正确结束。
// 加上 arr[3] = '\0';打印结果为 arr = abc
printf("arr = %s\n", arr); // arr = abc4567890
printf("---------------------\n");
char dest[30] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', '\0'};
memcpy(&dest[4], "1234", 6); // dest: abcd1234
printf("dest: %s\n", dest);
memmove(&dest[3], "*", 1);
printf("dest: %s\n", dest); // dest: abc*1234
printf("---------------------\n");
/*
字符串追加函数
格式:
char *strcat(char *dest, const char *src);
把 src 所指向的字符串追加到 dest 所指向的字符串结尾
char *strncat(char *dest, const char *src, size_t n);
把 src 所指向的字符串追加到 dest 所指向的字符串结尾,
直到 n 字符长度为止或者到末尾标记 '\0'
要求:
1. 末尾标记'\0'
2. 返回值数据类型为 char *,返回内容是 dest 对应的空间地址
3. dest 必须有对应内存空间
*/
strcat(arr, "hjkl");
printf("arr = %s\n", arr); // arr = abc4567890hjkl
printf("---------------------\n");
strncat(arr, "123", 8);
printf("arr = %s\n", arr); // arr = abc4567890hjkl123
printf("---------------------\n");
/*
字符串比较函数
格式:
int strcmp(const char *str1, const char * str2);
把 str1 所指向的字符串和 str2 所指向的字符串进行比较。
int strcmp(const char *str1, const char *str2, size_t n);
把 str1 和 str2 进行比较,最多比较前 n 个字节。
int memcmp(const void *str1, const void *str2, size_t n);
把 str1 和 str2 的前 n 个字节进行比较。
要求:
1. 0 表示 str1 和 str2 两个字符串前 N 个字符一致
2. 1 or -1 表示两个字符串前 N 个字符不一致。
*/
char *str1 = "12345678";
char *str2 = "1234567d";
// 定义 bool 记录判断结果
int bool = strcmp(str1, str2);
printf("bool : %d\n", bool); // bool : -44
bool = strncmp(str1, str2, 4);
printf("bool : %d\n", bool); // bool : 0
bool = memcmp(str1, str2, 5);
printf("bool : %d\n", bool); // bool : 0
printf("---------------------\n");
/*
字符串查找指定字符函数
格式:
char *strchr(const char *str, int c);
在参数 str 所指向的字符串中搜索第一次出现字符 c(一个无符号字符)的位置。
char *strrchr(const char *str, int c);
在参数 str 所指向的字符串中搜索最后一次出现字符 c(一个无符号字符)的位置。
char *strstr(const char*haystack, const char *needle);
在字符串 haystack 中查找第一次出现字符串 needle(不包含空结束字符)的位置。
void *memchr(const void *str, int c, size_t n);
在参数 str 所指向的字符串的前 n 个字节中搜索第一次出现字符 c(一个无符号字符)的位置。
*/
char *p = strchr(str1, '2');
printf("p : %s\n", p); // p : 2345678
printf("---------------------\n");
p = strrchr(str1, '4');
printf("p : %s\n", p); // p : 45678
printf("---------------------\n");
p = strstr(str1, "34"); // str : 12345678
printf("p : %s\n", p); // p : 345678
p = strstr(str1, "789"); // str : 12345678
printf("p : %s\n", p); // p : (null)
printf("---------------------\n");
p = memchr(str1, '5', 6);
printf("p : %s\n", p); // p : 5678
printf("---------------------\n");
/*
计算字符串长度
格式:
size_t strlen(const char *str);
计算字符串 str 的长度,直到空结束字符,但不包括空结束字符。
*/
size_t length = strlen(str);
printf("str : %s\n", str); // str : 1234567890
printf("strlen: %ld\n", length); // strlen: 10
return 0;
}
4. 文件操作
4.1 文件操作写入到数据文件中
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
// 1. 确定文件路径
char * filename = "./3.txt";
/*
2. fopen 打开文件,mode选择 w w+ a a+
w 和 w+ 都是清空文件内容写入数据操作。
如果文件不存在,可以创建文件
a 和 a+ 是在当前文件的末尾写入数据操作
如果文件不存在,可以创建文件
*/
FILE * fp = fopen(filename, "a");
// 3. 利用 fputc 写入数据到文件中
fputc('A', fp);
// 4. 关闭文件
fclose(fp);
return 0;
}
4.2 文件操作读取数据到程序中
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
// 1. 确定读取文件的路径
char *filename = "./1.txt";
/*
2. 通过 fopen 打开文件,mode 选择 r r+ w+ a+
*/
FILE *fp = fopen(filename, "r");
// 3. 通过 fgetc 读取数据
int content = -1;
while ((content = fgetc(fp)) != EOF)
{
printf("%c\n", content);
}
// 4. 关闭文件
fclose(fp);
}