【问题标题】:Printing a string due to a new line由于换行而打印字符串
【发布时间】:2015-10-17 15:38:09
【问题描述】:

是否有任何高效(在性能方面)的方式来打印一些任意字符串,但只到其中的第一个换行符(不包括换行符)?


例子:

char *string = "Hello\nWorld\n";

printf(foo(string + 6));

输出:

世界

【问题讨论】:

  • 当然有一种有效的方法。 + 6 应该是什么意思。我其实不明白你想要什么。 foo 函数应该做什么?
  • ummmmmmm...(string + 6)&string[6] 相同,它提供对字符串中'W' 字符的引用。而且我认为,如果你们中的任何一个人都无法理解这个问题,那不是我的错。.. 无法理解。
  • 那么我对你的理解正确吗?你想打印一个string 直到它包含的第一个换行符?
  • 我知道string+6 是什么意思...但我无法弄清楚您要实现什么foo 函数应该做什么。
  • 嗯,这是一个例子,所以 foo 确实会导致输出。 @muXXmit2X 你会的。

标签: c string performance pointers newline


【解决方案1】:

警告:不要使用没有格式说明符的printf 来打印变量字符串(或从变量指针)。请改用puts"%s", string

C 字符串以'\0' (NUL) 结尾,而不是换行符。因此,函数会打印到 NUL 终止符。 但是,您可以将自己的循环与putchar 一起使用。如果这是要测试的任何性能损失。通常printf 在库中的作用大致相同,并且可能会更慢,因为它必须处理更多额外的约束,因此您自己的循环可能会更快。

for ( char *sp = string + 6 ; *sp != '\0'; sp++ ) {
    if ( *sp == '\n' )  break;  // newline will not be printed
    putchar(*sp);
}

(如果要打印换行符,请将if-line 移动到循环的末尾。)

另一种方法是限制要打印的字符串的长度,但这需要在调用 printf 之前找到下一个换行符。

【讨论】:

    【解决方案2】:

    我不知道它是否足够快,但是有一种方法可以构建一个包含源字符串的字符串,直到一个新行字符,只涉及一个标准函数。

    char *string = "Hello\nWorld\nI love C"; // Example of your string
    static char newstr [256]; // String large enough to contain the result string, fulled with \0s or NULL-terimated
    
    sscanf(string + 6, "%s", newstr); // sscanf will ignore whitespaces
    sprintf(newstr); // printing the string
    

    【讨论】:

    • 计时。但这很可能是最慢的版本。我认为我的答案中的那个甚至会比printf 更快
    • 我认为不是高度优化的方式。虽然它的操作非常简单,而且只有一个格式说明符。如果涉及到缓存,我不知道它是否会比你直接的方法慢很多。
    • 现在注意到你正在分别打印每个字符。它可能在逻辑上更快,因为它不涉及printf,但它可能恰恰相反。可悲的是我不擅长测量。
    • Malina,我不再讨论。我认为我在进行了 30 多年的各种级别、架构等编程之后,可以很好地估计软件的运行时间。但是,欢迎您证明我错了! (顺便说一句:您认为printf 实际上如何打印字符串的单个字符?)
    • 抱歉,我不在乎任何人的教育水平、多年经验或头衔,只要他们证明他们的方法比我(遗憾地)发现的方法更快。
    【解决方案3】:

    如果您担心性能,这可能会有所帮助(未经测试的代码):

    void MyPrint(const char *str)
    {
      int len = strlen(str) + 1;
      char *temp = alloca(len);
    
      int i;
      for (i = 0; i < len; i++)
      {
        char ch = str[i];
        if (ch == '\n')
          break;
        temp[i] = ch;
      }
    
      temp[i] = 0;
    
      puts(temp);
    }
    

    strlen 很快,alloca 很快,将字符串复制到第一个 \n 很快,putsprintf 快,但很可能比前面提到的所有三个操作都慢得多在一起。

    【讨论】:

    • 是的。好东西。 (顺便说一句,memcpy 不比 strcpy 快)
    • 也许memcpystrcpy 更快(顺便说一句,我没有在我的答案中使用它),但是对于memcpy,您需要知道要复制的长度并找到您的长度无论如何都需要扫描字符串。
    • 啊,是的,对不起。我以某种方式设法看到strcpystrlen 并且忙于询问。
    • 无论如何puts 很可能比复制字符串等慢得多,所以mempystrcpyetc 之间的任何区别。没关系。如果您的环境中有puts 的源代码,您可以查看该函数。
    【解决方案4】:

    我想没有比简单地循环字符串直到找到第一个 \n 更有效的方法了。正如 Olaf 所提到的,C 中的字符串以终止 \0 结尾,因此如果您想使用 printf 打印字符串,您需要确保它包含终止 \0 或者您可以使用 putchar 打印逐个字符的字符串。

    如果你想提供一个函数来创建一个直到找到的第一个新行的字符串,你可以这样做:

    #include <stdio.h>
    #include <string.h>
    
    #define MAX 256
    
    void foo(const char* string, char *ret) 
    {
      int len = (strlen(string) < MAX) ? (int) strlen(string) : MAX;
      int i = 0;
      for (i = 0; i < len - 1; i++) 
      {
        if (string[i] == '\n') break;
        ret[i] = string[i];
      }
      ret[i + 1] = '\0';
    }
    
    
    int main()
    {
      const char* string = "Hello\nWorld\n";
      char ret[MAX];
      foo(string, ret);
      printf("%s\n", ret);
      foo(string+6, ret);
      printf("%s\n", ret);
    }
    

    这将打印出来

    Hello
    World
    

    【讨论】:

    • 在字符串上循环多次。请注意,printf 本身使用putchar,但在循环内外(格式解析)有更多开销(widht-field 等)。
    • 是的,你是对的,但是这样你就可以提供一个可以在foo() 之外进行操作的字符串。例如,您还可以将此功能用于 GUI 界面,而不仅仅是在stdout 上打印。使用起来更灵活一点。
    • 好的。 OP只是没有要求比,而是强调速度。但是根据 cmets 在中间改变主意(不更新答案)。而我看不到太多收益,因为无论如何这都是一个微不足道的循环。或者直接使用strtok
    【解决方案5】:
    size_t writetodelim(char const *in, int delim)
    {
      char *end = strchr(in, delim);
      if (!end)
        return 0;
      return fwrite(in, 1, end - in, stdout);
    }
    

    这可以稍微概括一下(将FILE* 传递给函数),但它已经足够灵活,可以在任何选定的分隔符上终止输出,包括'\n'

    【讨论】:

      【解决方案6】:

      另一种 快速 方式(如果换行符确实不需要) 简单地说:

      *strchr(string, '\n') = '\0';
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-02
        相关资源
        最近更新 更多