【C语言】14个常用的字符串函数和内存函数

文章目录

  • 一、strlen函数
    • 1. 函数原型
    • 2. 使用介绍
    • 3. 三种方法模拟实现strlen函数
      • 计数器法
      • 利用递归
      • 指针相减
  • 二、strcpy函数
    • 1. 函数原型
    • 2. 使用介绍
    • 3. 模拟实现strcpy函数
  • 三、strcat函数
    • 1. 函数原型
    • 2. 使用介绍
    • 3. 模拟实现strcat函数
  • 四、strcmp函数
    • 1. 函数原型
    • 2. 使用介绍
    • 3. 模拟实现strcmp函数
  • 五、strncpy函数
    • 1. 函数原型
    • 2. 使用介绍
    • 3. 模拟实现strncpy函数
  • 六、strncat函数
    • 1. 函数原型
    • 2. 使用介绍
    • 3. 模拟实现strncat函数
  • 七、strncmp函数
    • 1. 函数原型
    • 2. 使用介绍
    • 3. 模拟实现strncmp函数
  • 八、strstr函数
    • 1. 函数原型
    • 2. 使用介绍
    • 3. 模拟实现strstr函数(BF算法)
  • 九、strtok函数
    • 1. 函数原型
    • 2. 使用介绍
  • 十、strerror函数
    • 1. 函数原型
    • 2. 使用介绍
  • 十一、memcpy函数
    • 1. 函数原型
    • 2. 使用介绍
    • 3. 模拟实现memcpy函数
  • 十二、memmove函数
    • 1. 函数原型
    • 2. 使用介绍
    • 3. 模拟实现memmove函数
  • 十三、memcmp函数
    • 1. 函数原型
    • 2. 使用介绍
    • 3. 模拟实现memcmp函数
  • 十四、memset函数
    • 1. 函数原型
    • 2. 使用介绍

一、strlen函数

1. 函数原型

size_t strlen ( const char * str );

2. 使用介绍

  • 用于计算字符串长度。
  • 字符串以 '\0' 作为结束标志。
  • strlen 函数返回的是 '\0' 前面出现的字符个数,不包含 '\0'
  • 函数的返回值类型为size_t,即无符号整型。
    • 由于返回值类型无符号整型是没有负数的,在使用中要注意别出错。
      如下图,两个无符号整数相减得到的还是无符号整数,程序运行结果与我们想得到的相反。
      【C语言】14个常用的字符串函数和内存函数_第1张图片

3. 三种方法模拟实现strlen函数

计数器法

//计数器
int my_strlen1(const char* str)
{
	assert(str != NULL);

	int cnt = 0;
	while (*str++ != '\0')
	{
		cnt++;
	}

	return cnt;
}

利用递归

//递归
int my_strlen2(const char* str)
{
	assert(str != NULL);

	if (*str != NULL)
		return 1 + my_strlen2(str + 1);
	else
		return 0;
}

指针相减

//指针相减
int my_strlen3(const char* str)
{
	assert(str != NULL);

	const char* start = str;
	while (*++str != '\0')
		;

	return str - start;
}

二、strcpy函数

1. 函数原型

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

2. 使用介绍

  • 用于将一个字符串拷贝到目标处。
  • 源字符串必须以 '\0' 结束。
  • 会将源字符串中的 '\0' 拷贝到目标空间。
  • 目标空间必须足够大,确保能存放下源字符串。
  • 函数返回的是目标空间起始位置的地址,便于链式访问。

3. 模拟实现strcpy函数

char* my_strcpy(char* dest, const char* src)
{
	assert(dest != NULL && src != NULL);

	const char* start = dest;
	while (*dest++ = *src++)
		;

	return start;
}

三、strcat函数

1. 函数原型

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

