C语言--字符串函数2
创始人
2025-05-28 10:03:53
0

目录

  • strtok
  • strerror
    • perror
  • 字符分类函数
  • memcpy
    • memcpy的模拟实现
    • memcpy的局限性
  • memmove
    • memmove的模拟实现
  • memcmp
  • memset

本篇文章我们将继续学习相关字符串函数以及内存函数

strtok

我们先来看strtok库函数的书写格式

char * strtok ( char * str, const char * sep );
//其中str是要被分隔的字符串,sep是一个若干个分隔符组成的字符集合。

strtok的具体用法如下:

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

可能只看抽象的用法解释比较难理解,我们用具体的几个例子来搞清楚这个函数具体怎么使用的和效果如何,

int main()
{char arr[] = "192.168.3.212";char buf[30] = {0};strcpy(buf, arr);const char* p = ".";char* str = strtok(buf, p);//printf("%s\n", str);str = strtok(NULL, p);//printf("%s\n", str); str = strtok(NULL, p);//printf("%s\n", str);str = strtok(NULL, p);//printf("%s\n", str);return 0;
}

运行结果如图1
图1
我们结合图像来分析,如图2
图2

但是我们发现,如果只有几个分隔符还好,如果有成千上万个分隔符的时候,难道我们要写几千几万次重复的内容吗?很显然不可能,所以我们可以用一个巧妙的for循环来解决这个问题。
看下面这段代码:

int main()
{char arr[] = "abcdefgggg@yeah.net";char buf[30] = { 0 };strcpy(buf, arr);const char* p = "@.";char* str = NULL;for (str = strtok(buf, p); str != NULL; str=strtok(NULL, p)){printf("%s\n", str);}return 0;
}

运行结果如图3
图3
因为每次调用函数后str都被赋值为指向分隔符位置的指针,并把它作为下一个数组的首元素地址然后执行后续打印等操作,直到最后一次找不到标记时,strtok会返回一个空指针,str!=NULL判定为假,从而跳出了循环

由于这个函数的使用范围比较小,所以本篇文章就不对其进行模拟实现了。

strerror

我们先来看strerror库函数的书写格式

char * strerror ( int errnum );

strerror返回的是一个错误码,每个错误码对应不同的错误信息并将其打印出来
注意,要使用这个库函数需要引用头文件#include
看下面这段代码

int main()
{char* p = strerror(0);printf("%s\n", p);p = strerror(1);printf("%s\n", p);p = strerror(2);printf("%s\n", p);p = strerror(3);printf("%s\n", p);return 0;
}

运行结果如图4
图4
我们可以发现,不同的整型数字对应不同的错误,至于具体值是多少,这就是电脑自行判断给出的值了,我们以打开一个文件为例

int main()
{//打开文件//打开文件的时候,如果文件的打开方式是"r"//文件存在则打开成功,文件不存在打开失败//打开文件失败的话,会返回NULLFILE* pf = fopen("test.txt", "r");if (pf == NULL){printf("打开文件失败,原因是:%s\n", strerror(errno));return 1;}//读写文件//...//关闭文件fclose(pf);pf = NULL;return 0;
}

运行结果如图5
图5

根据注释内容,由于我的电脑上并没有这个test.txt文件,所以打开失败,返回NULL,并且error的值就为3(看整形3对应的错误信息)

perror

这个库函数实际意义上就是prinf+strerror

int main()
{//打开文件//打开文件的时候,如果文件的打开方式是"r"//文件存在则打开成功,文件不存在打开失败//打开文件失败的话,会返回NULLFILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("打开文件失败");//printf + strerrorreturn ;}//读写文件//...//关闭文件fclose(pf);pf = NULL;return 0;
}

运行结果和图5一样,如图6

图6

字符分类函数

我们来看一些字符分类函数

这些函数都是用来判断相关数据的,我们举几个例子
需要引用头文件**#include **

void test7()
{printf("%d\n", isdigit('6'));	printf("%d\n", isspace('2'));printf("%d\n", islower('x'));printf("%c\n", toupper('x'));printf("%c\n", tolower('X'));
}

打印结果如图

这里的toupper,tolower根据字面意思也能理解,作用就是大小写的转换
我们就以这个大小写转换函数为例

