【问题标题】:Is there any setfill() alternative for C?C 是否有任何 setfill() 替代方法?
【发布时间】:2011-04-21 12:35:36
【问题描述】:

在 C++ 中:

int main()
{
    cout << setfill('#') << setw(10) << 5 << endl;

    return 0;
}

输出:

#########5

C 是否有任何setfill() 替代方案?或者如何在不手动创建字符串的情况下在 C 中做到这一点?

【问题讨论】:

    标签: c++ c output-formatting


    【解决方案1】:

    不作为标准内置

    我可能会将数字 sprintf() 转换为字符串并获取字符数,然后在打印字符串之前首先输出正确的“#”数。

    【讨论】:

      【解决方案2】:

      下面将使用 C 中的 memset 来执行此操作,假设为 1 字节字符。它仍然会创建一个“字符串”,但我不确定您不希望它是多么手动。

      int main(void)
      {
      
         char buf[MAX_LENGTH];
      
         memset(buf, '#', 10);
         buf[10]='\0';
         printf("%s5\n", buf);
      }
      

      根据您实际想用它做什么,您可以动态地创建适当大小的缓冲区,并根据需要从辅助函数中返回它。

      【讨论】:

      • 无需假设sizeof (char) == 1。该标准将其定义为这样。 (可能会改变的是位数,请参阅 CHAR_BIT。)
      • 假设 5 是一个变量而不是文字 5 - 这将输出 10 '#' 然后是数字 - OP 想要打印一个 10chars 宽的字段,左填充 #
      • 啊确实,我看的不够仔细。那么是的,你基本上被困在确定你真正想要的任何东西的大小,然后将它与上面类似的东西结合起来。
      【解决方案3】:
       int x= 5; 
       printf("%010d",x);
      

      将输出: 0000000005

      现在,如果您真的想要 '#' 而不是 '0',则必须在字符串中手动替换它们。

      也许:

      char buf[11], *sp = buf; 
      snprintf(buf, 11, "%10d", x); 
      while( (sp = strchr(sp, ' ')) != '\0'){ *sp = '#'; }
      puts(buf); 
      

      【讨论】:

      • 使用printf 打印字符串变量的正确方法是printf("%s", buf); 或者更好的是,使用puts。
      【解决方案4】:

      不,没有直接的选择。

      但是,如果您有一个行为良好的snprintf(其行为符合 C99 标准的描述),则无需创建新字符串即可工作;仅创建 2 个临时 ints

      #include <stdio.h>
      
      int main(void) {
        int filler = '#'; /* setfill('#') */
        int width = 10;   /* setw(10)     */
        int target = 5;   /* 5            */
      
        /* ******** */
        int s = snprintf(NULL, 0, "%d", target);
        for (int i = 0; i < width - s; i++) {
          putchar(filler);
        }
        printf("%d\n", target);
        /* ******** */
      
        return 0;
      }
      

      编辑:在ideone 运行版本。


      EDIT2:C99 标准的 snprintf 和 Windows _snprintf 之间的差异(谢谢你的链接,Ben):

      • 原型:int snprintf(char *restrict buffer, size_t n, const char *restrict format, ...);
      • 原型:int _snprintf(char *buffer, size_t n, const char *format, ...);
      • snprintf 写入不超过 (n-1) 个字节和一个 NUL
      • _snprintf 写入不超过 (n) 个字节,最后一个字节可能是 NUL 或其他字符
      • snprintf 返回格式所需的字符数(可以大于n)或-1 以防编码错误
      • 如果n 对于字符串来说不大,_snprintf 返回负值;或 n 如果 NUL 字节尚未写入缓冲区。

      您可以循环运行行为不端的_snprintf,增加n,直到找到正确的值

      /* absolutely not tested, written directly on SO text editor */
      int i;
      size_t rightvalue = 0;
      char buffer[SOME_DEFAULT_VALUE];
      do {
          if (sizeof buffer < rightvalue) /* OOPS, BIG BIG OOPS */;
          i = _snprintf(buffer, rightvalue, "%d", 42);
      } while (i != rightvalue++);
      /* rightvalue already has space for the terminating NUL */
      

      【讨论】:

      • snprintf() 在 VS2008 中找不到。 snprintf 有什么问题?
      • VS2008 不是 C99 编译器。微软自己是这么说的。 snprintf 首次出现在标准上是针对 C99,但在此之前它存在于“野外”。其中一些“狂野”版本的工作方式与标准描述的方式不同。 (我认为 Windows 有一个行为不端的“狂野”版本)
      • 确实如此:_snprintf,此处描述:msdn.microsoft.com/en-us/library/2ts7cx93.aspx
      【解决方案5】:

      每个人都想调用printf 两次...printf 是最昂贵的函数之一。

      这里:

      char buffer[18] = "##########";
      puts(buffer + snprintf(buffer+strlen(buffer), 8, "%d", 5));
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多