字符串和数字的解析转换算法 纯C语言实现

字符串和数字的解析转换 纯C语言实现

灵感来源

很多脚本语言如python和js,都能做到字符串解析为整形或者小数型的变量,数字类型变量也能非常轻松的转化成字符串,今天突然想到用原始的C语言,设计算法自己手动实现一下这个功能。

主要功能

int类型0~9单个数字 <—相互转化—> 字符

int类型 <—相互转化—> 字符串

double类型 <—相互转化—> 字符串

源代码实现

直接新建一个main.c并将全部代码复制进去即可。调用对应的函数使用。

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

/**
 * 获取一个数字的第d位数字
 * @param number 数字
 * @param d 如果是1,就表示个位数字
 * @return 0~9之间的一个数字
 */
int getDig(int number, int d);

/**1
 * 将数字转化成字符
 * 3 -->  '3'
 * @param number 仅限 0 ~ 9
 * @return '0' ~ '9'
 */
char numToChar(int number);

/**
 * 将字符数字解析成数字整形
 * @param chrNum '0' ~ '9'
 * @return 0 ~ 9
 */
int charToInt(char chrNum);

/**
 * 实现整形数字转字符串
 * @param number int类型数字
 * @return 转化成字符串后的数字,如 "-1657"
 */
char *intToStr(int number);

/**
 * 将数字字符串解析成数字
 * @param str 数字字符串,如 "-123", "2223"
 * @return int 类型数字
 */
int strToInt(char *str);

/**
 * 将小数字符串解析成小数
 * @param str 如 "0.0"  "-1.992"
 * @return double 类型小数
 */
double strToDouble(char *str);

/**
 * 将double类型小数转化为字符串
 * @param number double类型小数
 * @return "0.0"  "-1.992"
 */
char *doubleToStr(double number);

// C99
int main() {

    /// long -> int
    /// int -> float
    /// float -> int
    /// int -> double, double -> int 同理
    /// short, int, long, float, double 互相转化同理
    // 直接强制转化即可

    /// int --ASCII--> char
    /// char  --ASCII--> int
    // 直接强制转化即可

    /// int 0~9 --字符化-->  char '0'~'9'
    for (int i = 0; i < 10; i++) {
        printf("%d -> '%c'\n", i, numToChar(i));
    }

    /// char '0'~'9'  ---字符解析-->  int
    printf("%d\n", charToInt('9'));

    /// int --> string
    for (int i = -100; i < 100; i++) {
        printf("string number is %d '%s'\n", i, intToStr(i));
    }

    /// string --> int
    for (int i = -100; i < 100; i++) {
        printf("%d -> '%s' -> %d\n", i, intToStr(i), strToInt(intToStr(i)));
    }

    /// string ---> double
    printf("%s -> %lf\n", "12.3", strToDouble("12.3"));

    /// double ---> string
    printf("%s\n", doubleToStr(1.414));
    printf("%s\n", doubleToStr(1.1));
    printf("%s\n", doubleToStr(2005.23));
    printf("%s\n", doubleToStr(-32.23));
    printf("%s\n", doubleToStr(-55.244));
    // printf("%s\n", doubleToStr(1.0));
    return 0;
}


double strToDouble(char *str) {
    int len = (int) strlen(str);
    if (len == 0) {
        return -0.0;  // 解析错误
    }
    int flag = 1;
    int di = 0; // 如果前面有负号占位,di=1
    if (str[0] == '-') {
        flag = -1;
        di = 1;
    }
    // 先寻找小数点所在的位置
    int dotIndex = -1;  // 小数点所在的下标
    for (int i = 0; i < len; i++) {
        if (str[i] == '.') {
            dotIndex = i;
            break;
        }
    }
    // 如果没有找到小数点,当成整形的算法处理
    if (dotIndex == -1) {
        return (double) strToInt(str);
    }

    double res = 0;
    int w = 1;
    // 先计算小数点前面的部分
    for (int i = dotIndex - 1; i >= 0 + di; i--) {
        res += charToInt(str[i]) * w;
        w *= 10;
    }
    // 逐步累加计算小数点后面的部分
    double dw = 0.1;
    for (int i = dotIndex + 1; i < len; i++) {
        res += charToInt(str[i]) * dw;
        dw /= 10;
    }
    return res * flag;
}


