36

我需要将 C 中的一系列数字与printf()对齐,如下例所示:

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

当然,所有这些之间都有数字,但这与手头的问题无关......哦,将破折号视为空格,我使用破折号以便更容易理解我想要的内容。

我只能这样做:

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

或这个:

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

但这都不是我想要的,我无法仅使用 printf() 实现第一个示例中显示的内容。有可能吗?

编辑:
对不起,我很着急,没有很好地解释自己......我的最后一个例子和你所有的建议(使用“%8d”之类的东西)都不起作用,因为虽然最后一个数字是 1000 它没有就这件事而言,不一定要一路达到 1000 甚至 100 或 10。

无论要显示多少位数,我最多只需要 4 个前导空格作为最大数字。假设我必须显示从 1 到 1000 (A) 和 1 到 100 (B) 的数字,并且我对两者都使用“%4d”,这将是输出:

A:

---1
....
1000

这是我想要的输出...

乙:

---1
....
-100

这不是我想要的输出,我实际上想要这个:

--1
...
100

但是就像我说的,我不知道我要打印的确切数字,它可以有 1 个数字,可以有 2 个、3 个或更多,该功能应该为所有人准备好。我想要四个额外的前导空格,但这并不重要。

编辑 2: 似乎我想要的,我需要的方式,这是不可能的(检查 David Thornley 和 Blank Xavier 的答案和我的评论)。谢谢大家的时间。

4

11 回答 11

53

为什么printf("%8d\n", intval);不适合你?它应该...

您没有显示任何“不工作”示例的格式字符串,所以我不确定还能告诉您什么。

#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]

编辑:对问题澄清的回应:

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

宽度计算计算以 10 + 1 为底的对数,它给出了位数。花式*允许您将变量用于格式字符串中的值。

您仍然必须知道任何给定运行的最大值,但没有任何语言或铅笔和纸的方法。

于 2009-04-16T19:23:03.560 回答
50

在我方便的 Harbison & Steele 中查找这个......

确定字段的最大宽度。

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

请记住, max_width 必须是int与星号一起使用的类型,并且您必须根据您想要拥有的空间来计算它。在您的情况下,您必须计算最大数字的最大宽度,然后加 4。

于 2009-04-16T20:14:47.757 回答
4
    printf("%8d\n",1);
    printf("%8d\n",10);
    printf("%8d\n",100);
    printf("%8d\n",1000);
于 2009-04-16T19:26:41.053 回答
4

[我意识到这个问题已有一百万年的历史,但它的核心还有一个(或两个)更深层次的问题,关于 OP、编程的教学法以及关于假设的问题。]

包括模组在内的一些人认为这是不可能的。而且,在某些——包括最明显的——上下文中,确实如此。但有趣的是,这对 OP 来说并不是很明显。

不可能假设contex 在面向行的文本控制台(例如,console+sh 或X-term+csh 或Terminal+bash)上运行从C 编译的可执行文件,这是一个非常合理的假设。但是,“正确”答案(“ %8d”)对于 OP 来说还不够好,同时也不明显,这一事实表明附近有相当大的蠕虫罐头……

考虑诅咒(及其许多变体)。在其中,您可以导航“屏幕”,“移动”光标,以及“重绘”基于文本的输出部分(窗口)。在 Curses 上下文中,绝对可以这样做;即,动态调整“窗口”的大小以容纳更大的数字。但即使是 Curses 也只是屏幕“绘画”的抽象。没有人建议它,而且可能是正确的,因为C中的 Curses 实现并不意味着它是“严格的 C”。美好的。

但这究竟意味着什么?为了使响应:“不可能”是正确的,这意味着我们正在谈论运行时系统。换句话说,这不是理论上的(如“如何对一个静态分配的ints 数组进行排序?”),这可以解释为完全忽略运行时任何方面的“封闭系统”。

但是,在这种情况下,我们有 I/O:特别是printf(). 但这就是有机会说一些更有趣的东西作为回应的地方(尽管,诚然,提问者可能没有挖得这么深)。

假设我们使用一组不同的假设。假设 OP 相当“聪明”并且理解不可能在面向行的流上编辑先前的行(您将如何更正行打印机输出的字符的水平位置??)。还假设 OP 不仅仅是一个做家庭作业的孩子,却没有意识到这是一个“技巧”问题,旨在梳理对“流抽象”含义的探索。此外,让我们假设 OP 想知道:“等等……如果 C 的运行时环境支持 STDOUT 的想法——如果 STDOUT 只是一个抽象——为什么拥有一个 1) 可以的终端抽象不是一样合理垂直滚动但 2) 支持可定位光标?两者都在屏幕上移动文本。

因为如果是我们试图回答的问题,那么您只需要看:

ANSI 转义码

看到:

几乎所有的视频终端制造商都添加了供应商特定的转义序列来执行操作,例如将光标放在屏幕上的任意位置。一个例子是 VT52 终端,它通过发送 ESC 字符、一个 Y 字符和两个表示等于 x,y 位置加 32 的数值的字符,允许将光标放置在屏幕上的 x,y 位置(因此从 ASCII 空格字符开始并避免控制字符)。Hazeltine 1500 具有类似的功能,使用 ~、DC1 调用,然后用逗号分隔 X 和 Y 位置。虽然这两个终端在这方面具有相同的功能,但必须使用不同的控制序列来调用它们。

第一个支持这些序列的流行视频终端是 1978 年推出的 Digital VT100。该型号在市场上非常成功,引发了各种 VT100 克隆,其中最早和最受欢迎的是价格更实惠的 Zenith Z -19 在 1979 年。其他包括 Qume QVT-108、Televideo TVI-970、Wyse WY-99GT 以及可选的“VT100”或“VT103”或“ANSI”模式,在许多其他品牌上具有不同程度的兼容性。这些的流行逐渐导致越来越多的软件(尤其是公告板系统和其他在线服务)假设转义序列有效,导致几乎所有新的终端和仿真程序都支持它们。

