当前位置:首页 » 《资源分享》 » 正文

C语言进阶笔记(四) | 万字详解字符串函数及其模拟_KYG__Y_O的博客

29 人参与  2021年09月13日 12:43  分类 : 《资源分享》  评论

点击全文阅读


目录

前言

函数介绍 

strlen

代码演示

模拟strlen

strcpy

代码演示

 模拟strcpy

strcat

代码演示

模拟strcat

strcmp

代码演示

模拟strcmp 

长度受限制的字符串函数 - strncpy、strncat、strncmp

strncpy

代码演示

strncat

代码演示 

strncmp 

代码演示

strstr

代码演示

模拟strstr

strtok

代码演示

strerror

代码演示

补充:perror函数


前言

C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在 常量字符串中或者字符数组中。 字符串常量适用于那些对它不做修改的字符串函数。

函数介绍 

strlen

size_t strlen ( const char * str );

1.字符串以 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0' )。
2.参数指向的字符串必须要以 '\0' 结束。
3.注意函数的返回值为size_t,是无符号的( 易错 )
4.学会strlen函数的模拟实现

功能 - 计算字符串的长度

代码演示

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

int main()
{
	char arr[] = "abc";
	int len = strlen(arr);
	printf("%d\n", len);
	return 0;
}

模拟strlen

计数器版本

#include<stdio.h>

int my_strlen(const char* str)//加const使函数更安全
{
	assert(str != NULL);//断言
	int count = 0;
	while(*str != '\0')
	{
		str++;
		count++;;
	}
	return count;
}

int main()
{
	char arr[] = "abc";
	int len = my_strlen(arr);
	printf("%d\n", len);
	return 0;
}

递归版本 - 不用创建临时变量count

#include<stdio.h>

int my_strlen(const char* str)
{
	assert(str != NULL);
	if (*str != '\0')
		return my_strlen(str + 1) + 1;
	else
		return 0;
}

int main()
{
	char arr[] = "abc";
	int len = my_strlen(arr);
	printf("%d\n", len);
	return 0;
}

除了以上两个版本,模拟strlen函数还有其他版本,大家有兴趣可以去搜索了解一下,这里就不一一列举了。

strcpy

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

Copies the C string pointed by source into the array pointed by destination, including the terminating nullcharacter(and stopping at that point).


1.源字符串必须以 '\0' 结束。

2.会将源字符串中的 '\0' 拷贝到目标空间。

3.目标空间必须足够大,以确保能存放源字符串。

4.目标空间必须可变。

 功能 - 将源字符串拷贝到目的字符串

代码演示

#define _CRT_SECURE_NO_WARNINGS

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

int main()
{
	char arr[20] = "#############";
	//arr = "hello";//err  arr表示数组首元素地址,是const类型,不能被赋值
	//printf("%c\n", "hello"[1]);//e   "hello"可以说本身是个地址

	/*char* p = "hello";
	strcpy(arr, p);*/

	strcpy(arr, "hello");//与上等效

	/*char arr2[] = { 'a','b','c' };
	strcpy(arr, arr2);*/ //err

	/*char* str = "#########";
	strcpy(str, "hello");*/ //err 源字符串为常字符串,不可改变

	printf("%s\n", arr);//hello
	return 0;
}

 模拟strcpy

#define _CRT_SECURE_NO_WARNINGS

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

char* my_strcpy(char* dest, const char* str)
{
	assert(str && dest);
	char* ret = dest;
	while (*dest++ = *str++)
	{
		;
	}
	return ret;
}

int main()
{
	char arr[20] = "#############";
	my_strcpy(arr, "hello");
	printf("%s\n", arr);//hello
	return 0;
}

strcat

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

Appends a copy of the source string to the destination string. 
The terminating null character in destination is overwritten by the first character of source, 
and a null - character is included at the end of the new string formed by the concatenation of both in destination.


1.源字符串必须以 '\0' 结束。

2.会将源字符串中的 '\0' 拷贝到目标空间。

3.目标空间必须有足够的大,能容纳下源字符串的内容。

4.目标空间必须可修改。

5.字符串自己给自己追加会如何? 不可以自己追加,会将自己的'\0'覆盖掉,死循环

 功能 - 将源字符串追加在目的字符串后面

代码演示

#define _CRT_SECURE_NO_WARNINGS

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

int main()
{
	char arr[20] = "hello ";
	strcat(arr, "world");
	printf("%s\n", arr);//hello world   
	
	return 0;
}

模拟strcat

#define _CRT_SECURE_NO_WARNINGS

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

