字符函数和字符串函数(C语言 介绍+示例+模拟实现)

字符串长度:strlen

长度不受限制的字符串函数 :strcpy strcat strcmp

长度受限制的字符串函数:strncpy strncat strncmp

字符串查找:strstr strtok

错误信息报告:sterror

内存操作函数:memcpy memmove memset memcmp

函数介绍:

strlen

size_t strlen (const char* str)
  • 字符串已'\0'作为结束标志,strlen函数返回的是在字符串中'\0'前面的字符串个数(不包含'\0')
  • 参数指向的字符串必须以'\0'结束
  • 注意函数的返回值是size_t,也就是无符号整形(size_t == unsigned int)

strlen的模拟实现

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

//strlen 的模拟实现
//size_t == unsigned int
int my_strlen(const char* str)
{
	int count = 0;
	assert(str != NULL);
	while (*str != '\0')
	{
		count++;
		str++;
	}
	return count;
}

int main()
{
	char arr[] = "abcdef";
	int len = my_strlen(arr);
	printf("len = %d\n", len);

	//  3  -  6 = -3但是strlen返回的是无符号整形
	if (strlen("abc") - strlen("abcdef") > 0)
	{
		printf("hehe\n");
	}
	else
	{
		printf("haha\n");
	}
	return 0;
}

strcpy

char* strcpy(char* destination, const char* source)
  • 源字符必须以'\0'结束, 否则拷贝的时候会发生越界访问
  • 目标空间必须足够大,能够容纳下源字符的内容
  • 目标空间必须可修改

strcpy的模拟实现:

#include <string.h>
#include <assert.h>
#include <stdio.h>
char* my_strcpy(char* str1,const char* str2)//源头的地址不发生变化,用const修饰
{
	assert(str1 != NULL);
	assert(str2 != NULL);
	//strcpy返回的是目的地的起始位置,后面的循环将str1的位置发生了变化,
	char* ret = str1;

	while (*str1++ = *str2++)//开始的时候将b赋值给str1,最后将'\0'赋值给str1,表达式的结果的ascall码值为0,跳出循环
	{
		;
	}
	//返回目的地起始位置的地址
	return ret;
}

int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "bit";
	
	//注意事项:
	//1 源头必须包含'\0',否则拷贝的时候会发生越界访问
	// char arr2 = {'a', 'b', 'c'};没包含'\0'
	//2 目标空间必须足够大,包含源字符串
	//3 目标空间可以被修改
	// char* p = "abcdef";p指向的是常量字符串,不能被修改
	my_strcpy(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

strcat

char* strcat(char* destination, const char* source)
  • 源字符必须以'\0'结束, 否则拷贝的时候会发生越界访问
  • 目标空间必须足够大,能够容纳下源字符的内容
  • 目标空间必须可修改

strcat的模拟实现:

#include <stdio.h>
#include <string.h>
#include <assert.h>
char* my_strcat(char* dest, char* src)
{
	assert(dest != NULL);
	assert(src != NULL);
	char* ret = dest;
	//1 找到目的地字符串的'\0'
	while(*dest != '\0')
	{
		dest++;
	}
	//2 开始将src的字符串赋值给dest
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}

int main()
{
	char arr1[30] = "abcdefg";//arr1 的空间必须足够大,必须要有'\0',arr2是从'\0'的位置开始追加
	char arr2[] = "bit";
	my_strcat(arr1, arr2);

	printf("%s\n", arr1);
	return 0;
}

strncat


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

模拟实现

char* my_strncat(char* dest, char* src, size_t n)
{
	assert("dest != NULL");
	assert("src != NULL");
	char* ret = dest;
	while (*dest != '\0')
	{
		dest++;
	}
	while (n--)
	{
		*dest++ = *src++;
	}
	return ret;
}

int main()
{
	char arr1[30] = "abcdef";
	char arr2[] = "sorry";

	my_strncat(arr1, arr2, 2);
	printf("%s\n", arr1);
	return 0;
}

strcmp

int strcmp(const char* str1, const char* str2)
  • 第一个字符串大于第二个字符串,返回大于0的数字
  • 第一个字符串等于第二个字符串,返回0
  • 第一个字符串小于第二个字符串,返回小于0的数字

strcmp的模拟实现:

#include <stdio.h>
#include <assert.h>
#include <string.h>
int my_strcmp(char* str1, char* str2)
{
	assert(str1 && str2);
	//比较
	while (*str1 == *str2)
	{
		if (*str1 == '\0')//两个都是'\0'
			return 0;
		str1++;
		str2++;
	}
	if (*str1 > *str2)
		return 1;//大于
	else
		return 0;//小于
}

int main()
{
	char* p1 = "abcdef";
	char* p2 = "aqwer";

	int ret = strcmp(p1, p2);//先比较两字符串的首地址的ASCLL码值,相等向后延伸比较

	printf("%d\n", ret); 
	return 0;
}

strncpy

char *strncpy( char *strDest, const char *strSource, size_t count )
  • 如果源字符串小于拷贝的字符串,拷贝过去后面补'\0'
  • 举例:


int main()
{
	char arr1[30] = "hello\0xxxxxx";
	char arr2[] = "world";

	//指定长度的增加
	strncat(arr1, arr2, 3);//将arr2前3个值拷贝到arr1中,拷贝完后系统自动加'\n'
	printf("%s\n", arr1);
}

模拟实现

char* my_strncpy(char* dest, const char* src, size_t num)
{
	assert(dest != NULL);
	assert(src != NULL);
	char* ret = dest;
	while (num--)
	{
		*dest++ = *src++;
	}
	return ret;
}

int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "haoren";

	my_strncpy(arr1, arr2, 3);
	printf("%s\n", arr1);
	return 0;
}

 

