C语言头文件<string.h>函数详解

目录
  • 1. strlen —— 求字符串长度
    • 1.1 strlen 的声明与用处
    • 1.2 strlen 的用法
    • 1.3 strlen 的模拟实现
  • 2. strcpy —— 字符串拷贝
    • 2.1 strcpy 的声明与用处
    • 2.2 strcpy 的用法
    • 2.3 strcpy 的模拟实现
  • 3. strcmp —— 字符串比较
    • 3.1 strcmp 的声明与用处
    • 3.2 strcmp 的用法
    • 3.3 strcmp 的模拟实现
  • 4. strcat —— 字符串追加
    • 4.1 strcat 的声明与用处
    • 4.2 strcat 的用法
    • 4.3 strcat 的模拟实现
  • 5. strncpy —— 长度受限制的字符串拷贝
    • 5.1 strncpy 的声明与用处
    • 5.2 strncpy 的用法
    • 5.3 strncpy 的模拟实现
  • 6. strncmp —— 长度受限制的字符串比较
    • 6.1 strncmp 的声明与用处
    • 6.2 strncmp 的用法
    • 6.3 strncmp 的模拟实现
  • 7. strncat —— 长度受限制的字符串追加
    • 7.1 strncat 的声明与用处
    • 7.2 strncat 的用法
    • 7.3 strncat 的模拟实现
    • 小结
  • 8. strstr —— 字符串查找
    • 8.1 strstr 的声明与用处
    • 8.2 strstr 的用法
    • 8.3 strstr 的模拟实现
  • 9. strtok —— 字符串切割
    • 9.1 strtok 的声明与用处
    • 9.2 strtok 的用法
  • 10. strerror —— 错误码解析
    • 10.1 strerror 的声明与用处
    • 10.2 strerror 的用法

1. strlen —— 求字符串长度

1.1 strlen 的声明与用处

strlen ,我们有一些英语基础的话不难通过字面意思来知道这个函数是干嘛用的,str 表 string ,字符串的意思,len 表 length ,长度的意思。也就是说,strlen 是求字符串长度的函数。我们通过 cplusplus 这个网站来观察 strlen 的函数声明以及各个参数的意义。

我们翻译可以知道,strlen 所求的字符串长度是字符串结束标志之前的字符个数。即我们假设有字符串 "hello world" ,那么所求的字符串长度就是 '\0' 之前的所有字符个数,也就是 11 。那么这个字符串长度是通过返回值返回的,所以我们要知道所求的字符串长度是多少就必须定义一个变量来接收返回值。那么参数部分当然就是字符串的首地址了。

1.2 strlen 的用法

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

int main()
{
	char str1[] = "hello world";
	char* str2 = "hello world";

	int len1 = strlen(str1);//数组名表首元素地址
	int len2 = strlen(str2);//str2 指针变量存放的也是首元素地址

	printf("%d\n", len1);
	printf("%d\n", len2);

	//这种写法也可以输出长度
	//printf("%d\n", strlen(str1));
	//printf("%d\n", strlen(str2));

	return 0;
}

我们要注意的一点是,strlen 的返回值是一个 size_t 类型,即无符号整数。 它的意义在于求长度时是不可能求出负数的,所以一定程度上优化了内存(使用有符号整形的话会浪费掉用来存储负数的空间)。

1.3 strlen 的模拟实现

我们上面已经分析过 strlen 的原理了,那么现在我们用自己所学过的只是来“创造”一个属于自己的 strlen 函数。

#include <stdio.h>
#include <assert.h>
unsigned int my_strlen(const char* str)//我们不改变字符串的内容,所以用 const 来进行修饰
{
	assert(str);//避免是一个空指针
	unsigned int count = 0;
	while (*str)
	{
		count++;
		str++;
	}
	return count;
}
int main()
{
	char str1[] = "hello world";
	char* str2 = "hello world";

	int ret1 = my_strlen(str1);
	int ret2 = my_strlen(str2);

	printf("%d\n", ret1);
	printf("%d\n", ret2);

	return 0;
}