2. 使用介绍

  • 用于在目标字符串尾部追加一个字符串。
  • 追加从目标字符串尾部的 '\0'开始,这个 '\0'会被源字符串的第一个字符替换。
  • 追加到'\0'为止,所以源字符串必须以 '\0' 结束。
  • 会将源字符串中的 '\0' 追加到目标空间。
  • 不能自己给自己追加。
  • 函数返回的是目标空间起始位置的地址,便于链式访问。

3. 模拟实现strcat函数

char* my_strcat(char* dest, const char* src)
{
	assert(dest != NULL && src != NULL);

	char* start = dest;
	while (*++dest != '\0')
		;

	while (*dest++ = *src++)
		;

	return start;
}

四、strcmp函数

1. 函数原型

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

2. 使用介绍

  • 用于比较字符串是否相同。
  • 字符的大小取决于ASCII码。
  • strcmp从第一个字符开始,逐字符比较大小,直到遇到第一个不相等的字符或者'\0'停止。
  • 大于,函数返回大于0的数。
  • 小于,函数返回小于0的数。
  • 等于,函数返回0

3. 模拟实现strcmp函数

int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 != NULL && str2 != NULL);

	while (*str1 == *str2)
	{
		if (*str1 == '\0')
			return 0;

		str1++;
		str2++;
	}

	return *str1 - *str2;
}

五、strncpy函数

1. 函数原型

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

2. 使用介绍

  • 类似 strcpy
  • 不同的是这个函数可以控制拷贝字符的个数为 num
  • 如果源字符串的长度小于 num,则拷贝完源字符串之后,继续追加'\0'直到num个为止。
  • 函数返回的是目标空间起始位置的地址,便于链式访问。

3. 模拟实现strncpy函数

char* my_strncpy(char* dest, const char* src, size_t num)
{
	assert(dest != NULL && src != NULL);

	const char* start = dest;
	while (num--)
	{
		if (*src == '\0')
		{
			*dest++ = '\0';
		}
		else
		{
			*dest++ = *src++;
		}
	}
		
	return start;
}

六、strncat函数

1. 函数原型

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

2. 使用介绍

  • 类似strcat
  • 不同的是这个函数可以控制追加的字符个数为num
  • 如果源字符串的长度小于num,则追加完源字符串之后,继续追加'\0'直到num个为止。
  • 函数返回的是目标空间起始位置的地址,便于链式访问。

3. 模拟实现strncat函数

char* my_strncat(char* dest, const char* src, size_t num)
{
	assert(dest != NULL && src != NULL);

	char* start = dest;
	while (*++dest != '\0')
		;

	while (num--)
	{
		if (*src == '\0')
		{
			*dest++ = '\0';
		}
		else
		{
			*dest++ = *src++;
		}
	}

	return start;
}

七、strncmp函数

1. 函数原型

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

2. 使用介绍

  • 类似strcmp
  • 直到遇到第一个不相等的字符或者num个字符全部比较完为止。

3. 模拟实现strncmp函数

int my_strncmp(const char* str1, const char* str2, size_t num)
{
	assert(str1 != NULL && str2 != NULL);

	while (num--)
	{
		if (*str1 == *str2)
		{
			str1++;
			str2++;
		}
		else
		{
			return *str1 - *str2;
		}
	}

	return 0;
}

八、strstr函数

1. 函数原型

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

2. 使用介绍

  • 用于在一个字符串里查找另一个字符串。
  • 找到了则返回第一次出现的位置,没找到则返回空指针。

3. 模拟实现strstr函数(BF算法)

BF算法,即暴力枚举。

char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 != NULL && str2 != NULL);
	if (*str2 == '\0')
		return (char*)str1;

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

		cp++;
	}

	return NULL;
}

进阶:KMP算法


九、strtok函数

1. 函数原型

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

2. 使用介绍

  • 用于除去字符串中的分隔符。
  • sep 是所有分隔符组成的字符串。
  • strtok找到一个分隔符后,会将其覆盖为'\0',并返回该分隔符的前一个子串。
  • strtok每次找到一个分隔符后都会自动保存该位置。
    • 第一次调用传非空指针
    • 后面每次调用要传空指针strtok会从上一次保存的位置开始往后找。
  • 如果字符串中已经找不到分隔符了,则返回空指针。

