我想知道我执行“itoa”功能是否正确。也许你可以帮我把它变得更“正确”,我很确定我错过了什么。 (也许已经有一个库按照我希望的方式进行转换,但是......找不到任何内容)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
char * itoa(int i) {
char * res = malloc(8*sizeof(int));
sprintf(res, "%d", i);
return res;
}
int main(int argc, char *argv[]) {
...
答案 0 :(得分:11)
// 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);
答案 1 :(得分:7)
唯一的实际错误是您没有检查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);
}
}
VS
void delete_temp_files() {
char filename[20];
strcpy(filename, "tmp_");
char *endptr = filename + strlen(filename);
for (int i = 0; i < 10; ++i) {
char *number = itoa(i, 10); // itoa allocates memory
strcpy(endptr, number);
free(number);
unlink(filename);
}
}
如果您有理由特别关注性能(例如,如果您正在实现包含itoa
的stdlib样式库),或者您正在实现sprintf
不支持的基础,那么你可能会考虑不调用sprintf
。但是如果你想要一个基数为10的字符串,那么你的第一直觉是正确的。关于%d
格式说明符绝对没有“错误”。
以下是itoa
的可能实现,仅适用于基数10:
char *itobase10(char *buf, int value) {
sprintf(buf, "%d", value);
return buf;
}
这是一个将snprintf风格的方法结合到缓冲区长度的方法:
int itobase10n(char *buf, size_t sz, int value) {
return snprintf(buf, sz, "%d", value);
}
答案 2 :(得分:3)
我认为你分配的内存太多了。 malloc(8*sizeof(int))
将在大多数机器上提供32个字节,这对于int的文本表示来说可能过多。
答案 3 :(得分:3)
好的int
到字符串或itoa()
具有以下属性;
[INT_MIN...INT_MAX]
,基础[2...36]
,无缓冲区溢出。int
大小。 unsigned
的正范围大于int
。换句话说,不使用unsigned
。 '-'
用于否定号码,即使base != 10
。根据需要定制错误处理。 (需要C99或更高版本):
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);
}
答案 4 :(得分:2)
我不太确定8*sizeof(int)
作为最大可能字符数的位置 - ceil(8 / (log(10) / log(2)))
会产生3*
的乘数。此外,在C99和一些较旧的POSIX平台下,您可以使用sprintf()
创建精确分配的版本:
char *
itoa(int i)
{
int n = snprintf(NULL, 0, "%d", i) + 1;
char *s = malloc(n);
if (s != NULL)
snprintf(s, n, "%d", i);
return s;
}
HTH
答案 5 :(得分:2)
我找到了一个有趣的资源来处理itoa实现的几个不同问题 你可能也想看一下 itoa() implementations with performance tests
答案 6 :(得分:1)
为此,您应该在printf
系列中使用一个函数。如果您要将结果写入stdout
或文件,请使用printf
/ fprintf
。否则,请使用snprintf
缓冲区,其大小足以容纳3*sizeof(type)+2
个字节或更多。
答案 7 :(得分:1)
sprintf非常慢,如果性能很重要,它可能不是最好的解决方案。
如果基本参数是2的幂,则可以通过移位和屏蔽来完成转换,并且可以通过记录最高位置的数字来避免反转字符串。例如,base = 16
这样的东西int num_iter = sizeof(int) / 4;
const char digits [] = {&#39; 0&#39;,&#39; 1&#39;,&#39; 2&#39;,&#39; 3&#39;,&#39; 4&#39;,&#39; 5&#39;,&#39; 6&#39;,&#39; 7&#39;,&#39; 8&#39;,&#39; 9&#39;, &#39; a&#39;,&#39;&#39;&#39; c&#39;,&#39; d&#39;,&#39; e&#39;,&#39; f& #39;};
/* 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];
}
对于小数,有一个很好的想法是使用足够大的静态数组以相反的顺序记录数字,请参阅here
答案 8 :(得分:1)
。
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;
}
答案 9 :(得分:0)
我可能会提出一些建议。您可以使用静态缓冲区和strdup来避免在后续调用中重复分配过多内存。我还会添加一些错误检查。
char *itoa(int i)
{
static char buffer[12];
if (snprintf(buffer, sizeof(buffer), "%d", i) < 0)
return NULL;
return strdup(buffer);
}
如果在多线程环境中调用它,请从缓冲区声明中删除“static”。
答案 10 :(得分:0)
这应该有效:
#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;
}
如果您不想使用数学/浮点函数(并且必须在数学库中链接),您应该能够通过搜索Web找到log10的非浮点版本并执行:< / p>
size_t len = my_log10(abs(x))+ 1;
这可能比你需要多1个字节,但你已经足够了。
答案 11 :(得分:-1)
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;
}