c语言字符函数与字符串函数

本文详细介绍了C语言中常用的字符和字符串处理函数,如islower/isupper转换字符大小写,strlen计算字符串长度,以及strncpy/strncat等函数的使用和模拟实现。
摘要由CSDN通过智能技术生成

在我们写代码的过程中,有时候遇到了关于字符和字符串的问题时,处理起来就会不太方便,这是c语言标准库就提供了一系列的库函数,方便我们使用。

字符函数:

函数        头文件<ctype.h>
islower判断是否为小写字符,如果是返回非0的数,反之返回0
isupper判断是否为大写字符,如果是返回非0的数,反之返回0
tolower将大写字母转换为小写字母
toupper将小写字母转换为大写字母

在我们之前需要将字符串全部转换为大写字母的是时候,我们可能这样写代码

//'A' = 65     'a' = 97
//'B' = 66     'b' = 98
int main()
{
	char arr[] = "i Am a StUdent";
	int i = 0;
	while (arr[i] != '\0')
	{
		//判断字母是否是小写
		if (arr[i] >= 'a' && arr[i] <= 'z')
		{
			//大写字母与小写字母的ASCII值相差32
			arr[i] = arr[i] - 32;
		}
		i++;
	}
	printf("%s\n", arr);
	return 0;
}

我们只能通过它们之间ASCII值来进行大小写的转换。

但是我们学习了上面的字符函数之后代码就可以这样写

int main()
{
	char arr[] = "i Am a StUdent";
	int i = 0;
	while (arr[i] != '\0')
	{
		//判断字母是否是小写
		if (islower(arr[i]))
		{
			//将小写字母转换为大写字母
			arr[i] = toupper(arr[i]);
		}
		i++;
	}
	printf("%s\n", arr);
	return 0;
}

字符串函数:

strlen()函数

头文件是<string.h>

参数:    size_t strlen ( const char * str );

str --- 要计算长度的字符串

返回一个size_t类型的值

作用:统计'\0'之前出现的字符个数

 我们简单写一个代码运用strlen()函数

int main()
{
	char arr[] = "abcdef";
	int ret = strlen(arr);
	printf("%d", ret);
	return 0;
}

这里我们在运用strlen()函数的时候有时候会出现问题

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

我们看到第一个strlen函数计算的结果应该是3,第二个strlen函数计算的结果应该是6,3-6 = -3,       -3<0所以打印的会是>=吗?

结果怎么是 >

解析

这里我们要知道strlen()函数返回的值是size_t,是无符号整数,那么两个无符号整数相减得到的也会是一个无符号的整数,虽然它是-3,但是它是无符号整数,肯定是会比0大的,所以结果是<

 这里我们学习了strlen()函数,那我们可以不可以模拟实现strlen()函数呢?

strlen()函数模拟实现:

方法一:计数法

思路:我们先创建一个变量当作计数器,用来记录循环的次数,通过循环让指针走向'\0'之后退出循环,这时,循环的次数就是字符串的个数

int my_strlen(const char* str)//这里加上const防止字符串被修改
{
	//首先断言str是否为空指针
	assert(str);
	//这里我们创建一个计数器
	int count = 0;
	while (*str != '\0') //遇到'\0'退出循环
	{
		count++;
		//进入循环count++
		str++;
		//让指针往后走
	}
	return count;
}
int main()
{
	char arr[] = "abcdef";
	int ret = my_strlen(arr);
	printf("%d", ret);
	return 0;
}

方法二:递归

这个方法不需要创建临时变量

思路:我们需要计算字符串"abcdef"的长度,我们就可以拆分为计算1+"bcdef",同理"bcdef"也可以拆分为计算1+"cdef"...理解了这个思路之后,我们就可以进行递归操作了,这个让递归停下来的条件就是指针走到了'\0'的位置,然后我们需要让指针一直往后走

int my_strlen(const char* str)
{
	assert(str);
	if (*str == '\0')
		return 0;
	else
		return 1 + my_strlen(++str);
}
int main()
{
	char arr[] = "abcdef";
	int ret = my_strlen(arr);
	printf("%d", ret);
	return 0;
}