来看一个例子:

/* strtok example */
#include 
#include 
int main ()
{
	 char str[] ="- This, a sample string.";
	 char* p;
	 printf ("Splitting string \"%s\" into tokens:\n",str);
	 p = strtok (str," ,.-");
	 while (p != NULL)
	{
		  printf ("%s\n", p);
		  p = strtok (NULL, " ,.-");
	}
	 return 0;
}

运行结果如下:

【C语言】14个常用的字符串函数和内存函数_第2张图片


十、strerror函数

1. 函数原型

char * strerror ( int errnum );

2. 使用介绍

  • C语言的库函数运行时如果发生错误,会将错误码存放在全局变量errno中。
  • 错误码是一些数字,我们可以用strerror函数把错误码翻译成错误信息。
  • strerror函数返回的就是包含错误信息的字符串的地址。

来看一个例子:

#include 
#include //strerror函数
#include //errno变量

int main ()
{
	FILE * pFile = fopen ("unexist.ent","r");
	
 	if (pFile == NULL)
  		printf ("%s\n",strerror(errno));
  	
 	return 0;
}

运行结果如下:
在这里插入图片描述
如果只想要打印错误信息,可以使用perror函数。


十一、memcpy函数

1. 函数原型

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

2. 使用介绍

  • source的位置开始,向后拷贝num个字节的数据到destination的内存位置。
  • 这个函数在遇到 '\0' 的时候并不会停下来。
  • 如果sourcedestination有重叠,结果是未定义的。
  • strncpy只能拷贝字符串不同,memcpy可以拷贝任意类型的数据。
  • 函数返回的是目标空间起始位置的地址,便于链式访问。

3. 模拟实现memcpy函数

void* my_memcpy(void* dest, const void* src, size_t num)
{
	assert(dest != NULL && src != NULL);
	
	void* start = dest;
	while (num--)
	{
		*(char*)dest = *(char*)src;
		++(char*)dest;
		++(char*)src;
	}

	return start;
}

十二、memmove函数

1. 函数原型

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

2. 使用介绍

  • 参考memcpy
  • memcpy的不同在于:memmove处理的源内存块和目标内存块是可以重叠的。

3. 模拟实现memmove函数

void* my_memmove(void* dest, const void* src, size_t num)
{
	assert(dest != NULL && src != NULL);
	void* start = dest;

	//考虑到源内存块和目标内存块的重叠问题
	if (dest < src)//从前向后拷贝
	{
		while (num--)
		{
			*(char*)dest = *(char*)src;
			++(char*)dest;
			++(char*)src;
		}
	}
	else//从后向前拷贝
	{
		while (num--)//利用num--往前,dest和src不动
		{
			*((char*)dest + num) = *((char*)src + num);
		}
	}

	return start;
}

注:现在很多库里的memcpy函数已经优化解决了源内存块和目标内存块的重叠问题,但还是建议能用memmove就用memmove


十三、memcmp函数

1. 函数原型

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

2. 使用介绍

  • strncmp类似,逐字节比较从 ptr1 开始和从 ptr2 开始的num个字节。
  • strncmp只能比较字符不同,memcmp可以比较任意类型。

3. 模拟实现memcmp函数

int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
{
	assert(ptr1 != NULL && ptr2 != NULL);

	while (num--)
	{
		if (*(char*)ptr1 == *(char*)ptr2)
		{
			++(char*)ptr1;
			++(char*)ptr2;
		}
		else
		{
			return *(char*)ptr1 - *(char*)ptr2;
		}
	}

	return 0;
}

十四、memset函数

1. 函数原型

void * memset( void * ptr, int value, size_t num );

2. 使用介绍

  • 以字节为单位来设置内存中的数据。
  • ptr是目标内存的地址,value是要设置的值,num是要设置多少个字节。

你可能感兴趣的:(C语言重点突破,c语言,开发语言)