前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C语言(进阶)—字符函数和字符串函数

C语言(进阶)—字符函数和字符串函数

作者头像
小李很执着
发布2024-06-15 08:18:29
730
发布2024-06-15 08:18:29
举报
文章被收录于专栏:学习笔记

1.求字符串长度 strlen

size_t strlen ( const char * str );

字符串已经 '\0' 作为结束标志, strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0' )。 参数指向的字符串必须要以 '\0' 结束。 注意函数的返回值为size_t,是无符号的( 易错 )

1.概念理解

代码语言:javascript
复制
#include <string.h>

int main()
{
	const char* str = "abcdef";

	size_t len1 = strlen("abcdef");
	size_t len2 = strlen(str);

	printf("%d\n", len1);
	printf("%d\n", len2);


	return 0;
}

1.size_t len1 = strlen("abcdef"); size_t len2 = strlen(str);两者是一样的

2.//两个无符号数相减得到的还是无符号数 // 3 - 6 //-3 //10000000000000000000000000000011 //11111111111111111111111111111100 //11111111111111111111111111111101 //-3的补码当做无符号数进行处理将是一个很大的正数

代码语言:javascript
复制
#include <string.h>

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


	return 0;
}

但若将返回值类型强转成 int

代码语言:javascript
复制
int main()
{
	if ((int)strlen("abc") - (int)strlen("abcdef") > 0)
		printf(">=\n");
	else
		printf("<\n");


	return 0;
}

2.学会strlen函数的模拟实现

1. 计数器

首先创建计数器count,根据指针str所指向的内容判断进行操作,如果str指向的是字符'\0'之外的字符,则count+1,并且str指向下一个字符;如果指向的是字符'\0'则停止计数;

代码语言:javascript
复制
size_t my_strlen(const char* str)
{
 
    assert(str != NULL);    
 
	int count = 0;			//count用来计数
 
	while (*str++)			//指针str指向字符串首元素地址,
                            //当str指向的不是字符'\0',进入循环count++,
                           //并且str指向字符串下一个元素
	{
		count++;
	}
 
	return count;
}
2. 递归

函数功能:接受一个字符指针,然后返回从该字符指针开始往后到字符'\\0'之间字符的个数;

递归:如果函数接收的字符指针str所指向的内容不为'\0',则说明当前字符串长度为1加上my_strlen(str+1),这里my_strlen(str+1)计算的是从字符指针str+1开始往后到字符'\0'之间字符的个数;

回归条件:如果函数接收的字符指针指向的内容是'\0'就返回0,并且结束递归;

代码语言:javascript
复制
size_t my_strlen(const char* str)
{
 
    assert(str != NULL);
 
	if (*str == '\0')
	{
		return 0;							//如果指针str指向的内容为字符'\0',
                                            //说明字符串长度为0,直接返回0
	}
	else
	{
		return 1 + my_strlen(str + 1);		//如果指针str指向的内容不为字符'\0',
                                            //说明字符串长度至少为1,
                                            //然后看看str+1指向的内容是否为'\0',
                                            //如果不是则+1,并且继续看看下一个元素,
                                            //否则直接返回结果
	}
}
3. 指针-指针

指针运算中,指针1与指针2相减的返回值为两指针之间元素个数,

所以一个指针指向字符串首元素,另一个指针指向字符'\0',两者相减即为字符串的长度;

代码语言:javascript
复制
size_t my_strlen(const char* str)
{
	assert(str != NULL);
 
	char* start = str;
 
	while (*str)			//若str指向字符'\0'循环停止
	{
		str++;
	}
 
	return str - start;
}

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

1.strcpy

复制—实现将第一个字符数组中的字符串复制到第二个字符数组中,将第一个字符数组中相应的字符覆盖

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

Copies the C string pointed by source into the array pointed by destination, including the terminating null character (and stopping at that point). 源字符串必须以 '\0' 结束 会将源字符串中的 '\0' 拷贝到目标空间 目标空间必须足够大,以确保能存放源字符串 目标空间必须可变 学会模拟实现

代码语言:javascript
复制
#include <string.h>

