字符串函数和字符函数

一.strlen
求结果?

#include<stdio.h>
int main()
{
    
    
	if (strlen("abc") - strlen("abcdef") > 0)
	{
    
    
		printf("hehe\n");
	}
	else
	{
    
    
		printf("haha\n");
	}
	return 0;
}

strlen 返回的是一个(size_t)unsigned int 类型的数。
所以结果返回的是hehe ,因为3-6 = -3 但是在内存中是以补码的形式进行存储的,返回的应该是一个size_t类型的值电脑认为-3的补码就是原码,所以这是一个很大的正数
strlen的两种实现方式

#include<assert.h>
//①计数器写法
int my_strlen(const char* str)
{
    
    
	int count = 0;
	assert(str != NULL);
	while (*str != '\0')
	{
    
    
		count++;
		str++;
	}
	return count;
}
//如果这里使用我们的my_strlen这个函数去求上面的my_strlen("abc") - strlen("abcdef") 得到的结果就应该是haha,因为这里我们自己所设定的返回值是int类型

//②递归写法(不创建临时变量,写一个求字符串长度的代码)
int my_strlen(const char* str)
{
    
    
	if (*str == '\0')
	{
    
    
		return 0;
	}
	else
	{
    
    
		return 1 + my_strlen(str + 1);
	}
}

长度不受限制的字符串函数
有时候对于目的地空间根本就不够大,你把源的字符串拷贝到目标空间内,即使程序崩溃了,但是依旧会显示你想要的的结果
二.strcpy
①源字符串必须以’\0’结束
char arr2[] = {‘b’,‘i’,‘t’}; 如果是这种形式进行拷贝,你就会发现他找不到‘\0’,就很有可能会造成越界访问
②会将源字符串中的’\0’拷贝到目标空间
③目标空间必须足够大,以确保能存放源字符串
④目标空间必须可变
char* p = “abcdef”; 这也是错的,因为这是常量字符串,不可变

