c - char array isn't printing every value - c

I am currently creating an encryption/decryption application as practice, and to do that I have been trying to convert an integer into a char array using snprintf however, for example, if I have an integer with 4 digits, it only adds the first 3. Here is my code so far:
int encrypt(int num, bool type)
{
char buffer[sizeof(num)];
snprintf(buffer, sizeof(buffer), "%d", num);
printf(buffer);
return 0;
}
Any help would be awesome!

The buffer should have a size large enough to hold the digits of the conversion plus a final '\0' and a potential minus sign. sizeof(num) is the number of bytes for the int variable, most likely 4, not enough for the conversion of numbers larger than 999, but snprintf will not write more than the size of the buffer including the final '\0', hence only the first 3 digits.
You can either make an assumption on the size of int and define buffer as:
char buffer[12]; /* large enough for -2147483648 */
Or you can do it precisely and portably:
char buffer[sizeof(num) * CHAR_BIT / 3 + 3];

Related

Function is returning a different value every time?

I'm trying to convert a hexadecimal INT to a char so I could convert it into a binary to count the number of ones in it. Here's my function to convert it into char:
#include <stdio.h>
#include <stdlib.h>
#define shift(a) a=a<<5
#define parity_even(a) a = a+0x11
#define add_msb(a) a = a + 8000
void count_ones(int hex){
char *s = malloc(2);
sprintf(s, "0x%x", hex);
free(s);
printf("%x", s);
};
int main() {
int a = 0x01B9;
shift(a);
parity_even(a);
count_ones(a);
return 0;
}
Every time I run this, i always get different outputs but the first three hex number are always the same. Example of outputs:
8c0ba2a0
fc3b92a0
4500a2a0
d27e82a0
c15d62a0
What exactly is happening here? I allocated 2 bytes for the char since my hex int is 2 bytes.
It's too long to write a comment so here goes:
I'm trying to convert a hexadecimal INT
int are stored as a group of value, padding (possible empty) and sign bits, so is there no such thing as a hexadecimal INT but you can represent (print) a given number in the hexadecimal format.
convert a ... INT to a char
That would be lossy conversion as an int might have 4 bytes of data that you are trying to cram into a 1 byte. char specifically may be signed or unsigned. You probably mean string (generic term) or char [] (standard way to represent a string in C).
binary to count the number of ones
That's the real issue you are trying to solve and this is a duplicate of:
How to count the number of set bits in a 32-bit integer?
count number of ones in a given integer using only << >> + | & ^ ~ ! =
To address the question you ask:
Need to allocate more than 2 bytes. Specifically ceil(log16(hex)) + 2 (for 0x) + 1 (for trailing '\0').
One way to get the size is to just ask snprintf(s, 0, ...)
then allocate a suitable array via malloc (see first implementation below) or use stack allocated variable length array (VLA).
You can use INT_MAX instead of hex to get an upper
bound. log16(INT_MAX) <= CHAR_BIT * sizeof(int) / 4 and the
latter is a compile time constant. This means you can allocate your string on stack (see 2nd implementation below).
It's undefined behavior to use a variable after it's deallocated. Move free() to after the last use.
Here is one of the dynamic versions mentioned above:
void count_ones(unsigned hex) {
char *s = NULL;
size_t n = snprintf(s, 0, "0x%x", hex) + 1;
s = malloc(n);
if(!s) return; // memory could not be allocated
snprintf(s, n, "0x%x", hex);
printf("%s (size = %zu)", s, n);
free(s);
};
Note, I initialized s to NULL which would cause the first call to snprintf() to return an undefined value on SUSv2 (legacy). It's well defined on c99 and later. The output is:
0x3731 (size = 7)
And the compile-time version using a fixed upper bound:
#include <limits.h>
// compile-time
void count_ones(unsigned hex) {
char s[BIT_CHAR * sizeof(int) / 4 + 3];
sprintf(s, "0x%x", hex);
printf("%s (size = %zu)", s, n);
};
and the output is:
0x3731 (size = 11)
Your biggest problem is that malloc isn't allocating enough. As Barmar said, you need at least 7 bytes to store it or you could calculate the amount needed. Another problem is that you are freeing it and then using it. It is only one line after the free that you use it again, which shouldn't have anything bad happen like 99.9% of the time, but you should always free after you know you are done using it.

Determine size of char array to convert numbers with the preprocessor