int main()
{
	char arr1[20] = {0};
	char arr2[] = "HELLO";

	strcpy(arr1, arr2);
	printf("%s\n", arr1);

	return 0;
}
1.目标空间必须足够大,以确保能存放源字符串
2.目标空间必须可变

3.my_strcpy的实现
代码语言:javascript
复制
#include <assert.h>


//strcpy函数返回的是目标空间的起始地址

char* my_strcpy(char* dest, const char* src)
{
	char* ret = dest;//断言判断这两个是否为空
	assert(dest && src);

	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}

2.strcat

追加—实现将第二个字符数组的字符串连接到第一个字符数组的字符串后面;

char * strcat ( char * destination, const char * source );

注意: 1.目标空间必须足够大,可以修改 2.目标空间中必须得有\0 (保证能找到目标空间的尾) 3.原字符串中也得有\0,在拷贝时将源字符串中 \0也要拷贝过去。

代码语言:javascript
复制
int main()
{
	char arr1[20] = "abc";
	strcat(arr1, arr1);
	printf("%s\n", arr1);

	return 0;
}
模拟实现
代码语言:javascript
复制
#include <stdio.h>
#include <string.h>
#include <assert.h>

//strcat函数,返回的是目标空间的起始地址
char* my_strcat(char* dest, const char* src)
{
	char* ret = dest;
	assert(dest && src);
	//1. 找到目标空间的末尾
	while (*dest != '\0')
	{
		dest++;
	}
	//2. 数据追加
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}

3.strcmp

比较—比较两个字符串,不是比较长度,而是比较对应位置上字符的大小,ASCII码值,不改变其内容。

int strcmp ( const char * str1, const char * str2 );

模拟实现
代码语言:javascript
复制
#include <string.h>

int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);

	while (*str1 == *str2)
	{
		if (*str1 == '\0')
			return 0;
		str1++;
		str2++;
	}
	if (*str1 > *str2)
		return 1;
	else
		return -1;
}
代码语言:javascript
复制
int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);

	while (*str1 == *str2)
	{
		if (*str1 == '\0')
			return 0;
		str1++;
		str2++;
	}
	return *str1 - *str2;
}

3.长度受限制的字符串函数介绍

1.strncpy

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

代码语言:javascript
复制
char * strncpy ( char * destination, const char * source, size_t num );
char * destination         ===> 要拷贝到哪儿的地址
const char * source  ===> 被拷贝过去的字符串地址
size_t num          ===> 拷贝的字符数
 拷贝 num 个字符从源字符串到目标空间
 如果源字符串的长度小于 num ,则拷贝完源字符串之后,在目标的后面追加 0 ,直到 num 个 

2.strncat

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

代码语言:javascript
复制
char * strncat ( char * destination, const char * source, size_t num );
 
返回类型是 char* 类型的,是追加到哪儿的首地址
 
char * destination        ===> 要追加到哪儿的地址
 
 const char * source  ===> 被追加过去的字符串地址
 
 size_t num       ===> 追加的字符数

3.strncmp

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

代码语言:javascript
复制
int strncmp ( const char * str1, const char * str2, size_t num );
返回值是int类型;
str1 > str2   返回 >0
str1 = str2   返回 =0
str1 < str2   返回 <0
 const char * str1  ===> 比较的第一个字符串地址
const char * str2  ===> 比较的第二个字符串地址
ize_t num        ===> 比较的字符串个数

4.字符串查找

1.strstr

char * strstr ( const char *, const char * );

strstr函数是C一个字符串查找函数,用于在一个字符串中查找另一个字符串的位置。它的函数原型为:extern char *strstr(char *str1, char *str2);,其中str1是要查找的字符串,str2是要查找的子字符串。strstr返回str l 中str2第一次出现的位置 如果找到了子字符串,则返回指向该子字符串的指针;否则返回NULL。该函数包含在string.h头文件中。

模拟实现

代码语言:javascript
复制
const char* my_strstr(const char* str1, const char* str2)
{
	const char* cp;//记录开始匹配的位置
	const char* s1;//遍历str1指向的字符串
	const char* s2;//遍历str2指向的字符串

	assert(str1 && str2);
	if (*str2 == '\0')
		return str1;

	cp = str1;
	while (*cp)
	{
		s1 = cp;
		s2 = str2;
		while (*s1 && *s2 && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
			return cp;

		cp++;
	}
	return NULL;
}

2.strtok

char * strtok ( char * str, const char * sep );

sep参数是个字符串,定义了用作分隔符的字符集合 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。 strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改 变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。) strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。 strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。 如果字符串中不存在更多的标记,则返回 NULL 指针。

