C语言中的部分字符函数,内存函数,和部分字符串函数的模拟实现


C语言中对字符串的处理是很频繁的,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串中或者字符数组中。
字符串常量适用于哪些对它不做修改的字符串函数、

1.求字符串长度

strlen

strlen
size_t strlen (const char *str);

  • 1.字符串已经’\0’作为结束标志,strlen函数返回的是在字符串中’\0’前面出现 的字符个数(不包含’\0’)。
  • 2.参数指向的字符的字符串必须要以’\0’结束。
  • 3.注意函数的返回值为sizeof_t,是无符号的!!!!!!!

模拟实现strlen

#include<stdio.h>
//方法1.计数器方式
int my_strlen(const char * str)
{
       int count = 0;
       while(*str)
       {
           count++;
           str++;
       }
       return count;
}
//方法2.不能创建临时的变量计数器(递归)
int my_strlen(const char* str)
{
	if (*str == '\0')
		return 0;
	else
		return 1 + my_strlen(str + 1);
}
//方法3.指针的方式
int my_strlen(char* s)
{
	char* p = s;
	while (*p != '\0')
		p++;
	return p - s;
}

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

strcpy

char* strcpy(char* destination,const char* source);
strcpy
Copies the C string pointed by source into the array pointed by destination,including the terminating null character(and stopping at the point)

  • 1.源字符串必须以’\0’结束。
  • 2.会将源字符串中的’\0’拷贝到目标空间。
  • 3.目标空间必须足够大,以确保能存放源字符串。
  • 4.目标空间必须可变。

模拟实现strcpy

#include<stdio.h>
#include<assert.h>
char* my_strcpy(char* str1,const char* str2)//str2不会改变所以拿const修饰
{
	assert(str1 != NULL);
	assert(str2 != NULL);//断言 指针是否为空
	char* ret = str1;
	while (*str1++ = *str2++)//当找到'\0'时 停止循环拷贝
	{
		;
	}
	return ret;
}
int main()
{
	char arr1[10] = "asdfghjkl";
	char arr2[10] = "bit";
	my_strcpy(arr1, arr2);
	printf("%s\n", arr1);
	printf("%s\n", arr2);
	return 0;
}

strcat

char* strcat(char* destination,const char* source);

  • Appends a copy of the source string to the destination string. The terminating null character in destination is overwritten by the first character of source,and a null -character is include at the end of the new string formed by concatenation of both in destination.

  • 1.源字符串必须以’\0’结束。

  • 2.目标空间必须足够大,能容纳下源字符串的内容。

  • 3.目标空间必须可修改

模拟实现 strcat

#include<stdio.h>
#include<assert.h>
char* my_strcat(char* dest,const char* src)//const修饰src防止其发生变化
{
	char* ret = dest;
	assert(dest != NULL);//断言防止指针为空
	assert(src != NULL);
	//1.找到'\0'
	while (*dest != '\0')
	{
		dest++;
	}
	//2.拷贝
	while (*dest++ = *src++)//*dest++=*src++//*dest=*src dest++,src++
	{                       
		;
	}
	return ret;
}
int main()
{
	char arr1[30] = "hello";
	char arr2[] = "world";
	my_strcat(arr1, arr2);
	printf("%s", arr1);
	return 0;
}

strcmp

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

  • This function starts comparing the fist character of each string. If they are equal to each other,it continues with the following pairs until the characters differ or until a terminating null-character is reached.
  • 1.第一个字符串大于第二个字符串,则返回大于0的数字。
  • 2.第一个字符串等于第二个字符串,则返回0.
  • 3.第一个字符串小于第二个字符串,则返回小于0的数字

模拟实现strcmp