I'm facing this simple "problem" literally every day and don't yet have a good solution for it:
char text[STRING_LENGTH + 1] = "";
int32_t number = -12312313;
itoa(number, text, 10); //or sprintf(text, "%d", number);
How do I determine STRING_LENGTH in the preprocessor? STRING_LENGTH should be the maximum length, the type to convert could produce. In my case int32_t => 11.
Surely, I could do something like this:
#define INT32_STRING_LENGTH 11
#define UINT32_STRING_LENGTH 10
//...
but it seems like there should already be a solution to this out there.
It's also an option to use snprintf in that case, but that would calculate the length while the application is already running. There's really no need to do this while running (if you have some spare-bytes):
int32_t number = -12312313;
char text[snprintf(NULL, 0, "%d", number) + 1];
snprintf(text, sizeof(text), "%d", number);
Maybe there's a solution using "%d", "%lu", ...?
Please correct me, if I'm wrong with anything I mentioned here.
Thanks in advance!
The GNU Portability Library has an amazing single header intprops part which has some amazing code available from github/coreutils/gnulib/intprops.h. The header contains INT_BUFSIZE_BOUND and INT_STRLEN_BOUND:
/* Bound on buffer size needed to represent an integer type or expression T,
including the terminating null. T must not be a bit-field expression. */
#define INT_BUFSIZE_BOUND(t) (INT_STRLEN_BOUND (t) + 1)
The documentation with usage example is available in the documentation https://www.gnu.org/software/gnulib/manual/html_node/Integer-Bounds.html :
INT_BUFSIZE_BOUND (t) is an integer constant expression that is a
bound on the size of the string representing an integer type or
expression t in decimal notation, including the terminating null
character and any leading - character. For example, if
INT_BUFSIZE_BOUND (int) is 12, any value of type int can be
represented in 12 bytes or less, including the terminating null. The
bound is not necessarily tight.
Example usage:
#include <intprops.h>
#include <stdio.h>
int
int_strlen (int i)
{
char buf[INT_BUFSIZE_BOUND (int)];
return sprintf (buf, "%d", i);
}
Note that the header is under GNU Lesser General Public License. Remember to copy the header with license and distribute your software with some contribution and license. Then just:
int32_t number = -12312313;
char text[INT_BUFSIZE_BOUND(int32_t)];
// or [INT_BUFSIZE_BOUND(-12312313)];
sprintf(text, "%"PRId32, number);
Note that %d may be invalid for int32_t. Use standard PRId32 from inttypes.h.
The heart of the implementation is this nice function, that can be used to basically calculate log10 of a number as a constant expression:
/* Bound on length of the string representing an unsigned integer
value representable in B bits. log10 (2.0) < 146/485. The
smallest value of B where this bound is not tight is 2621. */
#define INT_BITS_STRLEN_BOUND(b) (((b) * 146 + 484) / 485)
So basically to get maximum buffer size length, get the number of bits for a type, calculate * 146 + 484) / 485) of that number of bits, add +1 for minus sign and add +1 for zero terminating byte - that's the number of bytes that you need.

Size of formatted string

I am struggling to understand what happens during snprintf.
Let's say I have two numbers:
int i =11; int k = 3;
I want to format them like this "[%02d] %03d\t" and use snprintf.
Afterwards I use the resulting string with write().
snprintf needs the length/bytes n.
I do not understand what is the length I need to provide...
I have 2 theories:
a) It is
sizeof(int)*2
b) I check how many chars the formatted string will contain by counting the digits of the two integers and adding the other chars that the output will have:
2*sizeof(char) + 1*sizeof(char) + 2*sizeof(char) + 3*sizeof(char)+ 1*sizeof(char)
-> digits of i + digits of k + zeros added to first int + zeros added to second int + tab
I am struggling to understand what is the "n" I have to give to snprintf
It is the buffer size
According to a documentation:
Maximum number of bytes to be used in the buffer. The generated string
has a length of at most n-1, leaving space for the additional
terminating null character. size_t is an unsigned integral type.
Suppose you write to an array such as this:
char buf[32];
The buffer can hold 32 chars (including the null terminator). Therefore we call the function like this:
snprintf (buf, 32, "[%02d] %03d\t", i, k);
You can also check the return value to see how many chars have been written (or would have been written). In this case, if it's bigger than 32, then that would mean that some characters had to be discarded because they didn't fit.
Pass 0 and NULL first to obtain an exact amount
int n = snprintf(NULL, 0, "[%02d] %03d\t", i, k);
Then you know you need n + 1
char *buf = malloc(n + 1);
snprintf(buf, n + 1, "[%02d] %03d\t", i, k);
free(buf);
See it on ideone: https://ideone.com/pt0cOQ
n is the size of the string you're passing into snprintf, so it knows when to stop writing to the buffer. This is to prevent a category of errors knows as buffer overflows. snprintf will write n - 1 characters into the passed-in buffer and then terminate it with the null character.

Determining character array size effeciently to use snprintf()

