C中的动态分配

时间:2010-05-18 10:02:46

标签: c memory-management

我正在编写程序,我遇到以下问题:

char *tmp;
sprintf (tmp,"%ld",(long)time_stamp_for_file_name);

有人可以解释为字符串tmp分配多少内存。

多少个字符是长变量?

谢谢,

我还希望能够获得关于此类信息的详尽资源的链接。

谢谢

更新:

使用您的示例我遇到了以下问题:

root@-[/tmp]$cat test.c

       #include <stdio.h>
       int
       main()
       {
            int len;
            long time=12345678;
            char *tmp;
            len=snprintf(NULL,0,"%ld",time);
            printf ("Lunghezza:di %ld %d\n",time,len);      
            return 0;
       }

root@-[/tmp]$gcc test.c
root@-[/tmp]$./a.out 
Lunghezza:di 12345678 -1
root@-[/tmp]$

因此snprintf的len结果为-1,我使用标准编译器在Solaris 9上编译。

请帮助我!

7 个答案:

答案 0 :(得分:6)

如果您的编译器符合C99,您应该能够:

char *tmp;
int req_bytes = snprintf(NULL, 0, "%ld",(long)time_stamp_for_file_name);
tmp = malloc(req_bytes +1); //add +1 for NULL
if(!tmp) {
    die_horrible_death();
}
if(snprintf(tmp, req_bytes+1, "%ld",(long)time_stamp_for_file_name) != req_bytes) {
    die_horrible_death();
}

标准的相关部分(来自draft document):

  • 7.19.6.5.2:如果n为零,则不写任何内容,s可能是空指针。
  • 7.19.6.5.3:snprintf函数返回已写入的字符数 已经足够大,不计算终止空字符,或负数 如果发生编码错误,则为value。因此,空终止输出已经 当且仅当返回的值是非负且小于n时才完全写入。

如果这不起作用,我猜你的编译器/ libc不支持c99的这一部分,或者你可能需要明确启用它。我运行你的例子(使用gcc版本4.5.0 20100610(预发布),Linux 2.6.34-ARCH),我得到了

$./example
Lunghezza:di 12345678 8

答案 1 :(得分:5)

事先很难说,虽然我猜你可以猜测它最多只能是64位,因此“18,446,744,073,709,551,615”应该是最大的可能值。这是2 + 6 * 3 = 20位数,通常不包括逗号。负数是21。所以,将32个字节作为一个漂亮的圆形大小。

最好将其与使用snprintf()结合使用,这样如果您的估算已关闭,则不会出现缓冲区溢出。

答案 2 :(得分:5)

实际使用的字符数明显取决于值:如果time_stamp_for_file_name为0,则实际上需要 2个字节。如果有任何疑问,可以使用snprintf,它会告诉您需要多少空间:

int len = snprinf(0, 0, "%ld", (long)time_stamp_for_file_name) + 1;
char *tmp = malloc(len);
if (tmp == 0) { /* handle error */ }
snprintf(tmp, len, "%ld", (long)time_stamp_for_file_name);

注意snprintf为空间不足而返回-1的实现,而不是所需的空间。

正如Paul R所说,你可以根据实现中long的大小确定一个固定的上限。这样就可以完全避免动态分配。例如:

#define LONG_LEN (((sizeof(long)*CHAR_BIT)/3)+2)

(基于10的base-2 log大于3的事实)。 +2给出1为减号,1给出整数除法向下舍入的事实。你需要另外1个nul终结符。

或者:

#define STRINGIFY(ARG) #ARG
#define EXPAND_AND_STRINGIFY(ARG) STRINGIFY(ARG)

#define VERBOSE_LONG EXPAND_AND_STRINGIFY(LONG_MIN)
#define LONG_LEN sizeof(VERBOSE_LONG)

char tmp[LONG_LEN];
sprintf(tmp, "%ld", (long)time_stamp_for_file_name);

VERBOSE_LONG可能比您实际需要的字符串稍大一些。在我的编译器上它是(-2147483647L-1)。我不确定LONG_MIN是否可以扩展为十六进制文字或编译器内在的东西,但如果是这样,那么它可能太短,这个技巧将无效。但是,单元测试很容易。

如果你想要一个紧密的上限来涵盖标准内的所有可能性,达到一定限度,你可以尝试这样的事情:

#if LONG_MAX <= 2147483647L
    #define LONG_LEN 11
#else
    #if LONG_MAX <= 4294967295L
        #define LONG_LEN 11
    #else
        #if LONG_MAX <= 8589934591L
            ... etc, add more clauses as new architectures are
                     invented with bigger longs
        #endif
    #endif
#endif

但我怀疑这是值得的:更好的方法是在某种可移植头中定义它并为新平台手动配置它。

答案 3 :(得分:3)

这取决于系统中long的大小。假设64位的最坏情况,则最多需要22个字符 - 这允许20个数字,前面的-和终止\0。当然,如果你感觉奢侈,你可以总是允许一点点额外的东西,并使它成为一个很好的圆形数字,如32。

答案 4 :(得分:2)

以log 2 10(~3.32)位表示十进制数字;因此,您可以像这样计算数字位数:

#include <limits.h>
#include <math.h>

long time;
double bitsPerDigit = log10(10.0) / log10(2.0); /* or log2(10.0) in C99 */
size_t digits = ceil((sizeof time * (double) CHAR_BIT) / bitsPerDigit);

char *tmp = malloc(digits+2); /* or simply "char tmp[digits+2];" in C99 */

“+2”表示符号和0终结符。

答案 5 :(得分:1)

八进制每三位需要一个字符。打印到10的基数,对于相同的数字,它从不给出比八进制更多的数字。因此,为每三位分配一个字符。

sizeof(long)在编译时为您提供字节数。乘以8得到位。在除以3之前添加两个,这样你就可以获得天花板而不是地板。请记住,C字符串需要最后的零字节,因此在结果中添加一个字节。 (另一个是否定的,如评论中所述)。

char tmp[(sizeof(long)*8+2)/3+2];
sprintf (tmp,"%ld",(long)time_stamp_for_file_name);

答案 6 :(得分:0)

3*sizeof(type)+2是将整数类型type格式化为十进制字符串所需的字节数的安全通用规则,原因是3是log10(256)的上限并且n字节整数是base-256中的n个数字,因此基数为10的ceil(log10(256^n))==ceil(n*log10(256))个数字。+2用于说明终止NUL字节和可能的减号如果type非常小。

如果你想成为迂腐的人并且使用CHAR_BIT!=8支持DSP等,那么请使用3*sizeof(type)*((CHAR_BIT+7)/8)+2。 (请注意,对于POSIX系统,这是无关紧要的,因为POSIX需要UCHAR_MAX==255CHAR_BIT==8。)