【C语言】字符串函数「超详细」

🚩write in front🚩

🔎大家好,我是謓泽,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流🔎
🏅2021年度博客之星物联网与嵌入式开发TOP5~2021博客之星Top100~阿里云专家^ 星级博主~掘金⇿InfoQ创作者~周榜54»总榜2999🏅
🆔本文由 謓泽 原创 CSDN首发 🙉 如需转载还请通知⚠
📝个人主页-
謓泽的博客_CSDN博客💬
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​
📣系列专栏-
【C】系列_謓泽的博客-CSDN博客🎓
📢本文 de 创作时间  ⇨  2021  年  2  月  11  日📅
✉️我们并非登上我们所选择的舞台,演出并非我们所选择的剧本📩

🌴『C语言』字符串de函数 🌴

🚩write in front🚩

🎉前言🎉 

🎄strlen() - 计算字符串长度🎄

🎄strlen()函数代码示例🎄

🎄创建自定义函数实现strlen()的功能🎄

🎄strcpy() - 复制字符串🎄

🎄strcpy()函数代码示例🎄

🎄创建自定义函数实现strcpy()的功能🎄

🎄strcat() - 连接字符串🎄

🎄strcat()函数代码示例🎄 

🎄创建自定义函数实现strcat()的功能🎄

🎄strcmp() - 比较字符串🎄

🎄strcmp()函数代码示例🎄 

🎄创建自定义函数实现strcmp()🎄   

🔧 限制 🔧

🎋strncpy() - 复制字符串(受长度限制)🎋

🎋strncpy()函数代码示例🎋

🎋strncpy()源程序实现🎋 

🎋strncat() - 连接字符串(受长度限制)🎋

🎋strncat()函数代码示例🎋

🎋strncat()源程序实现🎋 

🎋strncmp() - 比较字符串(受长度限制)🎋 

🎋strncmp()函数代码示例🎋  

🎋strncat()源程序实现🎋

🎍strstr() - 在一个字符串中查找另外一个字符串🎍

🎍strstr()函数代码示例🎍

🎍创建自定义函数实现strstr()🎍

🎍strtok() - 切割字符串🎍

🎍strtok()函数代码示例🎍

🎍strtok()源程序实现🎍

🎍strerror() - 返回错误码🎍 

🎍strerror()函数代码示例🎍

🎍strerror()源程序实现🎍

✨最后✨

🎉前言🎉 

这篇博客我们来介绍下字符串函数的使用,可能对字符串函数的使用大多人刚开始学习会学习了一段时间只是知道几种字符串函数的使用 像 strlen()、strcpy()、strcat()、strcmp()、这四种字符串库函数的使用。而字符串函数绝对不仅仅只有这四种库函数,实际上字符串函数可以说是"五花八门"了,在这篇博客当中我就会详细介绍字符串函数的各种使用。

在使用C语言的字符串库函数的时候记得要添加相应的头文件#include<string.h>               

记得三连(o゚v゚)ノ

🎄strlen() - 计算字符串长度🎄

strlen() 函数的声明方式如下 👇

size_t strlen ( const char * str );

获取字符串长度。

返回 C 字符串 str 的长度。

 str  要计算长度的字符串。

字符串的'\0'作为结束标志,strlen函数的返回值是在字符串中出现的字符个数(不包含'\0')

注意:函数的返回值是无符号的 unsigned 容易出错の。

Size_t→是一个无符号(unisgned int)整型类型。 

🔥→strlen的工作原理:只要给我个地址,那么strlen就可以向后数字符,至到遇到'\0'就会停止。

🎄strlen()函数代码示例🎄

使用 strlen() 函数代码示例如下 👇

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>

int main(void)
{
	char str[20] = {"44778899"};

	int len = strlen(str);
	printf("%s 的长度是 %d\n", str, len);

	return(0);
}

运行结果如下→44778899 的长度是 8 

当然我们还要注意:char str[] = {'a','b','c'};如果是这样的话就没有'\0',那么产生的就是随机值!还是按照上面的代码进行演示。

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>

int main(void)
{
	char str[] = {'a','b','c'};

	int len = strlen(str);
	printf("%s 的长度是 %d\n", str, len);

	return(0);
}

这样的运行结果就会是随机值,因为我们不知道反斜杠'\0'在哪里。 

🎄创建自定义函数实现strlen()的功能🎄

