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

引言

在上一篇中,我们介绍了字符函数和一些字符串函数,在这一篇章中,我们会继续学习字符串函数,那我们现在就开始学习吧!!!

字符串函数

strncpy

1.strncpy的用法

strncpy是一个在C语言中常用的字符串处理函数,用于将源字符串的前n个字符复制到目标字符串中。其函数原型为:

char *strncpy(char *dest, const char *src, size_t n);

其中,参数的含义如下:

dest 是目标字符串,即你想要将源字符串的字符复制到的位置

src 是源字符串,即你想要从中复制字符的字符串

n 是你想要从源字符串中复制的字符数

如果源字符串的长度小于 n,strncpy 会复制源字符串的所有字符到目标字符串中,并在目标字符串的剩余位置上用 \0 填充,直到总共复制了 n 个字符

2.strncpy的使用

当src的字符串长度>=n

复制代码
int main()
{
	char src[12] = "hello world";
	char dest[] = "xxxxxxxxxxxx";
	strncpy(dest, src, 5);
	printf("最终的目标字符串:%s\n", dest);
	return 0;
}

运行结果为:

最终的目标字符串:helloxxxxxxx

当src的字符串长度<n

复制代码
int main()
{
	char src[25] = "hello world";
	char dest[] = "xxxxxxxxxxxxxx";
	strncpy(dest, src, 20);
	printf("最终的目标字符串:%s\n", dest);
	return 0;
}

运行结果为:

最终的目标字符串:hello world

3.strncpy的模拟实现

思路:通过自定义的 my_strncpy 函数,将源字符串 str2 的 n 个内容复制到目标字符串 str1 中,确保复制操作安全进行(通过断言检查指针非空),并返回目标字符串的起始地址。

代码如下:

复制代码
char* my_strncpy(char* dest,const char* src,size_t n)
{
	// 断言dest和src不是空指针,以确保它们是有效的内存地址
	assert(dest && src);
	// 保存dest的原始地址,以便稍后返回
	char* ret = dest;
	// 循环复制字符,直到遇到源字符串的结束符'\0',或者复制了n个字符
	while (*src && n)
	{
		*dest = *src;
		dest++;
		src++;
		n--;	// 递减n,表示已经复制了一个字符
	}
	// 如果n不为0,说明还有剩余的空间需要填充null终止符
	if (n != 0)
	{
		while (n)
		{
			*dest = '\0';
			dest++;
			n--;
		}
	}
	return ret;
}

int main()
{
	char arr1[10] = "abcdef";
	char arr2[] = "bbq";
	my_strncpy(arr1, arr2, 3);
	printf("%s\n", arr1);
	return 0;
}

strncat

1.strncat的用法

strncat()函数是C语言中的一个字符串函数,用于将一个字符串的前n个字符连接到另一个字符串的末尾。

函数的原型为:

char *strncat(char *dest, const char *src, size_t n);

其中,参数的含义如下:

dest:目标字符串,即要将源字符串连接到的位置

src:源字符串,即要连接到目标字符串末尾的字符串

n:要连接的字符个数

strncat函数的工作原理是将源字符串src中的字符逐个复制到目标字符串dest的末尾,直到复制了指定的字符个数n或者遇到了源字符串的结束符'\0'。连接完成后,目标字符串dest的末尾会添加一个新的结束符'\0'。如果源字符串的长度小于n,则strncat函数会将整个源字符串连接到目标字符串的末尾。

2.strncat的使用

当src的字符串长度>n

复制代码
int main()
{
	char str1[20] = "hello";
	char str2[20] = "hello world";
	strncat(str1, str2, 5);
	printf("%s\n", str1);
	return 0;
}

输出结果为:hellohello

当src的字符串长度<=n

复制代码
int main()
{
	char str1[20] = "hello";
	char str2[20] = "hello world";
	strncat(str1, str2, 15);
	printf("%s\n", str1);
	return 0;
}

输出结果为:hellohello world

3.strncat的模拟实现

思路:先找到目标字符串的末尾位置,然后将源字符串的前n个字符逐个追加到目标字符串的末尾,并更新目标字符串的长度

代码如下:

复制代码
char* my_strncat(char* dest, const char* src, int n)
{
	char* ret = dest;		//将dest首地址储存在ret中
	assert(dest && src);	//保证dest、src非空
	while (*dest != '\0')	//找到dest结尾的'\0'
	{
		dest++;
	}
	while (n && (*dest++ = *src++))//把src里的字符一个个放入dest后
	{
		n--;                //跳出循环的条件
	}
	if (n == 0)
	{
		*dest = '\0';		//如果n<src
	}
	return ret;				//返回dest字符串起始地址
}

int main()
{
	char str1[20] = "hello ";
	char str2[] = "world";
	my_strncat(str1, str2, 5);
	printf("%s\n", str1);
	return 0;
}

strncmp