2. strcpy —— 字符串拷贝

2.1 strcpy 的声明与用处

我们对其字面翻译进行理解,str 表 string ,即字符串,cpy 表 copy ,即拷贝。也就是 strcpy 这个函数是用来进行字符串拷贝的。那我们通过 cplusplus 这个网站来观察 strcpy 的声明以及各个参数的意义。

我们翻译过来就可以知道 strcpy 的功能,拷贝 source 指针指向的字符串至 destination 指针指向的数组当中,拷贝的内容包含字符串终止符。并且 destination 指针指向的数组必须有足够大的空间容纳拷贝之后的内容。 

由此我们知道, strcpy 需要两个参数,一个是数组,一个是字符串。并且数组的空间必须足够大。返回值是返回数组拷贝之前的地址。这么做的意义是防止拷贝之前的内容丢失。

2.2 strcpy 的用法

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

int main()
{
	char dest[20] = "row your boat";
	char src[] = "hello world";
	strcpy(dest, src);
	printf("%s\n", dest);
	return 0;
}

这是 strcpy 最最常用的用法,我们只需要记住一点即可:拷贝过去的内容是包含 '\0' 的。也就是说即使我拷贝过去的字符串长度没有数组原来的字符串长度长,但是我包含 '\0' 了,在 C 语言的角度来说 '\0' 之后的内容就不算从头往后看的字符串内容了。

2.3 strcpy 的模拟实现

#include <stdio.h>
#include <assert.h>

char* my_strcpy(char* dest, const char* src)//dest 指向的数组空间是要被改变的,但是 src 指向的字符串不需要改变
{
	assert(dest && src);//防止其中某个是无效指针
	char* ret = dest;
	while (*dest++ = *src++)
		;	//注意 while 循环执行了空语句

	return ret;
}
int main()
{
	char dest[30] = "gently down the stream";
	char src[] = "life is but a dream";

	my_strcpy(dest, src);
	printf("%s\n", dest);
	return 0;
}

3. strcmp —— 字符串比较

3.1 strcmp 的声明与用处

也是一样,我们可以通过字面翻译来大致了解这个函数是干嘛用的。str 表 string ,即字符串,cmp 表 compare ,即比较。我们同样通过 cplusplus 这个网站观察这个函数的声明以及各个参数的意义。

我们翻译即可知道这个函数的原理。其原理就是:都是从两个字符串的第一个字符开始比较,如果这两个字符相等,那么这两个字符串都会进行下一对字符比较,直到两个字符不相等,然后进行比较大小。如果第一个字符小于第二个字符,就会返回一个小于 0 的整数,等于则返回 0 ,大于则返回一个大于 0 的整数。

其两个参数都是要比较的字符串。为了方便理解,我们通过画图的形式来理解。

3.2 strcmp 的用法

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

int main()
{
	char* str1 = "abbbcd";
	char* str2 = "abbbdd";
	int ret = strcmp(str1, str2);
	if (ret > 0)
		printf("str1 > str2\n");
	else if (ret < 0)
		printf("str1 < str2\n");
	else
		printf("str1 == str2\n");
	return 0;
}

3.3 strcmp 的模拟实现

#include <stdio.h>
#include <assert.h>

int my_strcmp(const char* str1, const char* str2)//两个字符串的内容都不需要修改,用 const 修饰
{
	assert(str1 && str2);//防止是无效指针

	while (*str1 == *str2)//如果相等则进入循环
	{
		if (*str1 == '\0')//*str1 == '\0' 了并且进入循环了,说明两个字符串比较完成了,没有不相等的字符
			return 0;
		str1++;
		str2++;
	}
	return *str1 - *str2;//两个字符的差作为返回值
}
int main()
{
	char* str1 = "abbbcd";
	char* str2 = "abbbdd";
	int ret = my_strcmp(str1, str2);
	if (ret > 0)
		printf("str1 > str2\n");
	else if (ret < 0)
		printf("str1 < str2\n");
	else
		printf("str1 == str2\n");
	return 0;
}

4. strcat —— 字符串追加

