【C语言】一些字符串函数的介绍和实现


C语言中对字符和字符串的处理很是频繁,但是C语言本身是 没有字符串类型的,字符串通常放在 常量字符串 中或者 字符数组 中。
字符串常量适用于那些对它不做修改的 字符串函数
注: 本文提到的函数基本都在 #include <string.h> 头文件下

求字符串长度的函数

strlen

size_t strlen ( const char * str );

  • 字符串以 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )。
  • 参数指向的字符串必须要以 ‘\0’ 结束。
  • 注:strlen函数的返回值为size_t,是无符号

关于strlen的返回值测试:

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

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;
}

结果恒为str2>str1,因为strlen返回值为无符号数,故相减结果也为无符号数,自然大于0。

strlen函数的实现:
方法一(计数器):

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

int MyStrlen(const char *pstr)
{
	assert(pstr != NULL);
	int count = 0;
	while(*pstr)
	{
		count++;
		pstr++;
	}
	return count;
}
int main()
{
	char str[] = "abcdef";
	char *pstr = str;
	//printf("%d\n",MyStrlen(NULL));
	printf("%d\n",MyStrlen(pstr));
	return 0;
}

方法二:

//不能创建临时变量计数器
int my_strlen(const char * str)
{
 if(*str == '\0')
 return 0;
 else
 return 1+my_strlen(str+1); 

方法三:

//指针-指针的方式
int my_strlen(char *s)
{
 char *p = s;
 while(*p != ‘\0)
 p++;
 return p-s;
}

长度不受限制的字符串函数

strcpy

字符串复制函数

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

  • 源字符串必须以 ‘\0’ 结束。
  • strcpy会将源字符串中的 ‘\0’ 拷贝到目标空间。
  • 目标空间必须足够大,以确保能存放源字符串。
  • 目标空间必须可变

strcpy函数的实现:

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

char *MyStrcpy(char *dest,const char *src)
{//字符串复制
	assert(dest != NULL && src != NULL);
	char *p = dest;
	while (*src != '\0')
	{
		*dest = *src;
		src++;
		dest++;
	}
	*dest = '\0';
	return p;
}
int main()
{
	char dest[10] = { 0 };
	char *src = "abcdef";
	MyStrcpy(dest, src);//返回值是目的地的地址,为了支持链式表达式
	printf("%s\n", dest);
	return 0;
}

strcat

字符串拼接函数

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

  • 源字符串必须以 ‘\0’ 结束。
  • 目标空间必须有足够的大,能容纳下源字符串的内容。
  • 目标空间必须可修改

strcat函数的实现:

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

char *MyStrcat(char *dest,const char *src)
{//字符串拼接函数 
	assert(dest);
	if(src == NULL)
	{
		return dest;
	}
	char *p = dest;
	while(*dest != '\0')
	{
		dest++;
	}
	while(*src != '\0')
	{
		*dest = *src;
		dest++;
		src++;
	}
	*dest = '\0';
	return p;
}
int main()
{
	char dest[20] = "abcdef";
	char *src = "helloworld";
	MyStrcat(dest,src);
	printf("%s\n",dest);
	return 0;
}

strcmp

字符串比较函数

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

标准规定:

  • 第一个字符串大于第二个字符串,则返回大于0的数字
  • 第一个字符串等于第二个字符串,则返回0
  • 第一个字符串小于第二个字符串,则返回小于0的数字

strcmp函数的实现:

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

char *MyStrcmp(char *str1,char *str2)
{//字符串比较函数 
	assert(str1 && str2);
	if(str1 == NULL)
		return -1;
	if(str2 == NULL)
		return 1;
	while(*str1 == *str2)
	{
		if(*str1 == '\0')
		{
			return 0;
		}
		str1++;
		str2++;
	}
	//两字符串不相等故进行比较 
	if(*str1 > *str2)
	{
		return 1;
	}
	else
	{
		return -1;
	}
}
int main()
{
	char *str1 = "abcdef";
	char *str2 = "abfdef";
	int ret = MyStrcmp(str1,str2);
	/*返回值
	>0 STR1 > STR2 
	=0 STR1 = STR2
	<0 STR1 < STR2 */
	printf("%d",ret);
	return 0;
}

长度受限制的字符串函数

strncpy

拷贝n个字符

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

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

strncat

拼接n个字符

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

strncmp

比较n个字符

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

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

字符串查找函数

strstr

在主串中查找子串第一次出现的位置
注:KMP算法实现了类似的功能,复杂,比较高效。

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

strstr函数的实现:

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

char *MyStrstr(char *str1,char *str2)
{
	char *start = str1;
	while(*start != '\0')
	{
		char *s1 = start;
		char *s2 = str2;
		while(*s1 && *s2 && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if(*s2 == '\0')
		{
			return start;
		}
		start++;
	}
	return NULL;
}

int main()
{
	char *str1 = "heaabcdef";//主串 
	char *str2 = "abc";//子串 
	char *p = MyStrstr(str1,str2);
	printf("%s\n",p);
	return 0;
}

strtok

字符串分割函数

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

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

函数使用的例子:

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

输出为:
在这里插入图片描述

错误信息报告函数

strerror

返回错误信息的函数

char * strerror(int errnum);

返回错误码,所对应的错误信息。

#include <errno.h>//必须包含的头文件

函数使用的例子:

#include <stdio.h>
#include <string.h>
#include <errno.h>//必须包含的头文件

int main ()
{
 FILE * pFile;
 pFile = fopen ("unexist.ent","r");
 if (pFile == NULL)
 printf ("Error opening file unexist.ent: %s\n",strerror(errno));
 //errno: Last error number
 return 0;
}

输出为:
在这里插入图片描述

内存操作函数

memcpy

void * memcpy ( void * destination, const void * source, size_t num );

  • 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
  • 这个函数在遇到 ‘\0’ 的时候并不会停下来。
  • 如果source和destination有任何的重叠,复制的结果都是未定义的

memcpy函数的实现:
注意避免内存重叠

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

void  *MyMemcpy(void *dest,void *src,int count)
{
	void *ret = dest;
	assert(dest);
	assert(src);
	while (count != 0)
	{
		*(char *)dest = *(char *)src;
		((char *)dest)++;
		((char *)src)++;
		count--;
	}
	return ret;
}
int main()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
	MyMemcpy(arr, arr + 2, 16);
	for (int i = 0; i < 8; i++)
	{
		printf("%d", arr[i]);
	}
	printf("\n");
	return 0;
}

memmove

void * memmove ( void * destination, const void * source, size_t num );

  • 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
  • 如果源空间和目标空间出现重叠,就得使用memmove函数处理。

memmove函数的实现:
可以处理内存的重叠

#include <stdio.h>
#include <Windows.h>

void * MyMemmove(void *dest, void * src, int count)
{
	void *ret = dest;
	if (src > dest)
	{
		while (count != 0)
		{
			*(char *)dest = *(char *)src;
			((char *)dest)++;
			((char *)src)++;
			count--;
		}
	}
	else
	{
		count--;
		while (count >= 0)
		{
			*((char *)dest + count) = *((char *)src + count);
			count--;
		}

	}

	return ret;
}
int main()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
	MyMemmove(arr+2, arr, 16);
	for (int i = 0; i < 8; i++)
	{
		printf("%d", arr[i]);
	}
	printf("\n");
	system("pause");
	return 0;
}

memcmp

int memcmp ( const void * ptr1, const void * ptr2,size_t num );

比较从ptr1和ptr2指针开始的num个字节
(比较两份内存里面值的大小)
函数使用的例子:

#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; 
} 

输出为:
在这里插入图片描述

END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值