void test8()
{char arr[128] = {0};gets(arr);int i = 0;while (arr[i]){if (isupper(arr[i])){arr[i] = tolower(arr[i]);}printf("%c", arr[i]);i++;}
}

运行结果如下

可见,如果我们可以灵活运用这些库函数来实现许多功能,就可以大大简化代码复杂度。

讲到这里,我们回过去思考一个问题,我们前面学的内容都是对char类型字符串进行相关操作,那么如果是一个整型数组,浮点型数组又该怎么办呢?貌似用str为前缀的相关函数就行不通了,所以为了操作这些类型的数组,我们引入了使用范围更为广泛的内存函数

memcpy

我们还是先来看memcpy库函数的书写格式

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

具体的使用方法如下

  1. 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置
  2. 这个函数在遇到 ‘\0’ 的时候并不会停下来
  3. 如果source和destination有任何的重叠,复制的结果都是未定义的(这个后面和memmove比较再来讲)
    我们
    先来以复制一个整型数组为例,看下面这段代码
void test1()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[8] = { 0 };//把arr1中的前5个数据拷贝到arr2中memcpy(arr2, arr1, 20);
}

这里要特别注意!
这个size_t num是无符号整型,单位是字节!!!
因为这个函数并不知道我们传递的参数是什么类型,所以如果我们传递的是整型数组,整型是4个字节,所以如果要拷贝五个数据,就应该输入4*5=20.

memcpy的模拟实现

我们现在来模拟实现一下memcpy库函数的相关功能,看下面这段代码:

void* my_memcpy(void* dest, const void* src, size_t num)
{void* ret = dest;assert(dest && src);//断言while (num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}return ret;
}

因为memcpy的创建者并不知道我们这些使用者将来会用memcpy来操作什么类型的数据,所以用void*来书写,由于size_t num的单位是字节,为了方便循环次数对的上,我们就将dest和src指针都强制类型转换为char类型

memcpy的局限性

我们发现,当用memcpy来拷贝同一数组的元素时可能会出现bug,我们通过图来分析
图7
所以为了避免这种情况的发生,我们首先要对dest和src的位置先后进行一个判断,如果出现上述图中这种情况,就应该从后向前拷贝来避免覆盖,反之则从前向后拷贝
这其实就是接下来要讲的memmove库函数了

memmove

memmove库函数在memcpy函数的基础上又有优势,和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。如果源空间和目标空间出现重叠,就得使用memmove函数处理。
比如下面这段代码

void test2()
{int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };memmove(arr1+2, arr1, 20);for (int i = 0; i < 10; i++)printf("%d ", arr1[i]);
}

运行结果如图8
图8
我们可以发现被覆盖的部分在拷贝的时候并没有受到影响。

memmove的模拟实现

其实memmove函数的模拟实现就是在memcpy的模拟实现上优化了拷贝顺序
具体的代码修改如下:

void* my_memmove(void* dest, const void* src, size_t num)
{void* ret = dest;assert(dest && src);if (dest < src){//前->后while (num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}}else{//后->前while (num--){*((char*)dest + num) = *((char*)src + num);//num越来越小,从后向前拷贝}}return ret;
}

所以我们来总结一下
1. C语言中,memcpy拷贝不重叠内存
2. 重叠的就交给memmove
3. 在功能性上memmove>memcpy。

memcmp

类比strcmp,memcmp就是一个可以实现比较任意类型数据是否相等功能的库函数
举个例子

void test5()
{int arr1[] = { 1,2,3,4,7};//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 07 00 00 00int arr2[] = { 1,2,3,4,6};//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 06 00 00 00int ret = memcmp(arr1, arr2, 16);printf("%d\n", ret);
}

如果比较的是16个字节,那么就是相等的,但如果比较的是17个字节 07是大于06的,所以返回值是大于0的类比strcmp的返回值

memset

我们还是先来看书写格式

void *memset(void *s, int c, unsigned long n);

其中s是指向要操作的数组或字符串的首元素地址,c是要修改的值,n是要修改的字节长度
看下面这段代码

void test6()
{char arr[] = "hello world";memset(arr, 'x', 5);printf("%s\n", arr);
}

打印结果如图9
图9
我们再来看一段代码

	int arr[10] = { 0 };memset(arr, 1, sizeof(arr));int i = 0;for (i = 0; i < 10; i++){printf("%x ", arr[i]);}

运行结果如图10
图10
我们发现每个元素的值并没有被修改为1,这是因为memset是以字节为单位来修改数据的,但是int类型每个元素显然不是一个字节,所以这种写法是无法将数据的每个元素设置为1的。

以上就是关于字符串函数以及内存函数全部内容了,如有出入,欢迎指正。

相关内容

热门资讯

刚刚,大跳水!超42万人爆仓!... 来源:券商中国 加密货币,遭遇抛售潮! 凯文·沃什被提名为下一任美联储主席所产生的后续效应,正持续波...
做好银行网点“加减法” 国家金融监督管理总局网站披露的信息显示,2025年共有约1.1万家银行业金融机构的线下网点获准退出,...
金价暴跌引热议,网友:商场门口... 来源:中国基金报 随着国际金价急速下跌,国内首饰金价也迎来大幅回调。 1月31日,老庙报1546元/...
内蒙古一银行员工将储户220万... 内蒙古一银行员工将储户220万元存款转走并挥霍,银行称员工已离岗不愿承担赔偿 1月31日,有媒体报...
老年医学科进修轶事|老年医学如... 和年苑,北京协和医院老年医学科公众号,传递老年医学的价值和声音 在这里,了解当代老年医学 Autum...
和讯投顾余兴栋:周五杀跌,下周... 周五大盘大幅度的杀跌又探底回升,收出一根长长的下影线,不少的朋友又在问我,那这根k线是不是就意味着调...
【数智周报】马化腾评豆包手机;... 【数智周报将整合本周最重要的企业级服务、云计算、大数据领域的前沿趋势、重磅政策及行研报告。】 观点马...
和美字节,用字节连接和美 和美字节(Hemei Byte),是杭州桑桥网络科技有限公司于 2026 年 1 月完成品牌升级后启...
仙乐健康56岁副总姚壮民业务员... 瑞财经 刘治颖 1月29日,仙乐健康科技股份有限公司(以下简称:仙乐健康)向港交所主板递交上市申请书...
詹姆斯下家概率:骑士最高退役第... 近日,有关詹姆斯的未来引发了大众的热议,相关机构也更新了这位巨星的下家概率,回归骑士是最大可能。 相...
原创 猛... 在国际金价屡创历史新高之时,资本市场正经历一场有趣的分化:有人急于套现离场,有人却大举加码。近日,一...
原创 男... 在爱情的海洋中,星座与情感交织出无数动人的故事。当一个男性用以下这四个称呼来称呼你时,他的爱情之舟正...
民航持续回暖:南航、海航预计去... 时隔五年,南航预计在三大航中率先实现年度扭亏。 截至1月30日晚间,中国国航(601111.SH)、...
公募加仓非银金融,后市机会如何... 基金增配保险、券商股。 最新数据显示,公募基金2025年四季度的非银金融仓位提高1个百分点。继有色金...
赵慧芳主任中医治疗产后“月子病... 赵慧芳主任中医治疗产后“月子病”的临床智慧 产后调理是中华民族传承千年的养生智慧,在中医理论中占据重...
江西万年青水泥股份有限公司20... 本公司及董事会全体成员保证信息披露的内容真实、准确、完整,没有虚假记载、误导性陈述或重大遗漏。 一、...
科学应对甲状腺结节,别让“结节... 随着健康意识的提升 超声检查在体检中普及率不断提高 甲状腺结节的检出率也显著上升 不少人拿着“结节”...
春节前,政府债发行提速 来源:郁言债市 01 1月资金面,两轮波动,中枢平稳 回顾开年以来资金利率走势,月内资金经历两轮波动...
【央行多措并举护航,专家预期节... 【央行多措并举护航,专家预期节前流动性保持充裕】1月29日,中国人民银行以固定利率、数量招标方式开展...
季节性因素叠加市场需求不足,1... 来源:界面新闻 记者 辛圆 国家统计局周六公布数据显示,1月份,中国制造业采购经理人指数(PM...