【c语言】字符函数和字符串函数详解(浅谈库函数使用与实现)

0、前言

        c语言中对字符和字符串的处理都很频繁,但c语言本身是没有字符串类型的,字符串通常放在常量字符串字符数组中。

        字符串常量适用于那些对它不做修改的字符函数中。

1、函数介绍

1.1 strlen

  • strlen函数是以'\0'作为结束标志,它返回的是在字符串中'\0'前面的字符个数(不包括字符'\0')
  • 参数指向的字符串必须要以'\0'作为结束标志
  • 函数返回的类型是size_t类型,是无符号的(这是易错的)
  • strlen函数的模拟实现很重要

代码如下

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

int main()
{
	char arr1[] = "abc";
	char arr2[] = "abcdef";
	if ((strlen(arr1) - strlen(arr2))<0)
	{
		printf("<");
	}
	else
	{
		printf(">");
	}
	return 0;
}

 显然易知的是arr1的字符数是应该小于arr2的字符数的,但为什么结果却是大于呢?

由于strlen函数的返回类型是size_t无符号类型,所以当算出的是一个负数将被按着无符号计算,结果就将是一个很大的正数。

1.2 strcpy

  • strcpy函数是将源字符串的内容拷贝到目的地数组空间中,包含字符‘\0’
  • 源字符串必须以‘\0’结束
  • 拷贝时会将‘\0’一起拷贝的目的地空间中
  • 目的地空间必须足够大,以确保能存放源字符串
  • 目标空间必须可变
  • 同样strcpy的模拟实现是很重要的

1.3 strcat

  • 字符串追加strcat函数,可以将源字符串追加到目的地字符串的后面。
  • 源字符串必须以‘\0’结束。
  • 目的地字符串必须足够大,以能够容得下源字符串。
  • 目标空间必须可以被修改。
  • 不可以用来字符串给自己追加

1.4 strcmp

  • 字符串比较函数,可以用来比较两个字符串的大小,规则是从第一个字符开始比较其对应的ASCII码大小。
  • 标准规则:
  • 第一个字符串大于第二个字符串,返回大于0的数。
  • 第一个字符串等于第二个字符串,则返回0。
  • 第一个字符串小于第二个字符串,则返回小于0的数。

1.5 strncpy

  • 拷贝num个字符从源字符串到目的地空间中
  • 如果源字符串的字符的长度小于num,则拷贝完源字符串后在其后追加一个‘\0’,直到num个。

1.6 strncast

  • 字符串追加函数,可以在目的地字符串后追加长度为num的字符串
  • 规则是从源字符串num的长度追加到目的地字符串之后,并在最后追加‘\0’。

1.7 strncmp

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

1.8 strstr

  • 这是一个在字符串中找子字符串的函数。
  • 即在str1指向的主字符串中去找str2指向的字符串。
  • 找到将返回匹配到的字符串的首地址
  • 主字符串和子字符串都不可被修改
  • 都需要有‘\0’结束

1.9 strtok

  • delimiters参数是个字符串,定义了用作分隔符的字符集合。
  • 第一个str参数是字符串,它包含0个或多个由delimiters中的0个或多个分隔符分割的标记。
  • strtok函数找到str中下一个标记,并将其用‘\0’结尾,返回指向这个标记的指针(注:因strtok使用会改变字符串的内容,故一般在使用时都是切割的字符串都是临时拷贝的内容。)
  • strtok函数第一个参数不为NUL,函数将找到str指向字符串中的第一个标记,并保存该标记的位置。
  • strtok函数第一个参数为NULL,函数在同一个字符串中被保存的标记位置查找下一个标记。
  • 如果字符串中不存在更多标记,返回NULL。

1.10 strerror

  • 返回错误码所对应的信息
/* strerror example : error list */
#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;
}

字符分类函数:

字符转换函数:

int tolower(int c);

int toupper(int c);