We have a small assignment from college that requires us to perform some job X in C.
Part of that problem is to convert an unsigned long number, that is generated in the course of the program and hence without any way to predetrmine it, to a string. Naturally, i made use of snprintf. I initialized an array (str[50]) that was generously sized to avoid any sort of buffer errors.
On submission, however, my professor said that my method of avoiding buffer errors was ineffecient.
My question now is, when i create an char array to hold the unsigned long value, what size do i make it as? Is there some C macro to help determind the max number of characters that an unsigned long can hold?
something maybe like,
char str[MAX_NUMBER_OF_DIGITS_OF_UNSIGNED_LONG_ON_MACHINE];
I've skimmed throught limits.h and a few blogs and this forum but with no accord. Any help would be appreciated!
Go with #BLUEPIXY for brevity.
A deeper answer.
C allows various "locales" such that, in theory, snprintf(..., "%lu",...) could print a longer string than expected. Instead of "1234567", the output could be "1,234,567".
Recommend:
1. Determine the size in bits, n, of the maximum integer.
2. n * log2(10) rounded-up + 1 to get then char count.
3. Set-up a buffer that is 2x max need.
4. Check snprintf result.
5. Niche concern: Using the double call with snprintf() needs to insure the "locale" and number do not change between calls - not use here as snprintf() is a functionally expensive call.
char *ulong_to_buf(char *buf, size_t size, unsigned long x) {
int n = snprintf(buf, size, "%lu", x);
if (n < 0 || n >= size) return NULL;
return buf;
}
// Usage example
void foo(unsigned long x)
// 1/3 --> ~log2(10)
#define ULONG_PRT_LEN (sizeof(unsigned long)*CHAR_BIT/3 + 2)
char buf[ULONG_PRT_LEN*2 + 1]; // 2x for unexpected locales
if (ulong_to_buf(, sizeof buf, x)) {
puts(buf);
}
If code is really concerned, simple write your own
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#define PRT_ULONG_SIZE (sizeof(unsigned long) * CHAR_BIT * 10 / 33 + 3)
char *ulong_strnull(int x, char *dest, size_t dest_size) {
char buf[PRT_ULONG_SIZE];
char *p = &buf[sizeof buf - 1];
// Form string
*p = '\0';
do {
*--p = x % 10 + '0';
x /= 10;
} while (x);
size_t src_size = &buf[sizeof buf] - p;
if (src_size > dest_size) {
// Not enough room
return NULL;
}
return memcpy(dest, p, src_size); // Copy string
}
#if ULONG_MAX == 4294967295UL
# define SIZE (10 + 1)
#elif ULONG_MAX <= 18446744073709551615ULL
# define SIZE (20 + 1)
#endif
From the documetation for snprintf:
Concerning the return value of snprintf(), SUSv2 and C99
contradict
each other: when snprintf() is called with size=0 then SUSv2 stipulates
an unspecified return value less than 1, while C99 allows str to be
NULL in this case, and gives the return value (as always) as the number
of characters that would have been written in case the output string
has been large enough.
If you are using C99 you can determine the size using snprintf (as BLUEPIXY commented):
int size = snprintf(NULL, 0, "%lu", ULONG_MAX);
However if you can't use C99 then you can determine the string size by determining how many digits you require and adding an additional character for the terminating \0 character:
int size = (int) log10((double) ULONG_MAX) + 1;
In order to allocate your array with size bytes you can simply use
char str[size];
However this only works if your compiler/version supports VLAs, if you compiler doesn't support this you can dynamically allocate the array with
char *str = malloc(size); //< Allocate the memory dynamically
// TODO: Use the str as you would the character array
free(str); //< Free the array when you are finished

How much space to allocate for printing long int value in string?