4.1 strcat 的声明与用处

 我们通过 cplusplus 这个网站来观察 strcat 的声明以及各个参数的意义。

翻译一下即可直到 strcat 函数的用法:将 source 指针指向的字符串追加到 destination 指针指向数组并且有足够大的空间(本人尝试追加到字符串,但是失败了),其追加的位置是 destination 指针指向的字符串的 '\0' 处,即从这个位置拷贝。需要注意的是,追加的 '\0' 的位置第一个 '\0' 的位置。

4.2 strcat 的用法

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

int main()
{
	char str1[50] = "row row row your boat,";
	char* str2 = "gently down the stream";
	strcat(str1, str2);
	printf("%s\n", str1);
	return 0;
}

4.3 strcat 的模拟实现

#include <stdio.h>
#include <assert.h>

char* my_strcat(char* dest, const char* src)//src 指向的字符串是不改变内容的,所以用 const 修饰
{
	assert(dest && src);//确保两个指针有效
	char* ret = dest;
	while (*dest)
		dest++;//先找到 dest 指向的数组的第一个 '\0' 的位置
	while (*dest++ = *src++)//拷贝
		;
	return ret;
}
int main()
{
	char str1[50] = "row row row your boat,";
	char* str2 = "gently down the stream";
	my_strcat(str1, str2);
	printf("%s\n", str1);
	return 0;
}

5. strncpy —— 长度受限制的字符串拷贝

5.1 strncpy 的声明与用处

strncpy 与 strcpy 的区别就是 strncpy 多了一个参数。这个参数是一个无符号的整数,即可以自定义拷贝多少个字节的内容。这就大大的方便了我们的使用,提高了 C 语言的灵活性。

5.2 strncpy 的用法

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

int main()
{
	char str1[20] = "row your boat";
	char str2[] = "hello world";
	strncpy(str1, str2, 3);//我们从 str2 中拷贝三个字节的内容到 str1 去
	printf("%s\n", str1);
	return 0;
}
 

 我们可以看到输出的结果非常奇怪,这是因为当我们只拷贝三个字节的内容时,strncpy 是不会在后面补 '\0' 的(即要多少内容就拷多少内容),这就导致了我们能够看到 str1 数组里面拷贝之前的内容。

5.3 strncpy 的模拟实现

#include <stdio.h>
#include <assert.h>

char* my_strncpy(char* dest, const char* src, unsigned int num)
{
	assert(dest && src);//确保两个指针有效
	char* ret = dest;

	while (num--)//拷贝几个字节
	{
		*dest = *src;
		dest++;
		src++;
	}

	return ret;
}
int main()
{
	char str1[20] = "row your boat";
	char str2[] = "hello world";
	my_strncpy(str1, str2, 3);
	printf("%s\n", str1);
	return 0;
}

6. strncmp —— 长度受限制的字符串比较

6.1 strncmp 的声明与用处

strncmp 与 strcmp 的功能是一模一样的,原理也就是一模一样的。也就是说掌握了 strcmp 就能够掌握 strncmp 。strncmp 只是相较于 strcmp 多了一个参数,这个参数是一个无符号整数,代表的是字节。即我们想要比对多少字节。我们通过 cplusplus 这个网站可以观察这个函数的声明以及各个参数的意义。

6.2 strncmp 的用法

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

int main()
{
	char* str1 = "abbbcd";
	char* str2 = "abbbdd";
	int ret=strncmp(str1, str2,3);//我们只想比较字符串的前三个字节
	if (ret > 0)
		printf("str1 > str2\n");
	else if (ret < 0)
		printf("str1 < str2\n");
	else
		printf("str1 == str2\n");
	return 0;
}

6.3 strncmp 的模拟实现

#include <stdio.h>
#include <assert.h>

