字符串函数和内存函数

字符串函数

1、strlcpy 【字符串拷贝】

17f28735979d40068497efd8ba559765.png

(将原字符串中的字符拷贝到目标字符数组中,包括终止符号\0,并在这里停止;为了避免越界,目标字符串数组应该足够大去接收)👆

(返回值是 destination,是个地址,目标字符数组的首地址)

9f53e1ca37424aacad1b13d8f56af778.png

// strcpy  字符串拷贝
//模拟实现
char* my_strcpy(char* des, const char* sour)
{
	assert(sour&&des);

	char* ret = des;

	/*while (*sour)
	{
		*des++ = *sour++;
	}
	*des = *sour;*/

	while (*des++ = *sour++)
		;

	return ret;
}

int main()
{
	char arr[20] = { 0 };
	char sour[] = "i lovw you";

	my_strcpy(arr, sour);

	zhangsan
	//strcpy(arr, "zhangsan");
	//printf("%s\n", arr);
	//strcpy(arr, "zhang\0san");
	printf("%s\n", arr);
	拷贝遇到\0停下
	return 0;
}

2、strcat 【字符串追加】

487d537c722a46968e490975a1b2499b.png

(在目标地址\0处开始,将source指的字符串加到后面,包括source指向字符串的\0也加上去)

返回值是destination指向字符数组的首元素地址

// strcat   字符串追加
//模拟实现
char* my_strcat(char* des, const char* sour)
{
	char* ret = des;
	int len = strlen(des);
	des = des + len;
	while (*des++ = *sour++)
		;
	return ret;
}

int main()
{
	char arr[20] = "hello";
	char brr[] = ",lpp!";

	printf("%s\n",arr);
	my_strcat(arr, brr);
	printf("%s\n", arr);

	return 0;
}

3、strcmp 【字符串比较】

如何比较呢? 是一一对应的比较

a b c e o     字符串n

a b c p w     字符串m

= = = ×            ——>   m>n

bdf8ebdc29b14d1994de8435bebe80f7.png

(从俩字符串的第一个字符开始比较,如果相同,继续比较,直到不相等或者\0)

返回值由比较结果决定,前者大于后者,返回>0 ;相等返回 0 ;前小于后,返回 <0

67a62c3a75544d8f96132c18ad85a082.png

// strcmp 【比较字符串】
//模拟实现
int my_strcmp(const char* str1, const char* str2)
{
	while (*str1++ == *str2++ && *str1 != '\0')
		;
	return *str1 - *str2;

}

int main()
{
	char arr[] = "abwdef";
	char brr[] = "abwdefp";

	int n=my_strcmp(arr, brr);

	printf("%d\n", n);
}

strcmp 、strcpy 、strcat  是长度不受限制的字符串函数↑,由一定风险,发生越界



strncmp、strncpy、strncat  是长度受限制的字符串函数 ↓  (多一个个数的限制)

4、strncpy  【字符串拷贝,限定版】

42aca09e11594208bc5c737f491b94a1.png

(跟strcpy用法基本一样,只不过多了一层限定,限定了拷贝字符的个数,

     假如限定拷贝5个,source指向的字符串不止5个,就只拷贝 5个

                                    source指向的字符串没有5个,依旧拷贝5个,没有的补 \0 )  

int main()
{
	char arr1[20] = "ancd yiw********* ";
	char arr2[] = "hello";
	strncpy(arr1, arr2, 10);

	printf("%s\n", arr1);

	return 0;
}

没有 拷贝之前 arr1 里面的字符如下:

a61b6e880fb4434a84ba00af403ba666.png

 

拷贝之后 arr1 内字符如下 ↓   (可见,不足要求个数的时候补 \0)

02ad118ec5204db5bf0868fdbafce33c.png

 

5、strncat   【字符串追加  限定版】

995469f590ba4f2c9f46c111be3d9890.png

同strcat用法差不多,也是多个限定追加字符的个数

但是当 追加个数(num) 大于sourse指向的字符串 里的字符个数时,不会强制全补 \0,

追加完sourse 指向字符串,就不再追加

int main()
{
	char arr1[20] = "hello \0********";
	char arr2[] = "baby";
	strncat(arr1, arr2, 7);

	printf("%s\n", arr1);

// hello baby

}

追加前 arr1 内情况👇

3395fd482f8840168a97740915c03f33.png

 

