字符函数和字符串函数

目录

前言

函数介绍

1.求字符串函数

a.strlen

2.长度不受限制的字符串函数

a.strcpy

b.strcat

c.strcmp

3.长度不受限制的字符串函数

strcpy

strcat

strcmp

4.字符串查找

a.strstr

b.strtok

5.错误信息报告

strerror

6.字符操作

7.内存操作函数

a.memcpy

b.memmove

c.memcmp

d.memset


前言

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

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

函数介绍

1.求字符串函数

a.strlen

求字符串中的字符个数

strlen

Get the length of a string.

size_t strlen( const char *string );

 可以看到size_t是unsigned int通过typedef定义的新名字

strlen用来求字符串中字符的个数

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<string.h>
int main()
{
    char arr[] = "abcdef";
//这种数组在最后隐含了'\0'
    int len = strlen(arr);
//字符串以'\0'作为结束标志,strlen函数返回的是'\0'前出现的字符个数(不包含strlen)
    printf("%d\n",len);

    return 0;
}

结果是:6

int main()
{
    char arr[] = { 'b','i','t' };
    int len = strlen(arr);

    printf("%d\n",len);

    return 0;
}

结果是随机值,因为字符串并没有以\0作为结束标志

strlen的返回值是size_t,size_t是无符号整型

int main()
{
    if(strlen("abc")-strlen("abcdef")>0)
    printf('>\n');
    else
    printf('<=\n');

    return 0;
}

结果是:>,因为无符号整型-无符号整型还是一个无符号整型

模拟实现strlen

(这是计数器方法,一共三种方法分别为计数器方法,指针-指针,递归)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<assert.h>
unsigned int my_strlen(const char* str)
{
	assert(str);//传入的数组不能为空,那么使用assert,如果传入指针为空就报错
	unsigned int count = 0;
	while (*str != '\0')
	{
		count++;
		*str++;
	}
	return count;
}
int main()
{
	char arr[] = { "abcde" };
	unsigned int len = my_strlen(arr);
	printf("%u\n",len);

	return 0;
}

2.长度不受限制的字符串函数

a.strcpy

字符串拷贝

strcpy

Copy a string.

char *strcpy( char *strDestination, const char *strSource );

把源字符串的内容覆盖到目标空间,可不是交换

int main()
{
	char name[20] = { 0 };
	strcpy(name,"zhangsan");
	
	printf("%s\n",name);
//会打印zhangsan
	return 0;
}

strcpy只会打印\0之前的内容

int main()
{
	char name[20] = { 0 };
	strcpy(name,"zhang\0san");
	
	printf("%s\n",name);
//会打印zhang
	return 0;
}

拷贝一个没有'\0'作为结尾标志的字符串到另一个字符串就会报错

int main()
{
    char arr[] = "xxxxxxxxx";
    char str[] = { 'a','b','c','d' };

    strcpy(arr, str);

    return 0;
}

拷贝一个大的源字符串到小的目标空间也会报错

int main()
{
    char arr[3] = "abc";
    char str[] = { 'a','b','c','d' };

    strcpy(arr, str);

    return 0;
}

拷贝源字符串到常量字符串也会报错(因为目标空间不可变)

int main()
{
    char *arr = "xxxxxxxxx";
    char str[] = { "abcde" };

    strcpy(arr, str);

    return 0;
}

模拟实现strcpy

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

char* my_strcpy(char* dest,const char* src)
//只改变目标空间,不改变源字符串,所以用const限制源字符串
{
    assert(dest&&src);
    //确认传入参数的合法性,只要传入空指针就会报错
    char* ret = dest;
    while (*dest++ = *src++)
        ;
    return ret;
}
int main()
{
    char arr[] = "xxxxxxxxx" ;
    char str[] = "abcd";

    my_strcpy(arr, str);
    printf("%s\n",arr);
    return 0;
}

使用strcpy时要注意:

源字符串必须以'\0'作为结束标志

会将源字符串中的'\0'拷贝到目标空间

目标空间必须足够大,以确保能存放源字符串

目标空间必须可变