示例代码如下:👇 

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>//assert的头文件
int My_strlen(const char *arr)
{
	unsigned int Count = 0;//统计字符不可能是为负数的!
    assert(arr!=NULL);//这里加入到断言就能确保我们输入字符串的时候不会是空指针
	while (*arr != '\0')
	{
		Count++;
		*arr++;
	}
	return Count;//返回计算机长度
}
int main(void)
{
	char enter[20] = { 0 };
	printf("请输入字符串->:");
	scanf("%s", &enter);
	int ret = My_strlen(enter);
	printf("The total number of input strings:%d\n",ret);
	return 0;
}

运行结果如下 👇

请输入字符串:C语言天下第一 

The total number of input strings:7


🎄strcpy() - 复制字符串🎄

strcpy() 函数的声明方式如下 👇

char *strcpy(char *dest, const char *src)

把 src 所指向的字符串复制到 dest。

需要注意的是如果目标数组 dest 不够大,而源字符串的长度又太长,可能会造成缓冲溢出的情况。所以,dest 一定要足够大,这样才能被 src 给存放的下去。

dest 指向用于存储复制内容的目标数组。

src 要复制的字符串。

该函数返回一个指向最终的目标字符串 dest 的指针。

strcpy()在原来字符要保证拥有 src 存在字符的空间大小也就是下标。

注意:这里的返回值的指针类型可以是void *也可以是char *的类型。

🎄strcpy()函数代码示例🎄

使用 strcpy() 函数代码示例如下 👇

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

int main ()
{
  char str1[]="C语言";
  char str2[40];
  char str3[40];
  strcpy (str2,str1);
  strcpy (str3,"C++语言");
  printf ("str1: %s\nstr2: %s\nstr3: %s\n",str1,str2,str3);
  return 0;
}

运行结果如下 👇

str1: C语言
str2: C语言
str3: C++语言
 

当然我们还要注意:char str[ ] = {'a','b','c'};如果你是想这样子进行存放的话依旧还是不行的原因很简单'\0',示例代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>

int main()
{
	char str1[] = { 'a', 'b', 'c' };
	char str2[40];
	strcpy(str2, str1);
	printf("%s", str2);
	return 0;
}

运行结果如下 👇

  

就会是这个样子具有随机值后面,因为我们不清楚'\0'到底在哪里。

当然如果是这样char str1[] = { 'a', 'b', 'c','\0'};就不会因为我们在最后一个元素添加了'\0'。 

🎄创建自定义函数实现strcpy()的功能🎄

示例代码如下:👇 

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <assert.h>
void My_strcpy(char *dest, const char *src)
{
	assert(dest != NULL);
	assert(src != NULL);
	while (*src != '\0')
	{
		*dest = *src;//进行赋值
		*src++;
		*dest++;//指向下一个字符
	}
}
int main(void)
{
	char *p = "C语言";
	char str[20] = { 0 };
	My_strcpy(str, p);
	printf("str = %s\n",str);
	return 0;
}

运行结果如下 👇

str = C语言


🎄strcat() - 连接字符串🎄

strcat() 函数的声明方式如下 👇

char *strcat(char *dest, const char *src)

将源字符串的副本追加到目标字符串。

dest → 指向目标数组,该数组包含了一个 C 字符串,且足够容纳追加后的字符串。

src → 指向要追加的字符串,该字符串不会覆盖目标字符串。

该函数返回一个指向最终的目标字符串 dest 的指针。

把 src 所指向的字符串追加到 dest 所指向的字符串的结尾。

不能自己给自己追加程序,像这样:

char arr[20] = "Cyuyan"
strcat(arr,arr);
printf("%s\n",arr);

这样子是不行的,本来我的这个数组存放的是:Cyuyan\0,因为这块空间足够长后面还是有内容的。那么如果我们要进行追加的话就会是这个样子:CyuyanCyuyan,本质上我们的斜杠0会在CyuyanCyuyan这个字符串n的后面。但是斜杠0被覆盖了,那么被谁覆盖的呢,就是被自己所追加的 arr 所覆盖了。这样就会构成循环,因为我们永远都找不到反斜杠0-O-

🎄strcat()函数代码示例🎄 

使用 strcat() 函数代码示例如下 👇

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main(void)
{
	char arr1[20] = "hello C";
	char arr2[20] = "yuyan";
	strcat(arr1, arr2);
	printf("arr1 = %s\n", arr1);
	return 0;
}

