tags:

views:

1314

answers:

9

I need to align a series of numbers in C with printf() like this example:

-------1
-------5
------50
-----100
----1000

Of course, there are numbers between all those but it's not relevant for the issue at hand... Oh, consider the dashes as spaces, I used dashes so it was easier to understand what I want.

I'm only able to do this:

----1---
----5---
----50--
----100-
----1000

Or this:

---1
---5
--50
-100
1000

But none of this is what I want and I can't achieve what is displayed on the first example using only printf(). Is it possible at all?

EDIT:
Sorry people, I was in a hurry and didn't explain myself well... My last example and all your suggestions (to use something like "%8d") do not work because, although the last number is 1000 it doesn't necessarily go all the way to 1000 or even 100 or 10 for that matter.

No matter the number of digits to be displayed, I only want 4 leading spaces at most for the largest number. Let's say I have to display digits from 1 to 1000 (A) and 1 to 100 (B) and I use, for both, "%4d", this would be the output:

A:

---1
....
1000

Which is the output I want...

B:

---1
....
-100

Which is not the output I want, I actually want this:

--1
...
100

But like I said, I don't know the exact number of numbers I have to print, it can have 1 digit, it can have 2, 3 or more, the function should be prepared for all. And I want four extra additional leading spaces but that's not that relevant.

EDIT 2: It seems that what I want, the way I need it, it's not possible (check David Thornley and Blank Xavier answers and my comments). Thank you all for your time.

A: 

How is your last example not what you want? Just because there arent enough leading spaces on 1000?

Jason Coyne
I've edited the first post, please take a look.
Nazgulled
+18  A: 

Why is printf("%8d\n", intval); not working for you? It should...

You did not show the format strings for any of your "not working" examples, so I'm not sure what else to tell you.

#include <stdio.h>

int
main(void)
{
        int i;
        for (i = 1; i <= 10000; i*=10) {
                printf("[%8d]\n", i);
        }
        return (0);
}

$ ./printftest
[       1]
[      10]
[     100]
[    1000]
[   10000]

EDIT: response to clarification of question:

#include <math.h>
int maxval = 1000;
int width = round(1+log(maxval)/log(10));
...
printf("%*d\n", width, intval);

The width calculation computes log base 10 + 1, which gives the number of digits. The fancy * allows you to use the variable for a value in the format string.

You still have to know the maximum for any given run, but there's no way around that in any language or pencil & paper.

dwc
I've edited the first post, please take a look.
Nazgulled
A: 

So, you want an 8-character wide field with spaces as the padding? Try "%8d". Here's a reference.

EDIT: What you're trying to do is not something that can be handled by printf alone, because it will not know what the longest number you are writing is. You will need to calculate the largest number before doing any printfs, and then figure out how many digits to use as the width of your field. Then you can use snprintf or similar to make a printf format on the spot.

char format[20];
snprintf(format, 19, "%%%dd\\n", max_length);
while (got_output) {
    printf(format, number);
    got_output = still_got_output();
}
Matt Kane
I've edited the first post, please take a look.
Nazgulled
printf("%*d", width, value) is less work than constructing the format string, probably less error-prone, and probably clearer. It might conceivably be slower because of the additional argument to printf() (think lots of variable fields), so the technique you illustrate does have value in some cases.
RBerteig
A: 
    printf("%8d\n",1);
    printf("%8d\n",10);
    printf("%8d\n",100);
    printf("%8d\n",1000);
Alex B
I've edited the first post, please take a look.
Nazgulled
+3  A: 

Looking this up in my handy Harbison & Steele....

Determine the maximum width of fields.

int max_width, value_to_print;
max_width = 8;
value_to_print = 1000;
printf("%*d\n, max_width, value_to_print;

Bear in mind that max_width must be of type int to work with the asterisk, and you'll have to calculate it based on how much space you're going to want to have. In your case, you'll have to calculate the maximum width of the largest number, and add 4.

David Thornley
The problem is that I don't know the largest number, I'll never know until I reach it. And I need to do this on the fly...
Nazgulled
@Nazgulled: So in other words, you're asking a question that's impossible by definition?
Michael Myers
I guess... But I didn't know it was impossible until some of your answers.
Nazgulled
A: 

As far as I can tell from the question, the amount of padding you want will vary according to the data you have. Accordingly, the only solution to this is to scan the data before printing, to figure out the widest datum, and so find a width value you can pass to printf using the asterix operator, e.g.

loop over data - get correct padding, put into width

printf( "%*d\n", width, datum );
Blank Xavier
That won't possible... :/
Nazgulled
Then you can't do it. If you need to print a datum, and what you print depends on following data, and you don't know what those data will be, then you are attempting an impossible task.
Blank Xavier
A: 

If you can't know the width in advance, then your only possible answer would depend on staging your output in a temporary buffer of some kind. For small reports, just collecting the data and deferring output until the input is bounded would be simplest.

For large reports, an intermediate file may be required if the collected data exceeds reasonable memory bounds.

Once you have the data, then it is simple to post-process it into a report using the idiom printf("%*d", width, value) for each value.

Alternatively if the output channel permits random access, you could just go ahead and write a draft of the report that assumes a (short) default width, and seek back and edit it any time your width assumption is violated. This also assumes that you can pad the report lines outside that field in some innocuous way, or that you are willing to replace the output so far by a read-modify-write process and abandon the draft file.

But unless you can predict the correct width in advance, it will not be possible to do what you want without some form of two-pass algorithm.

RBerteig
A: 

Try converting to a string and then use "%4.4s" as the format specifier. This makes it a fixed width format.

MM
A: 

Looking at the edited question, you need to find the number of digits in the largest number to be presented, and then generate the printf() format using sprintf(), or using %*d with the number of digits being passed as an int for the * and then the value. Once you've got the biggest number (and you have to determine that in advance), you can determine the number of digits with an 'integer logarithm' algorithm (how many times can you divide by 10 before you get to zero), or by using snprintf() with the buffer length of zero, the format %d and null for the string; the return value tells you how many characters would have been formatted.

If you don't know and cannot determine the maximum number ahead of its appearance, you are snookered - there is nothing you can do.

Jonathan Leffler