"烦恼无影踪,丢宇宙~"
上一篇的模拟实现了好几个库函数,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"
空格直接跳过
遇到"-"时,会转换成整数的负号
当遇到'\0'时,函数就会终止
正常0时转为整数0
如果不是数字,那么也会直接终止
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;
}
测试;
本篇到此也就结束了,感谢你的阅读。
祝你好运,向阳而生~