5.错误信息报告

strerror

char * strerror ( int errnum );

perror

char * strerror ( int errnum );

直接打印错误码,所对应的错误信息 perror == printf + strerror

6.字符操作函数

1.字符分类函数:

函数 如果他的参数符合下列条件就返回真 iscntrl 任何控制字符 isspace 空白字符:空格‘ ’,换页‘\f’,换行'\n',回车‘\r’,制表符'\t'或者垂直制表符'\v' isdigit 十进制数字 0~9 isxdigit 十六进制数字,包括所有十进制数字,小写字母a~f,大写字母A~F islower 小写字母a~z isupper 大写字母A~Z isalpha 字母a~z或A~Z isalnum 字母或者数字,a~z,A~Z,0~9 ispunct 标点符号,任何不属于数字或者字母的图形字符(可打印) isgraph 任何图形字符 isprint 任何可打印字符,包括图形字符和空白字符

使用例子

2.字符转换:

int tolower ( int c );大写转小写 int toupper ( int c );小写转大写

7.内存操作函数

1.memcpy

void * memcpy ( void * destination, const void * source, size_t num );

函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。 这个函数在遇到 '\0' 的时候并不会停下来。 如果source和destination有任何的重叠,复制的结果都是未定义的。 size_t num 传递的是字节数

模拟实现

代码语言:javascript
复制
void* my_memcpy(void* dest, const void* src, size_t sz)
//size 为字节数
{
	assert(dest && src);//两个指针都不能为空指针
	while (sz--)
	{
		*(char*)dest = *(char*)src;
//void*是不能直接进行解引用操作的,不能直接进行+和-操作
//强制转换类型是临时的
		dest = (char*)dest +1;
		src = (char*)src + 1;
	}
}

模拟实现注意

*(char*)dest = *(char*)src;//强制转换类型是临时的 // 不能直接(char*)dest++;//可能会存在无法编译的问题 // (char*)src++;//可能会存在无法编译的问题

但重叠内存一般用memmove来实现

标准值规定,mmcpy来实现不重叠的内存的拷贝 重叠的内存的拷贝,由memmove实现 但是你会发现在当前的ⅤS2022这个环境中memcpy 能实现重叠内

例如

2. memmove

void * memmove ( void * destination, const void * source, size_t num );

和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。 如果源空间和目标空间出现重叠,就得使用memmove函数处理。

模拟实现
代码语言:javascript
复制
void* my_memmove(void* dest, const void* src, size_t sz)
{
	assert(dest && src);
	void* ret = dest;
	if (dest < src)
	{
		//前->后
		int i = 0;
		for (i = 0; i < sz; i++)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else
	{
		//后->前
		while (sz--)
		{
			*((char*)dest+sz) = *((char*)src + sz);
		}
	}
	return ret;
}

3.memset

int memcmp ( const void * ptr1,const void * ptr2,size_t num ); memset 是设置内存的 是以字节为单位设置内存的

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-10-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.求字符串长度 strlen
    • 1.概念理解
      • 2.学会strlen函数的模拟实现
        • 1. 计数器
        • 2. 递归
        • 3. 指针-指针
    • 2.长度不受限制的字符串函数
      • 1.strcpy
        • 1.目标空间必须足够大,以确保能存放源字符串
        • 2.目标空间必须可变
        • 3.my_strcpy的实现
      • 2.strcat
        • 模拟实现
      • 3.strcmp
        • 模拟实现
    • 3.长度受限制的字符串函数介绍
      • 1.strncpy
        • 3.strncmp
        • 4.字符串查找
          • 1.strstr
            • 2.strtok
            • 5.错误信息报告
              • strerror
                • perror
                • 6.字符操作函数
                  • 1.字符分类函数:
                    • 2.字符转换:
                    • 7.内存操作函数
                      • 1.memcpy
                        • 2. memmove
                          • 模拟实现
                        • 3.memset
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档