运行结果如下 👇 

arr1 = hello Cyuyan

让我们来看看它的调试结果的步骤🧐

🎄创建自定义函数实现strcat()的功能🎄

思路很简单其实 👇

Ⅰ→dest 找到目标字符串'\0'

Ⅱ→再把源数据追加到字符串'\0'的后面,注意:是包含'\0'的

示例代码如下:👇 

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
char *My_strcat(char *dest, const char *src)
{
	assert(dest && src != NULL);//断言
	char *ret = dest;
	while (*dest != '\0')//'\0'的ASCLL码值就是0
	{
		dest++;
	}
    //dest指向的是'\0'
	while (*dest++ = *src++)
	{
		;
	}
    /*相当于
	while (*src != '\0')
	{
		*dest++ = *src++;
	}*/
	return ret;
}
int main(void)
{
	char arr1[20] = "hello C";
 	char arr2[20] = "yuyan";
	printf("%s\n", My_strcat(arr1, arr2));
	return 0;
}

运行结果如下 👇 

hello Cyuyan

🍊⒈注→在上述的代码细节还是非常多的非常值得调试以下观察它的运行步骤。如

🍎⒉注→'\0'实际上也是对应着C语言的空字符NULL十进制为0的值。


🎄strcmp() - 比较字符串🎄

strcmp() 函数的声明方式如下 👇

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

将 C语言 字符串 str1 与 C语言 字符串 str2 进行比较。

此函数开始比较每个字符串的第一个字符。 如果它们彼此相等,则继续以下对,直到字符不同或到达终止空字符。此函数执行字符的二进制比较。

str1 → 要进行比较的第一个字符串。

str2 → 要进行比较的第二个字符串。

比较每一位字符比较的大小是ASCll码的值。

该函数返回值如下:该函数具有返回值 int 

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

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

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

🎄strcmp()函数代码示例🎄 

使用 strcmp() 函数代码示例如下 👇

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main()
{
	char str1[20] = { 0 };
	char str2[20] = { 0 };
	puts("请输入第一个字符串:");
	scanf("%s", &str1);
	puts("请输入第二个字符串:");
	scanf("%s", &str2);
	puts("返回的值:");
	printf("%d",strcmp(str1, str2));
	return 0;
}

🎄第一次的运行结果🎄

请输入第一个字符串:abc
请输入第二个字符串:abc
返回的值:0

🎄第二次的运行结果🎄

请输入第一个字符串:abcd
请输入第二个字符串:abc
返回的值:1

🎄第三次的运行结果🎄 

请输入第一个字符串:abc
请输入第二个字符串:abcd
返回的值:-1

🎄创建自定义函数实现strcmp()🎄   

思路很简单其实 👇

相等为0、大于返回1、小于返回-1,重要的点注释其实都是写了的。

示例代码如下:👇  

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
int my_strcmp(const char *str1, const char *str2)
{
	assert(str1 && str2 != NULL);
	while (*str1 == *str2)
	{
		//判断相等情况,有一个相等就代表*str2也是一样的
		if (*str1 == '\0')
		{
			return 0;
		}
		*str1++;
		*str2++;//自增比较
	}
	if (*str1 > *str2)
		return 1;//大于
	else
		return -1;//小于
	//其实还有一种更简单的方法,大于小于。
	//return *str1 - *str2;
	//这个是指针减指针的概念,前面介绍有说过!
}
int main()
{
	char str1[20] = { 0 };
	char str2[20] = { 0 };
	puts("请输入第一个字符串:");
	scanf("%s", &str1);
	puts("请输入第二个字符串:");
	scanf("%s", &str2);
	int ret = my_strcmp(str1, str2);
	printf("返回的值:%d\n",ret);
	return 0;
}

🎄第一次的运行结果🎄

请输入第一个字符串:abc
请输入第二个字符串:abc
返回的值:0

🎄第二次的运行结果🎄

请输入第一个字符串:abcd
请输入第二个字符串:abc
返回的值:1

🎄第三次的运行结果🎄 

请输入第一个字符串:abc
请输入第二个字符串:abcd
返回的值:-1

以上四个字符串函数是我们学C语言必须要掌握的,包括模拟字符串函数的实现也是有必要去实现的,这样的好处可以锻炼我们对函数库的了解,增强自己写代码的能力,建议反复观看,牢记掌握这四个字符串函数~ 