strncmp

int strncmp(const char *string1, const char *string2, size_t count);

举例:

int main()
{
	//strcmp - 字符串比较
	 const char* p1 = "abcdef";//指向的是常量字符串,最好用const修饰
         const char* p2 = "abcqwer";
	//int ret = strcmp(p1, p2);//返回的是大于、小于、等于0的数字
	int ret = strncmp(p1, p2, 3);//可以限制比较的字符个数   返回的是大于、小于、等于0的数字                                         (同strcmp)

	printf("%d\n", ret);
	return 0;
}

strstr - 查找字符串

char *strstr(const char *string, const char *strCharSet);因为是查找,不希望改变两个字符串,用const

举例:

int main()
{
	//NULL - 空指针
        //NUll/Null - '\0'
	char* p1 = "abcdefghi";
	char* p2 = "def";
	char* ret = strstr(p1, p2);//在p1里面查找p2是否存在  
	if (ret == NULL)
		printf("子串不存在\n");
	else
		printf("%s\n", ret);//defghi 找的是d地址第一次出现后面的字符串打印
	return 0;
}

strtok

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

  • int main()
    {
    	//zpw@bitedu.tech
    	//char arr[] = "zpw@bitedu.tech";
    	char* p = "@.";
    
    	char arr[] = "192.168.1.3";
    	char* p = ".";//把分隔符传过来 
    
    	char buf[1024] = {0};
    	//切割buf中的字符串
    	strcpy(buf, arr);
    
    	char* ret = NULL;
    	for (ret = strtok(arr, p); ret != NULL; ret = strtok(NULL, p))//strtok会记住上次分割的位置,下次从要分割的位置开始寻找,所以传空指针
    	{
    		printf("%s\n", ret);
    	}
    
    	//简单举例
    	//char* ret = strtok(arr, p);
    	//printf("%s\n", ret);//返回的是s的地址,并将@改成'\0'
    
    	//char* ret1 = strtok(NULL, p);//第二次以后不需要传数组地址,传空指针
    	//printf("%s\n", ret1);//返回的是b的地址,并将.改成'\0'
    
    	//char* ret2 = strtok(NULL, p);
    	//printf("%s\n", ret2);
    	return 0;
    }

    strerror

  • char* strerror(int errnum)

    返回错误码对应的错误信息。

  • 举例:

  • int main()
    {
    	//char* ret = strerror(1);
    	//printf("%s\n", ret);
    	//错误码   错误信息
    	//0        No error
    	//1        Operation not permitted
    	//2        No such file or directory
    	//...
    	//erron 是一个全局的错误码的变量
    	//当c语言的库函数在执行过程中,发生了错误,就会把对应的错误码,赋值到errno中
    
    	//char* str = strerror(errno);
    	//printf("%s\n", str);
    
    	//打开文件
    	FILE* pf = fopen("test.txt", "r");//打开text.txt文件,r是读文件
    
    	if (pf == NULL)
    	{
    		printf("%s\n", strerror(errno));
    	}
    	else
    		printf("open file sccess\n");
    	return 0;
    }

    字符转换:

  • int tolower( int c) 将字符转换成小写

  • int toupper( int c) 将字符转换成大写

  • 举例:

#include <ctype.h>
int main()
{
	//char ch = '1';
	int ret = islower(ch);//判断是否是小写字母,是返回大于0的数字
	//int ret = isdigit(ch);

	//printf("%d\n", ret);

	//char ch = tolower('q');//字母转小写函数 
	//putchar(ch);

	char arr[] = "I AM A Student";
	int i = 0;
	while (arr[i])
	{
		if (isupper(arr[i]))
		{
			arr[i] = tolower(arr[i]);
		}
		i++;
	}
	printf("%s\n", arr);
	return 0;
}

memcpy

void *memcpy(void *dest, const void *src, size_t count);
  • trcpy 只能拷贝字符串,不能拷贝数组  数组拷贝用memcpy
  • 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置
  • 这个函数在遇到'\0'的时候不会停下来
  • 如果source和destination有任何的重复,复制的结果都是未定义的
  • 举例:

  • struct S 
    {
    	char name[20];
    	int age;
    };
    
    int main()
    {
    	int arr1[] = { 1, 2, 3, 4, 5};
    	int arr2[5] = { 0 };
    	struct S arr3[] = { {"张三", "23"}, {"李四", "24"} };
    	struct S arr4[4] = {0};
    	memcpy(arr4, arr3, sizeof(arr3));
    
    	//memcpy(arr2, arr1, sizeof(arr1));//拷贝arr1的大小,5个字节
    	return 0;
    }

    模拟实现:

  • #include <stdio.h>
    #include <assert.h>
    struct S 
    {
    	char name[20];
    	int age;
    };
    
    void* my_memcpy(void* dest, void* src, size_t num)
    {
    	void* ret = dest;
    	assert(dest != NULL);
    	assert(src != NULL);
    	while (num--)//一共拷贝num次,单位字节
    	{
    		*(char*)dest = *(char*)src;//因为不清楚src里面放置的内容,通过一个一个字节进行拷贝
    		++(char*)dest;//先转换,再++
    		++(char*)src;
    	}
    	return ret;//最后返回起始位置的地址
    }
    
    int main()
    {
    	int arr1[] = { 1, 2, 3, 4, 5};
    	int arr2[5] = { 0 };
    	struct S arr3[] = { {"张三", "23"}, {"李四", "24"} };
    	struct S arr4[4] = {0};
    	memcpy(arr4, arr3, sizeof(arr3));
    	return 0;
    }

    memmove

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

    处理重叠拷贝的情况

  • 举例:

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

    memcmp -内存比较

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

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值