(C语言)常见字符函数和字符串函数

(C语言)常见字符函数和字符串函数_第1张图片 不烦下雨

​​​​  自我介绍 :  正在学习c语言,每天都在努力进步   

          ˙☆`·.·˙˙`··˙˙`··˙☆`·.·˙˙`··˙☆˙˙☆`·.·˙˙`··˙˙`··˙☆`·.·˙˙`··˙☆˙˙☆`·.·˙˙`··˙˙`··˙☆`·.·˙˙`··˙☆˙

  专栏 
   c语言Knowledge

  每日一题

                            记得点个关注和博主一起进步

         ˙☆`·.·˙˙`··˙˙`··˙☆`·.·˙˙`··˙☆˙˙☆`·.·˙˙`··˙˙`··˙☆`·.·˙˙`··˙☆˙˙☆`·.·˙˙`··˙˙`··˙☆`·.·˙˙`··˙☆˙

前言

      在C语言里有string.h这个头文件,但是C语言里没有字符串这个类型,字符串通常放在常量字符串中或者字符数组中,字符串常量适用于那些对她不做修改的字符串函数,string.h这个头文件里声明的函数原型也全是对char数组的操作,接下来这篇文章就简单介绍一下常用的函数

 strlen函数

 函数讲解

 size_t  strlen( const char*  str)

  功能:计算字符串长度,不包含’\0’

  返回值:返回字符串的长度

  • 字符串已经 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包
        含 '\0' )
  • 参数指向的字符串必须要以 '\0' 结束
  • 注意函数的返回值为size_t,是无符号的( 易错
  • 如果只定义没有给它赋初值,这个结果是不定的,它会从首地址一直找下去,直到遇到’\0’停止
#include
#include
int main()
{
    char arr1[] = { "abcdef" };
    char arr2[] = { 'a','b','c','d','e','f' };
    printf("%d\n", strlen(arr1));
    printf("%d\n", strlen(arr2));
    return 0;
}

【结果】:6   22(随机值)

函数模拟  ( 3种方式 )

方法一:

//计数器方式
int my_strlen(const char * str)
{
 int count = 0;
 while(*str)
 {
 count++;
 str++;
 }
 return count;
}

方法二:

//不能创建临时变量计数器
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* dest,char* src)

功能:将参数src字符串拷贝至参数dest所指的地址

返回值: 返回参数dest的字符串起始地址

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

 函数模拟

char *my_strcpy(char *dest, const char*src)
{ 
 char *ret = dest;
 assert(dest != NULL);
 assert(src != NULL);
 
 while((*dest++ = *src++))
 {
      ;
 }
 return ret;
}

【解释】:assert的作用是检验指针dest和src,防止其为空指针,*dest++ = *src++,当*src=‘ \0 ’时表达式为假,循环结束,但也会把‘\0’赋值给*dest

 

strncpy函数

 函数讲解

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

功能:将source指针所指字符串的前num个字符赋值给destination所指空间
返回值:返回参数destination的字符串起始地址

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

举例:

#include 
#include 
int main()
{
	char str[] = "abcdef";
//切记目标空间大小必须可修改
	char arr[10] = { 0 };
	strncpy(arr,str,3);
	printf("%s", arr);
	return 0;
}

(C语言)常见字符函数和字符串函数_第2张图片

 strcat函数

 函数讲解

char* strcat(char* dest,const char* src)

功能: 将src所指字符串接到dest所指字符串后边  (找到dest末尾再把src加进去)
返回值:返回dest所指字符串起始地址

  • 源字符串必须以 '\0' 结束,要把\0也接到末尾。
  • 目标空间必须有足够的大,能容纳下源字符串的内容。
  • 目标空间必须可修改,并且以为\0结尾,因为要保证可以顺利找到目标字符串结尾。

 函数模拟

char *my_strcat(char *dest, const char*src)
{
 char *ret = dest;
 assert(dest != NULL);
 assert(src != NULL);
//找到目标空间末尾
 while(*dest)
 {
 dest++;
 }
//把源字符串加进去
 while((*dest++ = *src++))
 {
       ;
 }
 return ret;
}

 

strncat函数

 函数讲解

