Formatting very large numbers in C - c

I have to output a large number, a double precision number using the following code:
fprintf(outFile," %11.0f %d O(g(n))",factorialNotRecursive(index,factCount),factValue);
now the number gets so big that it jumps out of alignment further down the
list of output. Once it gets past 11 digits, the max specified it continues
to grow larger. Is there a way to cope with this? I'm not sure how big the inputs
that will be run on this program.

I think you cannot do it directly. You have to print to a string, then change the string.
/* pseudo (untested) code */
value = factorialNotRecursive(index, factCount);
/* make sure buff is large enough (or use snprintf if available) */
n = sprintf(buff, "%11.0f", value);
if (n > 11) {
buff[10] = '+';
buff[11] = 0;
}
fprintf(outFile," %s %d O(g(n))", buff, factValue);

Related

Format Specifier Q and unique bug in Mario Solution to Pyramid algorithm

Okay I have two problems with my solution to this problem, I was hoping I could get some help on. The problem itself is being able to print out #s in a specific format based on user input.
My questions are:
When I input 7, it outputs the correct solution, but when I output 8 (or higher), my buffer, for whatever reason add some garbage at the end, which I am unsure why it happens. I would add a picture but I don't have enough rep points for it :(
In my code, where I've inputted **HELPHERE**, I'm unsure why this gives me the correct solution. I'm confused because in the links I've read (on format specifiers) I thought that the 1 input (x in my case) specified how many spaces you wanted. I thought this would've made the solution x-n, as each consequent row, you'd need the space segment to decrease by 1 each time. Am I to understand that the array somehow reverses it's input into the printf statement? I'm confused because does that mean since the array increases by 1, on each subsequent iteration of the loop, it eats into the space area?
int main(void){
printf("Height: ");
int x = GetInt();
int n = 1;
int k=0;
char buff[x]; /* creates buffer where hashes will go*/
while(n<=x){ /* stops when getint value is hit*/
while(k<n) /* fill buffer on each iteration of loop with 1 more hashtag*/
{
buff[k] = '#';
k++;
}
printf("%*s",x, buff); /*makes x number of spaces ****HELPHERE*****, then prints buffer*/
printf(" ");
printf("%s\n",buff); /*prints other side of triangle */
/*printf("%*c \n",x-n, '\0');*/
n++;
}
}
Allocate enough memory and make sure the string is null terminated:
char buff[x+1];//need +1 for End of the string('\0')
memset(buff, '\0', sizeof(buff));//Must be initialized by zero
Print as many blanks as requested by blank-padding an empty string:
printf("%*s", x, "");
※the second item was written by Jonathan Leffler.
In printf("%*s",x, buff);, buff in not null character terminated.
Present code "worked" sometimes as buff was not properly terminated and the result was UB - undefined behavior. What likely happened in OP's case was that the buffer up to size 7, fortunately had '\0' in subsequent bytes, but not so when size was 8.
1) As per #BLUEPIXY, allocated a large enough buffer to accommodate the '#' and the terminating '\0' with char buff[x+1];
2) Change while loop to append the needed '\0'.
while (k<n) {
buff[k] = '#';
k++;
}
buff[k] = '\0';
3) Minor:insure x is valid.
if (x < 0) Handle_Error();
char buff[x];
4) Minor: Return a value for int main() such as return 0;.

Estimate size of formatted snprintf() string?

I'm considering writing a function to estimate at least the full length of a formatted string coming from the sprintf(), snprintf() functions.
My approach was to parse the format string to find the various %s, %d, %f, %p args, creating a running sum of strlen()s, itoa()s, and strlen(format_string) to get something guaranteed to be big enough to allocate a proper buffer for snprintf().
I'm aware the following works, but it takes 10X as long, as all the printf() functions are very flexible, but very slow because if it.
char c;
int required_buffer_size = snprintf(&c, 1, "format string", args...);
Has this already been done ? - via the suggested approach, or some other reasonably efficient approach - IE: 5-50X faster than sprintf() variants?
Allocate a big enough buffer first and check if it was long enough. If it wasn't reallocate and call a second time.
int len = 200; /* Any number well chosen for the application to cover most cases */
int need;
char *buff = NULL;
do {
need = len+1;
buff = realloc(buff, need); /* I don't care for return value NULL */
len = snprintf(buff, need, "...", ....);
/* Error check for ret < 0 */
} while(len > need);
/* buff = realloc(buff, len+1); shrink memory block */
By choosing your initial value correctly you will have only one call to snprintf() in most cases and the little bit of over-allocation shouldn't be critical. If you're in a so tight environment that this overallocation is critical, then you have already other problems with the expensive allocation and formating.
In any case, you could still call a realloc() afterwards to shrink the allocated buffer to the exact size.
If the first argument to snprintf is NULL, the return value is the number of characters that would have been written.

