当前位置: 首页 > news >正文

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

文章目录

  • 1. 求字符串长度
    • 1.1 strlen库函数
      • 1.1.1 注意要点
      • 1.1.2 strlen模拟实现
  • 2. 长度不受限制的字符串函数
    • 2.1 strcpy库函数
      • 2.1.1 主要要点
      • 2.1.2 strcpy模拟实现
    • 2.2 strcat库函数
      • 2.2.2 strcat模拟实现
    • 2.3 strcmp库函数
      • 2.3.1 注意要点
      • 2.3.2 strcmp模拟实现
  • 3. 长度受限制的字符串函数
    • 3.1 strncpy库函数
      • 3.1.1 注意要点
      • 3.1.2 strncpy模拟实现
    • 3.2 strncat库函数
      • 3.2.1 注意要点
      • 3.2.2 strncat模拟实现
    • 3.3 strncmp库函数
      • 3.3.1 注意要点
      • 3.3.2 strncmp模拟实现
  • 4. 字符串查找函数
    • 4.1 strstr库函数
      • 4.1.1 注意要点
      • 4.1.2 strstr模拟实现
    • 4.2 strtok库函数
      • 4.2.1 注意要点
      • 4.2.2 strtok库函数的使用场景
  • 5. 错误信息报告
    • 5.1 strerror库函数
  • 6. 字符操作函数
  • 7.内存操作函数
    • 7.1 memcpy库函数
      • 7.1.1 注意要点
      • 7.1.2 模拟实现
    • 7.2 memmove库函数
      • 7.2.1 注意要点
      • 7.2.2 模拟实现
    • 7.3 memset库函数
      • 7.3.1 注意要点
      • 7.3.2 使用场景
    • 7.4 memcmp库函数
      • 7.4.1 注意要点

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的值

相关文章:

  • Es6的promise和async
  • Java项目本地部署宝塔搭建实战java中小医院管理系统源码
  • java 低耦合观察者模式
  • 七、OCR-PaddlePaddle训练源码解析系列-文字识别
  • 数据结构与算法之非递归遍历二叉树
  • Unity技术手册 - 创建物体有几种方式?
  • threejs中各种的对像详细介绍
  • 代码优化~关注核心逻辑,封装常用规则
  • Android车载开发基础学习——蓝牙通信是如何实现的?
  • 智慧政务、数字化优先与数字机器人,政务领域正在开启“政务新视界”
  • DES算法是对称算法吗,能否通过在线工具进行DES解密?
  • 【车间调度】基于GA/PSO/SA/ACO/TS优化算法的车间调度比较(Matlab代码实现)
  • springBoot 的默认线程池-ThreadPoolTaskExecutor
  • 暑期结束为你的新学期立下Flag吧
  • 大数字符串加法
  • 8年软件测试工程师感悟——写给还在迷茫中的朋友
  • CSS 提示工具(Tooltip)
  • Docker 笔记(2):Dockerfile
  • dva中组件的懒加载
  • ES6简单总结(搭配简单的讲解和小案例)
  • github指令
  • JavaScript服务器推送技术之 WebSocket
  • JS进阶 - JS 、JS-Web-API与DOM、BOM
  • js如何打印object对象
  • Linux学习笔记6-使用fdisk进行磁盘管理
  • nginx 负载服务器优化
  • pdf文件如何在线转换为jpg图片
  • yii2中session跨域名的问题
  • 给第三方使用接口的 URL 签名实现
  • 机器人定位导航技术 激光SLAM与视觉SLAM谁更胜一筹?
  • 解析 Webpack中import、require、按需加载的执行过程
  • 漫谈开发设计中的一些“原则”及“设计哲学”
  • 前端知识点整理(待续)
  • 前言-如何学习区块链
  • 使用docker-compose进行多节点部署
  • 线性表及其算法(java实现)
  • 用 vue 组件自定义 v-model, 实现一个 Tab 组件。
  • 用jQuery怎么做到前后端分离
  • 白色的风信子
  • mysql 慢查询分析工具:pt-query-digest 在mac 上的安装使用 ...
  • 如何在 Intellij IDEA 更高效地将应用部署到容器服务 Kubernetes ...
  • ​Python 3 新特性:类型注解
  • ​猴子吃桃问题:每天都吃了前一天剩下的一半多一个。
  • !!Dom4j 学习笔记
  • #QT项目实战(天气预报)
  • #绘制圆心_R语言——绘制一个诚意满满的圆 祝你2021圆圆满满
  • (ZT)北大教授朱青生给学生的一封信:大学,更是一个科学的保证
  • (博弈 sg入门)kiki's game -- hdu -- 2147
  • (附源码)ssm基于jsp高校选课系统 毕业设计 291627
  • (黑客游戏)HackTheGame1.21 过关攻略
  • (实战)静默dbca安装创建数据库 --参数说明+举例
  • (收藏)Git和Repo扫盲——如何取得Android源代码
  • (四)TensorRT | 基于 GPU 端的 Python 推理
  • (未解决)jmeter报错之“请在微信客户端打开链接”
  • (一)WLAN定义和基本架构转