char* my_strcat(char* dest, const char* src)
{
    assert(dest && src);
	char* ret = dest;
	while (*dest)
	{
		dest++;
	}

	/*do
	{
		*dest = *src;
		dest++;
		src++;
	} while (*src);*/

	//简洁写法
	while (*dest++ = *src++)
	{
		;
	}

	return ret;//返回目标空间的起始地址   意义:方便链式访问 - 返回值做另一个函数的参数
}

int main()
{
	char arr[20] = "hello ";

	//my_strcat(arr, "world");

	printf("%s\n", my_strcat(arr, "world"));//hello world   
	
	return 0;
}

strcmp

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

This function starts comparing the first character of each string. If they are equal to each other, it continues with the following pairs until the characters differ or until a terminating null - character is reached.

标准规定:(注意:比较的是两个字符串的首个不同字符的大小,而不是字符串长短)

第一个字符串大于第二个字符串,则返回1;

第一个字符串等于第二个字符串,则返回0;

第一个字符串小于第二个字符串,则返回-1。

 功能 - 比较字符串

代码演示

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

int main()
{
	//char* p1 = "abc";
	//char* p2 = "abcdef";
	//if (p1 > p2)//比较的是两个字符串首字母地址大小
	//{
	//	printf(">\n");
	//}
	//else
	//{
	//	printf("<=\n");
	//} //err

	//if ("abc" > "abcdef")//比较的是两个字符串首字母地址大小
	//{
	//	printf(">\n");
	//}
	//else
	//{
	//	printf("<=\n");
	//} //err

	int ret1 = strcmp("abb", "ac");
	printf("%d\n", ret1);//-1
	int ret2 = strcmp("ab", "ab");
	printf("%d\n", ret2);//0
	int ret3 = strcmp("ac", "abc");
	printf("%d\n", ret3);//1

	return 0;
}

模拟strcmp 

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

int my_strcmp(const char* p1, const char* p2)
{
	assert(p1 && p2);

	//写法一
	/*while (*p1 || *p2)
	{
		if (*p1 < *p2)
			return -1;
		else if (*p1 > *p2)
			return 1;
		p1++;
		p2++;
	}
	return 0;*/

	//写法二
	while (*p1 == *p2)
	{
		if (*p1 == '\0')
			return 0;
		*p1++;
		*p2++;
	}

	//此处可用 return *p1 - *p2;代替,二者等效
	if (*p1 < *p2)
		return -1;
	else
		return 1;
}

int main()
{
	char* p1 = "ab";
	char* p2 = "ac";
	int ret = my_strcmp(p1, p2);
	if (ret < 0)
		printf("%s<%s\n",p1,p2);
	else if (ret > 0)
		printf("%s>%s\n",p1,p2);
	else
		printf("%s=%s\n",p1,p2);
	return 0;
}

长度受限制的字符串函数 - strncpy、strncat、strncmp

下面将介绍strncpy、strncat、strncmp三个函数,与strcpy、strcat、strcmp三个函数相比,多个n,多个size_t num参数,长度受到限制。

strncpy

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

Copies the first num characters of source to destination.If the end of the source C string(which is signaled by a null - character) is found before num characters have been copied, destination is padded with zeros until a total of num characters have been written to it.
 
1.拷贝num个字符从源字符串到目标空间。

2.如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。

代码演示

#define _CRT_SECURE_NO_WARNINGS

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

int main()
{
	char arr1[] = "abcdefg";
	char arr2[] = "qwer";
	strncpy(arr1, arr2, 2);
	printf("%s\n", arr1);//qwcdefg
	strncpy(arr1, arr2, 6);
	printf("%s\n", arr1);//qwer
	return 0;
}

strncat

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

Appends the first num characters of source to destination, plus a terminating null - character.If the length of the C string in source is less than num, only the content up to the terminating null character is copied.


将源的前num个字符追加到目标,再加上一个终止字符'\0'。

如果源中的C字符串长度小于num,则仅复制终止字符'\0'之前的内容。

代码演示 

#define _CRT_SECURE_NO_WARNINGS

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

int main()
{
	char arr1[20] = "hello ";//需要初始化足够大被追加
	char arr2[] = "world";
	strncat(arr1, arr2, 2);
	printf("%s\n", arr1);//hello wo
}

strncmp 

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

比较到前num个字符,比到出现一个字符不一样或者num个字符全部比完或者一个字符串结束全部比完。

代码演示

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

int main()
{
	char* p1 = "abcdefg";
	char* p2 = "abcqaer";

	int ret = strncmp(p1, p2, 3);
	printf("%d\n", ret);//0

	ret = strncmp(p1, p2, 4);
	printf("%d\n", ret);//-1

	ret = strncmp(p1, p2, 5);
	printf("%d\n", ret);//-1

	return 0;
}

