我想知道我执行"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[]) {
...
Run Code Online (Sandbox Code Playgroud)
小智 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);
Run Code Online (Sandbox Code Playgroud)
唯一的实际错误是您没有检查malloc
null 的返回值.
这个名称itoa
已经被用于非标准的功能,但并非罕见.它不分配内存,而是写入调用者提供的缓冲区:
char *itoa(int value, char * str, int base);
Run Code Online (Sandbox Code Playgroud)
如果你不想依赖你的平台,我仍然建议遵循这种模式.在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);
}
}
Run Code Online (Sandbox Code Playgroud)
与
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);
}
}
Run Code Online (Sandbox Code Playgroud)
如果您有理由特别关注性能(例如,如果您正在实现stdlib样式库,包括itoa
),或者如果您实现的是sprintf
不支持的库,那么您可能会考虑不调用sprintf
.但是如果你想要一个基数为10的字符串,那么你的第一直觉是正确的.%d
格式说明符绝对没有"不正确" .
以下是itoa
仅对基数10 的可能实现:
char *itobase10(char *buf, int value) {
sprintf(buf, "%d", value);
return buf;
}
Run Code Online (Sandbox Code Playgroud)
这是一个将snprintf风格的方法结合到缓冲区长度的方法:
int itobase10n(char *buf, size_t sz, int value) {
return snprintf(buf, sz, "%d", value);
}
Run Code Online (Sandbox Code Playgroud)
一个好的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);
}
Run Code Online (Sandbox Code Playgroud)