🔧 限制 🔧

上述 strcpy、strcat、strcmp、长度是不受限制的字符串函数

而下面所说的是长度受限制的字符串函数了>>>

起始记住下面这个只需要在上面的基础上加上个str后面+n即可(^∀^●)ノシ

下面所介绍的3种函数相对比上的使用要更加安全,但并不是绝对安全。


🎋strncpy() - 复制字符串(受长度限制)🎋

这个函数实际上和strcpy()的功能是一模一样的,唯一不同的是在于strncpy()多了一个参数,那个参数就是受长度所限制的。

strncpy() 函数的声明方式如下 👇

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

把 src 所指向的字符串复制到 dest,最多复制 n 个字符。

当 src 的长度小于 n 时,dest 的剩余部分将用空字节填充。

dest → 指向用于存储复制内容的目标数组。

src → 要复制的字符串。

n → 要从源中复制的字符数。

Size_t→是一个无符号整型类型。

该函数最终返回所复制的字符串。 

🎋strncpy()函数代码示例🎋

使用 strncpy() 函数代码示例如下 👇

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main(void)
{
	char str1[20] = "helloC";
	char str2[] = "HELLO";
	printf("字节=%d\n", sizeof(str2));
	printf("str = %s\n",strncpy(str1, str2, sizeof(str2)));
	return 0;
}

运行结果如下 👇 

字节 = 6

str = HELLO 

sizeof(str2) 相当于为 6个字节,因为 char 为一个字节 里面元素有6个包括'\0'

✅来一起看看调试结果说不定会更好点✅

我们再来看下一个例子 👇 

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main(void)
{
	char str1[20] = "helloC";
	char str2[] = "HELLO";
	printf("字节=%d\n", sizeof(char));
	printf("str = %s\n", strncpy(str1, str2, sizeof(char)));
	return 0;
}

运行结果如下 👇 

字节 = 1

str = HELLO 

sizeof(char) 结果为一个字节,因为 char 类型大小为一个字节!

✅来一起看看调试结果说不定会更好点✅

🎋strncpy()源程序实现🎋 

示例代码如下:👇

char * __cdecl strncpy (
        char * dest,
        const char * source,
        size_t count
        )
{
        char *start = dest;

        while (count && (*dest++ = *source++))    /* copy string */
                count--;

        if (count)                              /* pad out with zeroes */
                while (--count)
                        *dest++ = '\0';

        return(start);
}

🎋strncat() - 连接字符串(受长度限制)🎋

strncat() 函数的声明方式如下 👇 

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

把 src 所指向的字符串追加到 dest 所指向的字符串的结尾,直到 n 的长度为止。

dest→指向目标数组,该数组包含了一个 C语言 字符串,且足够容纳追加后的字符串,包括额外的空字符。

src→要追加的字符串。

n→追加的最大字符串。

Size_t→是一个无符号(unisgned int)整型类型。 

该函数返回一个指向最终的目标字符串 dest 的指针。

注意:这里的返回值的指针类型可以是void也可以是char *🧨

🎋strncat()函数代码示例🎋

使用 strncpy() 函数代码示例如下 👇

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main(void)
{
	char str1[20];
	char str2[20];
	strcpy(str1, "Cyuyan");
	strcpy(str2, "yyds");
	printf(strncat(str1, str2, 5));//追加字符串!
	return 0;
}

运行结果如下 👇 

Cyuyanyyds 

✅来一起看看调试结果说不定会更好点✅

我们把 Size_t 参数改为④来看看

printf(strncat(str1, str2, 4));

运行结果依旧和上述结果是一样的。 

🎋strncat()源程序实现🎋 

示例代码如下:👇

char * __cdecl strncat (
        char * front,
        const char * back,
        size_t count
        )
{
        char *start = front;

        while (*front++)
                ;
        front--;

        while (count--)
                if (!(*front++ = *back++))
                        return(start);

        *front = '\0';
        return(start);
}

🎋strncmp() - 比较字符串(受长度限制)🎋 

strncmp() 函数的声明方式如下 👇

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

str1 → 要进行比较的第一个字符串。

str2 → 要进行比较的第二个字符串。

n → 要比较的最大字符数。

这个函数开始比较每个字符串的第一个字符。如果它们相等,则继续执行下面的对,直到字符不同,直到达到一个结束的空字符,或直到两个字符串中的num字符匹配,以先发生的为准。

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

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

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