char* strncat (char* dest,const char* src,size_t num)

功能:将src所指字符串前n个字符追加到dest所指字符串后
返回值:返回dest字符串的起始地址

 

strcmp函数

 函数讲解

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

 功能:字符串比较

返回值:若字符串str1和字符串str2相同则返回0,str1若大于str2则返回大于0的值,str1若小于str2则返回小于0的值

(C语言)常见字符函数和字符串函数_第3张图片

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

函数模拟

int my_strcmp(const char* str1, const char* str2)
{
	while (*str1== *str2)
	{
		if (*str1 == '0')  //表示两字符串都走到了\0的位置
			return 0;

		str1++;
		str2++;
	}

	if (*str1 > *str2)
		return 1;
	else
		return -1;

}

 

strncmp函数

 函数讲解

char * strncpy ( char * str1, const char * str2, size_t num );

功能:比较两字符串前num个字符

返回值:若字符串str1和字符串str2相同则返回0,str1若大于str2则返回大于0的值,str1若小于str2则返回小于0的值

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

 strstr函数

 函数讲解

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

功能:  查找str2所指字符串在str1所指字符串中首次出现的位置

返回值:返回字符串str1中第一次出现子串str2的地址,如果没有查找到子串,则返回NULL

例如:

#include 
#include 
int main ()
{
  char str[] ="This is a simple string";
  char * pch;
  pch = strstr (str,"simple");
  puts (str);
  return 0;
}

(C语言)常见字符函数和字符串函数_第4张图片

 函数模拟

char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);//检查传过来的指针是空指针

	const char* ret;  //记录开始匹配的位置
	const char* arr1; //遍历str1所指字符串
	const char* arr2; //遍历str2所指字符串
	ret = str1;       
	while (*ret)
	{
		arr1 =ret;  
		arr2 =str2;

		while (*arr1 && *arr2 && (*arr1 == *arr2))
		{
			arr1++;
			arr2++;
		}

		if (*arr2 == 0)
			return ret;
		ret++;
	}
	return NULL;
}

(C语言)常见字符函数和字符串函数_第5张图片

strtok函数

 函数讲解

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

功能:根据分隔符将字符串分隔成一个个片段

返回值:返回下一个分割后的字符串指针,如果已无从分割则返回NULL

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

举例:

#include 
#include 
int main()
{
	char p[] = "[email protected]";
	const char* sep = ".@";
	char arr[30];
	char* str = NULL;
	strcpy(arr, p);//将数据拷贝一份,处理arr数组的内容

	str = strtok(arr, sep);
	printf("%s\n", str);

	str = strtok(NULL, sep);
	printf("%s\n", str);

	str = strtok(NULL, sep);
	printf("%s\n", str);
	return 0;
}

(C语言)常见字符函数和字符串函数_第6张图片

但是,若要分割整个字符串,一般不会像上述代码那样写,因为如果目标字符串很长,分隔字符足够多,该调用多少次strtok函数呢,下面解锁一下正确的方式:

#include 
#include 
int main()
{
	char p[] = "[email protected]";
	const char* sep = ".@";
	char arr[30];
	char* str = NULL;
	strcpy(arr, p);//将数据拷贝一份,处理arr数组的内容

	for(str=strtok(arr, sep); str != NULL; str=strtok(NULL, sep))
  {
         printf("%s\n", str);
  }
	return 0;
}

 strerror函数

 函数讲解

char * strerror ( int errnum );

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

  • 必须包含头文件errno.h
  • strerror是将错误码翻译成错误信息,返回错误信息字符串的起始地址
  • c语言使用库函数的时候,如果使用失败,就会把错误码放在errno的变量中,errno是一个全局变量,可以直接使用

举例:

打开文件的例子:

fopen 以读的方式打开文件

如果文件存在,打开成功

如果文件不存在,打开失败

#include 
#include 
#include //必须包含的头文件
int main ()
{

  FILE * pFile;
  pFile = fopen ("add.txt","r");
  if (pFile == NULL)
    printf ("打开失败,原因是%s\n",strerror(errno));
    else
    printf("打开文件成功\n");
  return 0;
}

 

memcpy函数

 函数讲解