int my_strncmp(const char* str1, const char* str2, unsigned int num)//两个字符串的内容都不需要变,所以用 const 修饰
{
	assert(str1 && str2);
	while (num-- && *str1 == *str2)
	{
		if (*str1 == '\0')
			return 0;
		str1++;
		str2++;
	}
	return *str1 - *str2;
}
int main()
{
	char* str1 = "abbbcd";
	char* str2 = "abbbdd";
	int ret = my_strncmp(str1, str2, 3);//我们只想比较字符串的前三个字节
	if (ret > 0)
		printf("str1 > str2\n");
	else if (ret < 0)
		printf("str1 < str2\n");
	else
		printf("str1 == str2\n");
	return 0;
}

7. strncat —— 长度受限制的字符串追加

7.1 strncat 的声明与用处

同理,掌握了 strcat 就能掌握 strncat 。strncat 其参数多了一个无符号整形的参数,其意义代表字节数。即我们可以自定义想要追加多少个字符至另一个字符串的后面。我们可以通过 cplusplus 这个网站观察 strncat 的声明以及各个参数的意义。

7.2 strncat 的用法

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

int main()
{
	char str1[50] = "row row row your boat,";
	char str2[] = "gently down the stream";
	strncat(str1, str2, 6);//我们只想追加 6 个字节的字符到 str1 中
	printf("%s\n", str1);
	return 0;
}

 在这里如果我们注意观察的话,就会发现一个问题。我们追加过去的 6 个字节的字符并不包含 '\0' ,但是在最后输出打印的时候好像在字符串尾又被赋予了 '\0' 。那么这就不得不提及 strncat 的特性,即 strncat 会在要追加的字符串后面补 '\0' 。

7.3 strncat 的模拟实现

#include <stdio.h>
#include <assert.h>

char* my_strncat(char* dest, const char* src, unsigned int num)//str2 中的字符串不需要被修改,所以用 const 修饰
{
	assert(dest && src);//确保两个指针是有效指针
	char* ret = dest;//记录返回值

	while (*dest)//先找到 dest 指向的 '\0' 的位置
		dest++;
	while (num-- && (*dest++ = *src++) )//拷贝限制的字节数
		;
	*dest = '\0';

	return ret;

}
int main()
{
	char str1[50] = "row row row your boat,";
	char str2[] = "gently down the stream";
	my_strncat(str1, str2, 8);
	printf("%s\n", str1);
	return 0;
}

小结

我们上面介绍了许多长度不受限制的字符串函数和长度受限制的字符串函数。那么受限制和不受限制有什么区别呢? 首先不受限制的字符串函数的灵活性是比较低的,因为只能操作整个字符串。但是受限制的字符串函数的灵活性是比较高的,可以自定义操作的字符个数。并且,长度受限制的字符串函数相对于长度不受限制的字符串函数来说是比较安全的。注意是受限制的相对于不受限制的比较安全。

8. strstr —— 字符串查找

8.1 strstr 的声明与用处

strstr 通过字面翻译过来就是两个字符串。那么其意义是在其中一个字符串里面查找另外一个字符串。我们可以通过 cplusplus 这个网站来观察 strstr 的声明以及各个参数的意义。

我们翻译一下即可知道 strstr 的某些原理。如果在字符串 1 里面查找到了字符串 2 ,那么就返回字符串 2 出现在字符串 1 中的首地址。如果没有找到字符串,就返回一个空指针。

8.2 strstr 的用法

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

int main()
{
	char* str1 = "row row row your boat,gently down the stream";
	char* str2 = "row your boat";
	char* ret = strstr(str1, str2);//在 str1 中查找 str2
	printf("%s\n", ret);
	return 0;
}

可以看到返回值是返回 str2 第一次出现在 str1 中的首地址。 

8.3 strstr 的模拟实现

#include <stdio.h>
#include <assert.h>