🎋strncmp()函数代码示例🎋  

使用 strncpy() 函数代码示例如下 👇

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main(void)
{
	char str1[20];
	char str2[20];
	strcpy(str1, "Cyuyan");
	strcpy(str2, "Cyuyanyyds");
	printf("%d", strncmp(str1, str2, 6));

	return 0;
}

运行结果如下 👇 

0 → 代表str1 等于 str2

如果这里没有追加字符串的话结果就会是-1,因为str1<str2。正因为我们追加了字符为6,它才可以是str1 = str2。

🎋strncmp()源程序实现🎋

示例代码如下:👇

int __cdecl strncmp
(
    const char *first,
    const char *last,
    size_t      count
)
{
    size_t x = 0;

    if (!count)
    {
        return 0;
    }

    /*
     * This explicit guard needed to deal correctly with boundary
     * cases: strings shorter than 4 bytes and strings longer than
     * UINT_MAX-4 bytes .
     */
    if( count >= 4 )
    {
        /* unroll by four */
        for (; x < count-4; x+=4)
        {
            first+=4;
            last +=4;

            if (*(first-4) == 0 || *(first-4) != *(last-4))
            {
                return(*(unsigned char *)(first-4) - *(unsigned char *)(last-4));
            }

            if (*(first-3) == 0 || *(first-3) != *(last-3))
            {
                return(*(unsigned char *)(first-3) - *(unsigned char *)(last-3));
            }

            if (*(first-2) == 0 || *(first-2) != *(last-2))
            {
                return(*(unsigned char *)(first-2) - *(unsigned char *)(last-2));
            }

            if (*(first-1) == 0 || *(first-1) != *(last-1))
            {
                return(*(unsigned char *)(first-1) - *(unsigned char *)(last-1));
            }
        }
    }

    /* residual loop */
    for (; x < count; x++)
    {
        if (*first == 0 || *first != *last)
        {
            return(*(unsigned char *)first - *(unsigned char *)last);
        }
        first+=1;
        last+=1;
    }

    return 0;
}

🎍strstr() - 在一个字符串中查找另外一个字符串🎍

strstr() 函数的声明方式如下 👇 

char *strstr(const char *haystack, const char *needle)

在字符串 haystack 中查找第一次出现字符串 needle 的位置,不包含终止符 '\0'。

haystack→ 要被检索的 C 字符串。

needle→ 在 haystack 字符串内要搜索的小字符串。

该函数返回在 haystack 中第一次出现 needle 字符串的位置,如果未找到则返回 null。

注意:这里的返回值的指针类型可以是void也可以是char *🧨

🎍strstr()函数代码示例🎍

题目:在arr1中查找是否包含arr2中的数组。要求使用 strstr() 库函数。

使用 strncpy() 函数代码示例如下 👇

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main(void)
{
	char arr1[20] = "abcdef";
	char arr2[20] = "bcd";
	char ret = strstr(arr1, arr2);
	if (ret == NULL)
	{
		printf("没找到!\n");
	}
	else
	{
		printf("找到了→%s\n", ret);
	}
	return 0;
}

运行结果如下 👇 

找到了→bcdef

那没找到的情况下,我们把 arr2 数组修改下。其它值不变🎉

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
int main(void)
{
	char arr1[20] = "abcdef";
	char arr2[20] = "bf";
	char *ret = strstr(arr1, arr2);
	if (ret == NULL)
	{
		printf("没找到%s!\n",ret);
	}
	else
	{
		printf("找到了→%s\n", ret);
	}
	return 0;
}

运行结果如下 👇 

找不到(null)!

对比之下,你发现了区别了没👀

🎍创建自定义函数实现strstr()🎍

分析思路🧐

其实很容易,我们只需要拿首字符地址进行比较相等的话返回,不相等的时候进行自增++(注意:这里自增++只需要str1进行++而str2依旧拿首元素地址跟它进行比较),再进行比较直到'\0',没有就返回空指针NULL。如果str1有元素和str2首元素地址匹配上了的话那么就继续往后走~但是,这个仅仅是假设 abcd 和 bcd 所适用的场景。如果是 bbbc 和 bbc,这种怎么办?是不是发现用这种思路不行,下面就用代码来讲解下怎么实现。