#include<stdio.h>
#include<assert.h>
int my_strcmp(const char* str1,const char* str2)
{
	assert(str1 != NULL);
	assert(str2 != NULL);
	while (*str1 == *str2)
	{
		if (*str1 != '\0')//相等
		{
			return 0;
		}
		str1++;
		str2++;
	}
	if (*str1 > *str2)//大于
	{
		return 1;
	}
	if (*str1 < *str2)//小于
	{
		return -1;
	}
}
int main()
{
	char* p1 = "abcde";
	char* p2 = "cdefg";
	int ret = my_strcmp(p1,p2);
	printf("%d", ret);
	return 0;
}

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

strncpy

char* strncpy(char* destinal,const char* source,siz_t num);

  • Copies the first num characters of source to destination,If the end of the source C string(which is signaled by a null-character) is found before num characters have been copied, destination is padded with zeros until a total of num characters have been written to it.
  • 1.拷贝num个字符串从源字符串到目标空间。
  • 2.如果源字符串的长度小于num,则拷贝完源字符串之后,在目标后面追加0,直到num个。

与strcpy的区别为传参时多一个控制长度的参数

strncat

char* strncat(char* destination, const char* source,size_t num);

  • 1.Appends the first num characters of source to destination, plus a terminating null-character.
  • 2.If the length of the C string in source is less than num, only the content up to the terminating null- character is copied.

strncat的用法

/* strncat example */
#include <stdio.h>
#include <string.h>
int main () {
  char str1[20];
  char str2[20];
  strcpy (str1,"To be ");
  strcpy (str2,"or not to be");
  strncat (str1, str2, 6);
  puts (str1);
  return 0;
}

strncmp

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

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

strncmp的使用

/* strncmp example */
#include <stdio.h>
#include <string.h>
int main () 
{
  char str[][5] = { "R2D2" , "C3PO" , "R2A6" };
  int n;
  puts ("Looking for R2 astromech droids...");
  for (n=0 ; n<3 ; n++)
  if (strncmp (str[n],"R2xx",2) == 0)
  {
    printf ("found %s\n",str[n]);
  }
return 0;
 }

4.字符串查找

strstr

char* strstr(const char*,const char*)
Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1.

  • 1.查找一个字符串是否是另一个字符串的子串。
  • 2.被查找的字符串长度要大于查找的字符串长度。

模拟实现strstr

#include<stdio.h>
#include<assert.h>
char* my_strstr(const char* p1,const char* p2)
{
	assert(p1 != NULL);
	assert(p2 != NULL);
	char* s1 = NULL;
	char* s2 = NULL;
	char* cur = p1;
	if (*p2 == '\0')
	{
		return (char*)p1;//将p1强制类型转换为char*类型 防止报警告
	}
	while (*cur)//防止例如arr1="abbbc" arr2="bbc" 这种情况出现 不能只查找一次 需要查找多次 每次查找 s1向后移动一位
	{
		s1 = cur;
		s2 = p2;
		while ((*s1 != '\0') && (*s2 != '\0') && (*s1 == *s2))
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return cur;//找到子串
		}
		if(*s1=='\0')//判断arr1是否与arr2长
		{
		    return NULL;
		}
		cur++;//确定下一次s1的位置
	}
	return NULL;//找不到子串返回空指针
}
int main()
{
	char arr1[30] = "abcdef";
	char arr2[] = "def";
	char* out = my_strstr(arr1,arr2);
	printf("%s", out);
	return 0;
}

strtok

char*strtok(char t str, const char t sep);

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

strtok的使用

#include<stdio.h>
int main()
{
	char arr[] = "123456@234.com";
	char* p = "@.";
	char buf[1024] = { 0 };
	strcpy(buf, arr);//strtok是会破坏字符串的 所以拷贝一份arr到buf切割时切割buf
	char* ret = NULL;
	for (ret = strtok(arr, p); ret != NULL; ret = strtok(NULL, p))
	//第一次传参为要切割的字符串地址和分割符,它会在需要分割的地方放置'\0'并且记
	//录位置以便下一次分割。再次调用传NULL和分隔符它将找到上一次分割的位置继续向
	//后分割当遇到'\0'时返回NULL
	{
		printf("%s\n", ret);
	}
	return 0;
}