strcpy只负责拷贝,不考虑目标空间的大小,如果目标空间不合适,strcpy仍然会拷贝,执行结束后才会报错

b.strcat

字符串追加

strcat

Append a string.

char *strcat( char *strDestination, const char *strSource );

int main()
{
	char arr1[20] = "Hello";
	char arr2[] = " world";
	strcat(arr1, arr2);

	printf("%s\n",arr1);

	return 0;
}

模拟实现strcat

char* my_strcat(char* dest, const char* src)
{
	char* ret = dest;
	assert(dest&&src);
	while (*dest != '\0')
	{
		dest++;
	}
	while (*dest++ = *src++)
		;
	return ret;
}
int main()
{
	char arr[20] = "abcde";
	char str[] = "fghi";

	my_strcat(arr, str);

	printf("%s\n",arr);

	return 0;
}

c.strcmp

比较字符串(注意:比较的是字符串的内容,即字符串的ASSIC码值)

strcmp

Compare strings.

int strcmp( const char *string1, const char *string2 );

int main()
{
	char arr[] = "abcde";
	char str[] = "abq";
	int ret = strcmp(arr,str);
	if (ret < 0)
		printf("<\n");
	else if (ret == 0)
		printf("=\n");
	else
		printf(">\n");

	return 0;
}

比较的是字符串的内容,且比较到c<q时就输出结果,不再向后进行

模拟实现strcmp

int my_strcmp(const char*dest, const char*src)
{
	assert(dest&&src);
	while (*dest == *src)
	{
		if (*dest == '\0')
			return 0;
		dest++;
		src++;
	}
	return (*dest - *src);
}
int main()
{
	char arr[] = "abc";
	char str[] = "abcde";

	int len = my_strcmp(arr,str);
	if (len < 0)
		printf("<\n");
	else if (len == 0)
		printf("=\n");
	else
		printf(">\n");
	return 0;
}

3.长度不受限制的字符串函数

strcpy

strcat

strcmp

有安全隐患,以strcpy为例,即使程序会报错,但仍然会拷贝大的源字符串到小的目标空间里

于是有了长度受限制的字符串函数

strncpy

strncat

strncmp

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

    strncpy(arr1,arr2,5);

    return 0;
}

 

 可以控制拷贝覆盖的字节数,追加的字节数,比较的字节数

4.字符串查找

a.strstr

从子串1中查找是否含有子串2

strstr

Find a substring.

char *strstr( const char *string, const char *strCharSet );

模拟实现

char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	const char* s1 = str1;
	const char* s2 = str2;
	const char* p = str1;
	while (*p)
	{
		s1 = p;
		s2 = str2;
		while (*s2 == *s1 && *s1 != '\0' && *s2 != '\0')
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return (char*)p;
		}
		p++;
	}
	return NULL;
}
int main()
{
	char email[] = "abbbcde";
	char substr[] = "bbc";
	char* ret = my_strstr(email, substr);

	if (ret == NULL)
	{
		printf("子串不存在\n");
	}
	else
	{
		printf("%s\n", ret);
	}

	return 0;
}

b.strtok

切割字符串

strtok

Find the next token in a string.

char *strtok( char *strToken, const char *strDelimit );

int main()
{
	const char* sep = "@.";
	//sep是一个参数,定义了用作分隔符的字符集和
	//第一个参数指定一个字符串,它包含了0或多个由sep字符串中一个或多个分隔符分割的标记
	char email[] = "zhangpengwei@bitejiuyeke.com";
	char arr[30] = { 0 };
	strcpy(arr,email);

	char* ret = strtok(arr,sep);
	printf("%s\n",ret);
	ret = strtok(NULL,sep);
	printf("%s\n",ret);
	ret = strtok(NULL, sep);
	printf("%s\n",ret);
	return 0;
}

 和for循环结合使用

int main()
{
	const char* sep = "@.";
	char email[] = "zhangpengwei@bitejiuyeke.com.net";
	char arr[40] = { 0 };
	strcpy(arr,email);

	char* ret = NULL;
	for (ret = strtok(arr, sep); ret != NULL; ret = strtok(NULL, sep))
	{
		printf("%s\n",ret);
	}

	return 0;
}