示例代码如下:👇  

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
char *my_strstr(const char *str1, const char *str2)
{
	assert(str1 && str2 != NULL);
	const char* s1 = NULL;
	const char* s2 = NULL;//在不知道赋值什么的情况下直接赋值空指针。
	if (*str2 == '\0')
		return (char*)str1;//假设str2首元素地址为空字符串直接返回str1
	while (*str1)
	{
		s1 = str1;
		s2 = str2;
		while (*s1 && *s2 != '\0' && (*s1 == *s2))
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return (char*)str1;//注意返回类型强制转换!
		}
		str1++;
	}
	return NULL;
}
int main(void)
{
	char arr1[20] = "abbcdef";
	char arr2[20] = "bc";
	char *ret = my_strstr(arr1, arr2);
	if (ret == NULL)
	{
		printf("没找到%s!\n",ret);
	}
	else
	{
		printf("找到了→%s\n", ret);
	}
	return 0;
}

运行结果如下 👇 

bcdef 

这个代码的实现相对来说比上面的代码都要比较复杂,希望各位理解了可以自己上手做下,因为自有当你把代码打出来了,那么才是你学到的知识。


🎍strtok() - 切割字符串🎍

这个函数比较难懂,比较奇观,使用场景也不多见。

strtok() 函数的声明方式如下 👇 

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

对该函数的调用序列将str分割成标记,标记是由连续字符组成的序列,由分隔符的任何字符分隔。 

在第一次调用时,函数期望一个C的字符串作为str的参数,它的第一个字符被用作扫描标记的起始位置。在随后的调用中,该函数期望得到一个空指针,并使用最后一个标记结束后的位置作为新的扫描起始位置。

要确定标记的开始和结束,函数首先从开始位置扫描分隔符中不包含的第一个字符(它成为标记的开始)。然后从标记的这个开头开始扫描分隔符中包含的第一个字符,这个字符成为标记的结尾。如果找到终止的空字符,扫描也会停止。

这个标记的末尾会被一个空字符自动替换,而该标记的开头则由函数返回。

一旦在strtok调用中找到str的终止空字符,所有后续对该函数的调用(以空指针作为第一个参数)都返回一个空指针。

找到最后一个令牌的位置由函数保存在内部,以便下次调用时使用(为了避免数据竞争,不需要特定的库实现)。

str→要截断的C字符串。注意,这个字符串被分解成更小的字符串(令牌)。
或者,可以指定一个空指针,在这种情况下,函数继续扫描之前对该函数的成功调用结束的地方。

delimiters→包含分隔符字符的C字符串。这些在不同的调用之间可能是不同的。

返回值:如果找到令牌,则指向令牌开头的指针。否则,为空指针。当被扫描的字符串到达字符串的末尾(即一个空字符)时,总是返回一个空指针。

🎍strtok()函数代码示例🎍

题目:把字符串"Hello.Cyuyan.yyds",.之前语句进行分割最后进行打印。用strtok字符串函数实现。

使用 strtok() 函数代码示例如下 👇

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

int main(void)
{
	char str[] = "Hello.Cyuyan.yyds";
	printf("yiduanhua|%s|dezifu\n", str);
	char * pch=strtok(str, ".");
	while (pch != NULL)
	{
		printf("%s\n", pch);
		pch = strtok(NULL, ".");
	}
	return 0;
}

运行结果如下 👇 

Hello.Cyuyan.yyds

Hello

Cyuyan

yyds

不知道你是否明白了( ゚д゚)つ

在这里思考下,那么它使用什么进行保存的呢?就是这个函数它能够记住地址,其实这个只需要用到一个关键字 static 静态局部变量就可以完美实现这种类似于记忆功能,把生命周期延长,出了函数的范围内不会销毁保留原来的值。


🎍strtok()源程序实现🎍

示例代码如下:👇  

/***
*strtok.c - tokenize a string with given delimiters
*
*       Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:
*       defines strtok() - breaks string into series of token
*       via repeated calls.
*
*******************************************************************************/

#include <cruntime.h>
#include <string.h>
#ifdef _SECURE_VERSION
#include <internal.h>
#else  /* _SECURE_VERSION */
#include <mtdll.h>
#endif  /* _SECURE_VERSION */

