模拟实现C库函数(2)

"烦恼无影踪,丢宇宙~"

上一篇的模拟实现了好几个库函数,strlen\strcpy\memcpy\memmove,那么这一篇又会增加几个常用C库函数的模拟实现 memset\itoa\atoi。

一、memset

memset - fill memory with a constant byte
#include <string.h>
void *memset(void *s, int c, size_t n);
The memset() function fills the first n bytes of the memory area pointed to by s with the constant byte c.
memset()函数 将会用常量字节c ,填充s指向的内存区域空间,填充前n个字节。
RETURN VALUE
The memset() function returns a pointer to the memory area s.
返回s的起始地址

下面的代码演示取自这里:Here

    //我们相对下面的数组手动进行初始化
    int arr1[10];
    int arr2[10];
    memset(arr1, 0, sizeof(int) * 10);
    memset(arr2, 1, sizeof(int) * 10);

为什么它们的区别这么大?16843009从哪里来的??那么一定跟它底层的实现是有关系的。

void* my_memset(void* s, int c, size_t n)
{
    const unsigned uc = c;
    unsigned char* su = s;
    for (;n > 0;++su,--n)
    {
        *su = uc;
    }
    return s;
}

第3行先将int类型的c强转为unsigend char。第4行将void* 也强转为unsigned char*。

变量类型的本质只是标志从某一内存地址开始读取的位数,强制转换就是改变读取位数的大小。改变的不是变量本身,而是从内存中读取每个bit的方式。

我们再回到第一个问题上来。将int类型强转为unsigend char,也就意味着本身要读取bit位数为32,但是截断了24位。只用读取8位。

当整数1被传入进来时 00000000 00000000 00000000 00000001(32)

实质上读取的时候是00000001(8)。(unsigend char)s每次将原内存的比特位置位: 00000001。循环4(int)n次后,也就是构一个int的大小:00000001 00000001 00000001 00000001

当memset结束后,以int大小取去32位比特时:

不过,对于设置0而言,memset(arr1, 0, sizeof(int) * 10)可以完美做到。比较32个位都是0。

二、atoi

atoi, atol, atoll, atoq - convert a string to an integer
#include <stdlib.h>
int atoi(const char *nptr);
The atoi() function converts the initial portion of the string pointed to by nptr to int.
atoi() 将nptr指向的初始字串部分,转换为int整数返回。

RETURN VALUE
The converted value.

一个字符串的输入可能有哪些情况?

"123"

" 123"

"'\0'123"

"-123"

"''\0'123"

"12'\0'3"

"abc"

"123abc"

  1. 空格直接跳过

  1. 遇到"-"时,会转换成整数的负号

  1. 当遇到'\0'时,函数就会终止

  1. 正常0时转为整数0

  1. 如果不是数字,那么也会直接终止

int my_atoi(char* nptr)
{
    assert(nptr);
    //符号
    int flag = 1;
    //返回的ret
    long long ret = 0;
    
    //1.跳过空格
    while (isspace(*nptr))
    {
        nptr++;
    }

    //2.是否遇到'\0'?
    if (*nptr == '\0') return 0;

    //3.正负号
    if (*nptr == '-')
    {
        flag = -1;
        nptr++;
    }
    else if (*nptr == '+')

    {
        nptr++;
    }
    else {
        //do nothing
    }

    //处理字串
    while (isdigit(*nptr))
    {
        //字符是否合法
        ret = ret * 10 + flag * (*nptr - '0');
        //但 不能超过 限制
        if ((ret > INT_MAX) || (ret < INT_MIN))
        {
            return 0;
        }
        nptr++;
    }

    //正常截止的情况是 走到nptr的最后 或者 "123abc" || "123'\0'324"
    if (*nptr == '\0')
    {
        return (int)ret;
    }
    else
    {
        //遇到了非法字符
        //返回已经转成字符的
        return (int)ret;
    }
    return 0;
}

测试;

三、itoa

Convert integer to string (non-standard function)
char * itoa ( int value, char * str, int base );

Converts an integer value to a null-terminated string using the specified base and stores the result in the array given by str parameter.
itoa()让一个整形值以base的基准,转化为以nullptr结尾的字串,并把结果存储在被str管理的数组中
注:base实质为进制数
Numerical base used to represent the value as a string, between 2 and 36, where 10 means decimal base, 16 hexadecimal, 8 octal, and 2 binary.(2<= base <=36)
#include <stdio.h>
#include <stdlib.h>

int main ()
{
  int i;
  char buffer [33];
  printf ("Enter a number: ");
  scanf ("%d",&i);
  itoa (i,buffer,10);
  printf ("decimal: %s\n",buffer);
  itoa (i,buffer,16);
  printf ("hexadecimal: %s\n",buffer);
  itoa (i,buffer,2);
  printf ("binary: %s\n",buffer);
  return 0;
}
                                                                       取自"cplusplus.com"例子

char* my_itoa(int value, char* str, int base)
{
    //存放 处理好的字串
    int a[100] = { 0 };
    int sum = value;
    char* cp = str;
    if (base < 2 || base > 36)//增加了对错误的检测
    {
        *cp++ = 0;
        *cp = '\0';
        return str;
    }
    //按正数转换
    if (sum < 0) sum = -sum;

    int i = 0;
    char zm[37] = "0123456789abcdef";
    while (sum > 0)
    {
        //sum%base 如果是 十进制的8 % 10 那么得到的是8
        //如果是 十六进制的8 % 16 8
        //如果是 二进制的 8 % 2  0
        printf("%c\n", zm[sum % base]);
        a[i++] = zm[sum % base];
        sum /= base;
    }

    if (value < 0)
    {
        *cp++ = '-';
    }

    //填充
    for (int j = i - 1; j >= 0; j--)
    {
        *cp++ = a[j]; //从高位到低位转换
    }
    //null结尾
    *cp = '\0';
    return str;
}

测试;

本篇到此也就结束了,感谢你的阅读。

祝你好运,向阳而生~

主要内容:本文详细介绍了一种QRBiLSTM(分位数回归双向长短期记忆网络)的时间序列区间预测方法。首先介绍了项目背景以及模型的优势,比如能够有效利用双向的信息,并对未来的趋势上限和下限做出估计。接着从数据生成出发讲述了具体的代码操作过程:数据预处理,搭建模型,进行训练,并最终可视化预测结果与计算分位数回归的边界线。提供的示例代码可以完全运行并且包含了数据生成环节,便于新手快速上手,深入学习。此外还指出了模型未来发展的方向,例如加入额外的输入特性和改善超参数配置等途径提高模型的表现。文中强调了时间序列的标准化和平稳检验,在样本划分阶段需要按时间序列顺序进行划分,并在训练阶段采取合适的手段预防过度拟合发生。 适合人群:对于希望学习和应用双向长短时记忆网络解决时序数据预测的初学者和具有一定基础的研究人员。尤其适用于有金融数据分析需求、需要做多一步或多步预测任务的从业者。 使用场景及目标:应用于金融市场波动预报、天气状况变化预测或是物流管理等多个领域内的决策支持。主要目的在于不仅能够提供精确的数值预计还能描绘出相应的区间概率图以增强结论置信程度。 补充说明:本教程通过一个由正弦信号加白噪构造而成的简单实例来指导大家理解和执行QRBiLSTM流程的所有关键步骤,这既方便于初学者跟踪学习,又有利于专业人士作为现有系统的补充参考工具。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值