5.错误信息报告

strerror

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

strerror

Get a system error message (strerror) or prints a user-supplied error message (_strerror).

char *strerror( int errnum );

查看错误码对应的错误信息

int main()
{
	printf("%s\n", strerror(0));
	printf("%s\n", strerror(1));
	printf("%s\n", strerror(2));
	printf("%s\n", strerror(3));
	printf("%s\n", strerror(4));
	printf("%s\n", strerror(5));

	return 0;
}

查看错误原因

#include <errno.h>
int main()
{
	//errno - C语言设置的一个全局的错误码存放的变量
	FILE* pf = fopen("text.txt","r");
	if (pf == NULL)
	{
		printf("%s\n",strerror(errno));
		return 1;
	}
	else
	{

	}
	return 0;
}

6.字符操作

字符分类函数

 用法:

#include<ctype.h>
int main()
{
	//其他函数的用法类似,如果传入字符符合函数就返回一个正整数,否则返回0
	int a = isspace(' ');
	printf("%d\n",a);

	return 0;
}

字符转换

int tolower(int c);//字符转小写
int toupper(int c);//字符转大写

使用方法:

#include <ctype.h>
int main()
{
	printf("%c\n",tolower('W'));
	//把大写字符转换为小写字符,如果传入其他字符会打印原字符不会做任何改变
	return 0;
}

7.内存操作函数

a.memcpy

memcpy负责拷贝两块独立空间中的数据

memcpy

Copies characters between buffers.

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

用法

int main()
{
	int arr[] = { 1,2,3,4,5,6 };
	int str[] = { 0 };
	memcpy(str,arr,24);

	return 0;
}

模拟实现

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 arr[] = { 1,2,3,4,5,6 };
	int str[10] = { 0 };
	my_memcpy(str,arr,24);

	return 0;
}

b.memmove

重叠内存之间的数据拷贝

例如

arr[] = { 1,2,3,4,5,6,7,8,9 };

拷贝1,2,3,4,5到3,4,5,6,7上去也就是应该得到1,2,1,2,3,4,5,8,9

(这里就不能使用memcpy了,因为memcpy先拷贝1,2到3,4的位置,此时数组变成121256789,34的位置变成了12,会把34位置的12拷贝到56上,此时数组变成121212789,最后会把5位置上的1拷贝到7的位置上,最终得到121212189,与想得到的结果不同,所以不能使用memcpy拷贝重叠内存之间的数据)

(在VS编译器下,memcpy也可实现memmove的功能,但是在其他编译器未知,原来函数也卷,笑哭,总之,拷贝重叠内存的数据用memmove就完了)

memmove

Moves one buffer to another.

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

用法

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

	return 0;
}

 模拟实现

void* my_memmove(void* dest, const void* src, size_t count)
{
	assert(dest&&src);
	void* ret = dest;
	//从前向后拷贝
	if (dest < src)
	{
		while (count--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	//从后向前拷贝
	else
	{
		while (count--)
		{
			*((char*)dest + count) = *((char*)src + count);
		}
	}
	return ret;
}
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9 };
	my_memmove(arr + 2, arr, 16);
	int i = 0;
	for (i = 0; i < 9; i++)
	{
		printf("%d ", arr[i]);
	}

	return 0;
}

c.memcmp

内存比较

memcmp

Compare characters in two buffers.

int memcmp( const void *buf1, const void *buf2, size_t count );

用法

int main()
{
	int arr[] = { 1,2,3,4,5,6 };
	int str[] = { 1,3,2 };
	int ret = memcmp(arr,str,12);

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

		return 0;
}

 

d.memset

内存设置

memset

Sets buffers to a specified character.

void *memset( void *dest, int c, size_t count );

用法

int main()
{
	char arr[] = "hello bit";
	memset(arr + 6, 'x', 3);
	printf("%s\n",arr);

	return 0;
}

 注意:不能用来初始化数组,因为memset是一个字节一个字节地来修改数据

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值