方法三:指针-指针

思路:我们需要两个指针,并且他们都是指向字符串首元素的,然后让其中的一个指针往后走到'\0\,再让两个指针相减,得到的个数就是字符串的个数

int my_strlen(const char* str)
{
	assert(str);
	//我们创建一个指针保存字符串首元素的地址
	char* p = str;
	while (*str)
	{
		str++;
		//这里让指针一直往后走
	}
	//出循环之后刚好指针str在'\0'的位置
	return str - p;
}
int main()
{
	char arr[] = "abcdef";
	int ret = my_strlen(arr);
	printf("%d", ret);
	return 0;
}

strcpy()函数

头文件:<string.h>                 目的地                            源头   

参数:char * strcpy ( char * destination, const char * source );

destination: 指向用于存储拷贝内容的目标数组

source:要拷贝的字符串

返回一个指向目的地首元素的指针

作用:把source指向的字符串拷贝到destination指向的目标数组中。

条件:

1.源头指向的字符串必须以'\0'结尾

2.destination指向的目标数组空间必须足够大并且可修改

 简单写一个代码使用strcpy()函数

#include<string.h>
int main()
{
	char arr1[20] = "hello";
	char* arr2 = "abcdef";
	strcpy(arr1, arr2);//将arr2中的字符串拷贝到arr1里面
	printf("%s", arr1);
	return 0;
}

strcpy()函数模拟实现

思路:我们想要把src的内容拷贝到dest里面去,首先这两个肯定都不能是空指针,

然后利用循环,将src里面的值循环赋值给dest,当最后把'\0'赋值完了之后,条件为假,跳出循环,在循环前,我们也需要创建一个指针变量记录dest指向的目标数组的起始位置

char* my_strcpy(char* dest, const char* src)
{
	//判断dest和src是否是空指针
	assert(dest && src);
	//创建指针变量p保存dest指向的目标数组的起始地址
	char* p = dest;
	while (*dest++ = *src++)//循环赋值,当把'\0'赋值完之后,判断条件为假,跳出循环
	{
		;
	}
	return p;
}
int main()
{
	char arr1[20] = "hello";
	char* arr2 = "abcdef";
	char* p = my_strcpy(arr1, arr2);
	printf("%s", p);
	return 0;
}

strcat()函数(字符串追加)

头文件:<string.h>

参数:char * strcat ( char * destination, const char * source );

作用:将source指向的字符串追加到destination指向的目标数组中

简单写一个代码使用strcat()函数

int main()
{
	char arr1[20] = "hello ";
	char* arr2 = "world";
	strcat(arr1, arr2);//将arr2里面的字符串追加到arr1里面
	printf("%s", arr1);
	return 0;
}

 strcat()函数模拟实现

思路:我们想要把src的内容追加到dest里面去,首先我们要找到dest指向的数组中'\0'的位置,在\0的位置把我们的src里面的值循环赋值给dest

char* my_strcat(char* dest, const char* src)
{
	//判断dest和src是否为空指针
	assert(dest && src);
	//创建指针变量p保存dest指向的目标数组的起始地址
	char* p = dest;
	//我们先找到dest指向的目标数组中'\0'的位置
	while (*dest)
	{
		//让*dest往后一直走,直到遇到'\0'跳出循环
		dest++;
	}
	//这时的dest刚好指向'\0'
	while (*dest++ = *src++)//循环赋值,直到把'\0'赋值给dest后,判断为假跳出循环
	{
		;
	}
	return p;
}
int main()
{
	char arr1[20] = "hello ";
	char* arr2 = "world";
	char*p = my_strcat(arr1, arr2);
	printf("%s", p);
	return 0;
}

 strcmp()函数

头文件:<string.h>

参数 :int strcmp ( const char * str1, const char * str2 );

作用:比较str1指向的字符串和str2指向的字符串的大小

