IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C语言——常用字符串函数的实现 -> 正文阅读

[C++知识库]C语言——常用字符串函数的实现

用C语言实现常用的字符串函数

注:凡是要使用库里面的字符串函数,都需要引用头文件<stdio.h>

一、常用字符串函数介绍


1.strlen

size_t strlen(const char* str);
  • 功能是计算字符串的长度。字符串以’\0’作为结束标志,strlen的返回值是在’\0’前(不包括\0)的字符数

    char arr[] = "abc";
    printf("%d\n", strlen(arr));//3
    

请添加图片描述

  • 需要保证参数中的字符串有’\0’,不然返回的值是不确定的

    char arr[] = {'a', 'b', 'c'};
    printf("%d\n", strlen(arr));//随机值,因为字符没有结束标志,\0不在arr数组内而在数组后某个未知的位置
    
  • strlen函数返回值是size_t类型的无符号整数。因此以strlen(a)-strlen(b)为判断条件时,如果字符串a的长度小于b,计算结果不会是负值,而是一个极大的正值,需要注意
    请添加图片描述

2.strcat

char* strcat(char* dest, const char* src);
  • 功能是追加字符串。找到目标空间的’\0’,然后从’\0’处开始,逐字符替换为源字符串的内容,拷贝过程直到遇到源字符串的’\0’结束,返回目标字符串的首地址

    char arr1[20] = "hello ";
    char arr2[] = "world";
    strcat(arr1, arr2);
    printf("%s\n", arr1);//hello world
    

请添加图片描述

  • src代表源字符串首字符地址,dest代表目标字符串首字符地址(后面也一样)

  • 目标空间必须足够大,能容纳源字符串的内容

  • 目标空间必须可修改

    char* p = "abcdef";//指针所指向的空间不可修改
    char p[] = "abcdef";//数组空间可修改
    
  • 不能自己给自己追加字符串

    char* arr[] = "abc";
    printf("%s\n", strcat(arr, arr));//Error
    

    原因在strcat的实现原理,如图:

请添加图片描述

拷贝过程中,arr的首字符a会先被拷贝到原来的\0处,这导致源字符串的内容发生改变。

请添加图片描述

当需要将\0拷贝到后面的内存块中时,\0的内容已被覆盖,而源字符串的拷贝工作要遇到\0才会停止,结果可想而知,字符串会无限地以"abcabc"的形式拷贝下去,陷入死循环。这也是为什么源字符串前面要用关键字const修饰,因为源字符串的内容发生改动会带来很大的风险

长度有限制的同类字符串函数:strncat

char* strncat(char* dest, const char* src, size_t n);
  • 功能是在目标字符串末尾追加源字符串的前n个字符,并在后面补上空字符’\0’,返回目标字符串的首地址
  • 如果n的值大于源字符串长度,也只拷贝到源字符串的第n个字符为止,不会追加多余内容
char arr1[20] = "hello ";
char arr2[] = "world";
strncat(arr1, arr2, 3);
printf("%s\n", arr1);//hello wor

3.strcpy

char* strcpy(char* dest, const char* src);
  • 功能是复制字符串。将源字符串的全部内容复制到目标字符串空间中,包括空字符’\0’

    char arr1[20] = "aaa";
    char arr2[] = "bbb";
    strcpy(arr1, arr2);
    printf("%s\n", arr1);//bbb
    
  • 目标空间必须足够大,能容纳源字符串的内容

  • 目标空间必须可修改

    长度有限制的同类字符串函数:strncpy

    char* strncpy(char* dest, const char* src, size_t n);
    
    • 功能是从源字符串复制前n个字符到目标字符串空间中

      char arr1[20] = "aaa";
      char arr2[] = "bbb";
      strncpy(arr1, arr2, 2);
      printf("%s\n", arr1);//bba
      
    • 如果n的值大于源字符串长度,则在拷贝完源字符串所有内容后,在目标的后面追加0,直到n个

    例:

    char arr1[20] = "aaaaaaaaaaaaa";
    char arr2[] = "bbb";
    strncpy(arr1, arr2, 8);
    printf("%s\n", arr1);//bbb
    

    对于以上代码,arr1拷贝前的存储信息:

    请添加图片描述
    拷贝后:

    请添加图片描述