I want to store a long value (LONG_MAX in my test program) in a dynamically allocated string, but I'm confused how much memory I need to allocate for the number to be displayed in the string.
My fist attempt:
#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;
}
Compiled with
gcc test.c
And then running it (and piping it into hexdump):
./a.out | hd
Returns
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
Looking at the output, it seems my memory allocation of sizeof(char) * strlen(format) + 1 is wrong (too less memory allocated) and it works more accidentally?
What is the correct amount to allocate then?
My next idea was (pseudo-code):
sizeof(char) * strlen(format) + strlen(LONG_MAX) + 1
This seems too complicated and pretty non-idomatic. Or am I doing something totally wrong?
You are doing it totally wrong. LONG_MAX is an integer, so you can't call strlen (). And it's not the number that gives the longest result, LONG_MIN is. Because it prints a minus character as well.
A nice method is to write a function
char* mallocprintf (...)
which has the same arguments as printf and returns a string allocated using malloc with the exactly right length. How you do this: First figure out what a va_list is and how to use it. Then figure out how to use vsnprintf to find out how long the result of printf would be without actually printing. Then you call malloc, and call vsnprintf again to produce the string.
This has the big advantage that it works when you print strings using %s, or strings using %s with some large field length. Guess how many characters %999999d prints.
You can use snprintf() to figure out the length without worrying about the size of LONG_MAX.
When you call snprintf with NULL string, it'll return a number of bytes that would have been required if it was write into the buffer and then you know exactly how many bytes are required.
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);
Convert the predefined constant numeric value to a string, using macro expansion as explaned in convert digital to string in macro:
#define STRINGIZER_(exp) #exp
#define STRINGIZER(exp) STRINGIZER_(exp)
(code courtesy of Whozcraig). Then you can use
int max_digit = strlen(STRINGIZER(LONG_MAX))+1;
or
int max_digit = strlen(STRINGIZER(LONG_MIN));
for signed values, and
int max_digit = strlen(STRINGIZER(ULONG_MAX));
for unsigned values.
Since the value of LONG_MAX is a compile-time, not a run-time value, you are ensured this writes the correct constant for your compiler into the executable.
To allocate enough room, consider worst case
// 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);
Pedantic code would consider potential other locales
snprintf(description, n, format, LONG_MAX);
Yet in the end, recommend a 2x buffer
char *description = malloc(n*2);
sprintf(description, format, LONG_MAX);
Note: printing with specifier "%lu" ,meant for unsigned long and passing a long LONG_MAX in undefined behavior. Suggest ULONG_MAX
sprintf(description, format, ULONG_MAX);
With credit to the answer by #Jongware, I believe the ultimate way to do this is the following:
#define STRINGIZER_(exp) #exp
#define STRINGIZER(exp) STRINGIZER_(exp)
const size_t LENGTH = sizeof(STRINGIZER(LONG_MAX)) - 1;
The string conversion turns it into a string literal and therefore appends a null termination, therefore -1.
And not that since everything is compile-time constants, you could as well simply declare the string as
const char *format = "Room " STRINGIZER(LONG_MAX) " somedata\n";
You cannot use the format. You need to observer
LONG_MAX = 2147483647 = 10 characters
"Room somedata\n" = 15 characters
Add the Null = 26 characters
so use
malloc(26)
should suffice.
You have to allocate a number of char equal to the digits of the number LONG_MAX that is 2147483647. The you have to allocate 10 digit more.
in your format string you fave
Room = 4 chars
somedata\n = 9
spaces = 2
null termination = 1
The you have to malloc 26 chars
If you want to determinate runtime how man digit your number has you have to write a function that test the number digit by digit:
while(n!=0)
{
n/=10; /* n=n/10 */
++count;
}
Another way is to store temporary the sprintf result in a local buffer and the mallocate strlen(tempStr)+1 chars.
Usually this is done by formatting into a "known" large enough buffer on the stack and then dynamically allocated whatever is needed to fit the formatted string. i.e.:
#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;
}
Here, your using strlen(format) for allocation of memory is bit problematic. it will allocate memory considering the %lu lexicographically, not based on the lexicographical width of the value that can be printed with %lu.
You should consider the max possible value for unsigned long,
ULONG_MAX 4294967295
lexicographically 10 chars.
So, you've to allocate space for
The actual string (containing chars), plus
10 chars (at max), for the lexicographical value for %lu , plus
1 char to represnt - sign, in case the value is negative, plus
1 null terminator.
Well, if long is a 32-bit on your machine, then LONG_MAX should be 2147483647, which is 10 characters long. You need to account for that, the rest of your string, and the null character.
Keep in mind that long is a signed value with maximum value of LONG_MAX, and you are using %lu (which is supposed to print an unsigned long value). If you can pass a signed value to this function, then add an additional character for the minus sign, otherwise you might use ULONG_MAX to make it clearer what your limits are.
If you are unsure which architecture you are running on, you might use something like:
// this should work for signed 32 or 64 bit values
#define NUM_CHARS ((sizeof(long) == 8) ? 21 : 11)
Or, play safe and simply use 21. :)
Use the following code to calculate the number of characters necessary to hold the decimal representation of any positve integer:
#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;
}
Mind to add 1 when using a C-"string" to store the number, as C-"string"s are 0-terminated.
Use it like this:
#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;
}
Safest:
Rather than predict the allocation needed, uses asprintf(). This function allocates memory as needed.
char *description = NULL;
asprintf(&description, "Room %lu somedata\n", LONG_MAX);
asprintf() is not standard C, but is common in *nix and its source code is available to accommodate other systems.
Why Use Asprintf?
apple
android

Resources