这篇博客我将讲解C语言中常见的字符函数,其中包含strcat、strcmp、strcpy、memcpy、memmove等等一系列的字符串函数和内存函数。

字符串函数

strcat

详解

字符串连接函数

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

参数:

  • dest:指向目的地空间。
  • src:指向源头数据。

功能:将src追加在dest字符串的末尾。
演示:

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

int main()
{
	char arr1[20] = "shdfks";
	char arr2[20] = "fhufkh";
	strcat(arr1, arr2);
	printf("%s\n", arr1);

	return 0;
}

注意事项:

  • 源字符串必须以’\0’结束
  • 目标字符串也必须有’\0’,否则无法知道追加从哪里开始
  • 目标空间必须足够大,能容纳下源字符串的内容
  • 目标空间必须可修改

模拟实现

char* My_strcat(char* dest, char* src)
{
	assert(dest && src);
	char* p = dest;
	while (*dest!='\0')
	{
		dest++;
	}
	while (*dest++ = *src++)
	{
		;
	}
	return p;
}

strcmp

详解

字符串比较函数

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

功能:按ASCII码值,逐字符比较两个字符串,直到遇到不同字符或遇到’\0’结束。
返回值:

  • 返回0:str1==str2两个字符串完全相等。
  • 返回>0(正数):str1>str2第一个不同字符,str1的ASCII更大。
  • 返回<0(负数):str1<str2第一个不同字符,str1的ASCII更小。
    演示:
#include<stdio.h>
#include<string.h>

int main()
{
	char arr1[20] = "fhvfks";
	char arr2[20] = "fhufkh";
	int p = strcmp(arr1, arr2);
	printf("%d\n", p);

	return 0;
}

注意事项:

  • 按ASCII逐字节比较,第一个不同就停止比较,不是按字符串长度比较。
  • 大小写不相等。
  • 返回值只看正负和0。
  • 不能写 ==1 判断,只能写 >0 ,<0 ,==0判断。
  • 字符串必须以’\0’结尾。

模拟实现

int My_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while (*str1 == *str2)
	{
		if (*str1=='\0')
		{
			return 0;
		}
		str1++;
		str2++;
	}
	if (*str1 > *str2)
		return 1;
	else
		return -1;
}

strcpy

详解

字符串拷贝函数

char* strcmp(char*dest, const char* src);

参数:

  • dest:指向目的地空间。
  • src:指向源头数据。

功能:将src中的内容拷贝到dest中。
演示:

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

int main()
{
	char arr1[20] = { 0 };
	char arr2[20] = "fhufkh";
	strcpy(arr1, arr2);
	printf("%s\n", arr1);

	return 0;
}

注意事项:

  • 从源字符串src逐个字符拷贝到目标dest,连带末尾’\0’一起拷贝。
  • 目标数组空间必须足够大,能装下源字符串加上’\0’,不然越界访问。
  • 目标空间必须可修改。
  • 源字符串必须以’\0’结尾。
  • 不能拷贝自己,dest和src空间重叠,结果不可控。

模拟实现

char* My_strcpy(char* dest, char* src)
{
	assert(dest && src);
	char* p = dest;
	while (*src != '\0')
	{
		*dest = *src;
		dest++;
		src++;
	}
	return p;
}

strstr

详解

字符串查找函数

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

功能:查找str2指向的字符串在str1指向的字符串中第一次出现的位置,并返回它的地址。
返回值:

  • 找到返回第一次出现的地址。
  • 找不到返回NULL。

演示:

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

int main()
{
	char arr1[20] = "bcdefabcdefabcd";
	char arr2[20] = "abc";
	char* p = strstr(arr1, arr2);
	printf("%s\n", p);

	return 0;
}

模拟实现

char* My_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	const char* p1 = str1;
	const char* p2 = str2;
	while (*str1 != '\0')
	{
		p1 = str1;
		p2 = str2;
		while (*p1 == *p2)
		{
			p1++;
			p2++;
			if (*p2 == '\0')
			{
				return (char*)str1;
			}
		}
		str1++;
	}
	return NULL;
}

strtok

详解

字符串分割函数

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

参数:

  • str:首次调用时传入待分割的字符串;后续调用传入NULL,表示继续分割同一个字符串。
  • delim:包含所有分割符的字符串(每个字符都视为独立的分隔符)。

功能:分割字符串:根据delim参数中指定的分隔符,将输入字符串str拆分成多个子字符串。

返回值:

  • 成功时,返回指向当前子字符串的指针。
  • 没有更多子字符串时返回NULL。

使用步骤:

  • 首次调用:传入待分割字符串和分隔符。
  • 后续调用:传入NULL和相同的分隔符,继续分割。
  • 结束调用:当返回NULL时,表示分割完成。

演示:

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

int main()
{
	char arr1[20] = "hdj.cji@djc.@fjss";
	char arr2[5] = { '.','@' };
	char buf[20] = { 0 };
	strcpy(buf, arr1);
	char* p = NULL;
	for (p = strtok(buf, arr2);p != NULL;p = strtok(NULL, arr2))
	{
		printf("%s\n", p);
	}

	return 0;
}

注意事项:

  • 破坏性操作:如果需要保留源字符串,应先拷贝一份。
  • 连续分割符:多个连续的分割符会被视为单个分割符,不会返回空字符串。
  • 空指针处理:如果输入的str为NULL且没有前序调用,行为未定义(也就是跳过了strtok(buf,arr2)直接使用NULL)。