4.strcmp

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

计算机内的数据是以AscⅡ码的形式存储的,因此字符串比较实际是对一个一个字符的AscⅡ码进行比较,比如字符’b’的AscⅡ码98大于字符’a’的AscⅡ码97,因此’b’>‘a’

  • 功能是比较两个字符串。从两个字符串首地址处逐字符比较,当该次比较的两个字符相同时继续比较两个字符串的下一个字符,当出现相异字符或其中一个字符串结束时比较结束

    例:字符串str1"abcdef"和字符串str2"abqa"的比较

    请添加图片描述

    比较结果相同,指针p1和p2都往后移一个字符,继续比较下一个字符,直到遇到不同的字符或’\0’(字符串结束标志)

    请添加图片描述

    c<q,因此str1<str2,比较结束

  • 返回值:如果比较结果是str1(第一个参数)>str2(第二个参数),则strcmp函数会返回一个大于0的整型值;如果比较结果是str1<str2,则会返回一个小于0的整型值;如果str1=str2,即两个字符串完全相同,会返回0

    (图片来源于MSDN)

char arr1[] = "abcdef";
char arr2[] = "abqa";
int ret = strcmp(arr1, arr2);
printf("%d\n", ret);//小于0的数

除了比较字符串,strcmp函数最常用的应用还是将返回值作为判断条件来判断两个字符串是否相等

长度有限制的同类字符串函数:strncmp

int strncmp(const char* str1, const char* str2, size_t n);
  • 功能是比较两个字符串的前n个字符。和strcmp相似,比较到出现相异字符或其中一个字符串结束或n个字符全部比较完时结束

    char arr1[] = "abcdef";
    char arr2[] = "abqa";
    int ret = strncmp(arr1, arr2, 2);
    printf("%d\n", ret);//0
    

5.strstr

char* strstr(const char* str1, const char* str2)
  • 功能是检索字符串。在str1里寻找str2的内容,判断str2是否为str1的子串。如果str2是str1的子串,则返回str2在str1里首次出现时的指针,如果不是则返回NULL

    请添加图片描述

char arr1[] = "abbbcd";
char arr2[] = "bbc";
char* ret = strstr(arr1, arr2);
printf("%s\n", ret);//bbcd

6.strerror

char* strerror(int errnum);
  • 功能是打印错误信息。不同的错误码对应不同的错误信息,返回错误码对应的错误信息,可以告知用户或程序员错误原因

    请添加图片描述

这里要说到一个用于存放C语言全局错误码的变量——errno。当程序运出错时,会自动将对应的错误码存放在这个全局变量内,当程序运行出错我们又不知道原因时,就可以尝试将这个变量作为参数传递给strerror,让其打印我们所需要的错误信息

使用errno需要引用头文件<errno.h>

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>

int main()
{
    int* p = (int*)malloc(INT_MAX);
	if(p == NULL)//出错
	{
    	printf("%s\n", strerror(errno));//打印错误信息
    	return 1;//中断以保护程序的安全
	}
    
    //业务处理
    free(p);
    p = NULL;
    return 0;
}

7.strtok