char *doubleToStr(double number) {
    // 先记录整数部分,负数负号包含在了整数字符串中
    int integer = (int) number;
    char *intStr = intToStr(integer);
    int flag = 1;
    if (number < 0) {
        flag = -1;
    }
    double tile = (number - integer) * flag;
    printf("intStr: %s, tile: %f\n", intStr, tile);

    double n = tile * 10;
    int tileLen = 0;

    // char *tileStr = (char *) malloc(sizeof(char) * 2);
    int *digList = (int *) malloc(sizeof(int) * 1);
    int listLen = 1;

    while (n > 0) {
        int dig = (int) n;
        digList[tileLen] = dig;
        if (tileLen == listLen) {
            // 数组扩容一位
            digList = (int *) realloc(digList, sizeof(int) * listLen + 1);
        }
        listLen++;
        n -= dig;
        tileLen++;
        n *= 10;
    }
    char *res = (char *) malloc(sizeof(char) * (strlen(intStr) + 1 + tileLen));

    // 将整数部分写入
    for (int i = 0; i < strlen(intStr); i++) {
        res[i] = intStr[i];
    }
    // 写入小数点
    res[strlen(intStr)] = '.';
    // 写入小数部分
    for (int j = 0; j < tileLen; j++) {
        res[strlen(intStr) + 1 + j] = numToChar(digList[j]);
    }
    // free(digList);
    // free(intStr);
    return res;
}


int strToInt(char *str) {
    int len = (int) strlen(str);
    // printf("len: %d\n", len);
    if (len == 0) {
        return 0; // 解析异常
    }
    int flag = 1;  // 这个数是否是负数,正数1,负数-1;
    int res = 0;
    if (str[0] == '-') {
        flag = -1;
    }
    int w = 1;  // 表示当前正在遍历个位状态
    if (flag == 1) {
        for (int i = len - 1; i >= 0; i--) {
            res += charToInt(str[i]) * w;
            // printf("%d\n", res);
            w *= 10;
        }
    } else {
        for (int i = len - 1; i >= 1; i--) {
            res += charToInt(str[i]) * w;
            w *= 10;
        }

    }
    res *= flag;
    return res;
}


char numToChar(int number) {
    return (char) (48 + number);
}


int charToInt(char chrNum) {
    return (int) (chrNum - 48);
}


char *intToStr(int number) {
    // 首先获取这个数字有多少位
    // 看这个数字是正还是负
    // 根据字符串长度生成字符串
    if (number == 0) {
        return "0";
    }
    int flag = 0; // 0 表示是正数,1表示是负数
    if (number < 0) {
        number *= -1;
        flag = 1;
    }

    int len = 1;
    int n = 1;
    while (n <= number) {
        n *= 10;
        len++;
    }
    len--;
    char *res = (char *) malloc(sizeof(char) * (len + flag + 1));  // +1 是因为最后一个\0
    if (flag) {
        res[0] = '-';
        for (int i = 1; i <= len; i++) {
            res[len - i + 1] = numToChar(getDig(number, i));
        }
    } else {
        for (int i = 1; i <= len; i++) {
            res[len - i] = numToChar(getDig(number, i));
        }
    }
    return res;
}


int getDig(int number, int d) {
    return (number % (int) pow(10, d)) / (int) pow(10, d - 1);
}

不足

double转字符串(char*)类型,小数位会很长,会出很多问题

例如

1.414 会转化成 "1.41399999999999987920773492078296840190887451171875"

这是由于转化的方法设计的还不合理造成的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值