C语言中字符串函数与内存函数

1.前言


今天我们来了解一些常用的字符串库函数和内存函数

了解这些有什么用呢?

肯定是百益而无一害😎,下面我们就看看他有多么的好用。

https://legacy.cplusplus.com/reference/cstdio/printf/大家有什么函数想要查可以在这上面查


2.字符串库函数


1.strlen

size_t strlen ( const char * str );

这个函数的功能是读取字符串的长度

  • 它以’\0’为结束标志,返回’\0’前面字符个数,但是=='\0’不包括在内==
  • strlen函数返回值为无符号整型
  • strlen函数头文件==<string.h>==

下面看看他是如何用的

#include<stdio.h>
#include<stdio.h>
#include<string.h>
int main()
{
	char* ch = "hello world!";
	printf("%d\n", strlen(ch));
	return 0;
}

简简单单三行代码就可以搞定,如果没有这样的库函数,我们又要去费劲的写一个函数来实现,这样不就很麻烦。

所以说如果你会用库函数,那么写代码对你来说就会简单很多。

所以没事可以多看看C语言的库函数。一定要搞懂后再用,不然会出错

那么这个函数是如何实现的呢?

下面我们看看的是如何做到的,让我们仿照strlen写一个my_strlen函数来实现strlen函数的功能

strlen函数有一个参数,和一个返回值,

参数是:一个内容不可修改指针(在该函数中内容不可以修改)

返回值:是个无符号整型

#include<stdio.h>
#include<stdio.h>
size_t my_strlen(char* ch)
{
	int count = 0;
	while (*ch)     //如果遇到'\0'while循环停止
	{
		count++;
		ch++;
	}
	return count;
}
int main()
{
	char* ch = "hello world!";
	printf("%d\n",my_strlen(ch));
	return 0;
}

2.strcpy

char * strcpy ( char * destination, const char * source );

这个函数功能是将一个字符串(参数source原字符串)拷贝到另一个字符串(参数destination目标字符串)中

  • 以原字符串中的’\0’为结束标志
  • 同时会将原字符串中的==‘\0’==拷贝到目标字符串中
  • 目标字符串必须足够大,大过原字符串,这样才可以放下
  • 目标空间是可变的

例如:char * p = “ajdla”;

这是不能作为目标字符串的,以为"ajdla"是常量字符串,不可以修改

所以p不能作为目标字符串

说那么多了,看看他是怎么用的就懂了 —实践是理解最快的方法

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

int main()
{
	char ch1[20] = { 0 };
	printf("原来:%s\n", ch1);
	char* ch2 = "hello world!";
	strcpy(ch1, ch2);
	printf("拷贝后:%s\n", ch1);
	return 0;
}

请添加图片描述

相信看到这里,你们也就懂的了这个函数的用途

那它又是如何实现的呢?

strcpy函数有两个参数一个返回值

两个参数:一个是内容可修改的字符指针,一个是内容不可修改的字符指针 (在该函数中内容不可以修改)

返回值:字符指针

#include<stdio.h>
#include<stdio.h>
#include<assert.h>
char* my_strcpy(char* ch1, const char* ch2)
{
	assert(ch1 && ch2);  //判断ch1和ch2是否为空指针
	char* ret = ch1;

	while (*ch1++ = *ch2++)
	{
		;
	}
	return ret;
}

int main()
{
	char ch1[20] = { 0 };
	printf("原来:%s\n", ch1);
	char* ch2 = "hello world!";
	my_strcpy(ch1, ch2);
	printf("拷贝后:%s\n", ch1);
	return 0;
}

为什么这里的返回值是==char*==呢?

像我这样的小白就认为void当返回值就可以,为什么要用==cahr*==呢,这不是多此一举。

这样写肯定是有好处的

strcpy()可以直接作为printf()的参数进行显示

如:printf(“%s\n”,strcpy(ch1,ch2));

而如果定义成void类型便不能进行函数的链式访问了。


3.strcat

char * strcat ( char * destination, const char * source );

这个函数的作用是将source原字符串追加到destination目标字符串后面

  • 以原字符串中的’\0’结束标志
  • 将原字符串中的’\0’也拷贝到目标空间中
  • 目标空间足够大,能容下两个字符串之和
  • 目标空间可改变----和上面strcpy一样的原因

下面看看如何使用

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

int main()
{
	char ch1[20] = "hello ";
	printf("原来:%s\n", ch1);
	char* ch2 = "world!";
	strcat(ch1, ch2);
	printf("拷贝后:%s\n", ch1);
	return 0;
}

请添加图片描述

同样的问题,这个函数是如何实现呢?

strcat()函数有两个参数和一个返回值

参数:一个是内容可修改的字符指针,一个是内容不可修改的字符指针 (在该函数中内容不可以修改)

返回值:字符指针

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

char* my_strcat(char* ch1, char* ch2)
{
	assert(ch1 && ch2); // 判断两个字符串是否为空
	char* ret = ch1;
	while (*ch1 != '\0') //找到目标字符串的'\0'
	{
		ch1++;
	}
	while (*ch1++ = *ch2++) // 从'\0'开始将原字符串追加上去,直到'\0'
	{
		;
	}

	return ret;
}
int main()
{
	char ch1[20] = "hello ";
	printf("原来:%s\n", ch1);
	char* ch2 = "world!";
	my_strcat(ch1, ch2);
	printf("拷贝后:%s\n", ch1);
	return 0;
}

