【C语言】字符串函数、字符函数、内存函数

字符串函数

一、模拟实现字符函数

1、strlen(计算字符串长度)

方法一:循环实现,有计数器;
#include 
#include 

int my_strlen(const char* arr)
{
	assert(arr);
	int count = 0;
	while (*arr)
	{
		count++;
		arr++;
	}
	return count;
}

int main()
{
	char arr[] = "sadad";
	
	int count = my_strlen(arr);
	printf("%d\n", count);
	return 0;
}

 方法二:递归实现,无计数器;

#include 
#include 

int my_strlen(char* arr)
{
	assert(arr);
	if (*arr)
	{
		return 1 + my_strlen(arr + 1); // 这里不能使用arr++, 不能使用后加加, 否则会报错
	}
	else
	{
		return 0;
	}
}

int main()
{
	char arr[] = "sdlwoue";
	printf("%d\n", my_strlen(arr));
	return 0;
}

方法三: 指针实现;
#include 
#include 

int my_strlen(char* arr)
{
	assert(arr);
	char* p = arr;
	while (*p)
	{
		p++;
	}
	return p - arr;
}
int main()
{
	char arr[] = "ihaeshd";
	printf("%d\n", my_strlen(arr));
	return 0;
}


2、strcmp(字符串比较)

. 字符串比较是一个字符一个字符进行比较的。 

#include 
#include 
char* my_strcmp(char* dest, const char* src)
{
	assert(dest && src);
	char* arr = dest;
	while (*src)
	{
		*dest++ = *src++;
	}
	return arr;
}
int main()
{
	char arr[20] = { 0 };
	char arr1[] = "sdihfpa";
	printf("%s ", my_strcmp(arr, arr1));
	return 0;
}

3、strcpy(字符串拷贝) 

. 当目标数组遇到'\0',源数组才会进行拷贝,也会将'\0'拷贝过去。

#include 
#include 

char* my_strcpy(char* dest, char* src)
{
	assert(dest && src);
	char* arr = dest;
	while (*dest != '\0')
	{
		dest++;
	}
	while (*dest++ = *src++)
	{
		;
	}
	return arr;
}
int main()
{
	char arr1[] = "xx\0xxxxxxxxx";
	char arr2[] = "abcd";
	char* arr = my_strcpy(arr1, arr2);
	printf("%s\n", arr);
	return 0;
}

4、strcat(字符串追加) 

 .当目标字符串遇到'\0',就将源数组的字符串追加到目标数组,并且将'\0'也追加过去了。

#include 
#include 

char* my_strcat(char* dest, char* src)
{
	assert(dest && src);
	char* arr = dest;
	while (*dest != '\0')
	{
		dest++;
	}
	while (*dest++ = *src++)
	{
		;
	}
	return arr;
}
int main()
{
	char arr1[20] = "x\0xxxxxxxxxxxx";
	char arr2[] = "abcdef";
	char* arr = my_strcat(arr1, arr2);
	printf("%s\n", arr);
	return 0;
}

二、模拟实现固定字符函数

 1、strncmp(固定字符串比较)

#include 
#include 
int my_strncmp(char* arr1, char* arr2, size_t num)
{
	assert(arr1 && arr2);
	while (*arr1 == *arr2)
	{
		num--; // 注意:num--需要放在前面
		if (num == 0)
		{
			return 0;
		}
		arr1++;
		arr2++;
	}
	return *arr1 - *arr2;
}
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abcda";
	int num = my_strncmp(arr1, arr2, 4);
	if (num == 0)
	{
		printf("=\n");
	}
	else if (num > 0)
	{
		printf(">\n");
	}
	else
	{
		printf("<\n");
	}
	return 0;
}

2、strncpy(固定字符串拷贝) 

#include 
#include 
char* my_strncpy(char* dest, char* src, size_t num)
{
	assert(dest && src);
	char* arr = dest;
	while (num)
	{
		num--;
		*dest++ = *src++;
	}
	return arr;
}
int main()
{
	char arr1[20] = "xxxxxxxxxxxxx";
	char arr2[] = "abcdefgh";
	char* arr = my_strncpy(arr1, arr2, 4);
	printf("%s\n", arr);
	return 0;
}

3、strncat(固定字符串追加) 

#include 
#include 
char* my_strncat(char* dest, char* src, size_t num)
{
	assert(dest && src);
	char* arr = dest;
	while (*dest != '\0')
	{
		dest++;
	}
	while (num)
	{
		num--;
		*dest++ = *src++;
	}
	*dest = '\0';
	return arr;
}
int main()
{
	char arr1[] = "x\0xxxxxxxxxxx";
	char arr2[] = "abcdefgh";
	char* arr = my_strncat(arr1, arr2, 4);
	printf("%s\n", arr);
	return 0;
}

三、模拟实现字符函数(也需要认识的)

1、strstr(查找对应字符串)

. 查找对应字符串,返回以该字符串开头的地址;

#include 
#include 
const char* my_strstr(const char* arr1, const char* arr2)
{
	assert(arr1);
	// 创建以下变量的目的就是不改变arr1和arr2的地址
	const char* arr; // 用来存放查找后的地址
	const char* s1; // 用来遍历arr1数组
	const char* s2; // 用来遍历arr2数组
	arr = arr1;
	
	if (*arr2 == '\0') // 如果要查找的什么也没有,就直接返回源数组
	{
		return arr;
	}


	while (*arr != '\0') 
	{
		s1 = arr; // 需要注意
		s2 = arr2;
		while (*s1 && *s2 && *s1 == *s2) // 当指向的不是'\0'并且相等
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0') 
		{
			return arr;
		}
		arr++; // 没有查找到对应的就向后查找
	}
	return NULL;
}
int main()
{
	char arr1[] = "abbbcdefgh";
	char arr2[] = "bcd";
	char* arr = my_strstr(arr1, arr2);
	printf("%s\n", arr);
	return 0;
}

