我想连接一段文本,例如“答案是”,带有符号整数,输出“数字是42”。
我知道这段文字有多长(14个字符),但我不知道该字符串表示的字符数是多少。
我假设最坏的情况,最大的有符号16位整数有5位数,如果它是负数,还有一个额外的,所以下面的代码是正确的方法吗?
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *message;
message = malloc(14*sizeof(char)+(sizeof(int)*5)+1);
sprintf(message, "The answer is %d", 42);
puts(message);
free(message);
}
答案 0 :(得分:7)
使用:
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)。
答案 1 :(得分:3)
不完全是,您只需要多个字符,因此不需要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
的解决方案会产生运行时成本。-32768
(六个字符长)。你会注意到我仍然在最后有一个+1
- 那是因为你需要空格来表示字符串null终止符。答案 2 :(得分:1)
使用stdio
函数本身的一种方法(不一定推荐)为您提供字符数的确切大小。
例如,如果在分配内存之前打印号码(无论出于何种原因),可以将%n
格式标识符与printf
一起使用。 %n
不打印任何内容;相反,你为它提供了一个指向int
的指针,而printf
填充了到目前为止已写入了多少个字符。
另一个例子是snprintf
,如果有的话。您将它希望它写入字符串的最大字符数传递给它,并返回应该写入的字符数,而不是最后的nul。 (或者错误时为-1。)因此,使用1字节的虚拟字符串,snprintf
可以准确地告诉您您的号码是多少字符。
使用这些函数的一大优势是,如果您决定更改数字的格式(前导0,填充空格,八进制输出,long long,等等),您将不会超出内存。
如果您拥有stdio
的GNU扩展程序,则可能需要考虑使用asprintf
。这与sprintf
完全相同,除了它为您分配内存!无需组装。 (虽然你确实需要自己释放它。)但你不应该依赖它来携带它。
答案 3 :(得分:0)
malloc((14 + 6 + 1) * sizeof(char));
注意:Sizeof(int)为您提供byes中类型的大小。如果int是32位,则sizeof(int)== 4,如果是64位,则为8。
答案 4 :(得分:0)
我认为获得整数十进制表示的最大长度的正确公式是(floor(log10(INT_MAX))+ 1);你也可以用这种方式滥用预处理器:
#include <limits.h>
#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;
}
如果编译器足够智能,它可以完全扫除编译代码中的 dummy var,否则将var声明为static是明智的,以避免每次调用函数时重新初始化它
答案 5 :(得分:0)
签名int
的安全近似值是(包含潜在-
符号的位数):
(CHAR_BIT * sizeof(int) + 1) / 3 + 1
unsigned
的等价物是:
(CHAR_BIT * sizeof(unsigned) + 2) / 3
这计算了位数 - 如果为空终止字符串分配空间,则为它们添加一个以计算终结符。
这将稍微高估了很长类型所需的空间(并且在int
具有填充位的异常情况下也会高估),但是它是一个很好的近似并具有优势它是一个编译时常量。 CHAR_BIT
由<limits.h>
提供。{/ p>