Appending an output file in C

I am solving a problem on USACO. In the problem, I have to take two strings as inputs and calculate the numerical values modulo 47. If the values are same, then GO is to be printed otherwise STAY has to be printed. The initial numerical value will be calculated by taking the product of the numerical values of the alphabets ( 1 for A and similarily 26 for Z ) and then the final number will be calculated by using modulo.
My program is being compiled withour any error and the first case is also a success. But the problem is in the second case and the way my file is being appended. The program is as follows:-
#include<stdio.h>
#include<malloc.h>
#include<string.h>
#define MAX 6
main()
{
int cal(char *ptr);
int a,b;
char *comet,*group;
FILE *fptr;
comet=malloc(6*sizeof(char));
group=malloc(6*sizeof(char));
scanf("%s",comet);
a=cal(comet);
scanf("%s",group);
b=cal(group);
fptr=fopen("ride.out","a+"); (1)
//fptr=fopen("ride.txt","a+"); (2)
if(a==b)
fprintf(fptr,"GO\n"); (3)
//printf("GO\n"); (4)
else
fprintf(fptr,"STAY\n"); (5)
//printf("STAY\n"); (6)
fclose(fptr);
return 0;
}
int cal(char *ptr)
{
int c,prod=1,mod;
while(*ptr)
{
c=(*ptr++)-'A'+1;
prod=prod*c;
}
mod=prod%47;
return mod;
}
OUTPUT:-
The first case is the set two strings:-
COMETQ
HVNGAT
and the second case is given in the error notification itself.
If I remove the comment symbols from (2) and put it on (1), then the program is working fine because I can see the contents of the file and they appear just as the grader system wants. It isn't happening for the actual statement of (1). The comments of line (4) and (6) are also fine but not the line (1). I am not able figure this out. Any help?
First a few notes:
main(): a decent main is either:
int main(void)
or
int main(int argc, char *argv[])
Using malloc() you should always check if it returns NULL, aka fail, or not.
Always free() malloc'ed objects.
Everyone has his/hers/its own coding style. I have found this to be invaluable when it comes to C coding. Using it as a base for many other's to. Point being structured code is so much easier to read, debug, decode, etc.
More in detail on your code:
Signature of cal()
First line in main you declare the signature for cal(). Though this works you would probably put that above main, or put the cal() function in entirety above main.
Max length
You have a define #define MAX 6 that you never use. If it is maximum six characters and you read a string, you also have to account for the trailing zero.
E.g. from cplusplus.com scanf:
specifier 's': Any number of non-whitespace characters, stopping at the first whitespace character found. A terminating null character is automatically added at the end of the stored sequence.
Thus:
#define MAX_LEN_NAME 7
...
comet = malloc(sizeof(char) * MAX_LEN_NAME);
As it is good to learn to use malloc() there is nothing wrong about doing it like this here. But as it is as simple as it is you'd probably want to use:
char comet[MAX_LEN_NAME] = {0};
char group[MAX_LEN_NAME] = {0};
instead. At least: if using malloc then check for success and free when done, else use static array.
Safer scanf()
scanf() given "%s" does not stop reading at size of target buffer - it continues reading and writing the data to consecutive addresses in memory until it reads a white space.
E.g.:
/* data stream = "USACOeRRORbLAHbLAH NOP" */
comet = malloc(szieof(char) * 7);
scanf("%s", buf);
In memory we would have:
Address (example)
0x00000f comet[0]
0x000010 comet[1]
0x000011 comet[2]
0x000012 comet[3]
0x000013 comet[4]
0x000014 comet[5]
0x000015 comet[6]
0x000016 comet[7]
0x000017 /* Anything; Here e.g. group starts, or perhaps fptr */
0x000018 /* Anything; */
0x000019 /* Anything; */
...
And when reading the proposed stream/string above we would not read USACOe in to comet but we would continue reading beyond the range of comet. In other words (might) overwriting other variables etc. This might sound stupid but as C is a low level language this is one of the things you have to know. And as you learn more you'll most probably also learn to love the power of it :)
To prevent this you could limit the read by e.g. using maximum length + [what to read]. E.g:
scanf("%6[A-Z]", comet);
| | |
| | +------- Write to `comet`
| +-------------- Read only A to Z
+---------------- Read maximum 6 entities
Input data
Reading your expected result, your errors, your (N) comments etc. it sound like you should have a input file as well as an output file.
As your code is now it relies on reading data from standard input, aka stdin. Thus you also use scanf(). I suspect you should read from file with fscanf() instead.
So: something like:
FILE *fptr_in;
char *file_data = "ride.in";
int res;
...
if ((fptr_in = fopen(file_data, "r")) == NULL) {
fprintf(stderr, "Unable to open %s for reading.\n", file_data);
return 1; /* error code returned by program */
}
if ((res = fscanf(fptr_in, "%6[A-Z]%*[ \n]", comet)) != 1) {
fprintf(stderr, "Read comet failed. Got %d.\n", res);
return 2;
}
b = cal(comet);
if ((res = fscanf(fptr_in, "%6[A-Z]%*[ \n]", group)) != 1) {
fprintf(stderr, "Read group failed. Got %d.\n", res);
return 2;
}
...
The cal() function
First of, the naming. Say this was the beginning of a project that eventually would result in multiple files and thousand of lines of code. You would probably not have a function named cal(). Learn to give functions good names. The above link about coding style gives some points. IMHO do this in small projects as well. It is a good exercise that makes it easier when you write on bigger to huge ones. Name it e.g. cprod_mod_47().
Then the mod variable (and might c) is superfluous. An alternative could be:
int cprod_mod_47(char *str)
{
int prod = 1;
while (*str)
prod *= *(str++) - 'A' + 1;
return prod % 47;
}
Some more general suggestions
When compiling use many warning and error options. E.g. if using gcc say:
$ gcc -Wall -Wextra -pedantic -std=c89 -o my_prog my_prog.c
This is tremendous amount of help. Further is the use of tools like valgrind and gdb invaluable.

