字符函数和字符串函数

头文件ctype.h

字符分类函数

函数名 返回真的条件 考试核心备注
iscntrl 任意控制字符(ASCII 0~31、127) 不可打印,比如退格、响铃
isspace 空白字符:空格 、换页\f、换行\n、回车\r、水平制表\t、垂直制表\v 常用来分割字符串,区分普通空格
isdigit 十进制数字:'0' ~ '9' 只识别阿拉伯数字字符
isxdigit 十六进制字符:0~9,a~f,A~F 包含十进制数字 + abcdef 大小写
islower 小写英文字母:a ~ z
isupper 大写英文字母:A ~ Z
isalpha 英文字母:a~z 或 A~Z 纯字母,不含数字
isalnum 字母 或者 数字(`isalpha
ispunct 可打印标点符号(不属于字母、数字的图形字符) ! " # $ % & ' () * + , - . /
isgraph 任意可见图形字符(除空白以外的可打印字符) 字母、数字、标点都算,不含空格
isprint 全部可打印字符:图形字符 + 空格 范围最大,包含空格

方便记忆:


将小写字符转化为大写字符

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <ctype.h>

int main(){
	char arr[] = { "I am a student." };
	int i = 0;
	while (arr[i] != '\0') {
		if (islower(arr[i])) {
			arr[i] -= 32;
		}
		i++;
	}
	printf("%s\n", arr);
	return 0;
}

字符转换函数tolower、toupper

示例

cpp 复制代码
char ch = toupper('a');
printf("%c\n",ch);

将小写字符转化为大写字符

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <ctype.h>

int main(){
	char arr[] = { "I am a student." };
	int i = 0;
	while (arr[i] != '\0') {
		if (islower(arr[i])) {
			arr[i] = isupper(arr[i]);
		}
		i++;
	}
	printf("%s\n", arr);
	return 0;
}

strlen(求字符串长度)

头文件string.h

示例

cpp 复制代码
char arr[] = "abcdef";
size_t len = strlen(arr);
printf("%zd\n",len);

功能具体实现

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>

int main(){
	if (strlen("abc") - strlen("abcdef") > 0) {
		printf(">");
	}
	else {
		printf("<=");
	}
	return 0;
}

结果是>,因为size_t是无符号整型

要让结果是<=

换成方法1.strlen("abc") > strlen("abcdef")

或2.在strlen前加上(int)强制类型转换

strlen模拟实现

1.计数器方式

2.指针-指针

3.递归方式

1.计数器方式

要模拟实现strlen,创建一个计数器,在遍历字符串的过程中,每遇到一个非'\0'的字符,就让计数器+1

cpp 复制代码
size_t my_strlen(const char* str) {
	int count = 0;//创建一个计数器
	assert(str != NULL);//确保传入的不是空指针
//遍历字符串
	while (*str != '\0') {
		count++;//遇到有效字符,计数器+1
		str++;//移动到下一个字符
	}
	return count;
}

2.指针-指针

通过记录字符串的起始位置和结束位置,最后用两个指针相减得到长度

cpp 复制代码
size_t my_strlen(const char* str) {
	const char* strat = str;
	assert(str != NULL);
	while (*str != '\0') {
		str++;
	}
	return str - strat;
}

3.递归方式

计算一个字符串的长度,可以看作是1+剩余子串的长度

cpp 复制代码
size_t my_strlen(const char* str) {
	if (*str != '0') {
		return 1 + my_strlen(str + 1);
	}
	else {
		return 0;
	}
}

长度不受限制的字符串函数

strcpy(复制字符串到字符串数组中)

char* strcpy(char* destination,const char* source)

函数使用

cpp 复制代码
char arr1[ ] = "abcdef";
char arr2[20];
strcpy(arr2,arr1);

包括\0也会拷贝

拷贝到的目标空间必须足够大

strcpy的模拟实现

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <assert.h>
char* my_strcpy(char* dest, const char* src) {
	assert(dest && src);
	char* ret = dest;
	while (*src != '\0') {
		*dest = *src;
		src++;
		dest++;
	}
	*dest = *src;//处理\0
	return ret;
}

int main(){
	char arr1[] = "abcdef";
	char arr2[20];
	printf("%s\n", my_strcpy(arr2, arr1));
	return 0;
}

dest不加const,而src加const限制

是因为dest指向的空间要修改,src指向的空间不要被修改

优化
cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <assert.h>
char* my_strcpy(char* dest, const char* src) {
	assert(dest && src);
	char* ret = dest;
	while (*dest++ = *src++) {
		;
	}
	return ret;
}

int main(){
	char arr1[] = "abcdef";
	char arr2[20];
	printf("%s\n", my_strcpy(arr2, arr1));
	return 0;
}

*dest++ = *src++

将arr2中的字符拷贝过去后,再判断表达式的值

最后当拷贝完\0后,才会判断为假,停止循环


strcat(拼接字符串)

使用

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>

int main(){
	char arr1[20] = "hello";
	char arr2[] = "world";
	strcat(arr1, arr2);
	printf("%s\n",arr1);
	return 0;
}

字符串不能自己给自己追加

strcat的模拟实现

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <assert.h>
char* my_strcat(char* dest,const char* src) {
	char* ret = dest;
	assert(dest && src);
	//要存入arr1中,dest首先得找到\0
	while (*dest != '\0') {
		dest++;
	}
	//拷贝arr2到arr1里,将 arr1里的\0也覆盖掉
	while (*dest++ = *src++) {
		;
	}
	//要返回目标空间的起始地址
	return ret;
}
int main(){
	char arr1[20] = "hello ";
	char arr2[] = "world";
	my_strcat(arr1, arr2);
	printf("%s\n",arr1);
	return 0;
}

strcmp(比较对应位置上的字符大小)

使用

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main(){
	char arr1[20] = "abcdef ";
	char arr2[] = "abcdh";
	int ret = strcmp(arr1, arr2);
	printf("%d\n",ret);
	return 0;
}

VS上的返回值只有-1、0、1

标准的是<=、=、>=

strcmp模拟实现

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <assert.h>

int my_strcmp(const char* str1, const char* str2) {
	while (*str1 == *str2) {
		if (*str1 == '\0') {
			return 0;
		}
		str1++;
		str2++;
	}
	if (*str1 > *str2) {
		return 1;
	}
	else {
		return -1;
	}
	//也可以把这里的if语句换成return(*str1-*str2)
}
int main(){
	char arr1[20] = "abcdef ";
	char arr2[] = "abcdh";

	int ret = my_strcmp(arr1, arr2);
	printf("%d\n",ret);
	return 0;
}

长度受限制的字符串函数

strncpy函数

char* strncpy(char * dest,const char* src,size_t num)

比strcpy多了第三个参数,意思是最大拷贝的字符数

使用

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main(){
	char arr1[20] = "abcdef";
	char arr2[20] = "xxxxxxxx";

	strncpy(arr2, arr1, 3);
	printf("%s\n",arr2);
	return 0;
}

strncpy(arr2, arr1, 8);

如果要拷贝的数量大于字符串长度,比如这里,将arr1拷贝8个字符到arr2里面,但arr1中只有6个字符,剩下两位会补\0

如果拷贝的数量小于字符串长度,那就是复制几个就是几个,不补\0


strncat函数

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main(){
	char arr1[20] = "abcdef";
	char arr2[20] = "xxxx";

	strncat(arr2, arr1, 3);
	printf("%s\n",arr2);
	return 0;
}

追加几个然后自动补\0

字符串可以自己给自己追加

strncmp函数

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main() {
	char arr1[20] = "abcdef";
	char arr2[20] = "abqwqq";

	int ret = strncmp(arr1, arr2, 3);
	printf("%d\n", ret);
	return 0;
}

结果为-1


strstr的使用(长串中找短串)

在str1中找str2这个字符串,第一次出现的位置

如果找到了,就返回这个第一次出现的起始地址,打印出来的值就是从这个地址开始往后的字符串

如果找不到,就返回NULL

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main() {
	char arr[] = "abcdefabcdef";
	const char* p = "efab";
	char* ret = strstr(arr, p);
	if (ret == NULL) {
		printf("不存在\n");
	}
	else {
		printf("%s\n", ret);
	}
	return 0;
}

strstr的模拟实现

思路:

strstr函数功能实现在长串中匹配短串,匹配成功就返回该次匹配的起始地址

  1. 起始地址cur

  2. s1从cur位置出发,s2从str2位置出发,只要遇到字符相同,就同时++

3.判断结果

(1)字符相同就让s1和s2继续++,如果s2到了\0说明找完了,就返回当前的cur值

(2)字符不同,让cur++

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <assert.h>
char* my_strstr(const char* str1, const char* str2) {
	assert(str1 && str2);
	const char* s1 = NULL; //这个地址必须要受限制
	const char* s2 = NULL;
	const char* cur = str1;

	if (*str2 == '\0') { //特殊情况,c语言规定要这样返回
		return (char*)str1;
	}
	while (*cur != '\0') {
		s1 = cur;
		s2 = str2;
		while ( *s1 != '\0'&& *s2 != '\0'&& * s1 == *s2) {
			s1++;
			s2++;
		}
		if (*s2 == '\0') {
			return (char*)cur;
		}
		cur++;
	}
	return NULL;
}
int main() {
	char arr[] = "abcdefabcdef";
	const char* p = "efab";
	char* ret = my_strstr(arr, p);
	if (ret == NULL) {
		printf("不存在\n");
	}
	else {
		printf("%s\n", ret);
	}
	return 0;
}

还有更优的算法,KMP算法


strtok函数(按指定的分隔符拆分字符串)

192.168.110.123

ip地址,这是点分十进制的表示方式

这里的.点是分隔符

aaaamelia@qq.com

这里的@是分隔符
char* strtok(char* str,const char* sep)

第一个参数是整个字符串

sep放分隔符

此函数每次调用完之后,会保存上次找到的位置
//两个数组,一个放含有分隔符的字符串,一个放分隔符

char arr = "aaaamelia@qq.com";

char sep ="@.";

//如果不想破坏原始字符串,就在分割前先用 strcpy 拷贝一份副本到另一个数组中

char buf 256 = {0};

strcpy(buf,arr);

//要切割buf字符串,用strtok函数

char* ret = strtok ( buf , sep ) ;//首次调用:传入需要被分割的字符串指针

printf ( " %s\n ", ret ) ;

//strtok会将分隔符改变为\0

//后续调用:传入 NULL 就可以,函数会继续从上次断开的地方分割

//传NULL是因为strtok函数每次调用完之后,都会保存上次找到的位置

ret = strtok ( NULL , sep ) ;

printf ( "%s\n ", ret ) ;

正因为strtok函数每次调用完会保存上次找到的位置,

所以实际上写的时候利用循环调用strtok函数

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main() {
	char arr[] = "aaaamelia@qq.com";
	char buf[256] = { 0 };
	strcpy(buf, arr);
	const char* sep = "@.";
	char* ret = NULL;
	for(ret=strtok(buf,sep);ret!=NULL;ret = strtok(NULL,sep))
	{
		printf("%s\n", ret);
	}
	return 0;
}

strerror函数(错误码转文字)

char* strerror ( int errnum );

错误码里有对应的错误信息,strerror就会把这个错误信息的起始地址返回来

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main() {
	for (int i = 0; i <= 10; i++) {
		printf("%d:%s\n", i,strerror(i));
	}
	return 0;
}

结果:

strerror模拟实现

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main() {
	FILE* pf = fopen("data.txt", "r");//打开文件,以读文件的形式,如果文件不存在就打开失败
	if (pf == NULL) {
		printf("打开文件失败,原因是:%s", strerror(errno));
		return 1;
	}
	else {
		printf("打开文件成功\n");
		fclose(pf);
		pf = NULL;
	}
	return 0;
}

在文件对应位置手动新建data.txt

记得打开文件扩展名

用prror函数

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main() {
	FILE* pf = fopen("data.txt", "r");//打开文件,以读文件的形式,如果文件不存在就打开失败
	if (pf == NULL) {
		//printf("打开文件失败,原因是:%s", strerror(errno));
		perror("打开文件失败,原因是");
		return 1;
	}
	else {
		printf("打开文件成功\n");
		fclose(pf);
		pf = NULL;
	}
	return 0;
}

strerror :将错误码对应的错误信息的字符串的起始地址返回

perror :将errno中错误码对应的错误信息打印出来
perror函数先打印str指向的字符串打印,再打印一个空格,再打印错误码对应的错误信息

perror是printf和strerror函数一起的功能

相关推荐
夜月yeyue1 小时前
AUTOSAR CP 从上电到 Runnable
c语言·网络·tcp/ip·车载系统
城管不管2 小时前
ReAct、Plan-and-Execute、Reflection 三大智能 Agent 范式核心区别
java·人工智能·算法·spring·ai·动态规划
月疯3 小时前
二分法算法(水平等分图形面积)
算法
tq10863 小时前
开放与封闭:类型系统的安全哲学
笔记
豆瓣鸡3 小时前
算法日记 - Day3
java·开发语言·算法
白白白小纯3 小时前
算法篇—反转链表
c语言·数据结构·算法·leetcode
Achou.Wang3 小时前
深入理解go语言-第5章 并发编程——Go的灵魂
大数据·算法·golang
龙仔7253 小时前
人大金仓 KingbaseES V8 只读账号创建完整运维笔记
运维·笔记·sql·人大金仓
韭菜炒鸡肝天3 小时前
VTK开发笔记(一):VTK介绍,Qt..+VSx+VTK.编译
开发语言·笔记·qt