有一个问题,可以自己追加自己吗?

int main()
int main()

{
	char arr[30] ="abcdef";
	strcat(arr, arr + 2);
	printf("%s", arr);
	return 0;
}

正常情况下追加完后,输出:abcdefcdef

结果是这样吗? ------下面我们看看

请添加图片描述

为什和我们想的不一样呢?
请添加图片描述


4.strcmp

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

这个函数的作用是比较两个字符串是否相等

  • 如果两个字符串相等返回0
  • 如果第一个字符串大于第二个字符串返回>0的数
  • 如果第一个字符串小于第二个字符串返回<0的数

如何判断两个字符串谁大谁小呢?

通过ASIIC码进行判断

例如:char* ch1 = “abcdef”;

​ cahr* ch2 = “ac”;

一个一个字符比较,第一个字符相等则比较后面一个字符,第二个字符c的ASIIC码值大于b的则ch2>ch1

下面看看这个函数如何使用

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

int main()
{
	char ch1[20] = "hello ";
	char* ch2 = "hello ";
	int ret = strcmp(ch1, ch2);
	
	if (ret == 0)
		printf("=\n");
	else if (ret > 0)
		printf(">\n");
	else
		printf("<\n");

	return 0;
}

请添加图片描述

这个函数又是如何实现的呢?

strcmp()函数有两个参数一个返回值

参数:两内容不可修改的字符指针

返回值:整型

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

int my_strcmp(const char* ch1, const char* ch2)
{
	assert(ch1 && ch2);
	int ret = 0;
	
	while (	!(ret = *(unsigned char*)ch1 - *(unsigned char*)ch2) && *ch2)
	{
		ch1++;
		ch2++;
	}

	return *ch1 - *ch2;
}
int main()
{
	char ch1[20] = "hello ";
	char* ch2 = "hello ";
	int ret = my_strcmp(ch1, ch2);
	
	if (ret == 0)
		printf("=\n");
	else if (ret > 0)
		printf(">\n");
	else
		printf("<\n");

	return 0;
}

5.strstr

char * strstr (const char * str1, const char * str2 );

这个函数在字符串一中找是否含有字符串二,如果有返回其首地址,如果没有返回空指针。

说的多不如实践,我们看看如何用

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

int main()
{
	char* ch1 = "abcdef";
	char* ch2 = "cd";
	char* ret = strstr(ch1, ch2);
	if (ret == NULL)
	{
		printf("没有找到\n");
	}
	else
	{
		printf("%s\n", ret);
	}

	return 0;
}

请添加图片描述

如果有多组相同的字符,则返回第一组的地址。

这个函数如何实现?

strstr()函数有两个参数和一个返回值

参数:两个内容不可修改的字符指针

返回值:字符指针

char* my_strstr(const char* ch1, const char* ch2)
#include<stdio.h>
char* my_strstr(const char* ch1, const char* ch2)
{
	char* cp = (char*)ch1;
	char* s1, * s2;
	if (!*ch2)  //如果ch2为空,则直接返回ch1的内容
		return((char*)ch1);
	while (*cp)
	{
		s1 = cp;
		s2 = (char*)ch2;
		while (*s1 && *s2 && !(*s1 - *s2))
			s1++, s2++;
		if (!*s2)
			return(cp);
		cp++;
	}
	return(NULL);
}
int main()
{
	char* ch1 = "abcdef";
	char* ch2 = "cd";
	char* ret = my_strstr(ch1, ch2);
	if (ret == NULL)
	{
		printf("没有找到\n");
	}
	else
	{
		printf("%s\n", ret);
	}

	return 0;
}

这种算法比较暴力,时间复杂度比较高。

有一种KMP算法,感兴趣可以去了解一下。我会在下一篇文章中写这个。


6. strtok

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

这个函数的作用是分割字符串一,分隔符是字符串二中的内容

  • delimiters参数是个字符串,定义了分隔符的字符集合
  • str参数是个字符串,其中有0个或多个delimiters中的字符
  • strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。

注: strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容 并且可修 改。

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

说了这么多,看看如何用吧。

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

int main()
{
	char* ch1 = "123456789@qq.com";
	const char* ch2 = "@.";
	char p[30];
	strcpy(p, ch1);
	char* str = NULL;
	for (str = strtok(p, ch2);str != NULL;str = strtok(NULL, ch2))
	{ 
		printf("%s\n", str);
	}
	return 0;
} 

请添加图片描述

strtok第一次调用第一个参数要传目标字符串地址,往后再次调用第一个参数要传NULL指针

还有strtok会改变第一个参数的内容


7.strncpy

char * strncpy ( char * destination, const char * source, size_t num );

这个函数和strcpy函数很像,只是多了一个参数,第三个参数是个无符号整型

这个函数可以决定考入目标字符串的字符个数,而不会将source中的所以内容全部拷贝在目标字符串中。