追加后,arr1 内情况  👇

a6099e4ade164da5aa90d3b3132e1e19.png

 

6、strncmp   【字符串比较  限定版】

d550c95730be4abfba188d43bcad06a4.png

(比较停止条件 1、比出不同   2、比到 \0   3、比到超出要求数字(num))

int main()
{
	char arr1[] = "abcde";
	char arr2[] = "abcoi";

	int n=strncmp(arr1, arr2, 3);

	printf("%d ", n);


// 0

	return 0;
}

如上: 当num为3 的时候 返回值是0,只比到了第三个字符

            当num大于3时,返回值<0,因为第4对的 o 大于 d

 


如上,是长度受限制的字符串函数 👆


 

7、strstr  【查找子串】

aeff9fe4995c45afb83d42853affb6b0.png

返回的是查找到的那个字符串的首地址,如果没有查找到,返回空指针。

int main()
{
	char arr[] = "hello my baby nice to meet you.";
	char* ptr;
	ptr=strstr(arr, "baby");

	if (ptr != NULL)
		strncpy(ptr, "lpp,", 4);

	printf("%s\n", arr);

//hello my lpp, nice to meet you.

	return 0;
}

模拟strstr函数,实现它的功能:

const char* my_strstr(const char* str1, const char* str2)
{
	const char* s1 = str1;
	const char* s2 = str2;
	const char* p = str1;
	while (*s1)
	{
		s1 = p;
		s2 = str2;
		while (*s1!='\0'&&*s2!='\0'&& * s1 == *s2)
		{
			s1++;
			s2++;
		}

		if (*s2 == '\0')
			return (char*)p;

		p++;

	}

	return NULL;
}


8、strtok 【切割字符串】

29e15821c9ee421e83292627107fe6ae.png

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

 

8b515601f47e4ebcba9a53e6516ed988.png(返回值:第一次传非空指针,发现字符串,返回发现字符首字母地址,

   然后strtok记忆这个字符地址,下次NLULL进来,继续从这个位置开始,

   读取完整个字符,返回NULL)

 

int main()
{
	char arr[] = "i.study.every.day_365*day.";
	char a[100] = { 0 };
	strcpy(a, arr);

	char* ret;
	for (ret = strtok(a, "._*"); ret != NULL;ret=strtok(NULL,"._*"))
	{
		printf("%s ", ret);

	}


	return 0;
}

9、字符分类函数  <ctype.h>

字符分类函数
iscntrl任何控制字符
isspace空白字符:空格' ' ,   换页'\f',   换行'\n',   回车‘\r',   制表符'\t',   垂直符'\v'
isdigit

十进制数字0~9

islower小写字母
isupper大写字母
isalpha字母(包括大小写)
isalnum字母或数字
ispunct标点符号,任何不属于数字或字母的图形字符
isgraph任何图形字符
isprint任何可打印字符,包括图形字符和空白字符
isxdigit

十六进制数字,包括所有十进制数字,

小写字母a~f,大写字母A~F

函数  ↑↑↑如果·它的参数符合上面条件 就返回真

用法相似,举个列子,isupper 函数

9de3beda9e284c0bb8897935afa25dfa.png

因为字符在内存中都是以·ASCII值储存的

int main()
{
	char a = 'a';
	char b = 'A';

	printf("%d %d", isupper(a), isupper(b));

	// 0 1
	return 0;
}

假,返回 0,真,返回>0的值(1)

 

10、字符转换函数        tolower   toupper

tolower 将 大写字母 变成 小写字母

toupper将 小写字母 变成 大写字母

其他不符合条件的字符不会改变

int main()
{
	char a = 'A';
	char b;
	b = tolower(a);
	printf("%c\n", b);
	//a
	b = tolower(b);
	printf("%c\n", b);
	//a
	b = toupper(b);
	printf("%c\n", b);
	//A
	b = toupper('@');
	printf("%c\n", b);
	//@
	return 0;
}

11、strerror   【将错误码转换成错误信息】

e5f57570e76b4f01a9e738258fa220d2.pngc语言的库函数,在执行失败的时候,都会设置错误码

(给它一个错误信息码,它会找到对应的错误字符串,并且将首地址返回给你)

errno  是c语言设置的一个全局的 错误码 存放的变量    头文件<errno.h>