1.如果str1>str2,返回一个大于0的数字

2.如果str1 == str2,返回0

3.如果str1<str2,返回一个小于0的数字

两个字符串的比较,其实是比较两个字符串中对应位置上字符ASCII码值的大小

 简单写一个代码使用strcmp()函数

int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abq";
	int ret = strcmp(arr1, arr2);//比较arr1和arr2
	printf("%d", ret);
	return 0;
}

为什么是-1,因为q的ASCII码值比c的ASCII码值大,后面的就不会比了。

 strcmp()函数模拟实现

思路:我们知道,两个字符串的比较,其实是比较两个字符串中对应位置上字符ASCII码值的大小,那么一个一个的进行比较

int my_strcmp(const char* str1, const char* str2)
{
	//判断str1和str2是否为空指针
	assert(str1 && str2);
	while (*str1 == *str2)//str1 == str2才会进入循环
	{
		if (*str1 == '\0')//这里如果str1等于\0的话,那么str2也等于0了,提前返回0
		{
			return 0;
		}
		//让它俩往后走
		str1++;
		str2++;
	}
	//如果没进入循环直接相减
	return *str1 - *str2;
}
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abq";
	int ret = my_strcmp(arr1, arr2);
	printf("%d", ret);
	return 0;
}

以上介绍的这些函数都属于长度不受限制的字符串函数。


  strncpy()函数   

参数:char * strncpy ( char * destination, const char * source, size_t num );

  这个函数和上面的strcpy函数多了一个参数num。

num:要拷贝的个数

作用:把source指向的字符串拷贝num个到destination指向的目标数组中  

 简单写个代码使用strncpy()函数

int main()
{
	char arr1[20] = "abcde";
	char* arr2 = "xyzfn";
	strncpy(arr1, arr2, 3);//拷贝3个字符到arr1里面去
	printf("%s", arr1);
	return 0;
}

假如source指向的字符串长度小于num个,则拷贝完source指向的字符串之后,在destination指向的字符串的后面追加\0,直到num个。

strncat()函数

参数: char * strncat ( char * destination, const char * source, size_t num );

作用:将source指向的字符串追加num个到destination指向的目标数组中

简单写个代码使用strncat()函数

int main()
{
	char arr1[20] = "hello ";
	char* arr2 = "world";
	strncat(arr1, arr2, 3);//追加3个字符到arr1里面去
	printf("%s", arr1);
	return 0;
}

假如source指向的字符串长度小于num个,只会将source指向的字符串中到\0的内容追加到destination指向的字符串指向的末尾。

strncmp()函数

参数:int strncmp ( const char * str1, const char * str2, size_t num );

作用:最多比较num个str1指向的字符和str2指向的字符的大小

 简单写个代码使用strncmp()函数

int main()
{
	char* arr1 = "abcdef";
	char* arr2 = "abcdqf";
	int cmp = strncmp(arr1, arr2, 4);//比较arr1和arr2的前4个字符的大小
	printf("%d", cmp);
	return 0;
}

比较arr1和arr2的前num个字符,如果相等就继续往后比较,最多比较num个字符,如果提前发现不一样,就提前结束

int main()
{
	char* arr1 = "abcdef";
	char* arr2 = "abqdef";
	int cmp = strncmp(arr1, arr2, 5);//这里我们比较arr1和arr2的前5个字符
	printf("%d", cmp);
	return 0;
}

 提前发现不一样,提前返回了。

以上的这些就是长度受限制的字符串函数


strstr()函数

参数:const char * strstr ( const char * str1, const char * str2 );

作用:在str1中查找str2是否出现过,函数返回字符串str2在字符串str1中第一次出现的位置,如果str2不在str1中出现,则会返回一个空指针。

 简单写个代码使用strstr()函数

int main()
{
	char arr1[] = "i am a student";
	char* arr2 = "am";
	char* pc = strstr(arr1, arr2);//在arr1中查找arr2是否出现过
	if (pc != NULL)
	{
		printf("%s", pc);
	}
	else
	{
		printf("找不到!\n");
	}
	return 0;
}