早在 1978 年就有可能。C 本身是在 1972 年“诞生”的,而 K&R 版本是在 1978 年建立的。如果当时有“ANSI”转义序列,那么“in C”就有一个答案,如果我们也愿意规定:“好吧,假设您的终端支持 VT100。” 顺便说一句,不支持 ANSI 转义的控制台?你猜对了:Windows 和 DOS 控制台。但在几乎所有其他平台(Unices、Vaxen、Mac OS、Linux)上,您都可以期待。

TL;DR - 如果不说明有关运行时环境的假设,就无法给出合理的答案。由于大多数运行时(除非您使用 80 年代和 90 年代的台式计算机市场份额来计算“大多数”)都会有(从 VT-52 时代开始!),那么我不'认为说这是不可能的完全有道理 - 只是为了让它成为可能,这是一个完全不同数量级的工作,而不是那么简单%8d......它似乎有点像 OP 知道的.

我们只需要澄清假设。

以免有人认为 I/O 是异常的,即,我们唯一需要考虑运行时(甚至硬件)的时候,只需深入研究 IEEE 754 浮点异常处理。对于那些感兴趣的人:

英特尔浮点案例研究

根据加州大学伯克利分校的威廉·卡汉教授的说法,1996 年 6 月发生了一个经典案例。一枚名为阿丽亚娜 5 的卫星运载火箭在发射后不久就转动了车轮,并将自身和价值超过 50 亿美元的有效载荷散落在法国的一片沼泽中圭亚那。Kahan 发现这场灾难可归咎于一种无视 IEEE 754 中默认异常处理规范的编程语言。发射后,传感器报告的加速度如此之大,以至于导致用于重新校准火箭惯性的软件转换为整数溢出在发射台上进行指导。

于 2019-12-27T11:16:03.257 回答
2

那么,您想要一个以空格作为填充的 8 个字符宽的字段吗?试试“%8d”。这是一个参考

编辑:你想要做的不是 printf 可以单独处理的事情,因为它不会知道你写的最长数字是多少。在执行任何 printfs 之前,您需要计算最大数字,然后计算出要用作字段宽度的位数。然后你可以使用 snprintf 或类似的方法来制作一个 printf 格式。

char format[20];
snprintf(format, 19, "%%%dd\\n", max_length);
while (got_output) {
    printf(format, number);
    got_output = still_got_output();
}
于 2009-04-16T19:23:35.930 回答
1

尝试转换为字符串,然后使用“%4.4s”作为格式说明符。这使其成为固定宽度格式。

于 2009-04-16T21:43:43.657 回答
0

据我从问题中可以看出,您想要的填充量将根据您拥有的数据而有所不同。因此,唯一的解决方案是在打印之前扫描数据,找出最宽的数据,然后找到一个可以使用 asterix 运算符传递给 printf 的宽度值,例如

loop over data - get correct padding, put into width

printf( "%*d\n", width, datum );
于 2009-04-16T20:18:20.697 回答
0

如果您无法提前知道宽度,那么您唯一可能的答案将取决于将您的输出暂存于某种临时缓冲区中。对于小型报表,仅收集数据并延迟输出直到输入有界是最简单的。

对于大型报告,如果收集的数据超出合理的内存范围,则可能需要一个中间文件。

printf("%*d", width, value)获得数据后,使用每个值的习语将其后处理成报告很简单。

或者,如果输出通道允许随机访问,您可以继续编写假定(短)默认宽度的报告草稿,并在违反您的宽度假设时返回并编辑它。这还假设您可以以某种无害的方式在该字段之外填充报告行,或者您愿意通过读取-修改-写入过程替换到目前为止的输出并放弃草稿文件。

但除非你能提前预测正确的宽度,否则如果没有某种形式的两遍算法,就不可能做你想做的事。

于 2009-04-16T21:05:34.653 回答
0

查看已编辑的问题,您需要找到要呈现的最大数字中的位数,然后使用或使用作为 int 传递的位数生成printf()格式,然后是值。一旦你得到最大的数字(并且你必须提前确定),你可以用“整数对数”算法确定位数(在你得到零之前你可以除以 10 多少次),或者通过使用缓冲区长度为零、字符串的格式和空值;返回值告诉你有多少字符被格式化。sprintf()%*d*snprintf()%d

如果您不知道并且无法在其出现之前确定最大数量,那么您就会被斯诺克 - 您无能为力。

于 2009-04-16T22:01:58.763 回答
0
#include<stdio.h>
int main()
{
 int i,j,n,b;
 printf("Enter no of rows ");
 scanf("%d",&n);
 b=n;
 for(i=1;i<=n;++i)
 {
    for(j=1;j<=i;j++)
    {
        printf("%*d",b,j);
        b=1;
    }
        b=n;
    b=b-i;
    printf("\n");


 }
 return 0;
}
于 2013-11-28T18:37:45.130 回答
0
fp = fopen("RKdata.dat","w");
fprintf(fp,"%5s %12s %20s %14s %15s %15s %15s\n","j","x","integrated","bessj2","bessj3","bessj4","bessj5");
for (j=1;j<=NSTEP;j+=1)
    fprintf(fp,"%5i\t %12.4f\t %14.6f\t %14.6f\t %14.6f\t %14.6f\t %14.6f\n",
    j,xx[j],y[6][j],bessj(2,xx[j]),bessj(3,xx[j]),bessj(4,xx[j]),bessj(5,xx[j]));
fclose(fp);
于 2020-11-09T15:16:47.370 回答