为char数组分配内存以连接已知的文本和整数

我想连接一段文本,例如“答案是”带有符号整数,给出输出“数字是42”。

我知道这段文字有多长(14个字符),但我不知道该字符串表示的字符数是多少。

我假设最坏的情况,最大的有符号16位整数有5位数,如果它是负数,还有一个额外的,所以下面的代码是正确的方法吗?

#include  #include  int main() { char *message; message = malloc(14*sizeof(char)+(sizeof(int)*5)+1); sprintf(message, "The answer is %d", 42); puts(message); free(message); } 

使用:

 malloc(14*sizeof(char) /*for the 14 char text*/ +(sizeof(char)*5) /*for the magnitude of the max number*/ +1 /* for the sign of the number*/ +1 /* for NULL char*/ ); 

由于数字将表示为char,因此您必须使用sizeof(char)而不是sizeof(int)。

不完全是,您只需要多个字符,因此不需要sizeof(int)

但是,对于易于维护和可移植的代码,您应该具有以下内容:

 #define TEXT "The answer is " #undef CHARS_PER_INT #if INT_MAX == 32767 #define CHARS_PER_INT 6 #endif #if INT_MAX == 2147483647 #define CHARS_PER_INT 11 #endif #ifndef CHARS_PER_INT #error Suspect system, I have no idea how many chars to allocate for an int. #endif int main (void) { char *message; message = malloc(sizeof(TEXT)+CHARS_PER_INT+1); sprintf(message, TEXT "%d", 42); puts(message); free(message); return 0; } 

这有许多优点:

  • 如果更改字符串,则只更改一件事和一件事。 malloc的参数自动调整。
  • 表达式sizeof(TEXT)+CHARS_PER_INT+1在编译时计算。 涉及strlen的解决方案将具有运行时成本。
  • 如果您尝试在整数可能导致溢出的系统上编译代码,您将被告知它(修复代码)。
  • 实际上,您应该为该数字分配一个额外的字符,因为最大的16位数字(就字符数而言)是-32768 (长度为六个字符)。 您会注意到我最后仍然有一个+1 – 这是因为您需要空格作为字符串null终止符。

使用stdio函数本身的一种方法(不一定推荐)为您提供字符数的确切大小。

例如,如果在分配内存之前打印数字(某处,无论出于何种原因),则可以将%n格式标识符与printf%n不打印任何东西; 相反,你为它提供了一个指向int的指针, printf填充了到目前为止已写入多少个字符的指针。

另一个例子是snprintf ,如果有的话。 您将它想要写入字符串的最大字符数传递给它,并返回它应该写入的字符数,而不是最后的nul。 (或者错误时为-1。)因此,使用1字节的虚拟字符串, snprintf可以准确地告诉您您的数字是多少字符。

使用这些函数的一大优势是,如果您决定更改数字的格式(前导0,填充空格,八进制输出,long long,等等),您将不会超出内存。

如果你有stdio GNU扩展,你可能要考虑使用asprintf 。 这和sprintf完全一样,除了它为你做内存分配! 无需组装。 (虽然你确实需要自己释放它。)但你不应该依赖它来携带它。

malloc((14 + 6 + 1) * sizeof(char));

  • 14字符串的字符串
  • 6为de数字+符号
  • 1为’\ 0′

注意:Sizeof(int)为您提供byes中类型的大小。 如果int是32位,则sizeof(int)== 4,如果是64位,则为8。

我认为获得整数十进制表示的最大长度的正确公式是(floor(log10(INT_MAX))+ 1); 您也可以通过这种方式滥用预处理器:

 #include  #define TOSTRING_(x) #x #define TOSTRING(x) TOSTRING_(x) /* ... */ #define YOUR_MESSAGE "The answer is " char message[]=YOUR_MESSAGE "+" TOSTRING(INT_MAX); sprintf(message+sizeof(YOUR_MESSAGE),"%d", 42); 

,这也避免了堆分配。 您可能希望使用snprintf以获得更好的安全性,尽管使用此方法它不是必需的。

像这样的另一个技巧是创建这样的函数:

 size_t GetIntMaxLenght() { const char dummy[]=TOSTRING(INT_MAX); return sizeof(dummy)+1; } 

如果编译器足够智能,它可以完全扫除编译代码中的虚拟 var,否则将var声明为静态可能是明智的,以避免每次调用函数时重新初始化它。

signed int安全近似值是(包括潜在符号的位数):

 (CHAR_BIT * sizeof(int) + 1) / 3 + 1 

unsigned的等价物是:

 (CHAR_BIT * sizeof(unsigned) + 2) / 3 

这计算了位数 – 如果为空终止字符串分配空间,则为其添加一个以计算终结符。

这将略微高估非常长类型所需的空间(并且在int具有填充位的特殊情况下也会高估),但是它是一个很好的近似并且具有编译时常量的优点。 CHAR_BIT