IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> C语言之操作符详解 -> 正文阅读

[数据结构与算法]C语言之操作符详解


(一)求字符串长度函数

strlen

??strlen是求字符串长度函数,以\0为结束,长度不包括\0
??MSDN上解释为(这里的size_t是无符号整型):
????????????size_t strlen( const char *string );

int main()
{
	char arr1[]="abcdef";
	char arr2[]={ 'a','b','c' };
	size_t sz = strlen(arr1);
	printf("%d", sz);
	printf("%d", strlen(arr2));//打印随机值
	return 0;

??这里的arr2数组中找不到\0,strlen随即向后查找,输出随机值。

	if (strlen("abc") - strlen("abcdef") > 0)
	{
		printf("hehe\0");//打印hehe
	}
	else
	{
		printf("haha\0");
	}

??strlen返回无符号整型,计算过后不可能是负数,所以打印hehe。
??strlen的模拟实现如下,有三种方式
??1.计数器

size_t my_strlen(char* p)
{
	size_t x = 0;//计数器
	while (*p)
	{
		x++;
		p++;
	}
	return x;
}

2.指针 - 指针

size_t my_strlen(char* p)
{
	size_t x = 0;
	char* ch = p;//字符串头指针
	while (*p)
	{
		p++;
	}
	return p - ch;
}

3.递归

size_t my_strlen(char* p)
{
	if (*p)
	{
		return 1 + my_strlen(++p);
	}
	else
	{
		return 0;
	}
}

(二)字符串拷贝函数

strcpy — strncpy

??strcpy字符串拷贝函数,将一个字符串内容拷贝到另一个字符串中,遇到\0停下来,原字符串必须以\0结束。
??MSDN上解释为:
????????????char *strcpy( char *strDestination, const char *strSource );

int main()
{
	char arr1[] = "xxxxxxxxxxxxxxxxxx";
	char arr2[] = "hello";
	printf("%s\n", strcpy(arr1, arr2));//输出为abc
	return 0;
}

??将字符串arr2的内容拷贝到arr1中,连同\0一起拷贝过去。
??下面模拟实现strcpy函数

char* my_strcpy(char* str1,const char*  str2)
{
	assert(str1 && str2);//确保传入不为空
	char* ret = str1;
	while (*str1)
	{
		*str1++ = *str2++;
	}
	return ret;//返回目标空间的起始地址
}

??strncpy函数相对于strcpy在长度方面受限,比strcpy更加安全,可以指定拷贝字符的个数。
??MSDN上解释为:
????????????char *strncpy( char *strDest, const char *strSource, size_t count );

int main()
{
	char arr1[20] = "abcdefghi";
	char arr2[] = "xxx";
	strcpy(arr1, arr2, 2);
	printf("%s", arr1);//输出为xxcdefghi
	return 0;
}

??strncpy函数的模拟实现如下,

char* my_strncpy(char* str1, const char* str2, size_t count)
{
	assert(str1 && str2);//确保传入不为空
	char* ret = str1;
	for (int i = 0;i < count;i++)
	{
		*str1++ = *str2++;
	}
	return ret;//返回目标空间的起始地址
}

(三)字符串追加函数

strcat — strncat

??strcat是字符串连接/追加函数,在一个字符串末尾连接另一个字符串,原字符串必须以\0结束,且要保证目标空间大小足够。
??MSDN上解释为:
????????????char *strcat( char *strDestination, const char *strSource );

int main()
{
	char arr1[4] = "abf";
	char arr2[] = { 'a','b','f','\0' };//末尾必须是\0
	strcat(arr1, arr2);//出现错误,连接目标空间不够
	return 0;
}

??这时虽然打印仍然是abfabf,但是也会弹出对话框显示错误,arr1的空间不足,没有办法在后面连接,给arr1[4]分配更大的空间即可。
??下面是模拟实现strcat函数

char* my_strcat(char* dest,const char* src)
{
	assert(dest && src);
	char* ret = dest;
	//1.找到目标字符串的末尾,从\0开始
	while (*dest)
	{
		dest++;
	}
	//2.追加字符串
	while (*dest++ = *src++)//赋值dest为\0时,跳出循环
	{
		;
	}
	return ret;
}

??与strcpy和strncpy的关系类似,strncat函数相对于strcat在长度方面受限,比strcat更加安全,可以指定追加字符的个数。
??MSDN上解释为:
????????????char *strncat( char *strDest, const char *strSource, size_t count );

int main()
{
	char arr1[10] = "abf";
	char arr2[] = { 'a','b','f','\0' };//末尾必须是\0
	strncat(arr1, arr2, 2);
	printf("%s", arr1);//输出为abfab
	return 0;
}

??strncat函数的模拟实现如下,

char* my_strncat(char* dest,const char* src,size_t count)
{
	assert(dest && src);
	char* ret = dest;
	while (*dest)
	{
		dest++;
	}
	for(int i=0;i<count;i++)
	{
		*dest++ = *src++;
	}
	return ret;
}

(四)字符串比较函数

strcmp — strncmp

??strcmp是字符串比较函数,strcmp比较的是内容(即ASCII码值),不是长度,字符串1小于字符串2的时候返回-1(小于0),大于时返回1(大于0),等于时返回0。
??MSDN上解释为:
????????????int strcmp( const char *string1, const char *string2 );

int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abc";
	int ret = strcmp(arr1, arr2);
	if (ret == 0)
		printf("=");
	else if (ch > 0)
		printf(">");
	else if(ch<0)
		printf("<");
	return 0;
}

