C语言的字符串函数,内存函数笔记详解

编辑: admin 分类: c#语言 发布时间: 2021-12-12 来源:互联网
目录
  • strlen
    • strlen模拟实现
  • strcpy
    • strcpy的模拟实现
  • strcat
    • strcat的模拟实现
  • strcmp
    • strcmp模拟实现
  • strstr
    • strstr模拟实现
  • strncpy
    • strncat
      • strncmp
        • strtok
          • memcpy
            • memcpy模拟实现
          • memmove
            • memmove模拟实现
          • memcmp
            • 字符分类函数
              • 字符串换函数
                • 总结

                  strlen

                  此函数接收一个char*类型参数,返回字符串\0前字符数,注意返回类型是size_t型的

                  //关于strlen返回值的一个易错点
                  int main()
                  {
                  	const char* str1 = "abcdef";
                  	const char* str2 = "bbb";
                  	if (strlen(str2) - strlen(str1) > 0)
                  	{
                  		printf("str2>str1\n");
                  	}
                  	else
                  	{
                  		printf("srt1>str2\n");
                  	}
                  	return 0;
                  }
                  

                  strlen模拟实现

                  法一

                  使用计数器

                  size_t my_strlen1(const char* str)
                  {
                  	assert(str);
                  	int count = 0;
                  	while (*str++)
                  	{
                  		count++;
                  	}
                  	return count;
                  }
                  

                  法二

                  指针相减

                  size_t my_strlen2(const char* str)
                  {
                  	assert(str);
                  	char* start = str;
                  	while (*str!='\0')//注意这种写法不能写*str++;这里要先判断再++;*str++的写法在'\0'的地方也+1了
                  	{
                  		str++;
                  	}
                  	return str - start;//\0与起始位置的差就是字符数
                  }
                  

                  法三

                  递归,不适用临时变量

                  size_t my_strlen3(const char* str)
                  {
                  	if ('\0' == *str)
                  		return 0;
                  	else
                  		return 1 + my_strlen3(str + 1);
                  }
                  

                  strcpy

                  此函数接收两个char*类型参数,把后一个字符串拷贝到前一个字符串中,包括\0,注意前一个指针指向的数组空间要足够大,被拷贝的内容必须包含\0

                  strcpy的模拟实现

                  char* my_strcpy(char* dest, const char* src)
                  {
                  	assert(dest && src);
                  	char* ret = dest;
                  	while (*dest++ = *src++)
                  	{
                  		;
                  	}
                  	return ret;
                  }
                  int main()
                  {
                  	char arr1[20] = "hello underworld";//注意写成数组
                  	char arr2[20] = "hello world";
                  
                  	printf("%s\n", arr2);
                  	printf("%s\n", my_strcpy(arr2, arr1));
                  
                  	return 0;
                  }
                  

                  strcat

                  此函数接收两个char*参数,在前一个字符串\0的位置开始拷贝后一个字符串,直到后一个字符串的\0,返回前一个字符串首地址。注意要保证前一个指针指向的空间足够大

                  strcat的模拟实现

                  char* my_strcat(char* dest, const char* src)
                  {
                  	char* ret = dest;
                  	assert(dest && src);
                  	while (*dest)//让dest到达str1的\0位置
                  	{
                  		dest++;
                  	}
                  	while (*dest++ = *src++)//这一部分和strcpy同
                  	{
                  		;
                  	}
                  	return ret;
                  }
                  int main()
                  {
                  	char arr1[20] = "hello ";
                  	char arr2[20] = "underworld";
                  
                  	printf("%s\n", my_strcat(arr1, arr2));
                  
                  	return 0;
                  }
                  

                  strcmp

                  接收两个char*参数,依次比较每个字符,在第一个不相等的字符处比较他们的编码值,前者大则返回一个大于0的数,前者小则返回一个小于0的数,字符串完全相等则返回0

                  strcmp模拟实现

                  int my_strcmp(const char* str1, const char* str2)
                  {
                  	while (*str1 == *str2)
                  	{
                  		if (*str1 == '\0')//说明两个字符串同时到达结束标记
                  			return 0;
                  		str1++;
                  		str2++;
                  	}
                  	return *str1 - *str2;//如果不是在循环内部返回,就一定不相等,而字符相减可以反映大小
                  }
                  int main()
                  {
                  	char *str1 = "hello world";
                  	char *str2 = "hello underworld";
                  
                  	printf("%d\n", my_strcmp(str1, str2));//w比u大
                  
                  	return 0;
                  }
                  

                  strstr

                  接收两个char*参数,返回第二个字符串在第一个字符串第一次出现的首位置指针

                  strstr模拟实现

                  char* my_strstr(const char* str1, const char* str2)
                  {
                  	assert(str1 && str2);
                  
                  	char* s1;//s1维护str1
                  	char* s2;//s2维护str2
                  	char* cp = str1;//cp用来记录比较开始的位置
                  
                  	if (*str2 == '\0')//特殊情况
                  		return str1;
                  
                  	while (*cp)
                  	{
                  		s1 = cp;
                  		s2 = str2;
                  
                  		while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)//其实*s1='\0'且*s2!='\0'时已经没有比较下去的必要了
                  			//*s1==*s2就让两个维护指针分别+1;不等就让cp+1,s1和s2分别重置		
                  		{
                  			s1++;
                  			s2++;
                  		}
                  		if (*s2 == '\0')//*s2=='\0'说明找到了
                  		{
                  			return cp;
                  		}
                  		cp++;
                  	}
                  
                  	return NULL;
                  }
                  

                  应用KMP算法的strstr

                  void get_next(char* str, int* next)
                  {
                  	int i, k;
                  	i = 0;
                  	k = -1;
                  	next[0] = -1;//这个值没用;或者说是为了使i增加而j不增加
                  	int len = strlen(str);
                  	while (i < len - 1)//next数组最大下标是字符串长度减1,数组长度和字符串长度相同
                  	{
                  		if (k == -1 || *(str + i) == *(str + k))
                  		{
                  			++i;
                  			++k;
                  			next[i] = k;
                  		}
                  		else
                  			k = next[k];
                  	}
                  
                  	//测试打印next
                  	int z;
                  	printf("next:");
                  	for (z = 0; z < len; z++)
                  	{
                  		printf("%d ", next[z]);
                  	}
                  	printf("\n");
                  }
                  
                  int Index_KMP(char* str1, char* str2, int pos)
                  {
                  	int i = pos;
                  	int j = 0;
                  	int next[255];
                  	get_next(str2, next);
                  	int len1 = strlen(str1);
                  	int len2 = strlen(str2);
                  	int count = 0;
                  	while (i < len1 && j < len2)//i从0到10(len1=11),共11次,但是考虑到走else的回溯,单字符查找一共循环22次
                  	{
                  		count++;
                  		if (j == -1 || *(str1 + i) == *(str2 + j))//先判断,再把下标加1
                  		{
                  			++i;
                  			++j;
                  		}
                  		else
                  		{
                  			j = next[j];
                  		}
                  	}
                  	printf("i=%d\n", i);
                  	printf("j=%d\n", j);
                  	printf("count=%d\n", count);//是存在回溯的,那么这个函数的时间复杂度还是O(m)吗?
                  	//if ((len2!=1) && (j >=(len2-1)))//有缺陷,对于len2=1的情况无法处理
                  	if (j >= (len2 - 1))//单字符查找情形,while结束时j=0,而len2-1也=0,故不能作为找到了的标志
                  		//对于单字符查找以外的情形,len2-1一定大于0,len2-1代表的就是目标串最后一个字符的下标,既然j
                  		//到达了这个位置,就说明完全匹配了
                  		return i - len2;//由于字符串长度与数组下标的差异造成len2=1时
                  	else
                  		return 0;
                  }
                  int main()
                  {
                  	char* str1 = "hello underworld!";
                  	char* str2 = "under";
                  
                  	printf("%s\n", my_strstr(str1, str2));
                  	printf("%s\n", *(str1+Index_KMP(str1, str2, 0)));
                  
                  	return 0;
                  }
                  

                  strncpy

                  比strcpy多一个参数,描述拷贝的字节数,如果多于str2的长度,则会补0

                  int main()
                  {
                  	char arr1[20] = "abcdefghi";
                  	char arr2[] = "xxxx";
                  
                  	//strncpy(arr1, arr2, 6);//从arr2拷贝6个字符给arr1?如果arr2长度不够,则补0
                  	//strncpy(arr1, arr2, 3);//长度不够不拷贝\0
                  	//strncpy(arr1, arr2, 4);
                  	strncpy(arr1, arr2, 5);
                  
                  	printf("%s\n", arr1);
                  	return 0;
                  }
                  

                  strncat

                  比strcat多一个参数,最多只拷贝完整的str2(包括\0)

                  int main()
                  {
                  	char arr1[20] = "abc\0xxxxxxx";
                  	char arr2[] = "def";
                  
                  	//strncat(arr1, arr2, 6);//在arr1后面接上arr2的六个字符?最多只接arr2这么长的字符串,包括\0
                  	//strncat(arr1, arr2, 3);//自己会加上\0
                  	strncat(arr1, arr2, 2);
                  
                  	printf("%s\n", arr1);
                  	return 0;
                  }
                  

                  strncmp

                  比strcmp多一个参数,描述比较的字节数

                  int main()
                  {
                  	char arr1[] = "abcdew";
                  	char arr2[] = "abcdeqj";
                  
                  	printf("%d\n",strncmp(arr1, arr2, 5));
                  	printf("%d\n",strncmp(arr1, arr2, 6));
                  
                  	return 0;
                  }
                  

                  strtok

                  字符串分割函数,接收两个char*参数,第一个是要被分割的字符串,第二个是分割符,分割符顺序不重要;第一个参数不为NULL时,返回分割的第一段;第一个参数为NULL,将从上个位置开始查找下一段

                  int main()
                  {
                  	char arr1[] = "cjh@scu.edu";
                  	char arr2[100] = { 0 };//保存临时数据
                  	char sep[] = "@.";
                  	char* ret = NULL;//接收strtok的返回值
                  	strcpy(arr2, arr1);
                  	for (ret = strtok(arr2, sep); ret != NULL; ret = strtok(NULL, sep))
                  	{
                  		printf("%s\n", ret);
                  	}
                  
                  	return 0;
                  }
                  
                  int main()
                  {
                  	char str[] = "- This, a sample string.";
                  	char* pch;
                  	printf("Splitting string \"%s\" into tokens:\n", str);
                  	pch = strtok(str, ", .-");//分隔标记的位置不重要
                  	while (pch != NULL)
                  	{
                  		printf("%s\n", pch);
                  		pch = strtok(NULL, " ,.-");//注意这里有空格
                  	}
                  	return 0;
                  }
                  

                  memcpy

                  接收三个参数,第一个是char的目标位置,第二个是被拷贝的char的数据源,最后一个是size_t的拷贝字节数。注意标准未定义把自己的内容拷贝被自己的结果。

                  memcpy模拟实现

                  void* my_memcpy(void* dest, void* src, size_t count)
                  {
                  	void* ret = dest;
                  	assert(dest && src);
                  
                  	while (count--)
                  	{
                  		*(char*)dest = *(char*)src;
                  		dest = (char*)dest + 1;
                  		src = (char*)src + 1;
                  	}
                  	//printf("%d\n", count);//count=-1
                  	return ret;
                  }
                  int main()
                  {
                  	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
                  	int arr2[20] = { 0 };
                  
                  	my_memcpy(arr2, arr1, 10 * sizeof(int));
                  
                  	int i;
                  	for (i = 0; i < 20; i++)
                  	{
                  		printf("%d ", arr2[i]);
                  	}
                  
                  	return 0;
                  
                  

                  memmove

                  此函数原型和memcpy一样,包含额memcpy的功能,且可以处理把自己的内容拷贝给自己的情景

                  #include <stdio.h>
                  #include <string.h>
                  int main()
                  {
                  	char str[] = "memmove can be very useful......";
                  	printf("%c\n", *(str + 15));
                  	printf("%c\n", *(str + 20));
                  
                  	memmove(str + 20, str + 15, 11);//注意memmove和memcpy不会遇到\0停下来,什么时候停取决于第三个参数
                  	puts(str);
                  	return 0;
                  }
                  

                  memmove模拟实现

                  void* my_memmove(void* dest, void* src, size_t count)//关键在于拷贝之前先判断是否会出现overlap
                  {
                  	void* ret = dest;
                  	if (dest <= src || (char*)dest >= ((char*)src + count))
                  	{
                  		while (count--)
                  		{
                  			*(char*)dest = *(char*)src;
                  			dest = (char*)dest + 1;
                  			src = (char*)src + 1;
                  		}
                  	}
                  	else
                  	{
                  		dest = (char*)dest + count - 1;
                  		src = (char*)src + count - 1;
                  		while (count--)
                  		{
                  			*(char*)dest = *(char*)src;
                  			dest = (char*)dest - 1;
                  			src = (char*)src - 1;
                  		}
                  	}
                  	return ret;
                  }
                  int main()
                  {
                  	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
                  
                  	my_memmove(arr + 2, arr, 4 * sizeof(int));//1 2 1 2 3 4 7 8 9 10  
                  	//my_memcpy(arr + 2, arr, 4 * sizeof(int));//1 2 1 2 1 2 7 8 9 10
                  
                  	int i;
                  	for (i = 0; i < 10; i++)
                  	{
                  		printf("%d ", arr[i]);
                  	}
                  	return 0;
                  }
                  

                  memcmp

                  接收三个参数,前两个是void*型,指向被比较的两块内容,最后一个size_t的参数表示要比较多少字节

                  #include <stdio.h>
                  #include <string.h>
                  int main()
                  {
                  	char buffer1[] = "DWgaOtP12df0";
                  	char buffer2[] = "DWGAOTP12DF0";
                  	int n;
                  	n = memcmp(buffer1, buffer2, sizeof(buffer1));
                  	if (n > 0) printf("'%s' is greater than '%s'.\n", buffer1, buffer2);
                  	else if (n < 0) printf("'%s' is less than '%s'.\n", buffer1, buffer2);
                  	else printf("'%s' is the same as '%s'.\n", buffer1, buffer2);
                  	return 0;
                  }
                  

                  字符分类函数

                  函数 如果他的参数符合下列条件就返回真

                  • iscntrl 任何控制字符
                  • isspace 空白字符:空格‘ ',换页‘\f',换行'\n',回车‘\r',制表符'\t'或者垂直制表符'\v'
                  • isdigit 十进制数字 0~9
                  • isxdigit 十六进制数字,包括所有十进制数字,小写字母af,大写字母AF
                  • islower 小写字母a~z
                  • isupper 大写字母A~Z
                  • isalpha 字母az或AZ
                  • isalnum 字母或者数字,az,AZ,0~9
                  • ispunct 标点符号,任何不属于数字或者字母的图形字符(可打印)
                  • isgraph 任何图形字符
                  • isprint 任何可打印字符,包括图形字符和空白字符

                  字符串换函数

                  • tolower()
                  • toupper()
                  #include <stdio.h>
                  int main ()
                  {
                    int i=0;
                    char str[]="Test String.\n";
                    char c;
                    while (str[i])
                   {
                      c=str[i];
                      if (isupper(c)) 
                          c=tolower(c);
                      putchar (c);
                      i++;
                   }
                    return 0; }
                  

                  总结

                  本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注海外IDC网的更多内容!

                  【转自:荷兰服务器