char* strtok(char* str, char* sep);
  • 功能是切割字符串

  • str是需要切割的目标字符串的首字符地址。sep是一个字符串,包含了用作分隔符(字符串切割依据)的字符集合

  • 目标字符串中包含了一个或多个sep中的分隔符标记。strtok函数会将目标字符串逐字符与sep中的存在的分隔符标记进行对比,每在目标字符串中找到一个分隔符标记就将其替换为’\0’。显然这个操作会改变目标字符串内容,因此在切割的目标字符串往往都是临时拷贝的一个与目标字符串相同且可修改的字符串

  • strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置;strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记;如果字符串中不存在更多的标记,则返回 NULL 指针

    人话是只有第一次切割时传的参数是目标字符串首元素地址和分隔符字符串,第二次及以后切割都只传NULL和分隔符字符串就行了,因为strtok函数会保存上一次切割时的分隔断点

    请添加图片描述

    可以用循环来巧妙限制切割次数:

    char arr[100] = "805975991@dabuding.com";//待切割的字符串
    char sep[] = "@.";//分隔符为'@'和'.'
    
    //临时拷贝一份一样的字符串
    char tmp[100] = { 0 };
    strcpy(tmp, arr);
    
    //切割
    char* p = NULL;
    for (p = strtok(tmp, sep); p != NULL; p = strtok(NULL, sep))
    //p为NULL时,代表已无分隔符可切割,循环结束
    {
        printf("%s\n", p);
    }
    

    请添加图片描述

    切割结果

二、常用字符串函数的实现


提示:设计函数时善用const关键字和assert函数可以有效增强代码的健壮性

有写错的或更好的实现方法欢迎指出!|?・ω・` )Thanks?

1.strlen

size_t my_strlen1(const char* str)//计数器
{
	assert(str);
	int n = 0;
	while (*str++)
	{
		n++;
	}
	return n;
}

size_t my_strlen2(const char* str)//递归
{
	assert(str);
	if (*str == '\0')
		return 0;
	else
		return (my_strlen2(++str) + 1);

}

2.strcat

char* my_strcat(char* dest, const char* src)
{
	assert(dest && src);
	char* p = dest;

	//找到目标字符串的\0
	while (*dest != '\0')
	{
		dest++;
	}

	//将目标字符串从\0位置处开始替换为源字符串,直到检测到源字符串的\0
	while (*dest++ = *src++)
	{
		;
	}

	return p;//实现链式访问
}

3.strncat

char* my_strncat(char* dest, const char* src, size_t n)
{
	assert(dest && src);
	char* p = dest;
	while (*dest)
	{
		dest++;
	}
	while (n--)
	{
		if ((*dest++ = *src++) == '\0')
		{
			return p;
		}
	}
	*dest = '\0';//记得额外补上\0
	return p;
}

4.strcpy

char* my_strcpy(char* dest, const char* src)
{
	assert(dest && src);
	char* p = dest;
	while (*src != '\0')
	{
		*dest++ = *src++;
	}
	*dest++ = '\0';
	return p;
}

5.strncpy

char* my_strncpy(char* dest, const char* src, size_t n)
{
	assert(dest && src);
	char* p = dest;
	while (n && (*dest++ = *src++) != '\0')
	{
		n--;
	}
	while (n--)
	{
		*dest++ = '\0';
	}
	return p;
}

6.strcmp

int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while (*str1 == *str2)
	{
		if (*str1 == '\0')//指针内容相等且都为\0,表示两个字符串相等
		{
			return 0;
		}
		str1++;
		str2++;
	}
	return *str1 - *str2;//指针内容不等时,返回值的正负取决于str1和str2指向字符的大小
}

7.strncmp

int my_strncmp(const char* str1, const char* str2, size_t n)
{
	assert(str1 && str2);
	while (n-- && (*str1 != '\0' && *str2 != '\0'))
	{
		if ((*str1 - *str2) != 0)
			return (*str1 - *str2);
		else
		{
			str1++;
			str2++;
		}
	}
	return 0;
}

8.strstr

char* my_strstr(const char* dest, const char* src)
{
	assert(dest && src);
	const char* s1 = dest;
	const char* s2 = src;
	char* p = dest;
	while (*p)//*p不为\0时
	{
		s1 = p;
		s2 = src;
		while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
			return p;
		p++;
	}
	return NULL;
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-07-17 16:02:42  更:2022-07-17 16:05:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/13 21:39:27-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码