int main()
{
	//printf("%s\n", strerror(0));//No error
	//printf("%s\n", strerror(1));//Operation not permitted
	//printf("%s\n", strerror(2));//No such file or directory
	//printf("%s\n", strerror(3));//No such process
//fopen 是打开文件的函数, 里面放的是文件路径,和打开方式 r是 读
//如果打开失败 返回值是NULL
	FILE* pf = fopen("C:\\Users\\嗷~里~个~嗷\\Desktop", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));

	}

	else
	{
		;
	}
		//Permission denied
	return 0;
}


内存函数

12、memcpy   【内存拷贝】

84462975438c470d85958430fe71497d.png

与strncpy不同的是,memcpy是适用于所有类型,第三个参数,是字节个数    

其 返回值是 destination 所指向的首地址

memcpuy  负责 拷贝两块独立空间的数据,

不适用于重叠内存之间的数据拷贝

// 模拟实现
void* my_memcpy(const void* dis, const void* sou, size_t num)
{
//因为要保证整个函数具体范性,所以一个字节一个字节进行
//char* ,一次访问一个字节
	char* ret =(char*) dis;
	while (num--)
	{
		*(char*)dis = *(char*)sou;
		dis = (char*)dis + 1;
		sou = (char*)sou + 1;

	}

	return ret;
}


int main()
{
	int i = 0;
	int arr1[] = { 1,2,3,4,5,6,7,8 };
	int arr2[4] = { 11,22,33,44 };
	my_memcpy(arr1, arr2, sizeof(arr2));
	for (i = 0; i < (sizeof(arr1) / sizeof(arr1[0]));i++)
		printf("%d ",arr1[i]);

		putchar('\n');

	double brr1[] = { 1.1,2.2,3.3,4.4 };
	double brr2[] = { 11.11,22.22,33.33,44.44 };
	my_memcpy(brr1, brr2, sizeof(brr2));
		for (i = 0; i < (sizeof(brr1) / sizeof(brr1[0])); i++)
			printf("%.2lf ", brr1[i]);

	return 0;

}

13、memmove  【内存拷贝,加强版】

与memcpy相比,它可以实现,重叠内存数据的拷贝,其他用法一样。

void test_cpy()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };

	memcpy(arr + 2, arr, 20);

	int i = 0;
	for (i = 0; i < 10; i++)
		printf("%d ", arr[i]);
	putchar('\n');

}

void test_move()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };

	memmove(arr + 2, arr, 20);

	int i = 0;
	for (i = 0; i < 10; i++)
		printf("%d ", arr[i]);
	putchar('\n');
}

int main()
{
	test_cpy();
	test_move();

	return 0;
}

模拟实现  👇

void* my_memmove(const void* des, const void* sour, size_t num)
{
	assert(des && sour);
	void* ret = des;
	if (des < sour)
	{
		//从前往后拷贝
		while (num--)
		{
			*(char*)des = *(char*)sour;
			des = (char*)des + 1;
			sour = (char*)sour + 1;
		}
		
	}
	else
	{
		// 从后往前拷贝
		while (num--)
		{
			*((char*)des + num) = *((char*)sour + num);

		}

	}

}

图解如下所示:

76fd0ac0adc7465a8b57d95e6a691ff4.png

14、memcmp   【内存比较】

strncmp 函数相比,它是适用所有类型,其他基本一样

51dca2e4b9a5438cbf58511ff03399eb.png

int main()
{
	int arr[] = { 1,2,3,4,5 };
	int brr[] = { 1,2,3,8,5 };
	int x = memcmp(arr, brr, 12);
	int y = memcmp(arr, brr, 16);

	printf("%d %d", x, y);

	// 0 -1 
}

15、memset  【内存设置】

71b82ca117f947b0b5148393be6f5387.png

ptr 是指向我们要改变的位置,

value 是我们要变成的对象,

num是要改变字节的个数

 

int main()
{
	char arr[] = "hello baby.";
	memset(arr, '*', 5);
	printf("%s\n", arr);
	//***** baby.

	int brr[5] = { 1,2,3,4,5 };
	int i = 0;
	memset(brr+1, 0, 8);
	for (i = 0; i < 5; i++)
		printf("%d ", brr[i]);
	// 1 0 0 4 5
	//一个字节一个字节来

	return 0;
}

 

👏👏👏👏👏👏👏👏👏👏👏

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值