5.错误信息报告

strerror

char* strerror(int errnum);
返回错误码,所对应的错误信息

使用方法

int main()
{
	//错误码  错误信息
	//  0  -  No error     
	//  1  -  Operation not permitted 
	//  2  -  No such file or directory
	// ...
	//errno 是一个全局的错误码的变量
	//当C语言的库函数在执行过程中,发生了错误,就会把对应的错误码
	//赋值到errno中
	char* str = strerror(errno);
	printf("%s", str);
	return 0;
}

6.字符串操作

函数       如果他的参数符合下列条件就返回真

iscntrl   控制任何字符

isspace   空白字符:空格' ',换页'\f',换行'\n',回车'\r',制表符'\t'或者垂直制表符'\v'

isdigit   十进制数字 0~9

isxdigit  十六进制数字,包括所以十进制数字,小写字母a~f,大写字母A~F

islower   小写字母a~z

issupper  字母A~Z

isalpha   字母a~z或A~Z

isalnum   字母或者数字,a~z,A~Z,0~9

ispunct   标点符号,任何不属于数字或者字母的图形字符(可打印)

isgraph   任何图形字符

isprint   任何可打印字符,包括图形字符和空白字符

7.字符转换

常用的有:

int tolower(int c);//字母转换为小写
int toupper(int c);//字母转换为大写

8.内存函数

由于上述函数传参为char*类型所以只能在字符串中使用,若想处理其它类型 的数据则需要内存函数。内存函数传参类型为void*类型,所以它可以处理任何类型的数据。

memcpy

memcpy
void* memcpy(void* destination, const void* soure, size_t num);

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

模拟实现memcpy

#include<stdio.h>
#include<assert.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{
	void* ret = dest;
	assert(dest != NULL);//防止指针为空指针
	assert(src != NULL);
	while (num--)
	{
		*(char*)dest = *(char*)src;//由于为void*类型无法进行指针运算需要先强制类型转换
		++(char*)dest;
		++(char*)src;
	}
	return ret;

}
int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[10] = { 0 };
	my_memcpy(arr2,arr1,sizeof(arr1));//(拷贝到arr2,从arr1中拷贝,拷贝大小(字节))	
	return 0;
}

但是这个函数不能处理字符串重叠的情况例如

int arr[10] = {1,2,3,4,5,6,7,8,9};
memcpy(arr+2,arr,20);

memmove可以解决。

memmove

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

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

模拟实现memmove

#include<stdio.h>
#include<assert.h>
void* my_memmove(void* dest, void* src, size_t count)
{
	void* ret = dest;
	assert(dest != NULL);
	assert(src != NULL);
	if (dest < src)
	{
		//从前向后拷贝
		while (count--)
		{
			*(char*)dest = *(char*)src;
			++(char*)dest;
			++(char*)src;
		}
	}
	else
	{
		//从后向前拷贝
		while (count--)
		{
			*((char*)dest + count) = *((char*)src + count);
		}
	}
	return ret;
}
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr + 2, arr, 20);
	return 0;
}

memcmp

int memcmp(const void* ptr1, const void* ptr2, size_t num);
内存对比

memcmp的使用

int main()
{
	//01 00 00 00 02 00 00 00 03 00 00 ...
	//01 00 00 00 02 00 00 00 05 00 00 ...
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 1,2,5,4,3 }; 
	int ret = memcmp(arr1, arr2, 9);//对比的大小单位是字符
	printf("%d\n", ret);
	return 0;
}

memset

内存设置
memset用法

int main()
{
	char arr[10] = "";
	memset(arr,'#',10);
	//int arr[10] = { 0 };
	//memset(arr, 1, 10);
	//          err 因为设置的内存大小是字符串
	//小端储存中  00 00 00 00 00 00 00 00 00 ...
	//  被设置为  01 01 01 01 01 01 01 01 01 ...
}

第一篇博客 若有错误希望指出

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值