??strcmp函数的模拟实现如下,

int my_strcmp(const char* s1,const char* s2)
{
	assert(s1 && s2);
	while (*s1 == *s2)
	{
		if (*s1 == '\0')
			return 0;  //*s1 = *s2 = \0
		s1++;
		s2++;
	}
	return *s1 - *s2;
}

??strncmp函数相对于strcmp在长度方面受限,比strcmp更加安全,可以指定比较字符的个数。

int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abce";
	int ret = strncmp(arr1, arr2, 3);
	printf("%d",ret);//输出为0
	return 0;
}

??strncmp函数的模拟实现如下,

int my_strncmp(const char* s1,const char* s2,size_t count)
{
	assert(s1 && s2);
	for (int i = 0;i < count;i++)
	{
		if (*s1 == *s2)
		{
			if (*s1 == '\0')
				return 0;
			s1++;
			s2++;
		}
		else
			return *s1 - *s2;
	}
	return 0;
}

(五)字符串查找函数

strstr

??strstr是字符串查找函数,可以实现在一个字符串中查找另一个字符串是否存在,返回str2在atr1中第一次出现的位置(char*的指针),如果不存在,则返回为空。
??MSDN上解释为:
????????????char *strstr( const char *string, const char *strCharSet );

int main()
{
	char arr1[] = "i am a student";
	char arr2[] = "student";
	char* ret = strstr(arr1, arr2);
	if (ret == NULL)
	{
		printf("找不到");
	}
	else
	{
		printf("%s\n", ret);//输出为student
	}
	return 0;
}

??strstr函数的模拟实现如下,

char* my_strstr(const char* str1,const char* str2)
{
	assert(str1 && str2);
	char* cp = str1;
	char* s1;
	char* s2;
	if (*str2 == '\0')//排除arr2为空的情况
		return str1;
	while (*cp)
	{
		s1 = cp;
		s2 = str2;
		while (*s2 != '\0' && *s1 != '\0' && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return cp;
		}
		cp++;
	}
	return NULL;
}

??在实现过程中,要注意如下的情况,如果在匹配字符串过程中发现不相等,则需要从开始匹配的位置开始重新进行匹配。
在这里插入图片描述

(五)字符串切割函数

strtok

??strtok是字符串切割函数,它会找到str中的下一个标记,并将其用\0来结尾,返回一个指向这个标记的指针。
??MSDN上解释为:
????????????char *strtok( char *strToken, const char *strDelimit );
??第一个参数用来指定字符串,第二个参数sep是一个字符串,定义用作分隔符的字符集合。
??strtok函数的第一个参数不为NULL,将找到str中的第一个标记并且保存它在字符串中的位置。strtok函数的第一个参数为NULL时,函数将在同一个字符串被保存的位置开始,查找下一个标记。如果字符串中不存在更多的标记,则返回NULL指针。

int main()
{
	char arr1[] = "lyy@editor.csdn.net";//在@处和.处截断
	char arr2[30] = { 0 };
	char ch[] = "@.";
	strcpy(arr2, arr1);
	char* ret = NULL;
	for (ret = strtok(arr2, ch);ret != NULL;ret = strtok(NULL, ch))
	{
		printf("%s\n",ret);
	}
	return 0;
}

??此时的输出值如下:

(六)错误信息报告函数

strerror & perror