直接上代码看看。

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

int main()
{
	char ch1[20] = "abcdefg";
	char* ch2 = "hello";
	strncpy(ch1, ch2,3);
	printf("%s", ch1);

	return 0;
}

请添加图片描述


8.strncat

char * strncat ( char * destination, const char * source, size_t num );

这个函数同样和strcat函数很像,只不过多了一个参数,去决定追加多少个字符。

同时它可以让数组自己追加自己,不会像strcat那样无线追加。他自己在追加结束后自己补’\0’。

看看他如何用吧

#include<stdio.h>
#include<stdio.h>
#include<string.h>
int main()
{
	char arr[30] ="abcdef";
	strncat(arr, arr + 2,4);
	printf("%s", arr);
	return 0;
}

在这里插入图片描述


9.strncmp

int strncmp ( const char * str1, const char * str2, size_t num );

和前面两个一样多了个n所以它和strcmp函数类似,只是多一个参数,用来决定比较多少个字符。

看看如何用吧

#include<stdio.h>
#include<stdio.h>
#include<string.h>
int main()
{
	char* ch1 = "abcdef";
	char* ch2 = "abcfrgt";
	int ret = strncmp(ch1, ch2, 3);
	if (ret > 0)
		printf(">\n");
	else if (ret == 0)
		printf("=\n");
	else
		printf("<\n");

	return 0;
}

请添加图片描述

从这里可以看出,它只进行前三个字符的比较。


10.strerror

char * strerror ( int errnum );

这个函数作用:返回错误码,所对应的错误信息。

#include<stdio.h>
#include<stdio.h>
#include<string.h>
int main()
{
	printf("%s\n", strerror(0));
	printf("%s\n", strerror(1));
	printf("%s\n", strerror(2));
	printf("%s\n", strerror(3));
	printf("%s\n", strerror(4));
	printf("%s\n", strerror(5));
	printf("%s\n", strerror(6));

	return 0;
}

请添加图片描述

它会将一些我们看不懂的错误码转换成文字。

比如我们上网有时候出现404 ------指所请求的页面不存在、已被删除或无法访问。


3.内存函数

1.memcpy

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

其实这个函数和strncpy函数几乎一样,只不过它可以拷贝任意类型,而strncpy只针对字符串。

  • 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
  • 这个函数在遇到 ‘\0’ 的时候并不会停下来。
  • 如果source和destination有任何的重叠,复制的结果都是未定义的。(不能自己拷贝自己)

看看如何用吧

#include<stdio.h>
#include<stdio.h>
#include<memory.h>

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

	return 0;
}

请添加图片描述

下面看看他是如何实现的

#include<stdio.h>
#include<stdio.h>
#include<assert.h>
void* my_memcpy(void* dst, const void* src, size_t num) 
{
	void* ret = dst;
	assert(dst&& src);
	while (num--) 
	{
		*(char*)dst = *(char*)src;
		dst = (char*)dst + 1;
		src = (char*)src + 1;
	}
	return ret;
}

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

	return 0;
}

2.memmove

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

  • 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
  • 如果源空间和目标空间出现重叠,就得使用memmove函数处理。(可以自己拷贝自己)

看看它如何使用

#include<stdio.h>
#include<stdio.h>
#include<memory.h>

int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	memmove(arr1, arr1 + 2, 20);

	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

请添加图片描述

看看这个函数如何实现

#include<memory.h>
#include<stdio.h>
#include<assert.h>
void* memmove(void* dst, const void* src, size_t num) 
{
	assert(dst && src);
	void* ret = dst;
	if (dst <= src || (char*)dst >= ((char*)src + num)) 
	{
		while (num--) 
		{
			*(char*)dst = *(char*)src;
			dst = (char*)dst + 1;
			src = (char*)src + 1;
		}
	}
	else
	{
		dst = (char*)dst +num - 1;
		src = (char*)src + num - 1;
		while (num--) 
		{
			*(char*)dst = *(char*)src;
			dst = (char*)dst - 1;
			src = (char*)src - 1;
		}
	}
	return(ret);
}
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	memmove(arr1, arr1 + 2, 20);

	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

3.memcmp

int memcmp ( const void * ptr1, const void * ptr2, size_t num );

memcmp函数和strncmp函数基本相同,但是它可以比较任意类型

  • 比较从ptr1和ptr2指针开始的num个字节

  • 返回值:

    返回值比较结果
    >0ptr1>ptr2
    =0ptr1=ptr2
    <0ptr1<ptr2
#include<stdio.h>
#include<memory.h>

int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[6] = { 1,2,3,4,6,7};
	int ret = memcmp(arr1, arr2, 20);
	if (ret > 0)
		printf(">\n");
	else if (ret == 0)
		printf("=\n");
	else
		printf("<\n");

	return 0;
}

请添加图片描述


4.结束语

今天就写到这里了,库函数还有很多,希望大家没事可以去了解,它会使我们写代码变得轻松😄

有志者,事竟成。

在学习c语言的过程中,会有许多困难,希望大家可以克服,好好学,终究会有回报,终究会学到东西的。


  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值