void * memcpy ( void * destination, const void * source, size_t num );
  • 函数memcpysource的位置开始向后复制num字节的数据到destination的内存位置。
  • 这个函数在遇到 '\0' 的时候并不会停下来。
  • 如果sourcedestination有任何的重叠,复制的结果都是未定义的。
  • memcpy函数可以拷贝整形数据,字符型数据,结构体类型数据,这里想接收地址的话只能用void*

例如:
 

#include 
#include 
int main()
{
    int arr[10] = { 0 };
    int str[] = { 1,2,3,4,5 };
    memcpy(arr, str, 20);
    for (int i = 0; i < 5; i++)
    {
        printf("%d ", arr[i]);
    }
    return 0;
}

 (C语言)常见字符函数和字符串函数_第7张图片

函数模拟

void* my_memcpy(void* dest, const void* src, size_t sz)
{
	assert(dest && src);
	void* ret = dest;
	while (sz)
	{
		*(char*)dest = *(char*)src;
		 dest = (char*)dest + 1;
	     src = (char*)src + 1;
		 sz--;
	}
	return ret;
}

【注】:由于两个形参都是void* ,不可以随意赋值和加减运算,由于本函数是以字节为单位进行覆盖,所以可以把两指针强转为char *类型,每循环一次就覆盖一个字节的内存,循环sz次就覆盖了sz个字节,这里还要注意,不能写成dest++,这时dest又变成了void *类型,写成(char*)dest++, 也是不行的,因为++优先级比强制转换高,会先执行dest++,此时在把指针强制转换为char *类型毫无意义,

memmove函数

 函数讲解

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

引例:

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

上述代码我们的目的是想把1~5的数字共20个字节拷贝到原来3~7的数字的位置上,我们来看一下结果:
(C语言)常见字符函数和字符串函数_第8张图片

这个结果并不是我们预期的1 2 1 2 3 4 5 8 9 10,那是什么原因呢?

(C语言)常见字符函数和字符串函数_第9张图片

是由于我们把1 2拷贝到了3 4的位子,当我们想用3和4的值时他们已经被改变了,所以才会导致这样的结果,接下来我们看看memcpy和memmove的区别

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

(C语言)常见字符函数和字符串函数_第10张图片

可见memmove可以成功将1~5的数赋值给3~7的数

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

 函数模拟

这个函数的覆盖分为两种情况

  • dest >src
  • dest

我们先看dest>src的情况:

(C语言)常见字符函数和字符串函数_第11张图片

可以发现,若src从前往后覆盖dest,还是会发生上述错误,这时这种情况从后往前覆盖就可以完美避开这种错误

再看dest

(C语言)常见字符函数和字符串函数_第12张图片

这种情况从前向后覆盖就没问题

void* my_memmove(void* dest, const void* src, size_t sz)
{
	assert(dest && src);
	void* ret = dest;
	if (dest < src)
	{
		//从前往后
		while (sz)
	   {
		  *(char*)dest = *(char*)src;
		   dest = (char*)dest + 1;
	       src = (char*)src + 1;
		   sz--;
	    }
	}
	else
	{
		//从后往前
		while (sz--)
		{
			*((char*)dest + sz) = *((char*)src+sz);
		}
	}
	
	return ret;
}

字符分类函数:

函数
如果他的参数符合下列条件就返回真
iscntrl
任何控制字符
isspace
空白字符:空格 ‘ ’ ,换页 ‘\f’ ,换行 '\n' ,回车 ‘\r’ ,制表符 '\t' 或者垂直制表符 '\v'
isdigit
十进制数字 0~9
isxdigit
十六进制数字,包括所有十进制数字,小写字母 a~f ,大写字母 A~F
islower
小写字母 a~z
isupper
大写字母 a~z
isalpha
字母 a~z A~Z
isalnum
字母或者数字, a~z,A~Z,0~9
ispunct
标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph
任何图形字符
isprint
任何可打印字符,包括图形字符和空白字符

                                                          喜欢的话欢迎关注我,收藏、点赞、转发本文喔 (◍•ᴗ•◍)ゝ~原创不易感谢支持

(C语言)常见字符函数和字符串函数_第13张图片

 

你可能感兴趣的:(c语言,c语言)