??strerror是错误信息报告函数,返回的是错误码对应的错误信息。C语言库函数调用失败的时候,会把错误码存到errco变量里面去,再调用的时候,解释errno变量中对应的错误信息。
??MSDN上解释为:
????????????char *strerror( int errnum );

int main()
{
	FILE* pf = fopen("text,txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
	}
	else
	{
		printf("打开文件成功");
	}
	return 0;
}

??此时屏幕上打印为,
在这里插入图片描述
??perror也是错误信息报告函数,相对于strerror操作更为简单。
??MSDN上解释为:
????????????void perror( const char *string );

int main()
{
	FILE* pf = fopen("text,txt", "r");
	if (pf == NULL)
	{
		perror("测试");
	}
	else
	{
		printf("打开文件成功");
	}
	return 0;
}

??perror函数会打印自定义信息之后再添加一个冒号和空格,随后打印错误信息。需要注意的是,perror函数一旦使用就必须要打印,输出如下,
在这里插入图片描述

(七)内存操作函数

memcpy

??memcpy是内存拷贝函数,不仅限于字符串。(不能进行重叠拷贝)
??MSDN上解释为:
????????????void *memcpy( void *dest, const void *src, size_t count );
??前两个是目标地址和原始地址,最后是要拷贝地址的大小。

int main()
{
	int arr1[5] = { 1,2,3,4,5 };
	int arr2[10] = { 0 };
	memcpy(arr2, arr1, 5 * sizeof(int));
	for (int i = 0;i < 10;i++)
	{
		printf("%d ", arr2[i]);//输出为1 2 3 4 5 0 0 0 0 0 
	}
	return 0;
}

??memcpy函数的模拟实现如下,

void* my_memcpy(void* dest, const void* src, size_t count)
{
	char* ch = dest;
	assert(dest && src);
	while (count--)
	{
		 *(char*)dest = *(char*)src;//转化为char*后赋值
		 dest = (char*)dest + 1;
		 src = (char*)src + 1;
	}
	return ch;
}

memmove

??memmove函数和memcpy作用类似,不同的是memmove可以实现重复内存拷贝。
??MSDN上解释为:
????????????void *memmove( void *dest, const void *src, size_t count );

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
	memmove(arr+2, arr, 16);
	for (int i = 0;i < 10;i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

??同一个字符串内部进行拷贝时,memmove输出为1 2 1 2 3 4 7 8 9 0,但是对于memcpy来说,在拷贝过程中,原字符串发生改变,输出为1 2 1 2 1 2 7 8 9 0,后续并不是我们想要的效果。memmove在本质上相当于memcpy的高级版本。
??由于拷贝过程中可能存在原字符串改变的问题,我们需要考虑以下情况,当dest在低地址,src在高地址时,需要从前向后拷贝,当dest在高地址,src在低地址的时候,需要从后向前拷贝(拷贝顺序与指针位置有关)。
在这里插入图片描述
??memmove函数的模拟实现如下,

void* my_memmove(void* dest, const void* src, size_t count)
{
	char* ch = dest;
	if (dest < src)//从前向后
	{
		while (count--)
		{
			 *(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			 src = (char*)src + 1;
		}
	}
	else//从后向前
	{
		while (count--)
		{
			*((char*)dest+count) = *((char*)src+count);
			//指向末尾后赋值
		}
	}
	return ch;
}

memcmp

??memcmp是内存比较函数,比较的是内存数据的大小,可以指定字节个数,大于返回1(大于0的数),小于返回-1(小于0的数),相等返回0。
??MSDN上解释为:
????????????void *memcpy( void *dest, const void *src, size_t count );

int main()
{
	int arr1[] = { 1,2,3,4,5 };
	//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00
	int arr2[] = { 1,2,3,6,6 };
	//01 00 00 00 02 00 00 00 03 00 00 00 06 00 00 00
	int ret = memcmp(arr1, arr2, 12);//前12个字节,输出为0
	return 0;
}

memset

??memset是内存设置函数,以字节为单位改变内存中的数据。
??MSDN上解释为:
????????????void *memset( void *dest, int c, size_t count );

int main()
{
	int arr[] = { 1,2,3,4,5 }; 
	memset(arr, 1, 24);//24是改动字节的数目
	//目标空间起始地址,改成目标值,改动字节数(以字节为单位)
	return 0;
}

??内存中显示为,

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-09-24 10:50:25  更:2021-09-24 10:50:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 4:27:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码