strstr

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

Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1.

返回指向str1中第一个出现的str2的指针,如果str2不是str1的一部分,则返回空指针。

功能 - 在str1字符串中查找str2字符串

代码演示

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

int main()
{
	char arr1[] = "abcdefabcdef";
	char arr2[] = "bcd";

	char* ret = strstr(arr1, arr2);//在arr1中查找是否包含arr2数组
	
	if (ret == NULL)
		printf("没找到\n");
	else
		printf("找到了:%s\n", ret);//找到了:bcdefabcdef

	return 0;
}

模拟strstr

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

char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);

	if (*str2 == '\0')
		return (char*)str1;

	const char* s1, *s2, *cp = str1;
	
	while (*cp)
	{
		s1 = cp;
		s2 = str2;
		while ((*s1 == *s2) && *s1 && *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
			return (char*)cp;
		cp++;
	}

	return NULL;
}

int main()
{
	char arr1[] = "abcdefabcdef";
	char arr2[] = "bcd";
	
	char* ret = my_strstr(arr1, arr2);

	if (ret == NULL)
		printf("没找到\n");
	else
		printf("找到了:%s\n", ret);//找到了:bcdefabcdef

	return 0;
}

strtok

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

sep参数是个字符串,定义了用作分隔符的字符集合

第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。

strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向此段首字符的指针。

strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。

strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。

如果字符串中不存在更多的标记,则返回 NULL 指针。

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

功能 - 分割字符串

如:

将192.168.3.122分割成           此处 . 为分隔符
192
168
3
122

将kyg@abc.qwe分割成           此处 @ 和 . 为分隔符
kyg
abc
qwe

代码演示

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

int main()
{
	char arr[] = "kyg@abc.qwe";
	char* p = "@.";
	char tmp[20] = { 0 };
	strcpy(tmp, arr);
	//strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。
    
    char* ret = NULL;
    
    //
	ret = strtok(tmp, p);//kyg@abc.qwe\0 -> kyg\0abc.qwe\0 - 返回指向k的指针,并保存原 @ 的位置
	//strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
	printf("%s\n", ret);//kyg

	ret = strtok(NULL, p);//kyg\0abc.qwe\0 -> kyg\0abc\0qwe\0 - 返回指向a的指针,并保存原 . 的位置
	//strtok函数的第一个参数为 NULL ,函数将在上一个字符串中被保存的位置开始,查找下一个标记。
	printf("%s\n", ret);//abc

	ret = strtok(NULL, p);//kyg\0abc\0qwe\0 - 返回指向q的指针,并保存最后\0的位置
	printf("%s\n", ret);//qwe

	ret = strtok(NULL, p);
	//如果字符串已结束,则返回 NULL 指针。
	printf("%s\n", ret);//(null)
    //以上部分可简单写为下面代码

	/*for (ret = strtok(tmp, p); ret != NULL; ret = strtok(NULL, p))
	{
		printf("%s\n", ret);
	}*/

	return 0;
}

strerror

char* strerror(int errnum);

返回错误码所对应的错误信息(字符串)的首字符地址。

功能 - 调用库函数失败时,都有设置错误码,strerror可返回错误码所对应的错误信息。

int errno; - 全局的错误码

代码演示

#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
#include<string.h>
#include<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

	FILE* pf = fopen("test.txt", "r");//以读的方式打开test.txt文件,打开失败会返回NULL空指针
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));//No such file or directory - 没有这个文件或文件夹
		return 1;//若打开失败,则返回1终止代码
	}
	//...省略读文件一系列操作代码
	fclose(pf);//关闭文件
	pf = NULL;

	return 0;
}

补充:perror函数

void perror( const char *string );      头文件 - stdio.h

strerror只是返回错误码所对应的错误信息;而perror会直接打印出错误信息,使用很方便。

代码演示

#define _CRT_SECURE_NO_WARNINGS

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

int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("error");//No such file or directory - 没有这个文件或文件夹
		return 1;//若打开失败,则返回1终止代码
	}
	//...省略读文件一系列操作代码
	fclose(pf);//关闭文件
	pf = NULL;

	return 0;
}

打印结果

perror函数的参数为一个字符串,可自己随意确定;

由打印结果可以看出,perror函数会先打印出参数字符串并在其后加上:和一个空格,然后才是错误信息字符串。


点击全文阅读


本文链接:http://zhangshiyu.com/post/27741.html

字符串  函数  代码  
<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1