/***
*char *strtok(string, control) - tokenize string with delimiter in control
*
*Purpose:
*       strtok considers the string to consist of a sequence of zero or more
*       text tokens separated by spans of one or more control chars. the first
*       call, with string specified, returns a pointer to the first char of the
*       first token, and will write a null char into string immediately
*       following the returned token. subsequent calls with zero for the first
*       argument (string) will work thru the string until no tokens remain. the
*       control string may be different from call to call. when no tokens remain
*       in string a NULL pointer is returned. remember the control chars with a
*       bit map, one bit per ascii char. the null char is always a control char.
*
*Entry:
*       char *string - string to tokenize, or NULL to get next token
*       char *control - string of characters to use as delimiters
*
*Exit:
*       returns pointer to first token in string, or if string
*       was NULL, to next token
*       returns NULL when no more tokens remain.
*
*Uses:
*
*Exceptions:
*
*******************************************************************************/

#ifdef _SECURE_VERSION
#define _TOKEN *context
#else  /* _SECURE_VERSION */
#define _TOKEN ptd->_token
#endif  /* _SECURE_VERSION */

#ifdef _SECURE_VERSION
char * __cdecl strtok_s (
        char * string,
        const char * control,
        char ** context
        )
#else  /* _SECURE_VERSION */
char * __cdecl strtok (
        char * string,
        const char * control
        )
#endif  /* _SECURE_VERSION */
{
        unsigned char *str;
        const unsigned char *ctrl = control;

        unsigned char map[32];
        int count;

#ifdef _SECURE_VERSION

        /* validation section */
        _VALIDATE_RETURN(context != NULL, EINVAL, NULL);
        _VALIDATE_RETURN(string != NULL || *context != NULL, EINVAL, NULL);
        _VALIDATE_RETURN(control != NULL, EINVAL, NULL);

        /* no static storage is needed for the secure version */

#else  /* _SECURE_VERSION */

        _ptiddata ptd = _getptd();

#endif  /* _SECURE_VERSION */

        /* Clear control map */
        for (count = 0; count < 32; count++)
                map[count] = 0;

        /* Set bits in delimiter table */
        do {
                map[*ctrl >> 3] |= (1 << (*ctrl & 7));
        } while (*ctrl++);

        /* Initialize str */

        /* If string is NULL, set str to the saved
         * pointer (i.e., continue breaking tokens out of the string
         * from the last strtok call) */
        if (string)
                str = string;
        else
                str = _TOKEN;

        /* Find beginning of token (skip over leading delimiters). Note that
         * there is no token iff this loop sets str to point to the terminal
         * null (*str == '\0') */
        while ( (map[*str >> 3] & (1 << (*str & 7))) && *str )
                str++;

        string = str;

        /* Find the end of the token. If it is not the end of the string,
         * put a null there. */
        for ( ; *str ; str++ )
                if ( map[*str >> 3] & (1 << (*str & 7)) ) {
                        *str++ = '\0';
                        break;
                }

        /* Update nextoken (or the corresponding field in the per-thread data
         * structure */
        _TOKEN = str;

        /* Determine if a token has been found. */
        if ( string == str )
                return NULL;
        else
                return string;
}


🎍strerror() - 返回错误码🎍 

该函数的功能是:返回错误码,所对应的错误信息。

strerror() 函数的声明方式如下 👇 

char * strerror ( int errnum );

获取指向错误消息字符串的指针。

errnum的值,生成一个字符串,该字符串带有一条描述错误条件的消息,就像库的函数设置为errno一样。头文件是:#include <errno.h>

返回的指针指向一个静态分配的字符串,该字符串不能被程序修改。对该函数的进一步调用可能会覆盖其内容(为了避免数据竞争,不需要特定的库实现)。

strerror产生的错误字符串可能特定于每个系统和库实现。

返回值:该函数返回一个指向错误字符串的指针,该错误字符串描述了错误 errnum。

🎍strerror()函数代码示例🎍

打开文件函数是:fopen()

#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(void)
{
	FILE* Pf = fopen("test.txt", "r");//打开文件如果以读的形式存在那么这个文件就会打开失败!
	//一旦打开失败那个得到的就是NULL
	if (Pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;//返回main函数结束
	}
	fclose(Pf);
	Pf = NULL;
	return 0;
}

运行结果如下 👇 

Error: No such file or directory 

当然如果你在安装路径新建上一个test.txt文件就不会显示如上问题。

🎍strerror()源程序实现🎍

示例代码如下:👇  

#include <cruntime.h>
#include <errmsg.h>
#include <stdlib.h>
#include <syserr.h>
#include <string.h>
#include <mtdll.h>
#include <tchar.h>
#include <malloc.h>
#include <stddef.h>
#include <dbgint.h>
#include <internal.h>

