zoukankan      html  css  js  c++  java
  • c++实现atoi()和itoa()函数(字符串和整数转化)

    (0)

    c++类型所占的字节和表示范围

    c 语言里 类型转换那些事儿(补码 反码)

    应届生面试准备之道

    最值得学习阅读的10个C语言开源项目代码

    一:起因

    (1)字符串类型转化为整数型(Integer)。还是字符串类型(String)转化为Double类型,这在java里面有非常好的内部函数。非常easy的事情;

    (2)可是在c里面没有Integer Double等包装类,由char[]数组转化为整数型就变得不那么简单了,atoi()  itoa()在widows以下有,可是网上说linux 下好像没有 itoa() 函数,用 sprintf() 好了。可是本人測试了一下sprintf()  sscanf()的效率非常低。

    (3)所以自己手动实现了一下atoi()(字符串转整数)  itoa(整数转字符串)两个函数,有哪里不正确的地方,大家指正。

    (4)我也幼稚过 请看 当初写的关于int --> string 的 blog

    (插入———— begin)

    (0) 在区间(0,1)上任取三个数,则这三个数之和小于1的概率为?

    答案是1/6,怎么计算的,求具体解答?
    设所取的三个数分别为 x、y、z ,则 0<x<1,0<y<1,0<z<1 ,
    满足上述条件的点 P(x,y,z)构成一个棱长为 1 的正方体,体积为 V=1*1*1=1 ,
    满足 x+y+z=1 的点是分别过(1,0,0)、(0,1,0)、(0,0,1)的平面,
    而满足 x+y+z<1 的点位于正方体内、平面的下方,体积为 V1=1/3*1/2*1*1*1=1/6  (要是三个随意小于2的数呢?) 

    (1)先看一段程序

    // test for begin
    #define fuc(a) ((a)*(a))
    //test for end
    	// test for begin
    	int aa = 5;
    	cout << "fuc(a++): " << fuc(aa++) <<endl;//25
    	aa = 5;
    	cout << "fuc(++a): " << fuc(++aa) <<endl;//49
    	aa = 5;
    	cout << aa << aa++ << endl;//6,5
    	aa = 5;
    	cout << aa++ << aa << endl;// 5,5
    
    	int b[7] = {1,2,3,4,5,7,8};
    	int *ptr = (int*)(&b+1);// 如今的ptr指向数组长度的下一位置
    	printf("%d,%d
    ",*(b+1),*(ptr-1));// ptr-1指向b[len-1]最后一个元素
    	cout << &b << "," << ptr << "," << b << "," << (*ptr) << endl;
    
    	int d = 5;
    	int c =10;
    	int &ii = d;// 大哥啊,这是引用啊~~~哎~~~这都不会了,还笔试个毛啊。这都忘了,还面试个毛啊
    	int *jj = &c;
    	int *&kk = jj;// 从右往左读,指针的引用;
       	 //int*&p 是 指针的引用,它是一个 指针 的 别名 ,一般能够当成 指针 使用。

    cout << ii << endl; //test for end

    解析

    int *ptr=(int *)(&a+1)

    【理论知识】:首先须要搞明确a,&a.     a既是数据名,又是指向数组第一个元素的指针。

    sizeof(a)=20, 此时a的类型为int[5]数组。

    sizeof(*a)=4,由于有取值符*,表示把a当成一个指针(int*),而a指向数组的首地址,即a=&(a[0]),即sizeof(*a)=sizeof(*&(a[0]))=sizeof(a[0])=sizeof(int)=4。

    *(a+1)中把a当成一个指针,a+1=a+sizeof(int)。a+1指向a的下一个整形地址既&a[1]。因此*(a+1)=*(&a[1])=a[1]=2。

    (&a+1)先取变量a的地址,并依据a的地址获得下一个与a同类型的相邻地址。依据前面所说的a的类型为int[5]数组。

    &a+1=&a+sizeof(5*int),因此&a+1指向的地址为&a[5](数组a[5]的下一个地址)。(int*)(&a+1)把这个相邻地址显式类型转换为int类型的地址int*ptr=(int*)(&a+1);所以ptr指向&a[5],而且ptr是一个int类型的指针。

    ptr-1=ptr-sizeof(int),故ptr-1指向&a[4]。

    因此,*(ptr-1)的值即为a[4]=5。

    【个人理解】:
    a[5]即能够看成是一个一维数组,也能够看成是一个仅仅有一行的二维数组a[1][5]。
    所以a指向一维数组的首地址,即a=&a[0],a+1指向&a[1]。

    每次加的地址长度为sizeof(int).
    而&a指向二维数组的首地址,即&a=&a[0][5],&a+1指向&a[1][5]。每次加的地址长度为sizeof(5*int).

    (3)【题目】

    Given a singly linked list L: L0→L1→…→Ln-1→Ln,
    reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→…
    You must do this in-place without altering the nodes' values.

    【分析】
    题目思路比較直接:
    (1)找到链表的中间节点,把链表划分成2个子链表。假设原链表长度为奇数。那么第一个子链表的长度多1。
    (2)翻转第二个子链表;
    (3)交叉合并两个子链表。


    比如{1,2,3,4,5,6,7}
    (1)找到链表的中间节点为4,把链表划分成2个子链表:{1,2,3,4}和{5,6,7}。
    (2)翻转第二个子链表得到{7,6,5}
    (3)交叉合并{1,2,3,4}和{7,6,5}得到{1,7,2,6,3,5,4}

    //
    /*
        version: 1.0
        author: hellogiser
        blog: http://www.cnblogs.com/hellogiser
        date: 2014/5/30
    */
    #include "stdafx.h"
    
    
    struct ListNode
    {
        int value;
        ListNode *next;
    };
    
    // find middle node of list
    ListNode *FindMiddleNode(ListNode *head)
    {
        if(NULL == head)
            return NULL;
        ListNode *fast = head, *slow = head;
        while(fast != NULL && fast->next != NULL)
        {
            // move fast 2 steps
            fast = fast->next->next;
            if (fast == NULL)
                break;
            // move slow 1 step
            slow = slow->next;
        }
        return slow;
    }
    
    // reverse list
    ListNode *ReverseList(ListNode *head)
    {
        if(NULL == head || NULL == head->next)
            return head;
        ListNode *prev = NULL, *cur = head, *next = NULL;
        while(cur != NULL)
        {
            // save next
            next = cur->next;
            // reverse
            cur->next = prev;
            // update prev and cur
            prev = cur;
            cur = next;
        }
        return prev;
    }
    
    // cross merge list
    ListNode *CrossMergeList(ListNode *head1, ListNode *head2)
    {
        if(NULL == head1)
            return head2;
        else if (NULL == head2)
            return head1;
    
    
        ListNode *node1 = head1, *node2 = head2;
        while(node2 != NULL)
        {
            ListNode *temp1 = node1->next;
            ListNode *temp2 = node2->next;
            node1->next = node2;
            node2->next = temp1;
            // update node1 node2
            node1 = temp1;
            node2 = temp2;
        }
        return head1;
    }
    
    
    // reorder list
    ListNode *ReOrderList(ListNode *head)
    {
        if(NULL == head || NULL == head->next)
            return head;
    
    
        // find middle node of list
        ListNode *middle = FindMiddleNode(head);
        // split into 2 lists
        ListNode *head1 = head;
        ListNode *head2 = middle->next;
        // detach the 2 lists
        middle->next = NULL;
        // reverse list2
        head2 = ReverseList(head2);
        // cross merge 2 lists
        return CrossMergeList(head1, head2);
    }

    (插入——————end)

    二:实现

    (1)atoi()函数原型:int atoi(char *str)  头文件 stdlib.h

    函数用途:将字符串转换成一个整数值
    输入參数:str 待转换为整型数的字符串
    返回值:成功返回转换后的数值,失败则返回0.

    (2)代码实现

    int my_atoi(char s[])
    {
        int i,n,sign;
    
        for(i=0;isspace(s[i]);i++);   //跳过空白,isspace()这个函数在type.h头文件里;也能够s[i]==' '实现
    
        sign=(s[i]=='-')?

    -1:1; if(s[i]=='+'||s[i]=='-') //跳过符号位 i++; for(n=0;isdigit(s[i]);i++) n=10*n+(s[i]-'0'); //将数字字符转换成整形数字,isdigit()这个函数在type.h头文件里。也能够s[i]>='0' && s[i]<='9''实现; 0x30是 '0' return sign*n; }

    (3) itoa()函数的原型:char *itoa( int value, char *str,int radix)

    函数用途:将整数型值value转换成一个字符串
    输入參数:value待转换的整型数 。str
    目标字符串的地址,即返回值。radix:转换后的进制数,能够是10进制、16进制等。

    返回值:成功返回一个字符串.

    (4)代码实现

    /*
    Converts an int or long into a character string
    将一个整数转化为字符串
    */
    char* my_itoa(int n,char str[])
    {
        int i,j,len,sign;
    
        if((sign=n)<0)    //记录符号
            n=-n;         //使n成为正数
        i=0;
        do{
            str[i++]=n%10+'0';    //取下一个数字
        }while((n/=10)>0);      //循环相除
    
        if(sign<0)
            str[i++]='-';
        str[i]='';
        len = i;//
        for(j=len-1,i=0;j>i;j--,i++)        //生成的数字是逆序的,所以要交换
        {
            str[j] ^= str[i];
            str[i] ^= str[j];
            str[j] ^= str[i];
        }
        return str;
    }

    (5) 主函数測试

    #include "stdio.h"
    #include "ctype.h"
    #include "stdlib.h"
    int main()
    {
        int n;
        char str[32],*ans;
        ans = my_itoa(-123,str);
        printf("自编自导的整形转字符串函数my_itoa():%s %s
    ",ans,str);
        printf("系统自带的整形转字符串函数itoa():%s %s
    ",itoa(-1,str,16),str);
        printf("自编自导的字符串转整形函数my_atoi():%d
    ",my_atoi("  22qqq"));
        printf("系统自带的字符串转整形函数atoi():%d
    ",atoi("  -2qqq "));
        system("pause");
        return 0;
    }

    (6)測试结果:



    三:不足之处

    (1) itoa()函数的原型:char *itoa( int value, char *str,int radix),自己并未全然实现。仅仅是简单的实现了10进制的

    (2)以下会改进的,上面有不足之处,请大神不吝赐教

    (3) itoa()函数的原型:char *itoa( int value, char *str,int radix)。自己简单的实现。默认是实现了10进制的

    char __itoa[] = {'0','1','2','3','4','5','6','7','8','9',
                    'a','b','c','d','e','f'};
    const unsigned int MY_MAX = 0xFFFFFFFFu;
    char* my_itoa2(int n,char str[],int radix=10)
    {
        int i,j,len,sign;
        unsigned int tmp;
        i = 0;
        if(n<0)    //
        {
            tmp = MY_MAX + n + 1;// 这样貌似能够了,依照取反加一的方式进行的
            do{
                str[i++]=__itoa[tmp%radix];    //取下一个数字
            }while((tmp/=radix)>0);//循环相除
        }
        else
        {
            do{
                str[i++]=__itoa[n%radix];    //取下一个数字
            }while((n/=radix)>0);//循环相除
        }
    
        str[i]='';
        len = i;//
        for(j=len-1,i=0;j>i;j--,i++)        //生成的数字是逆序的,所以要交换
        {
            str[j] ^= str[i];
            str[i] ^= str[j];
            str[j] ^= str[i];
        }
        return str;
    }


  • 相关阅读:
    PDF文件中的Form保存问题
    Understanding IP Fragmentation
    tcp ip guide IPsec IKE
    Windows安全事件日志中的事件编号与描述
    Cisco PIX fix up and Juniper firewall FTP ALG
    很好的IPSec介绍,详细解释了IKE协商的2个阶段的作用
    virtualbox 下运行Ubuntu 8.10的分辨率和guest additions的问题。
    Fixing the ‘Do you want to display nonsecure items’ message
    windows xp 开始菜单里面所有项目右键不起作用。
    HP backup and recovery manager
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/5154943.html
Copyright © 2011-2022 走看看