char* my_strcpy(char* dest, const char* src)
{
    
    
	assert(dest != NULL);
	assert(src != NULL);
	char* ret = dest;
	while (*src != '\0')
	{
    
    
		*dest = *src;
		dest++;
		src++;
	}
	return ret;
	
int main()
{
    
    
	char arr1[] = "abcdefghi";
	char arr2[] = "bit";
	my_strcpy(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

上面的代码不够精简,这样的代码才是最完美的

char* my_strcpy(char* dest, const char* src)
{
    
    
	assert(dest != NULL);
	assert(src != NULL);
	char* ret = dest;
	//拷贝src指向的字符串到dest指向的空间,包含'\0'
	while (*dest++ = *src++) // 解引用的优先级比++高
	{
    
    
		;
	}
	//返回目的地空间的起始地址
	return ret;
}

三.strcat(字符串追加函数)
①源字符串必须以’\0’结束
②目标空间必须有足够大,能容纳下源字符串的内容
目标空间不够大的情况。
在这里插入图片描述
对于这段代码来说,你是会在上面看到显示的结果,但是程序也崩溃了,因为arr1的空间不够,并不能够把arr2里面的内容直接追加过去。
模拟实现strcat

char* my_strcat(char* dest, const char* src)
{
    
    
	assert(dest != NULL);
	assert(src != NULL);
	char* ret = dest;
	//1.找到目的字符串的'\0'
	while (*dest != '\0')
	{
    
    
		dest++;
	}
	//2.追加
	while (*dest++ = *src++)
	{
    
    
		;
	}
	return ret;
}
int main()
{
    
    
	char arr1[30] = "hello";
	char arr2[] = "world";
	strcat(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

四.strcmp(字符串比较)
在这里插入图片描述
标准规定:
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字
那么strcmp比较的是两个字符串谁长吗?

int main()
//比较'a' 和'c'哪一个ASCII的值更大,在VS编译器下,直接就判断出来了第一个字符串大于第二个字符串
	char* p = "abcdef";
	char* pp = "crgjk";
	
	//第一个字符一样时,顺序比较下一个字符的大小
	char* p = "abcd";
	char* pp = "aced"

	//	相等的时候
	char* p = "abcd";
	char* pp = "abcd"
}

难道因为第一个字符串长度为6,第二个字符串长度为5,所以第一个就大于第二个吗? 不是的,strcmp比较的是字符串首字符的大小(在VS编译器下如果字符串1的首字符大于第二个字符串的首字符,就会直接返回一个大于0的数(一般是1))如果两个首字符一样大,那就比较第二个字符,顺序往下推。
模拟实现strcmp

int my_strcmp(const char* str1, const char* str2)
{
    
    
	assert(str1 != NULL); 
	assert(str2 != NULL);
	//比较
	while (*str1 == *str2)
	{
    
    
		if (*str1 == '\0')
		{
    
    
			return 0;  //相等
		}
		str1++;
		str2++;
	}
	//vs编译器下实现的结果
	if (*str1 > *str2)
		return 1; // 大于
	else
		return -1; // 小于
	//gcc编译器下返回的结果
	//return (*str1 - *str2);
}
int main()
{
    
    
	char* p1 = "abcdef";
	char* p2 = "abcqwe";
	int ret = my_strcmp(p1, p2);
	printf("ret = %d\n", ret);
	return 0;
}

长度受限制的字符串函数
strncpy
①拷贝num个字符从源字符串到目标空间
②如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后面追加0,直到num个
strncat
strncmp
int strncmp(const char* string1,const char* string2,size_t count)

strstr---------查找字符串函数
找到了就给我返回查找到的那个字符串的地址,没有找到你就给我返回一个NULL。这个函数的实现逻辑还是挺复杂的,需要在后续多次的重复理解。

#include<assert.h>
char* my_strstr(const char* p1, const char* p2)//  这里我只是需要查找,所以不会改变里面的内容
{
    
    
	assert(p1 != NULL);
	assert(p2 != NULL);
	char* s1 = NULL;
	char* s2 = NULL;
	char* cur = (char*)p1;//可能报警告//记住他们两个相等的的位置,方便返回地址和进行下一次继续判断(字符串还有可能是"abbbcdef"     "bbc")
	if (*p2 == '\0')   // 传过去的字符串p2有可能是空字符串的情况
	{
    
    
		return (char*)p1;
	}
	//在p1里面查找p2,如果p1是一个空字符串那就根本没有办法查找,但是当p1不是空字符串的时候,说明就是可以查找的,我用p1的第一个字符和p2的
	//第一个字符相比较,如果不一样,我让p1的指针往后走一下,在比较直到p1指向的和p2指向的字符相等了,然后让他们一起向后走

	while (*cur) // 只有第一个字符串不为空,才有查找的必要 
	{
    
    
		s1 = cur;
		s2 = (char*)p2; // 因为p2是一各const类型的,所以可能汇报警告,需要强制类型转换一下
		//循环停止的条件有三个
		//1.首先p1先找到了'\0' 说明找不到p2了
		//2.在p1里面把p2彻底找到了,且p2已结遇见了'\0'所以停止了
		//3.*p1 != *p2循环也要停下来的
		//    "abcde"  "def"   "abcdef"  "def"  
		while ((*s1 != '\0') && (*s2 != '\0') && (*s1 == *s2))
		//库里面的函数写法(*s1 && *s2 && !(*s1-s2))
		{
    
    
			s1++;
			s2++;
		}
		if (*s2 == "\0") // 唯有这个条件下说明查找到,但是你会发现代码写到这里的时候,p1和p2的值一直都在改变,但是当我想要返回地址的时候
			//我不知道该怎么返回了,所以这里需要把起始的地址保存在一个变量里面,好方便下一次的继续使用
		{
    
    
			return cur;
		}
		cur++;
	}
	return NULL;
}

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

int main()
{
    
    
	char arr[] = "[email protected]";
	char* p = "@.";
	char buf[1024] = {
    
     0 };
	strcpy(buf, arr);
	//切割buf中的字符串
	char* ret = NULL;
	for(ret = strtok(arr,p);ret !=NULL;ret = strtok(NULL,p))
	{
    
    
		printf("%s\n",ret);
	}
//这里之所以这么写,是因为你会发现在切割字符串的时候,只有第一次传字符串的首地址,其余都是传NULL,这样子的写法就要比下面的方法感觉好很多。





	char* ret = strtok(arr,p);
	printf("%s\n", ret);
	
	ret = strtok(NULL, p);
	printf("%s\n", ret);
	
	ret = strtok(NULL, p);
	printf("%s\n", ret);
	return 0;
}

strerror
可以把错误码转换成我们所认识的内容。

字符函数
#include<ctype.h>需要引入的头文件
在这里插入图片描述

int main()
{
    
    
	//char ch = 'w';
	//如果是小写就会返回一个大于0的数
	//int ret = islower(ch);
	//printf("%d\n",ret);

	//char ch = tolower('Q');
	//char ch = toupper('q');
	//putchar(ch);
	
	//把字符串内容全部转为小写
	char arr[] = "I Am A Student";
	int i =0;
	while(arr[i] != '\0')
	{
    
    
		if(isupper(arr[i]))
		{
    
    
			arr[i] = tolower(arr[i]);
		}
		i++
	}
	printf("%s\n",arr);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/MEANSWER/article/details/109805310