char* my_strstr(const char* str1, const char* str2)//不需要改变其内容,用 const 修饰
{
	assert(str1 && str2);//避免是无效指针
	const char* s1 = str1;
	const char* s2 = str2;
	const char* cp = str1;//这个指针变量是至关重要的
	while (*cp)
	{
		s1 = cp;
		s2 = str2;

		//在 str1 中查找 str2 的核心循环
		while (*s1 && *s2 && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')//查找完成
			return (char*)cp;

		cp++;
	}
	return NULL;
}
int main()
{
	char* str1 = "row row row your boat,gently down the stream";
	char* str2 = "row your boat";
	char* ret = my_strstr(str1, str2);
	printf("%s\n", ret);
	return 0;
}

我们来通过画图来详解一下思路。 

9. strtok —— 字符串切割

9.1 strtok 的声明与用处

对于这个函数,我们只要了解了基本的使用方法即可。我们通过 cplusplus 这个网站来观察 strtok 的声明以及各个参数的意义。

这段英文的篇幅太长了,我来解释一下核心部分:我们提供两个参数给 strtok ,一个是字符串,一个是要切割的标记。如果在这个字符串当中出现了这个标记,那么这个位置将被修改为 '\0' ,并且返回这个标记之前的字符串地址。如果要进行二次传参,那么只需要传一个空指针即可。

9.2 strtok 的用法

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

int main()
{
	char* str1 = "row@row~row%your^boat,gently@down~the^stream";
	char* str2 = "@~%^";

	//将 str1 拷贝至 tmp 数组,这样不会丢失 str1 的原始数据
	char tmp[50] = { 0 };
	strcpy(tmp, str1);

	char* ret = NULL;
	for (ret = strtok(tmp, str2); ret != NULL; ret = strtok(NULL, str2))
	{
		printf("%s ", ret);
	}
	return 0;
}

10. strerror —— 错误码解析

10.1 strerror 的声明与用处

我们需要普及的一个点是,在 C 语言中,程序发生错误的时候,是有一个隐藏的全局变量 errno 的,这个变量是一个整数的,譬如 0 ,1,2,3,....等都代表不同的错误信息,而 strerror 的作用就是翻译这个错误码。我们可以通过 cplusplus 这个网站来观察 strerror 的声明以及各个参数的意义。 

10.2 strerror 的用法

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

int main()
{
	FILE* p;
	p = fopen("test.txt", "r");//在我们的工程目录下并没有 test.txt 这个文件
	if (p == NULL)//那么打不开 p 就是一个空指针
	{
		printf("%s\n", strerror(errno));//这里就会解释为什么是空指针的原因
	}
	return 0;
}

到此这篇关于C语言头文件<string.h>函数详解的文章就介绍到这了,更多相关C语言头文件<string.h>函数详解内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 仿写C语言string.h头文件检验字符串函数

    目录 c语言string.h头文件字符串检验函数仿写 strlen字符串求长度 strcmp / strncmp字符串比较 strchr / strrchr 字符串中查找字符ch 第一个出现的字符ch 最后一个出现的字符ch strstr 字符串匹配:src_str中查找des_str,返回匹配的起始位置,没有为NULL(BF算法) strcpy / strncpy字符串拷贝 strcat / strncat字符串的粘贴 strdup 字符串申请堆区空间存放字符串的副本 总结 c语言string

  • vue2.x中h函数(createElement)与vue3中的h函数详解

    目录 1. vue2.x的 h 函数(createElement) 2. vue3 h函数配置项 2.1 v-model实现(以下开始为官网实现) 2.2 v-on 2.3 事件修饰符 2.4 插槽 2.5 component 和 is 2.6 自定义指令 2.7 内置组件 2.8 渲染函数的返回值 2.9 JSX 总结 1. vue2.x的 h 函数(createElement) 使用方法及介绍:(参考官网提取) h函数第一个是标签名字 或者是组件名字,第二个参数是配置项,第三个参数是 inn

  • R语言学习笔记之lm函数详解

    在使用lm函数做一元线性回归时,发现lm(y~x+1)和lm(y~x)的结果是一致的,一直没找到两者之间的区别,经过大神们的讨论和测试,才发现其中的差别,测试如下: ------------------------------------------------------------- ------------------------------------------------------------- 结果可以发现,两者的结果是一样的,并无区别,但是若改为lm(y~x-1)就能看出+1和

  • Python文件读写open函数详解

    前言: open()函数的定义:def open(file, mode='r', buffering=None, encoding=None, errors=None, newline=None, closefd=True) 常用的参数有 file.mode.encoding file是文件名称, mode是文件的打开方式.encoding是文件编码格式 mode常见的有 只读模式®.写入模式(w).追加模式(a).读写模式(r+/w+/a+) r+要求文件必须存在:锚点置于末行末位字符处 w+

  • C语言基础文件操作方式超全详解建议收藏

    目录 什么是文件 文件名 文件类型 文件指针 文件的打开与关闭 打开方式 文件的顺序读写 关于fread的返回值 对比一组函数 文件随机读取 文件结束判断 perror() ferror() 什么是文件 磁盘上的文件是文件. 在程序设计中,我们一般读的文件有两种:程序文件 和 数据文件 程序文件包括源程序文件(后缀为.c).目标文件(win下后缀为 .obj).可执行文件(win下环境后缀为.exe) 数据文件:文件的内容不一定是程序,而是运行时读写的程序,比如程序运行需要从中读取数据的文件,或

  • C语言中操作字符串的函数详解

    目录 一.函数表 二.strlen 实例 三.strcmp 实例 四.strcpy 实例 五.stract 实例 六.strchr 实例 总结 一.函数表 函数名 函数 功能 strlen size_t strlen(const char* s); 返回字符串 s 的长度(不包括结尾的0) strcmp int strcmp(const char* s1, const char* s2); 比较两个字符串,返回:如果 s1 == s2,返回 0:如果 s1<s2 则返回小于 0 (如 -1):如

  • python如何调用php文件中的函数详解

    前言 python调用php代码实现思路:php文件可通过在terminal中使用php命令行进行调用,因此可使用python开启子进程执行命令行代码.函数所需的参数可通过命令行传递. 测试环境 1.操作系统:macos10.13.2 2.php版本:PHP 7.1.7(mac自带) 3.python版本:python3.6.0 4.python库:subprocess 调用php函数 php命令行调用php文件中的函数 php文件:test_hello.php <?php function h

  • C语言返回值指针的函数详解

    #include<stdio.h> void main() { int a[5] = { 1,3,5,7,9 }; int* name[5] = { &a[0],&a[1],&a[2] ,&a[3] ,&a[4] }; int i; for (i = 0; i < 5; i++) { printf("%d ", *name[i]); } printf("\n\n"); } #include<stdio.

  • C语言memset函数详解

    目录 一.memset函数原型: 二.使用memset函数 三.给int类型赋值为1 四.扒开内存 五.memset给变量赋值 总结 在c语言中,使用变量前,需要先对变量的值进行初始化.数组在内存中占用一片连续的存储块.而c语言提供了memset函数(头文件string.h)对数组进行组团赋值.(memset函数也能对变量赋值,但只有无聊的人才会这么做.详见下文目录五) 一.memset函数原型: void memset ( void *s , char ch, unsigned n ) 函数功

  • C语言的动态内存分配及动态内存分配函数详解

    目录 malloc malloc的使用: free calloc calloc的使用: realloc realloc的使用改进: realloc的另一种用法: 常见的动态内存错误 对空指针的解引用操作 对动态开辟空间的越界访问 对非动态开辟内存使用free释放 使用free释放一块动态开辟内存的一部分 对同一块动态内存多次释放 动态开辟内存忘记释放(内存泄露) 找出下面问题: T1: T2: T3: T4: 柔性数组 柔性数组的定义 柔性数组的特点: 总结 malloc void *mallo

  • C语言头文件<string.h>函数详解

    目录 1. strlen —— 求字符串长度 1.1 strlen 的声明与用处 1.2 strlen 的用法 1.3 strlen 的模拟实现 2. strcpy —— 字符串拷贝 2.1 strcpy 的声明与用处 2.2 strcpy 的用法 2.3 strcpy 的模拟实现 3. strcmp —— 字符串比较 3.1 strcmp 的声明与用处 3.2 strcmp 的用法 3.3 strcmp 的模拟实现 4. strcat —— 字符串追加 4.1 strcat 的声明与用处 4.

随机推荐