/* [NOTE: The error message buffer is shared by both strerror
   and _strerror so must be the max length of both. */
/* Max length of message = user_string(94)+system_string+2 */
#define _ERRMSGLEN_ (94+_SYS_MSGMAX+2)

#ifdef _UNICODE
#define _terrmsg    _werrmsg
#else  /* _UNICODE */
#define _terrmsg    _errmsg
#endif  /* _UNICODE */

/***
*char *strerror(errnum) - Map error number to error message string.
*
*Purpose:
*       The strerror runtime takes an error number for input and
*       returns the corresponding error message string.  This routine
*       conforms to the ANSI standard interface.
*
*Entry:
*       int errnum - Integer error number (corresponding to an errno value).
*
*Exit:
*       char * - Strerror returns a pointer to the error message string.
*       This string is internal to the strerror routine (i.e., not supplied
*       by the user).
*
*Exceptions:
*       None.
*
*******************************************************************************/

#ifdef _UNICODE
wchar_t * cdecl _wcserror(
#else  /* _UNICODE */
char * __cdecl strerror (
#endif  /* _UNICODE */
        int errnum
        )
{
        _TCHAR *errmsg;
        _ptiddata ptd = _getptd_noexit();
        if (!ptd)
                return _T("Visual C++ CRT: Not enough memory to complete call to strerror.");

        if ( (ptd->_terrmsg == NULL) && ((ptd->_terrmsg =
                        _calloc_crt(_ERRMSGLEN_, sizeof(_TCHAR)))
                        == NULL) )
                return _T("Visual C++ CRT: Not enough memory to complete call to strerror.");
        else
                errmsg = ptd->_terrmsg;

#ifdef _UNICODE
        _ERRCHECK(mbstowcs_s(NULL, errmsg, _ERRMSGLEN_, _get_sys_err_msg(errnum), _ERRMSGLEN_ - 1));
#else  /* _UNICODE */
        _ERRCHECK(strcpy_s(errmsg, _ERRMSGLEN_, _get_sys_err_msg(errnum)));
#endif  /* _UNICODE */

        return(errmsg);
}

/***
*errno_t strerror_s(buffer, sizeInTChars, errnum) - Map error number to error message string.
*
*Purpose:
*       The strerror_s runtime takes an error number for input and
*       copies the corresponding error message string in the destination
*       buffer. If the buffer is too small, the message is truncated.
*
*Entry:
*       TCHAR * buffer - Destination buffer.
*       size_t sizeInTChars - Size of the destination buffer.
*       int errnum - Integer error number (corresponding to an errno value).
*
*Exit:
*       The error code.
*
*Exceptions:
*       Input parameters are validated. Refer to the validation section of the function.
*
*******************************************************************************/

#ifdef _UNICODE
errno_t __cdecl _wcserror_s(
#else  /* _UNICODE */
errno_t __cdecl strerror_s(
#endif  /* _UNICODE */
        TCHAR* buffer,
        size_t sizeInTChars,
        int errnum
        )
{
        errno_t e = 0;

        /* validation section */
        _VALIDATE_RETURN_ERRCODE(buffer != NULL, EINVAL);
        _VALIDATE_RETURN_ERRCODE(sizeInTChars > 0, EINVAL);

        /* we use mbstowcs_s or strncpy_s because we want to truncate the error string
         * if the destination is not big enough
         */
#ifdef _UNICODE
        e = _ERRCHECK_EINVAL_ERANGE(mbstowcs_s(NULL, buffer, sizeInTChars, _get_sys_err_msg(errnum), _TRUNCATE));
        /* ignore the truncate information */
        if (e == STRUNCATE)
        {
                e = 0;
        }
#else  /* _UNICODE */
        _ERRCHECK(strncpy_s(buffer, sizeInTChars, _get_sys_err_msg(errnum), sizeInTChars - 1));
#endif  /* _UNICODE */
    return e;
}

✨最后✨

字符串函数的使用是我们必须要掌握的知识点很多面试知识点包括对于程序当中运用到字符串函数的形式还是比较多的,所以我们是必须要了解掌握这个知识点的。尽管知识点比较多,但是我们还是要好好吸收消化这个知识点的。听说长按收藏按钮会有惊喜╰(*°▽°*)╯

评论 76
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

謓泽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值