Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/64.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/video/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 什么是正确的实施“良好”的方法;itoa();功能?_C_String_Char - Fatal编程技术网

C 什么是正确的实施“良好”的方法;itoa();功能?

C 什么是正确的实施“良好”的方法;itoa();功能?,c,string,char,C,String,Char,我想知道我对“itoa”函数的实现是否正确。也许你能帮我把它弄得更“正确”,我很确定我遗漏了什么。(可能已经有一个库按照我希望的方式进行转换,但是……找不到任何库) #包括 #包括 #包括 #包括 char*itoa(国际一级){ char*res=malloc(8*sizeof(int)); sprintf(res,“%d”,i); 返回res; } int main(int argc,char*argv[]){ ... 我认为您分配的内存可能太多了。malloc(8*sizeof(int))

我想知道我对“itoa”函数的实现是否正确。也许你能帮我把它弄得更“正确”,我很确定我遗漏了什么。(可能已经有一个库按照我希望的方式进行转换,但是……找不到任何库)

#包括
#包括
#包括
#包括
char*itoa(国际一级){
char*res=malloc(8*sizeof(int));
sprintf(res,“%d”,i);
返回res;
}
int main(int argc,char*argv[]){
...

我认为您分配的内存可能太多了。
malloc(8*sizeof(int))
将在大多数计算机上为您提供32字节,这对于int的文本表示可能太多了。

我可能会提出一些建议。您可以使用静态缓冲区和strdup来避免在后续调用中重复分配太多内存。我还将添加一些错误检查

main()
{
  int i=1234;
  char stmp[10];
#if _MSC_VER
  puts(_itoa(i,stmp,10));
#else
  puts((sprintf(stmp,"%d",i),stmp));
#endif
  return 0;
}
char *itoa(int i)
{
  static char buffer[12];

  if (snprintf(buffer, sizeof(buffer), "%d", i) < 0)
    return NULL;

  return strdup(buffer);
}
char*itoa(int i)
{
静态字符缓冲区[12];
如果(snprintf(缓冲区,sizeof(缓冲区),“%d”,i)<0)
返回NULL;
返回strdup(缓冲区);
}

如果将在多线程环境中调用此函数,请从缓冲区声明中删除“static”。

我不太确定从何处获得
8*sizeof(int)
作为最大可能的字符数--
ceil(8/(log(10)/log(2)))
产生的乘数为
3*
。此外,在C99和一些较旧的POSIX平台下,您可以使用
sprintf()
创建一个精确分配的版本:

HTH

这应该可以:

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

char * itoa_alloc(int x) {
   int s = x<=0 ? 1 ? 0; // either space for a - or for a 0
   size_t len = (size_t) ceil( log10( abs(x) ) );
   char * str = malloc(len+s + 1);

   sprintf(str, "%i", x);

   return str;
}
#包括
#包括
#包括
字符*itoa_alloc(整数x){

int s=x为此,应使用
printf
系列中的函数。如果要将结果写入
stdout
或文件,请使用
printf
/
fprintf
。否则,请使用
snprintf
,并使用足够大的缓冲区来容纳
3*sizeof(type)+2个字节或更多。

唯一的实际错误是没有检查
malloc
的返回值是否为null

名称
itoa
是一种非标准函数,但并不少见。它不分配内存,而是写入调用者提供的缓冲区:

char *itoa(int value, char * str, int base);
如果你不想依赖你的平台,我仍然建议你遵循这个模式。用C语言返回新分配内存的字符串处理函数通常比它们在长期运行中的价值要麻烦得多,因为大多数时候你会做进一步的操作,因此你必须释放大量的中间结果。例如,比较:

void delete_temp_files() {
    char filename[20];
    strcpy(filename, "tmp_");
    char *endptr = filename + strlen(filename);
    for (int i = 0; i < 10; ++i) {
        itoa(endptr, i, 10); // itoa doesn't allocate memory
        unlink(filename);
    }
}
下面是一个结合了snprintf风格的缓冲区长度方法:

int itobase10n(char *buf, size_t sz, int value) {
    return snprintf(buf, sz, "%d", value);
}

我发现了一个有趣的资源,涉及itoa实现的几个不同问题
你可能也想查一下

//还有一个很好的itoa实现
//返回:数字字符串的长度
int itoa(int值,字符*sp,int基数)
{
char tmp[16];//注意缓冲区的长度
char*tp=tmp;
int i;
无符号v;
整数符号=(基数==10&&value<0);
如果(签名)
v=-值;
其他的
v=(无符号)值;
while(v | | tp==tmp)
{
i=v%基数;
v/=radix;//v/=radix使用的CPU时钟比v=v/radix少
如果(i<10)
*tp++=i++'0';
其他的
*tp++=i++'a'-10;
}
int len=tp-tmp;
如果(签名)
{
*sp++='-';
len++;
}
而(tp>tmp)
*sp++=*--tp;
回程透镜;
}
//用法示例:
char int_str[15];//注意缓冲区的长度
int n=56789;
int len=itoa(n,int_str,10);

一个好的
int
到字符串或
itoa()
具有这些属性

  • 适用于所有
    [INT\u MIN…INT\u MAX]
    ,基本
    [2…36]
    ,无缓冲区溢出
  • 不假定
    int
    size
  • 不需要2的补码
  • 不要求
    unsigned
    的正范围大于
    int
    。换句话说,不使用
    unsigned
  • 允许对负数使用
    '-'
    ,即使
    base!=10
根据需要定制错误处理。(需要C99或更高版本):

char*itostr(char*dest,size\u t size,int a,int base){
//itostr需要的最大文本数(dest、size、INT_MIN、2)
字符缓冲区[a*char_位的大小+1+1];
静态常量字符数字[36]=“0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ”;
如果(基底<2 | |基底>36){
fprintf(stderr,“无效基”);
返回NULL;
}
//从末尾开始填充
char*p=&buffer[sizeof buffer-1];
*p='\0';
//使用负数'int`
intan=a<0?a:-a;
做{
*(-p)=位数[-(基数百分比)];
an/=基础;
}while(an);
if(a<0){
*(-p)='-';
}
size\u t size\u used=&buffer[sizeof(buffer)]-p;
如果(使用的尺寸>尺寸){
fprintf(标准,“不足缓冲区%zu>%zu”,使用的大小,大小);
返回NULL;
}
返回memcpy(目的地、p、使用的大小);
}

sprintf相当慢,如果性能很重要的话,它可能不是最好的解决方案

如果基参数是2的幂,转换可以通过移位和掩蔽来完成,并且可以通过记录最高位置的数字来避免字符串反转。例如,对于base=16,类似这样的情况

int  num_iter = sizeof(int) / 4;
常量字符数字[]={0',1',2',3',4',5',6',7',8',9',a',b',c',d',e',f'}

/* skip zeros in the highest positions */
int i = num_iter;
for (; i >= 0; i--)
{
    int digit = (value >> (bits_per_digit*i)) & 15;
    if ( digit > 0 )  break;
}

for (; i >= 0; i--)
{
    int digit = (value >> (bits_per_digit*i)) & 15;
    result[len++] = digits[digit];
}
对于小数,最好使用一个足够大的静态数组,以相反的顺序记录数字,请参见
  • 整数到ASCII需要从标准整数类型转换数据 转换为ASCII字符串
  • 所有操作都需要使用指针算法执行,而不是数组索引
  • 要转换的数字作为有符号32位整数传入
  • 你应该
    char *itobase10(char *buf, int value) {
        sprintf(buf, "%d", value);
        return buf;
    }
    
    int itobase10n(char *buf, size_t sz, int value) {
        return snprintf(buf, sz, "%d", value);
    }
    
    // Yet, another good itoa implementation
    // returns: the length of the number string
    int itoa(int value, char *sp, int radix)
    {
        char tmp[16];// be careful with the length of the buffer
        char *tp = tmp;
        int i;
        unsigned v;
    
        int sign = (radix == 10 && value < 0);    
        if (sign)
            v = -value;
        else
            v = (unsigned)value;
    
        while (v || tp == tmp)
        {
            i = v % radix;
            v /= radix; // v/=radix uses less CPU clocks than v=v/radix does
            if (i < 10)
              *tp++ = i+'0';
            else
              *tp++ = i + 'a' - 10;
        }
    
        int len = tp - tmp;
    
        if (sign) 
        {
            *sp++ = '-';
            len++;
        }
    
        while (tp > tmp)
            *sp++ = *--tp;
    
        return len;
    }
    
    // Usage Example:
    char int_str[15]; // be careful with the length of the buffer
    int n = 56789;
    int len = itoa(n,int_str,10);
    
    char* itostr(char *dest, size_t size, int a, int base) {
      // Max text needs occur with itostr(dest, size, INT_MIN, 2)
      char buffer[sizeof a * CHAR_BIT + 1 + 1]; 
      static const char digits[36] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    
      if (base < 2 || base > 36) {
        fprintf(stderr, "Invalid base");
        return NULL;
      }
    
      // Start filling from the end
      char* p = &buffer[sizeof buffer - 1];
      *p = '\0';
    
      // Work with negative `int`
      int an = a < 0 ? a : -a;  
    
      do {
        *(--p) = digits[-(an % base)];
        an /= base;
      } while (an);
    
      if (a < 0) {
        *(--p) = '-';
      }
    
      size_t size_used = &buffer[sizeof(buffer)] - p;
      if (size_used > size) {
        fprintf(stderr, "Scant buffer %zu > %zu", size_used , size);
        return NULL;
      }
      return memcpy(dest, p, size_used);
    }
    
    int  num_iter = sizeof(int) / 4;
    
    /* skip zeros in the highest positions */
    int i = num_iter;
    for (; i >= 0; i--)
    {
        int digit = (value >> (bits_per_digit*i)) & 15;
        if ( digit > 0 )  break;
    }
    
    for (; i >= 0; i--)
    {
        int digit = (value >> (bits_per_digit*i)) & 15;
        result[len++] = digits[digit];
    }
    
    uint8_t my_itoa(int32_t data, uint8_t *ptr, uint32_t base){
            uint8_t cnt=0,sgnd=0;
            uint8_t *tmp=calloc(32,sizeof(*tmp));
            if(!tmp){exit(1);}
            else{
                for(int i=0;i<32;i++){
                if(data<0){data=-data;sgnd=1;}
                if(data!=0){
                   if(data%base<10){
                    *(tmp+i)=(data%base)+48;
                    data/=base;
                   }
                   else{
                    *(tmp+i)=(data%base)+55;
                    data/=base;
                   }
                cnt++;     
                }
               }
            if(sgnd){*(tmp+cnt)=45;++cnt;}
            }
         my_reverse(tmp, cnt);
         my_memcopy(tmp,ptr,cnt);
         return ++cnt;
    }
    
    int32_t my_atoi(uint8_t *ptr, uint8_t digits, uint32_t base){
        int32_t sgnd=0, rslt=0;
        for(int i=0; i<digits; i++){
            if(*(ptr)=='-'){*ptr='0';sgnd=1;}
            else if(*(ptr+i)>'9'){rslt+=(*(ptr+i)-'7');}
            else{rslt+=(*(ptr+i)-'0');}
            if(!*(ptr+i+1)){break;}
            rslt*=base;
        }
        if(sgnd){rslt=-rslt;}
        return rslt;
    }