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的。

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

相关内容

热门资讯

在大吉订购APP订购交易亏损被...   近期,不少投资者反映在“大吉订购App”上投资白银、铂金等商品遭遇严重亏损。该平台宣称提供现货订...
铂银壹号APP商品订购交易亏损...   许多中小投资者误以为网上的“商品现货订购”是合规合法的理财渠道,殊不知这背后隐藏着巨大的合规风险...
兴鑫淘金APP贵金属订购交易亏...   白银、贵金属或其他商品类投资,除国家批准的正规期货交易场所及持牌期货公司外,市面上大量第三方交易...
铂银掘金APP无资质的违规平台...   铂银掘金等平台的投资者,往往是被“注册送现金”“充值返现券”“首单免亏”等广告话术吸引,进而下载...
八方淘金APP订购交易不合规,...   “八方淘金APP”“铂银掘金APP”“铂银壹号APP”等软件被指以“现货订购”为名,实际采用高杠...
在指尖订购APP订购商品亏损被...   指尖订购APP这类平台,表面是“订购交易”,实则是披着电商外衣的非法期货陷阱。绝大多数投资者被蒙...
在犀贝易购APP做商品订购交易...   市面上打着“现货投资”“贵金属交易”旗号的APP并不少,但真正合规、受监管的平台并不多。犀贝易购...
易达淘金APP虚假商品订购交易...   易达淘金APP存在严重的虚假宣传与违规交易行为。该平台打着“商品订购”的旗号,实则通过不合规的交...
大浪淘金APP白银订购亏损被骗...   大浪淘金APP最隐蔽的套路,在于其完全封闭的内盘交易系统。表面上,它宣称与国际贵金属市场接轨;实...
一品好购APP上订购白银出现亏...   一品好购APP原名“一品订购”,运营方为上海宝智未来信息技术有限公司。近期不少投资者反映在该平台...
九州订购APP贵金属订购投资骗...   九州订购APP正通过抖.音、快手、今日头条等平台大量投放投资广告,用“5元起投”“充值返现”“0...
坚锅淘金APP交易软件并不正规...   当前,市面上大量所谓的“现货商城订购”交易软件,早已偏离了正常的实物商品买卖,演变为高杠杆、高手...
斗金订购APP贵金属期货交易骗...   斗金订购APP的投资者往往被铺天盖地的广告宣传所诱导——注册即送现金、充值返现券等看似诱人的福利...
警惕!云启购APP违规经营,披...   "5元起投、充值返现、稳赚不赔"——这些诱人的广告语背后,可能是一个精心设计的金融陷阱。  近期...
量子淘金APP贵金属投资不合规...   "4元起投""充值返券""月入过万"——这些极具诱惑力的广告语在短视频平台、社交软件上铺天盖地。...
鑫汇智投APP贵金属商品订购骗...   鑫汇智投APP非法期货投资骗局,受害者在投资过程中根本不懂交易,也不去研究和验证这个平台是否正规...
矅光智策APP平台违规经营非法...   矅光智策APP对外宣称是“商城订购”“现货交易”,但查询其经营范围,并未显示具备开展现货期货交易...
黄金珠宝怎么选?内侧刻字都代表... 潮新闻客户端 记者 马焱 通讯员 任倩影 9月8日下午,“云游杭州 乐购金秋”——“浙城·浙放心”活...
原创 冰... 最近全球国债市场正在上演魔幻一幕: 美债、日债、欧债遭遇猛烈抛售,收益率冲到几十年新高,美国财政部都...
日韩股市开盘表现分化 上证报中国证券网讯 9月9日,日韩股市开盘表现分化,韩国综合指数开盘上涨0.26%,报6972.87...