2、strtok(切割字符串)使用方法

 . 切割字符串定义的切割符是无顺序的;

. 切割字符串有记忆功能,第一次切割后会记住切割后的结束位置;

. 注意:下面代码里面的第二个strtok的条件为NULL;

#include 
int main()
{
	// 使用切割字符串函数,strtok
	char arr[] = "xiaobaicai-*-return-*-dabaicai";
	char arr1[200];
	strcpy(arr1, arr);
	char* s;
	for (s = strtok(arr1, "-*"); s != NULL; s = strtok(NULL, "-*")) // 因为strtok有记忆功能,在for语句中使用了一次strtok,所以第二次只需要传空指针进去。
	{
		printf("%s\n", s);
	}
	return 0;
}

3、strerror (字符串错误信息)

 . strerror函数是将错误码翻译成错误信息,最后返回错误信息的其实地址;

. errno 全局的变量,可以直接使用;strerror(errno);

#include 
#include 
int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

. perror函数是直接打印错误码对应的错误信息;

. 可以理解为:perror = printf + strerror;

#include 
int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

 字符函数

一、字符分类函数

函数 如果他的参数符合下列条件就返回真
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 任何可打印字符,包括图形字符和空白字符

 代码例子:

#include 
#include 
int main()
{
	char c = " ";
	if (isalnum(c))
	{
		printf("是字母或者数字!\n");
	}
	else
	{
		printf("不是字母或者数字!\n");
	}
	return 0;
}

二、字符转换 

. tolower转换成小写字母;toupper转换成大写字母;

. 字符转换函数只有这两个函数;

#include 
#include 
int main()
{
	printf("%c\n", toupper('a'));
	putchar(tolower('A'));
	return 0;
}

 内存相关函数

一、memcpy(内存拷贝)

. 两块不重叠的内存进行拷贝,使用memcpy进行拷贝;

. 里面有很多细节和注意点,都在代码里面备注了;

(空间不重叠)代码:

#include 
#include 
void* my_memcpy(void* dest, const void* src, size_t sz)
{ // 因为传过来的不确定类型,所以使用void*指针接接收
	assert(dest && src);
	while (sz--)
	{
		// 因为void* 指针类型不能直接进行加减操作和解引用操作
		// 所以需要强转,但是强制转换只是临时的,只针对当前这行代码
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1; 
		src = (char*)src + 1;
	}
}
int main()
{
	int arr1[20] = { 0 };
	int arr2[] = { 1, 2, 3, 4, 5 };
	my_memcpy(arr1, arr2, sizeof(arr2));
	for (int i = 0; i < sizeof(arr2) / sizeof(arr2[0]); i++)
	{
		printf("%d\n", arr1[i]);
	}
	return 0;
}

 二、memmove(内存移动)

. 重叠的内存空间要使用memmove进行拷贝;

【C语言】字符串函数、字符函数、内存函数_第1张图片

【C语言】字符串函数、字符函数、内存函数_第2张图片

(空间重叠)代码: 

#include 
#include 
void* my_memmove(void* dest, const void* src, size_t sz)
{
	assert(dest && src);
	while (sz--)
	{
		// 因为dest的位置在src的后面,所以src从后向前进行拷贝
		// src最后的位置就在,(char*)src + sz
		if (dest < src)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
		else
		{
			*((char*)dest + sz) = *((char*)src + sz);
		}
	}
}
int main()
{
	int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int arr1[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	my_memmove(arr + 3, arr, 20);
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		printf("%d\n", arr[i]);
	}
	my_memmove(arr1, arr1 + 3, 20);
	for (int i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++)
	{
		printf("%d\n", arr1[i]);
	}
	return 0;
}

 三、memset(内存设置) 

. memset 是以字节为单位来设置内存的;

. 所以memset会更适用于字符类型;

#include 
#include 

void* my_memset(void* ptr, char value, size_t num)
{
	assert(ptr);
	while (num--)
	{
		*(char*)ptr = value;
		ptr = (char*)ptr + 1;
	}
}
int main()
{
	char arr[20] = { "this is memset!" };
	my_memset(arr, 'x', 20);
	return 0;
}

 四、memcmp(内存比较)

. memcpy 是一个字节一个字节进行比较的

#include 
#include 
#include 
int my_memcmp(const void* arr1, const void* arr2, size_t num)
{
	assert(arr1 && arr2);
	size_t ret = num;
	while (num--)
	{
		if (*(char*)arr1 == *(char*)arr2)
		{
			if (num == 0)
			{
				return 0;
			}
			arr1 = (char*)arr1 + 1;
			arr2 = (char*)arr2 + 1;
		}
		return *(char*)arr1 - *(char*)arr2;
	}
}
int main()
{
	int arr1[] = { 1, 2, 3 ,4, 5, 6, 7 };
	int arr2[] = { 1, 2, 3, 4, 5, 1};
	int ret = my_memcmp(arr1, arr2, 20);
	int ret1 = my_memcmp(arr1, arr2, 21);
	printf("%d %d\n", ret, ret1);
	return 0;
}

我现在写的这个memcmp还有错,暂时还没找到错误点在哪里。

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