我想在动态分配的字符串中存储一个长值(LONG_MAX
在我的测试程序中),但是我混淆了需要为字符串中显示的数字分配多少内存
我的拳头尝试:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
int main(void)
{
char *format = "Room %lu somedata\n";
char *description = malloc(sizeof(char) * strlen(format) + 1);
sprintf(description, format, LONG_MAX);
puts(description);
return 0;
}
编译
gcc test.c
然后运行它(并将其管道输入hexdump):
./a.out | hd
返回
00000000 52 6f 6f 6d 20 39 32 32 33 33 37 32 30 33 36 38 |Room 92233720368|
00000010 35 34 37 37 35 38 30 37 20 62 6c 61 62 6c 61 0a |54775807 blabla.|
00000020 0a |.|
00000021
查看输出,似乎sizeof(char) * strlen(format) + 1
的内存分配是错误的(分配的内存太少)而且它的工作更加意外?
分配的正确金额是多少?
我的下一个想法是(伪代码):
sizeof(char) * strlen(format) + strlen(LONG_MAX) + 1
这看起来太复杂,非常不具体。或者我做错了什么?
答案 0 :(得分:3)
你这样做完全错了。 LONG_MAX是一个整数,因此您无法调用strlen()。并且它不是给出最长结果的数字,LONG_MIN是。因为它也会打印一个减号字符。
一个很好的方法是编写一个函数
char* mallocprintf (...)
与printf具有相同的参数,并返回使用具有完全正确长度的malloc分配的字符串。如何执行此操作:首先弄清楚va_list是什么以及如何使用它。然后弄清楚如何使用vsnprintf来找出printf的结果有多长没有实际打印。然后调用malloc,再次调用vsnprintf生成字符串。
这有一个很大的优势,它可以在您使用%s打印字符串时使用,或者使用%s使用一些大字段长度的字符串。猜猜%999999d打印了多少个字符。
答案 1 :(得分:3)
您可以使用snprintf()
计算长度,而无需担心LONG_MAX
的大小。
当你使用NULL
字符串调用snprintf时,如果它被写入缓冲区然后你确切地知道需要多少字节,它将返回一些所需的字节数。
char *format = "Room %lu somedata\n";
int len = snprintf(0, 0, format, LONG_MAX); // Returns the number of
//bytes that would have been required for writing.
char *description = malloc( len+1 );
if(!description)
{
/* error handling */
}
snprintf(description, len+1, format, LON_MAX);
答案 2 :(得分:3)
使用宏扩展将预定义的常量数值转换为字符串,如convert digital to string in macro中所述:
#define STRINGIZER_(exp) #exp
#define STRINGIZER(exp) STRINGIZER_(exp)
(代码由Whozcraig提供)。然后你可以使用
int max_digit = strlen(STRINGIZER(LONG_MAX))+1;
或
int max_digit = strlen(STRINGIZER(LONG_MIN));
表示签名值,
int max_digit = strlen(STRINGIZER(ULONG_MAX));
表示无符号值。
由于LONG_MAX
的值是编译时,而不是运行时值,因此可以确保为编译器写入正确的常量进入可执行文件。
答案 3 :(得分:1)
要分配足够的空间,请考虑最坏的情况
// Over approximate log10(pow(2,bit_width))
#define MAX_STR_INT(type) (sizeof(type)*CHAR_BIT/3 + 3)
char *format = "Room %lu somedata\n";
size_t n = strlen(format) + MAX_STR_INT(unsigned long) + 1;
char *description = malloc(n);
sprintf(description, format, LONG_MAX);
迂腐代码会考虑潜在的其他语言环境
snprintf(description, n, format, LONG_MAX);
但最后,建议使用2x缓冲区
char *description = malloc(n*2);
sprintf(description, format, LONG_MAX);
注意:使用说明符"%lu"
进行打印,适用于unsigned long
并在未定义的行为中传递long
LONG_MAX
。建议ULONG_MAX
sprintf(description, format, ULONG_MAX);
答案 4 :(得分:1)
@Jongware对答案给予了赞赏,我相信这样做的最终方法如下:
#define STRINGIZER_(exp) #exp
#define STRINGIZER(exp) STRINGIZER_(exp)
const size_t LENGTH = sizeof(STRINGIZER(LONG_MAX)) - 1;
字符串转换将其转换为字符串文字,因此附加一个空终止,因此为-1。
并不是因为一切都是编译时常量,你也可以简单地将字符串声明为
const char *format = "Room " STRINGIZER(LONG_MAX) " somedata\n";
答案 5 :(得分:0)
您无法使用该格式。你需要观察者
LONG_MAX = 2147483647 = 10 characters
"Room somedata\n" = 15 characters
添加Null = 26个字符
所以使用
malloc(26)
应该足够了。
答案 6 :(得分:0)
好吧,如果您的计算机上的long
是32位,则LONG_MAX
应为2147483647
,即10个字符长。您需要考虑到这一点,字符串的其余部分以及空字符。
请注意,long
是一个有符号值,最大值为LONG_MAX
,您正在使用%lu
(应该打印unsigned long
值)。如果您可以将带符号的值传递给此函数,则为减号添加一个附加字符,否则您可以使用ULONG_MAX
使其更清楚您的限制。
如果您不确定自己运行的是哪种体系结构,可以使用以下内容:
// this should work for signed 32 or 64 bit values
#define NUM_CHARS ((sizeof(long) == 8) ? 21 : 11)
或者,安全玩,只需使用21.:)
答案 7 :(得分:0)
你必须分配一个数字等于数字LONG_MAX的数字2147483647.你必须再分配10位数。
在你喜欢的格式字符串中
你必须使用malloc 26 chars
如果你想确定运行时人数如何编号,你必须编写一个数字来测试数字的函数:
while(n!=0)
{
n/=10; /* n=n/10 */
++count;
}
另一种方法是将临时sprintf结果存储在本地缓冲区和mallocate strlen(tempStr)+1个字符中。
答案 8 :(得分:0)
在这里,使用strlen(format)
来分配内存有点问题。考虑到%lu
字典,它将分配内存,而不是基于可以使用%lu
打印的值的词典宽度。
您应该考虑unsigned long
,
ULONG_MAX 4294967295
按字典顺序10
char
s。
所以,你要为
分配空间char
s),加上char
s(最多),%lu
的词典值,加上-
符号,如果值为负,加上答案 9 :(得分:0)
通常这是通过格式化为&#34;已知&#34;堆栈上有足够大的缓冲区,然后动态分配适合格式化字符串所需的任何内容。即:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
int main(void)
{
char buffer[1024];
sprintf(buffer, "Room %lu somedata\n", LONG_MAX);
char *description = malloc( strlen( buffer ) + 1 );
strcpy( description, buffer );
puts(description);
return 0;
}
答案 10 :(得分:0)
使用以下代码计算保存任何正整数的十进制表示所需的字符数:
#include <math.h>
...
size_t characters_needed_decimal(long long unsigned int llu)
{
size_t s = 1;
if (0LL != llu)
{
s += log10(llu);
}
return s;
}
注意在使用C-“string”存储数字时添加1,因为C-“string”是0
- 终止。
像这样使用:
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
size_t characters_needed_decimal(long long unsigned int);
int main(void)
{
size_t s = characters_needed_decimal(LONG_MAX);
++s; /* 1+ as we want a sign */
char * p = malloc(s + 1); /* add one for the 0-termination */
if (NULL == p)
{
perror("malloc() failed");
exit(EXIT_FAILURE);
}
sprintf(p, "%ld", LONG_MAX);
printf("LONG_MAX = %s\n", p);
sprintf(p, "%ld", LONG_MIN);
printf("LONG_MIN = %s\n", p);
free(p);
return EXIT_SUCCESS;
}
答案 11 :(得分:0)
最安全:
不是预测所需的分配,而是使用asprintf()
。此函数根据需要分配内存。
char *description = NULL;
asprintf(&description, "Room %lu somedata\n", LONG_MAX);
asprintf()
不是标准C,但在* nix中很常见,其源代码可用于容纳其他系统。