编写一个不使用标准C库函数将字符串转换为整数的程序

j7dteeu8  于 2023-02-15  发布在  其他
关注(0)|答案(3)|浏览(135)
#include <assert.h>
#include <stddef.h>
#include <string.h>

int StringToInteger(const char *str) {
    int num = 0;
    int sign = 1;
    assert(str != NULL); //assert that str different from NULL
    if (*str == '+' || *str == '-') {
        sign = (*str == '-') ? -1 : 1;
        str++;
        return sign; // if sign start with character
    }
    
    while (*str != '\0') { 
        if (*str >= '0' && *str <= '9') {
            num = num * 10 + (*str - '0');
        } else {
            return 0;
        }
        str++;
    }
    return 0;
}

我尝试编写一个不同版本的代码,而不使用常规转换函数,但没有成功。

4c8rllxm

4c8rllxm1#

问题:

    • 不总是返回0**@tkausl
    • 发现 * 符号后没有理由再回来***@Barmar

删除该行,然后在代码中按sign调整num
提示:也运行拼写检查.

// return sign; // if sign start with charcter

    // End of code
    return num * sign; // Include this line
    // return 0;
    • 高级:避免int溢出**
  • 像处理StringToInteger("-2147483648")一样处理INT_MIN文本
  • 在溢出发生之前检测它。这防止了 * 未定义的行为 *(UB)。
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stddef.h>

int StringToInteger(const char* str) {
  assert(str != NULL);

  // TBD code if desired to ignore leading white-spaces. 

  int sign = *str;
  if (*str == '+' || *str == '-') {
    str++;
  }

  const char *first = s;
  int num = 0;
  while (*str >= '0' && *str <= '9') { 
    int digit = *str - '0';
    if (num <= INT_MIN/10 && (num < INT_MIN/10 || digit > -(INT_MIN%10))) {
      errno = ERANGE;
      num = INT_MIN;
    } else {
      // Sum as a negative value as the - range is more than + range.
      num = num * 10 - digit;
    }
    str++;
  }
  if (*str) {
    ; // May want to set errno.
    return 0; // Non-null character stopped loop.
  }
  if (s == first) {
    ; // May want to set errno.
    return 0; // No digits.
  }

  if (sign != '-') {
    if (num < -INT_MAX) {
      num = INT_MAX;
      errno = ERANGE;
    } else {
      num = -num;
    }
  }

  return num;
}
4xrmg8kj

4xrmg8kj2#

该函数有许多没有意义的return语句,例如

return sign; // if sign start with charcter

并且你的函数返回符号或0,实际上它没有考虑字符串中存储值的符号。
还要考虑字符串可以包含前导或尾随白色字符。
您可以使用way.as标准C函数strtol来实现该函数,简化的函数可以忽略存储的数字太大而无法放入int类型的对象的情况。
下面是一个演示程序,说明如何实现该功能。

#include <ctype.h>
#include <stdio.h>

int StringToInteger( const char *str )
{
    const int Base = 10;

    int sign = 0;

    while (isspace( ( unsigned char )*str )) ++str;

    if (*str == '-' || *str == '+')
    {
        if (*str == '-') sign = 1;
        ++str;
    }

    int value = 0;

    for (unsigned char c = *str;  isdigit( c ); c = *++str )
    {
        int digit = c - '0';
        value = Base * value + ( sign ? -digit : digit );
    }

    while (isspace( ( unsigned char )*str )) ++str;

    return *str == '\0' ? value : 0;
}

int main( void )
{
    const char *str = " -12345\t";

    printf( "\"%s\" = %d\n", str, StringToInteger( str ) );

    str = " 12345\t";

    printf( "\"%s\" = %d\n", str, StringToInteger( str ) );

    str = " 12345\tA";

    printf( "\"%s\" = %d\n", str, StringToInteger( str ) );

    str = " @12345\t";

    printf( "\"%s\" = %d\n", str, StringToInteger( str ) );

    str = " 123@45\t";

    printf( "\"%s\" = %d\n", str, StringToInteger( str ) );
}

程序输出为

" -12345        " = -12345
" 12345 " = 12345
" 12345 A" = 0
" @12345        " = 0
" 123@45        " = 0
cwtwac6a

cwtwac6a3#

将字符串转换为整数(如果有足够的数字/字母/符号,则为任意基数)以表示该基数中的数字的函数。

int myisspace(int c)
{
    switch(c)
    {
        case ' ':
        case '\t':
        case '\r':
        case '\n':
        return 1;
    }
    return 0;
}

char *mystrchr(const char *str, const char ch)
{
    while(*str)
    {
        if(*str == ch) return str;
        str++;
    }
    return NULL;
}

int long long cnv(const char *str, unsigned base)
{
    const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    int sign = 1;
    int long long result = 0;

    if(str && (base >=2 && base < sizeof(digits)))
    {
        while(myisspace(*str)) str++;
        if(*str == '-' || *str == '+') { sign = *str == '-' ? -1 : 1; str++;}
    }
    while(*str)
    {
        //you may check for overflow as well
        //TODO integer overflow code if needed
        char *rch = mystrchr(digits, *str);
        if(!rch || (rch - digits) >= base)
        {
            if(!myisspace(*str))
            {
                result = 0;
                break;
            }
            else
            {
                *str++;
                continue;
            }
        }
        result *= base;
        result += rch - digits;
        str++;
    }
    return result * sign;
}

int main(void)
{
    printf("%lld\n", cnv("934", 10));
    printf("%lld\n", cnv("934", 12));
    printf("%lld\n", cnv("ffff", 16));
    printf("%lld\n", cnv("01100110011", 2));
    printf("%lld\n", cnv("      -01100110011", 2));
    printf("%lld\n", cnv("      -42313442323", 5));
    printf("%lld\n", cnv("      -42313442323      ", 12));
}

相关问题