Help needed for basic C input and output

I need to get two inputs- hexadecimal address and number of bits- and then I need to print out the index and the offset of the address.
Thus, If the inputs are 20 and 0x0FF10100, the output should be 0x0FF1 for index and 0100 for the offset.
int bits, index, offset, count;
short addr[10], addr2;
printf("# of bits: ");
scanf("%d", &bits);
index = (bits / 4) + 2;
offset = 10 - index;
printf("Integer (in hex): ");
scanf("%hi", addr);
Then I need to output the index which is (20/4)+2 = 7 that means first 7 characters of the address. And the rest as offset.
I could not use printf i tried many times. But i could not fix I hope someone could help
Thanks everyone.
For output I tried to use
while (count < index)
{
printf("", addr[count], addr[count]);
count++;
}
It did not print out anything...
then I tried many variations of that and I got error. I dont know what to use to output..
Thanks
Maybe I'm missing something, but your printf call is using an empty string instead of a format string. You can see the various format specifiers here.
Always check the return value of scanf if you intend on using the input; it will return the number of items that it has successfully scanned. If you ignore the return value, you risk attempting to read indeterminate values, which means your program has undefined behaviour.
Also, in your second call to scanf, you aren't asking for a hexadecimal integer, you are asking for a short integer (h means short, and i means integer). If you want to scan a hexadecimal short integer, you need to use hx, but this also means you need to provide the address of an unsigned short, rather than a plain short.
int bits, index, offset, count;
unsigned short addr[10], addr2;
printf("# of bits: ");
if (scanf("%d", &bits) != 1)
{
// could not scan
// handle scan error here. Exit, or try again, etc.
}
index = (bits / 4) + 2;
offset = 10 - index;
printf("Integer (in hex): ");
if (scanf("%hx", addr) != 1)
{
// could not scan
// do whatever makes sense on scan failure.
}
If you are reading into consecutive elements of your addr array, you might want the following instead:
printf("Integer (in hex): ");
if (scanf("%hx", &addr[count]) != 1)
{
// could not scan
// do whatever makes sense on scan failure.
}
Finally regarding your use of printf: the first argument to printf tells it how to print the provided data. You have given it an empty string which means printf is not told to print anything. Perhaps you are looking for something like this:
printf("%d: %hx", count, addr[count]);

Inserting leading zeros into an integer