strstr()函数模拟实现

思路:我们这里先创建一个指针变量cp,用来记录str1开始匹配的位置,然后还得需要两个指针变量s1,s2循环比较,如果*str1 != *str2,cp++,从str1的起始位置后一个字符开始匹配,如果*s2 == \0,说明匹配成功,如果cp走到\0,就代表str1中没有出现str2.

char* my_strstr(const char* str1, const char* str2)
{
	//这里先让cp指针保存str1的起始位置
	const char* cp = str1;
	//这里先设置两个空指针
	const char* s1 = NULL;
	const char* s2 = NULL;
	//如果这里传过来的str2为空字符串,直接返回str1
	if (*str2 == '\0')
		//类型不一样,需要强转成char*类型的
		return (char*)str1;
	while (*cp)
	{
		//这里将s1和s2都指向两个字符的起始位置
		s1 = cp; 
		s2 = str2;
		while(*s1!='\0'&&*s2!='\0'&& * s1 == *s2)
		{
			//这里如果两个指针相等,就让他们往后走继续比对
			s1++;
			s2++;
		}
		if (*s2 == '\0')//这里*s2走到\0代表str字符串已经遍历完了提前返回
		{
			return (char*)cp;
		}
		cp++;
	}
	//这里就是str1字符串走完了表示没有匹配成功
	return NULL;
}
int main()
{
	char arr1[] = "abcde";
	char* arr2 = "bcd";
	char* pc = my_strstr(arr1, arr2);//在arr1中查找arr2是否出现过
	if (pc != NULL)
	{
		printf("%s", pc);
	}
	else
	{
		printf("找不到!\n");
	}
	return 0;
}

strtok()函数 

参数:char * strtok ( char * str, const char * delimiters );

str:指向要被分割的字符串

delimiters:指向⼀个字符串,定义了⽤作分隔符的字符集合

作用:将str指向的字符串分割成一系列的字串

返回值:该函数返回被分割的第一个子字符串,如果没有可检索的字符串,则返回一个空指针

简单写一个代码实现strtok()函数

int main()
{
	char arr[] = "owq.cc.@.com";
	const char* sep = ".@";//这里分隔符不分前后,也可以写成@.
	char* ret = NULL;
	for (ret = strtok(arr, sep); ret != NULL; ret = strtok(NULL, sep))
	{
		printf("%s\n",ret);
	}
	return 0;
}

1.strtok函数找到str中的第一个标记,并将其修改成 \0 ,然后返回⼀个指向这个标记的指针。

2.strtok函数的第二次调用,前面的参数就写成NULL ,strtok函数将在第一次被标记的位置开始,查找下一个标记。

3.如果字符串中不存在更多的标记,则返回 NULL 指针

简单来说 strtok函数需要多次调用,strtok()函数可以将目标字符串,以分隔符为标记,分成一系列的字串。

 strerror()函数

头文件:<errno.h>

参数:char * strerror ( int errnum );

errnum:错误码 (一般用errno来表示)

作用:可以将参数部分错误码对应的错误信息的字符串地址返回来,strerror()生成的错误字符串取决于编译器。

 简单写个代码使用strerror()函数

int main()
{
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d:  %s\n", i, strerror(i));
	}
	return 0;
}

1. No error 没有错误

2.Operation not permitted 操作不允许

3.No such file or directory 没有这样的文件

4.No such process 没有这样的过程

5.Interrupted function call 中断功能调用

 strerror()函数常用于动态内存开辟和文件操作

int main()
{
	FILE* pf = fopen("text.c", "r");//以读的形式打开名为text.c的文件
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//读文件

	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

刚好对应我们的错误码5, 没有这样的文件

perror函数也可达到相似的效果,perror函数打印完参数部分的字符串之后,还会打印一个冒号和一个空格,再打印错误信息。

int main()
{
	FILE* pf = fopen("text.c", "r");//以读的形式打开名为text.c的文件
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件

	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

  • 23
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值