c语言分层理解(c语言字符串+内存库函数)

1. 求字符串长度

1.1 strlen库函数

size_t strlen ( const char * str );

1.1.1 注意要点

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

1.1.2 strlen模拟实现

#include <stdio.h>
#include <assert.h>
int my_strlen(const char* str)
{
	assert(str);
	const char* start = str;
	const char* end = str;
	while (*end != '\0')
	{
		end++;
	}
	return end - start;
}
int main()
{
	char arr[] = "abcdef";
	int ret = my_strlen(arr);
	printf("%d\n", ret);
	return 0;
}

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

2.1 strcpy库函数

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

2.1.1 主要要点

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

2.1.2 strcpy模拟实现

#include <stdio.h>
#include <assert.h>
char* my_strcpy(char* destenation, const char* source)
{
	assert(destenation && source);
	char* ret = destenation;
	while (*destenation++ = *source++)
	{
		;
	}
	return ret;

}
int main()
{
	char arr1[] = "xxxxxxxxxxx";
	char arr2[] = "hello";
	printf("%s\n", my_strcpy(arr1, arr2));
	return 0;
}

2.2 strcat库函数

##3 2.2.1 注意要点

  1. 源头字符串必须以’\0’结束
  2. 目标空间必须足够大,能容纳源头字符串的内容
  3. 目标空间必须可修改
  4. strcat库函数自己给自己追加造成死循环

2.2.2 strcat模拟实现

#include <stdio.h>
#include <assert.h>
char* my_strcat(char* destenation, const char* source)
{
	char* record = destenation;
	while (*record != '\0')
	{
		record++;
	}
	while (*record++ = *source++)
	{
		;
	}
	return destenation;
}
int main()
{
	char arr1[20] = "math ";
	char arr2[] = "easy";
	printf("%s\n",my_strcat(arr1, arr2));
	return 0;
}

2.3 strcmp库函数

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

2.3.1 注意要点

  1. 第一个字符串大于第二个字符串返回大于0的数字;第一个字符串等于第二个字符串返回0;第一个字符串小于第二个字符串返回小于0的数字
  2. 从左到右一个一个字符依次比较,比较的是字符的ASCII值

2.3.2 strcmp模拟实现

#include <stdio.h>
#include <assert.h>
int my_strcmp(const char* s1, const char* s2)
{
	assert(s1 && s2);
	while (*s1 == *s2)
	{
		if (*s1 == '\0')
		{
			return 0;
		}
		s1++;
		s2++;
	}
	return *s1 - *s2;
}

int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abd";
	int ret = my_strcmp(arr1, arr2);
	if (ret > 0)
	{
		printf("arr1>arr2");
	}
	else if (ret < 0)
	{
		printf("arr1<arr2");
	}
	else
	{
		printf("arr1=arr2");
	}

	return 0;
}

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

3.1 strncpy库函数

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

3.1.1 注意要点

  1. 拷贝num个字符从源头字符串到目标空间
  2. 如果源头字符串的长度小于num,则拷贝完源头字符串之后,在目标的后边追加’\0’,知道num个

3.1.2 strncpy模拟实现

#include <stdio.h>
char* my_strncpy(char* dest,const char* source,size_t count)
{
    char* start = dest;
    while (count && (*dest++ = *source++) != '\0')
    {
        count--;
    }

    if (count)
    {
        while (--count)
        {
            *dest++ = '\0';
        }
    }
    return start;
}

int main()
{
	char arr1[] = "xxxxxxxxxxx";
	char arr2[] = "hello";
	printf("%s\n", my_strncpy(arr1, arr2,3));
	return 0;
}

3.2 strncat库函数

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

3.2.1 注意要点

  1. 可以实现自己给自己追加的情况,通常追加后后面加上一个’\0’来结束
  2. 目标空间必须足够大
  3. 目标空间必须可修改

3.2.2 strncat模拟实现

#include <stdio.h>
char* my_strncat(char* front,const char* back,size_t count)
{
    char* start = front;
    while (*front++)
    {
        ;
    }
    front--;
    while (count--)
    {
        if ((*front++ = *back++) == 0)
        {
            return start;
        }
    }
    *front = '\0';
    return start;
}
int main()
{
	char arr1[20] = "math ";
	char arr2[] = "easy";
	printf("%s\n",my_strncat(arr1, arr2,3));
	return 0;
}

3.3 strncmp库函数

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

3.3.1 注意要点

和strcmp需要注意的地方一样

3.3.2 strncmp模拟实现

