C 什么是正确的实施“良好”的方法;itoa();功能?
我想知道我对“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))
#包括
#包括
#包括
#包括
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;
}