Dynamic allocation in C
I'm writing开发者_Python百科 a program and I have the following problem:
char *tmp;
sprintf (tmp,"%ld",(long)time_stamp_for_file_name);
Could someone explain how much memory allocate for the string tmp.
How many chars are a long variable?
Thank you,
I would appreciate also a link to an exahustive resource on this kind of information.
Thank you
UPDATE:
Using your examples I got the following problem:
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]$
So the len result from snprintf is -1, I compiled on Solaris 9 with the standard compiler.
Please help me!
If your compiler conforms to C99, you should be able to do:
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();
}
Relevant parts of the standard (from the draft document):
- 7.19.6.5.2: If n is zero, nothing is written, and s may be a null pointer.
- 7.19.6.5.3: The snprintf function returns the number of characters that would have been written had n been sufficiently large, not counting the terminating null character, or a negative value if an encoding error occurred. Thus, the null-terminated output has been completely written if and only if the returned value is nonnegative and less than n.
If this is not working, I'm guessing your compiler/libc does not support this part of c99, or you might need to explicitly enable it. Wh I run your example (with gcc version 4.5.0 20100610 (prerelease), Linux 2.6.34-ARCH), I get
$./example
Lunghezza:di 12345678 8
The number of chars actually used obviously depends on the value: if time_stamp_for_file_name
is 0 you only actually need 2 bytes. If there's any doubt, you can use snprintf
, which tells you how much space you need:
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);
Beware implementations where snprintf
returns -1 for insufficient space, rather than the space required.
As Paul R says, though, you can figure out a fixed upper bound based on the size of long
on your implementation. That way you avoid dynamic allocation entirely. For example:
#define LONG_LEN (((sizeof(long)*CHAR_BIT)/3)+2)
(based on the fact that the base-2 log of 10 is greater than 3). That +2 gives you 1 for the minus sign and 1 for the fact that integer division rounds down. You'd need another 1 for the nul terminator.
Or:
#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
might be a slightly bigger string than you actually need. On my compiler it's (-2147483647L-1)
. I'm not sure whether LONG_MIN
can expand to something like a hex literal or a compiler intrinsic, but if so then it could be too short, and this trick won't work. It's easy enough to unit-test, though.
If you want a tight upper bound to cover all possibilities within the standard, up to a certain limit, you could try something like this:
#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
But I doubt it's worth it: better just to define it in some kind of portability header and configure it manually for new platforms.
It's hard to tell in advance, although I guess you could guesstimate that it'll be at the most 64 bits, and thus "18,446,744,073,709,551,615" should be the largest possible value. That's 2+6*3 = 20 digits, the commas are generally not included. It'd be 21 for a negative number. So, go for 32 bytes as a nice and round size.
Better would be to couple that with using snprintf()
, so you don't get a buffer overflow if your estimate is off.
It depends on how big long
is on your system. Assuming a worst case of 64 bits then you need 22 characters max - this allows for 20 digits, a preceding -
and a terminating \0
. Of course if you're feeling extravagant you could always allow a little extra and make it a nice round number like 32.
It takes log210 (~3.32) bits to represent a decimal digit; thus, you can compute the number of digits like so:
#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 */
The "+2" accounts for sign and the 0 terminator.
Octal requires one character per three bits. You print to base of ten which never gives more digits than octal for same number. Therefore, allocate one character for each three bits.
sizeof(long) gives you amount of bytes when compiling. Multiply that by 8 to get bits. Add two before dividing by three so you get ceiling instead of floor. Remember the C strings want a final zero byte to their end, so add one to the result. (Another one for negative, as described in comments).
char tmp[(sizeof(long)*8+2)/3+2];
sprintf (tmp,"%ld",(long)time_stamp_for_file_name);
3*sizeof(type)+2
is a safe general rule for the number of bytes needed to format an integer type type
as a decimal string, the reason being that 3 is an upper bound on log10(256)
and a n
-byte integer is n
digits in base-256 and thus ceil(log10(256^n))==ceil(n*log10(256))
digits in base 10. The +2
is to account for the terminating NUL byte and possible minus sign if type
is very small.
If you want to be pedantic and support DSPs and such with CHAR_BIT!=8
then use 3*sizeof(type)*((CHAR_BIT+7)/8)+2
. (Note that for POSIX systems this is irrelevant since POSIX requires UCHAR_MAX==255
and CHAR_BIT==8
.)
精彩评论