1.strncmp的用法

strncmp 是一个字符串比较函数,用于比较两个字符串的前n个字符

函数原型为:

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

其中,参数的含义如下:

str1:要比较的第一个字符串

str2:要比较的第二个字符串

n:要比较的最大字符数

返回值:

如果返回值 < 0,则表示 str1 小于 str2。

如果返回值 > 0,则表示 str1 大于 str2。

如果返回值 = 0,则表示 str1 等于 str2。

2.strncmp的使用

复制代码
int main()
{
	char arr1[20] = "abcdef";
	char arr2[20] = "abcddd";
	char arr3[20] = "abcdff";
	int ret1 = strncmp(arr1, arr2, 3);
	int ret2 = strncmp(arr1, arr2, 8);
	int ret3 = strncmp(arr1, arr2, 6);
	int ret4 = strncmp(arr1, arr3, 6);
	printf("%d %d %d %d\n", ret1, ret2, ret3, ret4);
	return 0;
}

输出结果为:0 1 1 -1

3.strncmp的模拟实现

思路:逐个比较两个字符串的前n个字符的ASCII值,直到遇到不同字符、遇到空字符或比较完n个字符为止,根据比较结果返回相应的整数。

代码如下:

复制代码
int my_strncmp(const char* str1, const char* str2, size_t n)
{
    assert(str1 && str2);
    // 如果n为0,说明不需要比较任何字符,直接返回0,表示两个字符串的前0个字符是相同的。  
    if (n == 0)
    {
        return 0;
    }
 
    // 循环条件中,*str1 == *str2 确保两个字符相同,  
    // *str1 确保str1没有到达字符串结束符,  
    // --n 确保已经比较了n个字符或n已经减到0。  
    while (*str1 == *str2 && *str1 && --n)
    {
        // 如果两个字符相同且没有到达字符串结束符,继续比较下一个字符。  
        str1++;
        str2++;
    }
    //返回的是两个字符的ASCII码差值。  
    return *str1 - *str2;
}

int main()
{ 
    char str1[] = "abcddd";
    char str2[] = "abcdef";  
    int ret1 = my_strncmp(str1, str2, 4);
    int ret2 = my_strncmp(str1, str2, 6);
    printf("%d %d\n", ret1, ret2);
    return 0;
}

strstr

1.strstr的用法

strstr用于查找一个字符串 str2 是否存在于另一个字符串 str1 中,并返回 str2 在 str1 中首次出现的位置。以下是关于strstr函数的详细介绍。

函数原型为:

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

其中,参数的含义如下:

str1:这是主串,即你希望在其中查找子串的字符串。

str2:这是子串,即你希望在主串中查找的字符串。

返回值:

如果str2是str1的子串,strstr返回一个指向str1中str2首次出现的位置的指针。

如果str2不是str1的子串,strstr返回NULL。

2.strstr的使用

复制代码
int main() 
{
    const char* str1 = "hello world";
    const char* str2 = "world";
    char* result = strstr(str1, str2);

    if (result != NULL) 
    {
        printf("找到了,子字符串为:%s\n", result);
    }
    else 
    {
        printf("找不到\n");
    }
    return 0;
}

输出结果为:找到了,子字符串为:world

3.strstr的模拟实现

思路:通过遍历主串,依次比较每个位置开始的子串是否与目标子串匹配,直到找到匹配或遍历完整个主串

代码如下:

复制代码
char* my_strstr(const char* str1, const char* str2)
{
	const char* s1 = NULL;	//用于遍历str1
	const char* s2 = NULL;	//用于遍历str2
	const char* cp = str1;	//指向str1的起始地址
	//检查传入的第二个字符串str2是否为空字符串(即只包含一个结束字符\0)
	//如果str2是空字符串,函数会立即返回str1的起始地址。
	if (*str2 == '\0')
		return (char*)str1;
	//遍历str1的字符
	while (*cp)
	{
		s1 = cp;		//初始化s1为当前cp的位置
		s2 = str2;		//初始化s2为当前str2的位置
		//s1和s2均为到达末尾,且字符相等,则继续比较
		while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)
		{
			s1++;		//s1向后移动一位
			s2++;		//s2向后移动一位
		}
		//如果s2到达str2末尾,说明str2在str1中从cp位置被找到
		if (*s2 == '\0')
		{
			return (char*)cp;	//返回找到的位置的指针
		}
		cp++;			//没找到则继续遍历str1
	}
	return NULL;		//遍历完没找到则返回NULL
}

int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "eg";
	char* ret = my_strstr(arr1, arr2);
	if (ret == NULL)
		printf("找不到\n");
	else
		printf("%s\n", ret);
	return 0;
}

strtok

1.strtok的用法

strtok用于分割字符串,该函数的主要目的是将字符串按照指定的分隔符切分成多个子串,并返回指向这些子串的指针。

函数原型为:

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

其中,参数的含义如下:

str:在第一次调用时,str是传入需要被切割字符串的首地址;在后续调用时,str应设置为NULL,以便strtok函数能够在之前的位置基础上继续查找下一个标记。

sep:这是一个字符串,它定义了用作分隔符的字符集合。字符串中的每个字符都会被当作一个分割符。

工作机制:

1.strtok在str字符串中查找由sep字符串定义的分隔符。当找到分隔符时,strtok会将其替换为\0字符,从而结束当前子串。

2.strtok返回指向当前找到的子串的指针。这个子串是从str开始,到当前找到的分隔符(现在已替换为\0)结束的部分。

3.在第一次调用之后,strtok会保存其在str中的位置,以便在后续调用时能够继续查找下一个子串。因此,在后续的调用中,需要将str参数设置为NULL。

4.如果字符串中不存在更多的分隔符,strtok将返回NULL指针。

需要注意的是,strtok函数会破坏被分解字符串的完整性。调用strtok后,原字符串str的内容会被修改,因为它会将分隔符替换为\0。因此,通常建议对原始字符串进行拷贝,并在拷贝的字符串上使用strtok,以避免修改原始数据。

2.strtok的使用

复制代码
int main()
{
	char arr1[] = "114514.2314.666";
	char* sep = ".";
	char* str = NULL;
	for (str = strtok(arr1, sep); str != NULL; str = strtok(NULL, sep))
	{
		printf("%s\n", str);
	}
	return 0;
}

输出结果为:

114514

2314

666

我们来分析一下:

114514.2314.666

使用strtok函数后,它会在在找到分隔符的位置后,将那个位置的字符设置为\0来结束当前的标记

然后从上一次标记的地方开始找下一个标记,直至结束

简单来说,就是"strtok会把目标字符串中间的符号作为分隔符,将目标字符串分为几个子串"

strerror

1.strerror的用法

在不同的系统和C语⾔标准库的实现中都规定了⼀些错误码,⼀般是放在 errno.h 这个头⽂件中说明的,C语⾔程序启动的时候就会使⽤⼀个全⾯的变量errno来记录程序的当前错误码,只不过程序启动的时候errno是0,表⽰没有错误,当我们在使⽤标准库中的函数的时候发⽣了某种错误,就会讲对应的错误码,存放在errno中,⽽⼀个错误码的数字是整数很难理解是什么意思,所以每⼀个错误码都是有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址返回。

函数原型为:

char* strerror(int errnum);

2.strerror的使用

复制代码
int main()
{
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%s\n", strerror(i));
	}
	return 0;
}

输出结果为:

No error(没有错误。这通常表示操作成功,没有发生任何错误)

Operation not permitted(操作不允许。这表明尝试进行的操作由于权限不足或其他限制而未能执行)

No such file or directory(没有这样的文件或目录。这通常意味着程序试图访问一个不存在的文件或目录)

No such process(没有这样的进程。这通常发生在尝试运行或管理一个不存在的进程时)

Interrupted function call(被中断的函数调用。这可能是由于某些外部因素(如用户中断)导致正在执行的函数被突然终止)

Input/output error(输入/输出错误。这通常发生在读取或写入文件或其他设备时,可能是由于设备故障、文件系统损坏或其他问题导致的)

No such device or address(没有这样的设备或地址。这通常表示程序试图访问一个不存在的设备或网络地址)

Arg list too long(参数列表过长。这通常发生在命令行参数超过系统限制时)

Exec format error(执行格式错误。这通常意味着尝试执行的程序或文件格式不正确或不被支持)

Bad file descriptor(错误的文件描述符。这通常表明程序尝试使用了一个无效或未正确初始化的文件描述符)

结束语

字符函数和字符串函数的内容就先讲到这里,下一篇文章我们将会学习内存操作函数

看到这里的友友们,感谢你们的支持,

求个点赞收藏加关注!!!

十分感谢!!!

相关推荐
isyangli_blog2 小时前
OpenDayLight (Carbon 版本) 启动与组件安装
开发语言·php
vb2008112 小时前
FastAPI APIRouter
开发语言·python
Benszen2 小时前
KVM虚拟化解决方案
开发语言·perl
会编程的土豆2 小时前
Go 语言反射(Reflection)详解
开发语言·后端·golang
東雪木2 小时前
多线程与并发编程 专属复习笔记
java·开发语言·笔记·java面试
杨充3 小时前
1.3 浮点型数据设计灵魂
开发语言·python·算法
噜噜噜阿鲁~3 小时前
python学习笔记 | 11.3、面向对象高级编程-多重继承
java·开发语言
basketball6163 小时前
Go 语言从入门到进阶:4. 数组和MAP使用方法总结
开发语言·后端·golang
春生野草3 小时前
反射、Tomcat执行
java·开发语言
雪的季节4 小时前
企业级 Qt 全功能项目
开发语言·数据库·qt