I have a function in C which generates a number of hours from a rtc peripheral, which I then want to fill an array within a struct object. The array is set up to take 5 digits, but I need to prepend leading zeros to the number when it is less than 5 digits.
Could anyone advise on an easy way of achieving this?
char array[5];
snprintf(array, 5, "%05d", number)
A couple little routines that'll do what you want without having a printf() library hanging around. Note that there's not a way for the routines to tell you that the int you've passed in is too big for the buffer size passed in - I'll leave adding that as an exercise for the reader. But these are safe against buffer overflow (unless I've left a bug in there).
void uint_to_str_leading( char* dst, unsigned int i, size_t size )
{
char* pCurChar;
if (size == 0) return;
pCurChar = dst + size; // we'll be working the buffer backwards
*--pCurChar = '\0'; // take this out if you don't want an ASCIIZ output
// but think hard before doing that...
while (pCurChar != dst) {
int digit = i % 10;
i = i /10;
*--pCurChar = '0' + digit;
}
return;
}
void int_to_str_leading( char* dst, int i, size_t size )
{
if (size && (i < 0)) {
*dst++ = '-';
size -= 1;
i *= -1;
}
uint_to_str_leading( dst, i, size);
return;
}
Note that these routines pass in the buffer size and terminate with a '\0', so your resulting strings will have one less character than the size you've passed in (so don't just pass in the field size you're looking for).
If you don't want the terminating '\0' character because you're dealing with a fixed char[] array that's not terminated, it's easy enough to take out that one line of code that does the termination (but please consider terminating the char[] array - if you don't, I'll bet you'll see at least one bug related to that sometime over the next 6 months).
Edit to answer some questions:
dst is a pointer to a destination buffer. The caller is responsible to have a place to put the string that's produced by the function, much like the standard library function strcpy().
The pointer pCurChar is a pointer to the location that the next digit character that's produced will go. It's used a little differently than most character pointers because the algorithm starts at the end of the buffer and moves toward the start (that's because we produce the digits from the 'end' of the integer). Actually, pCurChar points just past the place in the buffer where it's going to put the next digit. When the algorithm goes to add a digit to the buffer, it decrements the pointer before dereferencing it. The expression:
*--pCurChar = digit;
Is equivalent to:
pCurChar = pCurChar-1; /* move to previous character in buffer */
*pCurChar = digit;
It does this because the test for when we're done is:
while (pCurChar == dst) { /* when we get to the start of the buffer we're done */
The second function is just a simple routine that handles signed ints by turning negative numbers into positive ones and letting the 1st function do all the real work, like so:
putting a '-' character at the start of the buffer,
adjusting the buffer pointer and size, and
negating the number to make it positive
passing that onto the function that converts an unsigned int to do the real work
An example of using these functions:
char buffer[80];
uint_to_str_leading( buffer, 0, 5);
printf( "%s\n", buffer);
uint_to_str_leading( buffer, 123, 6);
printf( "%s\n", buffer);
uint_to_str_leading( buffer, UINT_MAX, 14);
printf( "%s\n", buffer);
int_to_str_leading( buffer, INT_MAX, 14);
printf( "%s\n", buffer);
int_to_str_leading( buffer, INT_MIN, 14);
printf( "%s\n", buffer);
Which produces:
0000
00123
0004294967295
0002147483647
-002147483648
like #Aaron's solution, the only way to do it in C is to treat it like a character instead of a number. Leading zeros are ignored when they occur as a value and indicate an octal constant when appearing in code.
int a = 0000015; // translates to decimal 13.
Initialize every element in the array to 0 before inserting the digits into the array. That way you're guaranteed to always have 5 digits with leading zeroes.
If the type is int, then no. Set the type to string?
try this :
char source[5+1] = { '1','2', 0, 0, 0, 0 };
char dest[5+1];
int nd = strlen(source) ;
memset ( dest, '0', 5 - nd );
sprintf ( dest+nd+1, "%s", source );
Doesn't simple total bzero() or something like this and then filling with new value suit you? Could you please describe more details if not?
I'm not joking, I have seen several cases when total filling with 0 is faster then tricks to add 0s, especially if memory was cached and bzero() had some burst write support.
int newNumber [5] = 0;
for ( int i=0; givenNumber != 0 && i < 5 ; i++ ) {
newNumber[i] = givenNumber%10;
givenNumber = givenNumer/10;
}
apologies for the lack of detail. My code generates a 32-bit integer, which I am expecting to only get to 5 decimal digits in size. I then call the function:
numArray = numArrayFill(12345, buf, sizeof(buf));
(uint32_t number, char *buffer, int size)
{
char *curr = &buffer[size];
*--curr = 0;
do
{
*--curr = (number % 10) + '0';
number /= 10;
}
while (number != 0);
if (curr == buffer && number != 0)
return NULL;
return curr;
}
The problem comes when I put in a less than 5 digit number and I get random behaviour. What I need to do is to append zeros to the front so that it is always a 5 digit number.
Thanks
Dave

Resources