#include <stdio.h>
#include <assert.h>
int my_strncmp(const char* str1, const char* str2, size_t num)
{
    assert(str1 && str2);

    if (!num)return 0;

    while (--num && *str1 && (*str1 == *str2))
    {
        str1++;
        str2++;
    }

    return *str1 - *str2;
}
int main()
{
	char arr1[] = "adegcongdwg";
	char arr2[] = "adegavd";
	int ret = my_strncmp(arr1, arr2,5);
	if (ret > 0)
	{
		printf("arr1>arr2");
	}
	else if (ret < 0)
	{
		printf("arr1<arr2");
	}
	else
	{
		printf("arr1=arr2");
	}

	return 0;
}

4. 字符串查找函数

4.1 strstr库函数

char * strstr ( const char *str1, const char * str2);

4.1.1 注意要点

在一个字符串中另外一个字符川是否存在。如果存在,则返回子串第一次出现的位置;如果不存在,则返回NULL

4.1.2 strstr模拟实现

#include <stdio.h>
char* my_strstr(const char* s1, const char* s2)
{
	const char* str1 = s1;
	const char* str2 = s2;
	const char* p = s1;
	while (*p)
	{
		str1 = p;
		str2 = s2;
		while (*str1 == *str2)
		{
			str1++;
			str2++;
		}
		if (*str2 == '\0')
		{
			return (char*)p;
		}
		p++;
	}
	return NULL;
}

int main()
{
	char arr1[] = "adefghadefgh";
	char arr2[] = "efg";
	char* ret = my_strstr(arr1, arr2);
	if (ret == NULL)
	{
		printf("不存在\n");
	}
	else
	{
		printf("%s\n", ret);
	}
	return 0;
}

4.2 strtok库函数

char * strtok ( char * str, const char * delimiters );

4.2.1 注意要点

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

4.2.2 strtok库函数的使用场景

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

int main()
{
	char arr[] = "code-eye@qq.com";
	char buff[200] = { 0 };
	//strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改
	strcpy(buff, arr);
	const char* p = "-@.";

	char* str = NULL;
	for (str = strtok(buff, p); str != NULL; str = strtok(NULL, p))
	{
		printf("%s\n",str);
	}

	return 0;
}

5. 错误信息报告

5.1 strerror库函数

char* strerror(int errnum);

strerror库函数作用:返回错误码,所对应的错误信息。

6. 字符操作函数

  1. iscntrl库函数:判断是否为任何控制字符
  2. isspace库函数:判断是否为空白字符:‘空格’,换页‘\f’,换行‘\n’,回车‘\r’,制表符‘\t’
  3. isdigit库函数;判断是否为十进制数字
  4. isxdigit库函数:判断是否为十六进制数字包括十进制数字
  5. islower库函数:判断是否为小写字母
  6. isupper库函数:判断是否为大写字母
  7. isalpha库函数:判断是否为字母az或者AZ
  8. isalnum库函数:判断是否为字母或者数字
  9. ispunct库函数:判断是否为标点符号,任何不属于数字或者字母的图形字符
  10. isgraph库函数;判断是否为任何图形字符
  11. isprint库函数:判断是否为任何可打印字符

7.内存操作函数

7.1 memcpy库函数

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

7.1.1 注意要点

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

7.1.2 模拟实现

#include <stdio.h>
#inlcude <assert.h>
void* my_memcpy(void* dest, void* src, size_t num)
{
	void* ret = dest;
	assert(dest && src);
	while(num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}

int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	my_memcpy(arr2, arr1, 20);

	int i = 0;
	for (i = 0; i < (20 / sizeof(int)); i++)
	{
		printf("%d ",arr2[i]);
	}
	return 0;
}

7.2 memmove库函数

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

7.2.1 注意要点

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

7.2.2 模拟实现

#include <stdio.h>
void* my_memmove(void* dest, void* src, size_t num)
{
	void* ret = dest;
	assert(dest && src);
	//从前往后覆盖
	if (dest < src)
	{
		while(num--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	//从后往前覆盖
	else 
	{
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);
		}
	}
	return ret;
}

print(int arr[],int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr+3,arr,16);
	int sz = sizeof(arr) / sizeof(arr[0]);
	print(arr,sz);
	return 0;
}

7.3 memset库函数

void * memset ( void * ptr, int value, size_t num );

7.3.1 注意要点

  1. memset是用来把ptr指针指向的内容后的num个字节全部改为value值

7.3.2 使用场景

7.4 memcmp库函数

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

7.4.1 注意要点

这里和strncpy很相似,但是memcpy针对各种类型,strncpy只能比较char类型的。
这里的num单位是字节,所以比较的是从ptr1和ptr2指针开始的num个字节
ptr1的字符ASCII码值大于ptr2就返回大于0的值,等于返回0,小于则返回小于0的值

  • 20
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 35
    评论
评论 35
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

脚踏车(crush)

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

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

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

打赏作者

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

抵扣说明:

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

余额充值