1 atoi函数的模拟实现
1.1 atoi的使用
文档:int atoi (const char* string);
atoi:把字符串nptr转换为int。
atoi函数使用实例:
#include <stdio.h> #include <stdlib.h> int main() { char arr[100] = "12345"; int ret = atoi(arr); printf("%d\n", ret); return 0; }
1.2 初步模拟实现
初步模拟实现可以把数字字符串转换为整数,由于没有考虑正负号,所以只能转换为正数;
还有很多特殊情况没有考虑,这里先来看看初步的模拟实现;
#include <stdio.h> #include <stdlib.h> int my_atoi(const char* str) { int n = 0; while (*str != '\0') { n = n * 10 + (*str - '0'); str++; } return n; } int main() { char arr[10] = "12345"; //int ret = atoi(arr); int ret = my_atoi(arr); printf("%d\n", ret); return 0; }
1.3 atoi函数的具体实现(考虑6种特殊情况)
面试时写上面的那就真是面逝了,下面我们来考虑6种特殊的情况:
1.空指针
2.空字符串
3.字符串中的空格
4.非数字字符
5.溢出问题(所得数字大于INT_MAX或者小于INT_MIN)
6.正负号问题
1.空指针的问题很容易解决:使用assert函数断言即可;
2.空字符串的第一个元素即为'\0',在前面判断是否为'\0'返回就可以了,
但是有一个问题,返回的0时原字符是'0还是空字符串,这里存在非法转换和合法转换,
可以使用枚举解决,创建一个枚举类型初始化为非法,因为非法的情况比较多,合法的情况就一种。初始化为非法有利于问题的解决,空字符串转换为整数0是一种非法转换。
3.当遇到字符串中有空格的时候,可以直接跳过空格所在的内容,指针++指向下一个字符。
4.非数字字符,例如"123a456",这里在指针走到a的时候,直接返回123就行了,
不需要继续往下走了,此时是一种非法转换。
5.溢出问题是数字字符的一种情况,当所得的n的值大于最大整型或者小于最小整型的时候,
返回最大整型或者最小整型,溢出问题是一种非法转换。
6.正负号的问题可以找一个变量flag来记录,初始化为1,当是正数的时候flag的值不变为1;
若字符串中有'-',flag的值变为-1,记录符号位。
代码实现:
#include <stdio.h> #include <stdlib.h> #include <assert.h> #include <ctype.h>//isspace isdigit #include <limits.h>//INT_MAX INT_MIN enum State { INVALID, VALID }state=INVALID;//初始化为invalid 非法的,无效的 int my_atoi(const char* str) { assert(str != NULL);//空指针 if (*str == '\0')//空字符串 { return 0; } while (isspace(*str))//字符串中的空格 { str++; } int flag = 1; if (*str == '-') //正负号问题 { flag = -1; str++; } if (*str == '+') { flag = 1; str++; } long long n = 0; while (*str != '\0') { if (isdigit(*str))//数字字符 { n = n * 10 + (*str - '0'); if (n > INT_MAX || n < INT_MIN)//5.溢出问题 { break; } } else//不是数字字符直接跳出循环,state此时还是INVALID { break; } str++; } if (*str == '\0') { state = VALID; } return (int)(n*flag); } int main() { char arr[50] = " -123"; //int n = atoi(arr); int n = my_atoi(arr); //判断合法非法转换 if (state == VALID) { printf("合法转化:n = %d\n", n); } else { printf("非法转换:n = %d\n", n); } return 0; }
2 strncpy函数的模拟实现
strncpy还有下面的strncat和其它字符串函数我们在之前字符串的篇章讲过。
文档:char * strncpy ( char * destination, const char * source, size_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.
从源字符串拷贝num个字符到目标空间。
如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
#include<stdio.h> #include<string.h> #include<assert.h> char* my_strcpy(char* dest, const char* src, int n) { assert(dest != NULL); assert(src != NULL); char* ret = dest;//先让ret指向dest的起始地址 int i = 0; for (i = 0; i < n && src[i]; i++) { dest[i] = src[i]; } if (i < n) { dest[i] = '\0'; } return ret; } int main() { char arr1[30] = "##########################"; char arr2[] = "hello world"; //printf("%s\n", strncpy(arr1, arr2,5)); printf("%s\n", my_strcpy(arr1, arr2, 5)); return 0; }
3 strncat函数的模拟实现
文档:char * strncat ( char * destination, const char * source, size_t num );
追加 num个字符到目标空间
Appends the first num characters of source to destination, plus a terminating null character.
If the length of the C string in source is less than num, only the content up to the terminating null-character is copied
注意事项:如果源字符串的长度小于 num,则只复制 \0 之前的内容。
#include<stdio.h> #include<string.h> #include<assert.h> char* my_strncat(char* dest, const char* src,int n) { assert(dest != NULL); assert(src != NULL); char* ret = dest;//让ret指向dest的起始地址 while (*dest)//找到'\0' '\0'的ASCII码为0跳出循环 { dest++; } int i = 0; for (i = 0;i < n && src[i];i++) { dest[i] = src[i]; } if (i < n) { dest[i] = '\0'; } return ret; } int main() { char arr1[20] = "hello "; char arr2[] = "world"; //printf("%s\n", strncat(arr1, arr2,3)); printf("%s\n", my_strncat(arr1, arr2,3)); return 0; }
C语言进阶21收尾(编程练习)(atoi,strncpy,strncat,offsetof模拟实现+找单身狗+宏交换二进制奇偶位)(下):https://developer.aliyun.com/article/1513291