【问题标题】:Convert int to string in standard C在标准 C 中将 int 转换为字符串
【发布时间】:2016-03-29 03:31:21
【问题描述】:

我是 C 新手。

我正在寻找一个可以调用函数将int 转换为字符串的示例。我找到了itoa但这不是标准 C 的一部分。

我还找到了sprintf(str, "%d", aInt);,但问题是我不知道所需 str 的大小。因此,我怎样才能为输出字符串传递正确的大小

【问题讨论】:

  • 你在使用 gcc 吗? asprintf 是你的朋友。
  • 如果 aint 是 32 位(有符号或无符号)数量,则 12 个字符(10 位数字,符号,尾随空)就足够了。如果是 64 位有符号数,那么 21 个字符就足够了(19 位,符号,尾随空);对于没有符号的无符号量,21 就足够了,但有符号的则需要 22。通常的技巧是分配比必要的空间稍多的空间。您可以使用空字符串和零长度检查来自snprintf() 的返回值,以找到您需要多少空间。您可以按照建议查看asprintf(),但它是相当新的并且仍然具有有限的可移植性。

标签: c


【解决方案1】:

有一些最佳方法可以适当地调整数组的大小以解决sizeof(int) 的变化,但是乘以 4 就足以满足基数 10 的需求。对于 sizeof(int)==1 的边缘情况,需要 +1。

int x; // assign a value to x
char buffer[sizeof(int) * 4 + 1];
sprintf(buffer, "%d", x);

如果你需要从函数返回指向字符串的指针,你应该分配缓冲区而不是使用堆栈内存:

char* integer_to_string(int x)
{
    char* buffer = malloc(sizeof(char) * sizeof(int) * 4 + 1);
    if (buffer)
    {
         sprintf(buffer, "%d", x);
    }
    return buffer; // caller is expected to invoke free() on this buffer to release memory
}

【讨论】:

  • 谢谢...如果我把上面的代码放在一个函数中,这个函数应该返回什么,char * 或 char[]?
  • @user836026:你不能只从函数中返回一个数组。您需要将适当大小的数组传递给函数(最简单),或者您需要进行动态内存分配(使用malloc() 等 - 这更难)。如果传入数组,还要传递大小,并在函数内部使用snprintf() 以确保安全。如果你这样做了,你应该检查溢出错误——但是你应该检查大多数函数。
  • @user836026 - 乔纳森刚刚说的话。我更新了答案以显示如何使用 malloc 分配数组。
  • @selbie 谢谢。
  • @selbie 周围有 sizeof(int)==1 系统(它们的最小可寻址单元为 16 位或 32 位)。我猜代码应该是sizeof(int) * CHAR_BIT / 2
【解决方案2】:

在可移植 C 中,最简单的方法是使用 snprintf 计算所需数组的大小,然后使用 sprintf 进行实际转换。例如:

char buffer[snprintf(NULL, 0, "%d", x) + 1];
sprintf(buffer, "%d", x);

值得注意的是,这在 C99 之前不起作用,并且还有一个更简洁的替代方法,它在 C99 之前起作用并且是所有整数的类型通用。这在another answer to this question using the multiplication trick 中有描述,但是我注意到提出的技巧也不是严格可移植的。在CHAR_BIT 不是 8 的环境中(例如,某些 DSP 使用 16 位或 32 位字节),您需要更改乘数。

我提交了a similar trick in response to a different question。该代码使用CHAR_BIT 来确保可移植性,即使CHAR_BIT 发生更改。它以宏的形式呈现,因此它是内部文档;它告诉你高级描述是什么,单靠乘法是做不到的。

#include <limits.h>
#include <stddef.h>
#include <stdio.h>

#define digit_count(num) (1                                /* sign            */ \
                        + sizeof (num) * CHAR_BIT / 3      /* digits          */ \
                        + (sizeof (num) * CHAR_BIT % 3 > 0)/* remaining digit */ \
                        + 1)                               /* NUL terminator  */

int main(void) {
    short short_number = -32767;
    int int_number = 32767;
    char short_buffer[digit_count(short_number)] = { 0 };
    char int_buffer[digit_count(int_number)];
    sprintf(short_buffer, "%d", short_number);
    sprintf(int_buffer, "%d", int_number);
}

【讨论】:

  • +1 建议使用snprintf 来计算数组大小。然而,值得一提的是,这种行为在 C99 之前似乎并没有这样定义。来自man snprintfCONFORMING TO:“SUSv2 和 C99 相互矛盾:当使用 size=0 调用 snprintf() 时,SUSv2 规定了一个小于 1 的未指定返回值,而 C99 在这种情况下允许 str 为 NULL,并且将返回值(一如既往)作为在输出字符串足够大的情况下将被写入的字符数。"
  • @Will 是的,但只是一个小问题,我假设因为 SUS 现在使用更新的标准定义 C,除非使用 [SUSv2] 或 [C89] 标签,否则 C是 C99 或 C11。此外,VLA 不能在 C89 中工作......这可能会很好地延续到它后面的部分。我现在编辑:)
  • @Will 你觉得这个答案怎么样?
【解决方案3】:

使用C99 snprintf()。它会计算需要多少空间

int needed = snprintf(NULL, 0, "%s", value);
if (needed < 1) /* error */;
char *representation = malloc(needed + 1); // add 1 for '\0'
if (!representation) /* error */;
sprintf(representation, "%d", value);
// ... use representation ...
free(representation);

【讨论】:

    【解决方案4】:

    有一种方法可以不使用任何函数,例如这个(它可能有点原始,但仍然):

    char dec_rev[255];
    dec_rev[0] = '\0';
    int i = 0;
    
    while (val != 0) {
        int temp = val % 10;
        dec_rev[i] = temp + '0';
        //printf("%c\n", dec_rev[i]);
        val /= 10;
        if (val == 0) {
            dec_rev[i + 1] = '\0';
            break;
        }
        i++;
    }
    
    char dec[255];
    i = 0;
    for (int j = strlen(dec_rev) - 1; j != -1; j--) {
        dec[i] = dec_rev[j];
        i++;
    }
    

    毕竟我们将 int 存储在 dec[255] 中。

    【讨论】:

      【解决方案5】:

      奇怪的是这个没有提到,但是以10为底的int的表示大小是ceil(log10(value)); (或者log10整数版本,如果你想写的话)

      因此ceil(log10(5)) =&gt; 1

      ceil(log10(555)) =&gt; 3

      ceil(log10(1000000000)) => 9
      

      显然,如果您需要,您需要一个额外的空间来放置标志,而另一个空间用于“\0”。

      【讨论】:

        猜你喜欢
        • 2012-01-26
        • 1970-01-01
        • 1970-01-01
        • 2011-07-11
        • 2013-05-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多