【问题标题】:Output indentation in CC中的输出缩进
【发布时间】:2021-04-14 10:12:00
【问题描述】:

基本上我想打印这样的东西:

Process No.(Size)    Block No.(Size)
1(200)               3(300)
2(3)                 1(50)
3(1000)              4(1200)

由于间距是可变的,如何通过%d中的宽度说明符来做到这一点?

printf("%d(%d)%d(%d)",processNo,processSize,blockNo,blockSize)

间距值放在哪里?

【问题讨论】:

  • 只有知道的情况下才能指定字段宽度。由于您的间距取决于 2 个变量,因此您只有在打印 processNoprocessSize 后才知道它。因此,我看不到在单个函数调用中执行此操作的方法。您可以将第一部分打印到缓冲区中,然后根据该缓冲区的strlen 进行调整。

标签: c printf width


【解决方案1】:

您可以先将表格的每个“字段”打印成字符串,然后使用左对齐、固定宽度的格式说明符打印每个此类字段字符串。后者是使用- 标志和%s 格式说明符(即-n%s)中的width 值来完成的。

以下代码显示了您需要的内容(我使用字段来保存列标题和每一行数据,但这是一个“可选额外”)。

#include <stdio.h>

int main(void)
{
    // Test data ...
    int procNo[3] = { 1, 2, 3 };
    int procSize[3] = { 200, 3, 1000};
    int blockNo[3] = { 3, 1, 4 };
    int blockSize[3] = { 300, 50, 1200 };

    char procField[32] = "Process No.(Size)";
    char blockField[32] = "Block No.(Size)";

    // Print rubric ...
    printf("%-22s%-22s\n", procField, blockField);

    // Print data rows ...
    for (int i = 0; i < 3; ++i) {
        // Write each field to string ...
        snprintf(procField, sizeof(procField), "%d(%d)", procNo[i], procSize[i]);
        snprintf(blockField, sizeof(blockField), "%d(%d)", blockNo[i], blockSize[i]);
        // ... then print fields as left-justified, fixed-length fields
        printf("%-22s%-22s\n", procField, blockField);
    }
    return 0;
}

【讨论】:

  • 虽然这些字符串大小不太可能成为问题,但我会使用 snprintf 而不是 sprintf 使其更加健壮。
  • @user694733 公平点(sprintf 和堂兄弟会有点懒惰)。见编辑。
【解决方案2】:

printf 有两个很少使用的功能,可以简单直接地完成此操作。

第一个特征是来自printf 的返回值。是的,printf 实际上返回了一些东西,它是打印的字符数。考虑以下两行代码:

int width = printf("Process No.(Size)    ");
int used  = printf("%d(%d)", procNum[i], procSize[i]);

第一行打印列标题,并将变量width 设置为该标题中的字符数。第二行打印进程信息,并将变量used 设置为打印两个数字和括号所需的字符数。所以进程信息的结尾和块信息的开头之间所需的空格字符数就是width - used

第二个特性是可变字段宽度说明符。来自手册页:“字段宽度或精度,或两者都可以用星号 '*' [...] 在这种情况下,int 参数提供字段宽度或精度。” 考虑以下代码行:

printf("%*s", width - used, "");

代码使用"%s" 转换说明符打印字符串,但字符串"" 为空,因此通常不会打印任何内容。但是我们使用星号作为字段宽度。因此,字符串 (width - used) 之前的参数 提供了字段宽度。该字符串将用空格填充以填充该宽度。

注意,如果width - used小于1,代码应该设置字段宽度为1,这样进程信息和块信息之间至少要插入一个空格。

综合起来,代码如下:

#include <stdio.h>
#define max(a,b) ((a) > (b) ? (a) : (b))

int main(void)
{
    int procNum[]   = { 1, 2, 3 };
    int procSize[]  = { 200, 3, 1000 };
    int blockNum[]  = { 3, 1, 4 };
    int blockSize[] = { 300, 50, 1200};

    int width = printf("Process No.(Size)    ");    // print first column header, and save the width
    printf("Block No.(Size)\n");

    for (int i = 0; i < 3; i++)
    {
        int used = printf("%d(%d)", procNum[i], procSize[i]);      // print process information, and save the number of characters used
        printf("%*s%d(%d)\n", max(width - used, 1), "", blockNum[i], blockSize[i]);   // print spaces followed by the block information
    }
}

【讨论】:

  • 另一个完美的答案,我认为我们可以省略 #define 行并将 max(width - used, 1) 替换为 width - used + 1 以获得更简单和更短的代码
  • @mr.loop 使用max 宏的原因是为了处理第一列标题不够宽而无法打印信息的情况。要查看示例,请将标头更改为"ProcInfo ",将procNum[0] 更改为123456789,将procSize[0] 更改为1000000000。在这种情况下,width 是 9,used 是 21,所以 width - used + 1 是 -11,但 max(width - used, 1) 是 1。
【解决方案3】:

有关宽度如何作为参数传递给printf 的示例,请参阅printf format string 中的“宽度字段”小节。

我从Finding the length of an integer in C得到宽度算法。

我在Code Chef 测试了我的代码。如果您打算使用gcc 编译此代码,则需要-lm 选项为math.h 引入库。见How to compile a C program that uses math.h?

如果您需要不同的表头,您可以调整printspaces(11-w) 中的常量 11 和printspaces(5-w) 中的 5,直到数据与表头对齐。

#include <stdio.h>
#include <math.h>
#include <stdlib.h>

int width(int v){
    return floor(log10(abs(v))) + 1;
}

int printspaces(int s){
    int x;
    for (x=0;x<s;x++)
        printf(" ");
}

int main(void){
    int i,j,w;
    int a[3][4] = {{1,200,3,300},{2,3,1,50},{3,1000,4,1200}};
    //int a[3][4] = {{10,200,37,3000},{278,3565,1131,50},{390,100,4567,1200}};
    char *separator[4]  = {"","","","\n"};
    printf("Process No.(Size)   Block No.(Size)\n");
    for(i=0;i<3;i++){
        for (j=0;j<4;j++){
            w = width(a[i][j]);
            if (j%2==0){
                printspaces(11-w);
                printf("%*d%s",w,a[i][j],separator[j]);
            }
            else{
                printf("(%*d)",w,a[i][j]);
                printspaces(5-w);
                printf("%s",separator[j]);
            }
        }
    }
    return 0;
}

以下是结果(代码中的两个示例数组):

int a[3][4] = {{1,200,3,300},{2,3,1,50},{3,1000,4,1200}};

Process No.(Size)   Block No.(Size)
          1(200)            3(300)  
          2(3)              1(50)   
          3(1000)           4(1200) 


int a[3][4] = {{10,200,37,3000},{278,3565,1131,50},{390,100,4567,1200}};

Process No.(Size)   Block No.(Size)
         10(200)           37(3000) 
        278(3565)        1131(50)   
        390(100)         4567(1200) 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-30
    • 2023-01-25
    • 2012-07-29
    • 1970-01-01
    • 2018-02-22
    • 1970-01-01
    • 2012-05-13
    相关资源
    最近更新 更多