/* isupper example */
#include <stdio.h>
#include <ctype.h>
int main ()
{
    int i=0;
    char str[]="Test String.\n";
    char c;
    while (str[i])
    {
        c=str[i];
        if (isupper(c))
            c=tolower(c);
        putchar (c);
        i++;
    }
    return 0;
}

1.11 memcpy

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

1.12 memmove

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

1.13 memcmp

  • 比较从ptr1和ptr2指针开始的num个字节。
  • 返回值如下:

2、库函数的模拟实现

2.1 模拟实现strlen

//模拟实现strlen()
//1.计数器
// 2.递归
// 3.指针-指针
#include<stdio.h>
//计数器实现
size_t my_strlen(const char* str)
{
	int count = 0;
	while (*str++ != '\0')
	{
		count++;
	}
	return count;
}

//递归实现
size_t my_strlen(const char* str)
{
	if (*str != '\0')
	{
		return 1 + my_strlen(str + 1);
	}
	else
	{
		return 0;
	}
}

//指针-指针实现
size_t my_strlen(const char* str)
{
	const char* start = str;
	while (*str != '\0')
	{
		str++;
	}
	return str - start;
}
int main()
{
	char arr[] = "abcd";
	size_t ret = my_strlen(arr);
	printf("%zd\n", ret);
	return 0;
}

2.2 模拟实现strcpy

#include<stdio.h>
#include<assert.h>
char* my_strcpy(char* dest,const char* src)
{
	char* start = dest;
	assert(dest && src);
	while (*dest ++ = *src ++)
	{
		;
	}
	return start;
}
int main()
{
	char arr1[] = "xxxxxxxxxxxx";
	char arr2[] = "abcdef";
	my_strcpy(arr1,arr2);
	printf("%s\n", arr1);
	return 0;
}

2.3 模拟实现strcat

#include<stdio.h>
#include<assert.h>
char* my_strcat(char* dest, const char* src)
{
	assert(dest && src);
	char* ret = dest;
	while (*dest !='\0')
	{
		dest++;
	}
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}
int main()
{
	char arr1[100] = "abcd";
	char arr2[] = "abc";
	my_strcat(arr1,arr2);
	printf("%s\n", arr1);
	return 0;
}

2.4 模拟实现strcmp

#include<stdio.h>
#include<assert.h>
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;
	}*/
	return *str1 - *str2;
}
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abcq";
	int ret = my_strcmp(arr1,arr2);
	if (my_strcmp(arr1, arr2) > 0)
	{
		printf(">\n");
	}
	else if(my_strcmp(arr1,arr2)==0)
	{
		printf("=\n");
	}
	else
	{
		printf("<\n");
	}
	return 0;
}

2.5 模拟实现strstr

#include<stdio.h>
#include<assert.h>
const char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	const char* cp;//记录开始匹配的位置
	const char* s1;//遍历str1指向的字符串
	const char* s2;//遍历str2指向的字符串
	cp = str1;
	while (*cp)
	{
		s1 = cp;
		s2 = str2;
		while (*s1 && *s2 && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return cp;
		}
		cp++;
	}
	return NULL;
}
int main()
{
	char arr1[] = "abbbcdef";
	char arr2[] = "bbc";
	const char* ret = my_strstr(arr1, arr2);
	if (ret == NULL)
	{
		printf("找不到\n");
	}
	else
	{
		printf("%s\n", ret);
	}
	return 0;
}

2.6 模拟实现memcpy


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

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;
	}
	return ret;
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[] = { 3,4,5,6,7 };
	my_memcpy(arr1,arr2,20);
	
	return 0;
}

2.7 模拟实现memmove

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

void* my_memmove(void* dest, 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;
		}
	}

	else
	{
		while (sz--)
		{
			*((char*)dest + sz) = *((char*)src + sz);
		}
	}
	return ret;
}
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr, arr + 2, 20);
	return 0;
}

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

花影随风_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值