strncat

详解

和strcat几乎相同,只不过多了一个参数。

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

参数:

  • dest:指向目的地空间。
  • src:指向源头数据。
  • num:最多追加的字符个数。

功能:将src最多num个字符追加在dest字符串的末尾。
演示:

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

int main()
{
	char arr1[20] = "shdfks";
	char arr2[20] = "fhufkh";
	strncat(arr1, arr2,4);
	printf("%s\n", arr1);

	return 0;
}

和strcat比较:

  • 多了一个参数。
  • strncat函数中源字符串不一定要有’\0’了。
  • strncat更加灵活,也更加安全。
  • 在设计参数时会多一层考虑:目标空间大小够不够用。

注意事项:不足num个只补一个’\0’。

模拟实现

char* My_strncat(char* dest, char* src,size_t num)
{
	assert(dest && src);
	char* p = dest;
	while (*dest != '\0')
	{
		dest++;
	}
	while (num--)
	{
		*dest++ = *src++;
	}
	return p;
}

strncmp

详解

和strcmp几乎相同,只不过多了一个参数。

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

功能:按ASCII码值,逐字符比较两个字符串,最多比较num次。

演示:

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

int main()
{
	char arr1[20] = "fhvfks";
	char arr2[20] = "fhufkh";
	int p = strncmp(arr1, arr2, 4);
	printf("%d\n", p);

	return 0;
}

和strcmp比较:

  • 可以比较任意长度,更加灵活、安全。

模拟实现

int My_strncmp(const char* str1, const char* str2, size_t num)
{
	assert(str1 && str2);
	while (*str1 == *str2 && num != 0)
	{
		if (*str1 == '\0')
		{
			return 0;
		}
		str1++;
		str2++;
		num--;
	}
	if (num == 0)
	{
		return 0;
	}
	if (*str1 > *str2)
		return 1;
	else
		return -1;
}

strncpy

详解

和strcpy几乎相同,只不过多了一个参数。

char* strncmp(char*dest, const char* src, size_t num);

参数:

  • dest:指向目的地空间。
  • src:指向源头数据。
  • num:最多拷贝的字符串个数。

功能:将src中的内容拷贝到dest中。
演示:

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

int main()
{
	char arr1[20] = { 0 };
	char arr2[20] = "fhufkh";
	strncpy(arr1, arr2, 5);
	printf("%s\n", arr1);

	return 0;
}

和strcpy比较:

  • strcpy函数拷贝到’\0’为止,如果目标空间不够的话,容易出现越界行为。
  • strncpy函数指定了拷贝的长度,源字符串不一定要用’\0’。
  • 在设计参数的时候会多一层思考:目标空间大小够不够用。
  • strncpy相对strcpy函数更加安全。

注意事项:

  • strncpy函数,拷贝数目不足num个,直接补’\0’,不管后面是什么,直到数目到达到num个。
  • 当src>num时,不会在最后补’\0’。

模拟实现

char* My_strncpy(char* dest, char* src, size_t num)
{
	assert(dest && src);
	char* p = dest;
	while (num>0)
	{
		*dest = *src;
		if (*src != '\0')
		{
			src++;
		}
		dest++;
		num--;
	}
	while (num > 0)
	{
		*dest = '\0';
		num--;
	}
	return p;
}

内存函数

memcpy

详解

内存块拷贝函数(不可重叠)

void* memcpy(void* dest, const void* src, size_t num);

memcpy是完成内存块拷贝的,不关注内存中存放的数据是什么,但不能解决内存重叠问题。
功能:函数memcpy从src的位置开始向后复制num个字节的数据到dest指向的内存位置。

演示:

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

int main()
{
	char arr1[20] = { 0 };
	char arr2[20] = "hd,kjs fhkf";
	memcpy(arr1, arr2, 20 * sizeof(char));
	printf("%s\n", arr1);

	return 0;
}

注意事项:如果src和dest有任何的重叠,复制的结果都是未定义的。

模拟实现

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

	return ret;
}

memmove

详解

内存块拷贝函数(可重叠)

void* memmove(void* dest, const void* src, size_t num);

memove和memcpy的差别就是,memmove函数处理的源内存块的目标内存块是可以重叠的
演示:

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

int main()
{
	char arr1[20] = "123456789";
	char arr2[20] = "123456789";
	memmove(arr1, arr1 + 5, 10);
	memmove(arr2 + 5, arr2, 10);
	printf("%s\n", arr1);
	printf("%s\n", arr2);

	return 0;
}

模拟实现

void* My_memmove(void* dest, const void* src, size_t num)
{
	assert(dest && src);
	void* ret = dest;
	//从前向后拷贝
	if(dest<src)
	{
		while (num--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	//从后向前拷贝
	else
	{
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);
		}
	}

	return ret;
}

memset

详解

设置内存块的内容

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

功能:memset函数是用来设置内存块内容的,将内存中指定长度的空间设置为特定的内容。
参数:

  • ptr:指针,指向要设置的内存空间,也就是存放了要设置的内存空间的起始地址。
  • value:要设置的值,函数将会把value值转换成unsigned char的数据进行设置的,也就是以字节为单位来设置内存块的。
  • num:单位字节。

演示:

int main()
{
	char arr1[20] = "123456789";
	memset(arr1,1,20*sizeof(char));
	printf("%s\n", arr1);

	return 0;
}

通过观察内存,我们可以发现,每个字节都被改成了1。
在这里插入图片描述

Logo

更多推荐