5

I have to print a certain number of blank spaces to stdout, but this number is not fixed. I'm using putchar(), but I'm not sure if this is fast. What is the fastest way to print a certain number of characters to stdout in C? Also, I cannot use system functions.

Thanks for you help!

Tianyang Li
  • 1,755
  • 5
  • 26
  • 42
  • Lots of interesting answers here. Of course, you'd need to measure the performance of each one to know the right answer. But with modern OS's there's probably little between them all as the bottleneck is disk IO / console output. – Skizz May 12 '11 at 09:00

7 Answers7

4

I would just use fwrite. Simple. Correct. Easy.

void put_spaces(int n)
{
    static const char SPACES[32] = "                                ";
    for (; n >= 32; n -= 32)
        fwrite(SPACES, 32, 1, stdout);
    if (n)
        fwrite(SPACES, n, 1, stdout);
}

Note, however, that the naive version is also quite fast:

void put_spaces(int n)
{
    while (n--)
        putchar(' ');
}

Why is it fast? On most systems, putchar is a macro which writes directly into a buffer most of the time. If you're not sure it's fast, the correct answer is profile your application, not "optimize first".

Stay away from malloc (it's just unnecessary), puts (which adds a '\n' every time you call it), and printf (it's too complicated for such a simple task).

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
1

I would try to use the system commands instead of making my own.

something like:

void print_spaces(unsigned int number_of_spaces) {
  char* spaces = malloc(sizeof(char)*number_of_spaces + 1);
  memset (spaces,' ',number_of_spaces);
  spaces[number_of_spaces] = '\0';
  printf("%s",spaces);
  free(spaces);
}

would do the trick.

Martin Kristiansen
  • 9,875
  • 10
  • 51
  • 83
0

I don't known c, but here is the basic idea. create an array of size 8192, and completely fill that particular array with spaces, now you can use puts or write system call or use something which is efficient, and then print this array. Here I have a code snippet in go, but if you prefer c, you can see an example of how you do it, its actually GNU's yes program which is freaking fast at printing things, there is followed up explanation over there.

package main

import (
    "bufio"
    "os"
)

func main() {
    t := []byte{'y', '\n'}
    var used int
    const tot = 8192
    buf := make([]byte, 0, tot)

    for used < tot {
        buf = append(buf, t...)
        used += 2
    }

    //Filled complete array named as buf with "y\n"
    w := bufio.NewWriter(os.Stdout)
    for {
        w.Write(buf) //using write system call to print.
    }
    w.Flush()
}

//syscall.Write({without buf}) : 1.40MiB/s
//syscall.Write(buf) : 1.5GiB/s
nilsocket
  • 1,441
  • 9
  • 17
0

printf() allows you to adjust the number of spaces to be print, but this has to be stated in the format string. Se here for reference.

char format[256];
sprintf(format, "%%%ds", number_of_spaces); // creates the format string
printf(format, " ");
Constantinius
  • 34,183
  • 8
  • 77
  • 85
  • Won't this (and paxdiablo's) be dependent on the implementation of printf? Is printf's padding looping one character at a time? – Skizz May 12 '11 at 08:42
  • @Skizz, library functions are almost always implemented smarter than what you would expect naive C code to compile to. That's because they're used so often. – paxdiablo May 12 '11 at 08:45
  • @Skizz: no, the format options of printf are defined as a standard and **should** not divert. – Constantinius May 12 '11 at 08:46
  • As paxdiablo mentioned in a comment to my answer, printf still has to parse the format string. – Skizz May 12 '11 at 08:58
0

I'm assuming by "system functions", you mean non-standard extensions. In which case, it all depends on whether you mean fastest to write or fastest to execute?

If the former, and assuming there's an upper limit, you can just use something like:

void outSpaces (unsigned int num) {
    static char *lotsaSpaces = "                       ";
    printf ("%*.*s", num, num, lotsaSpaces);
}

If the latter, something like this should be a good starting point:

void outSpaces (unsigned int num) {
    static char *hundredSpaces = "<<insert 100 spaces here>>";
    while (num >= 100) {
        puts (hundredSpaces);
        num -= 100;
    }
    printf ("%*.*s", num, num, hundredSpaces);
}

You need to be aware that function calls can be expensive, even with output buffering. In that case, it may be best to call puts once to output a hundred characters rather than call putchar a hundred times.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
0

Perhaps:

void PrintSpaces (int num_spaces)
{
  char *spaces = "                    "; /* twenty spaces */
  while (num_spaces > 20)
  {
    puts (spaces);
    num_spaces -= 20;
  }

  if (num_spaces)
  {
    puts (&spaces [19 - num_spaces]);
  }
}
Skizz
  • 69,698
  • 10
  • 71
  • 108
0
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>

int main() {
    const size_t size = 5;
    char* const data = (char*)malloc(size * sizeof(char) + 1);
    if (!data) {
        return EXIT_FAILURE;
    }
    memset(data, ' ', size);
    data[size] = '\0'; // not needed (in this case)
    fwrite(data, sizeof(char), size, stdout);
    free(data);
    return EXIT_SUCCESS;
}

(If the number of spaces isn't outrageous)

Shadow2531
  • 11,980
  • 5
  • 35
  • 48
  • `sizeof(char)` is always 1, according to the C spec. And it seems rather wasteful to allocate a memory buffer, just to copy the data into another memory buffer... – Dietrich Epp May 12 '11 at 09:27
  • I'm just showing intent with `sizeof(char)`. For the extra buffer issue, `setbuf(stream, NULL)` might help with that. Not sure if it works as intended on stdout though. For a stream to an actual file, it should work and writing in binary mode should help even more. – Shadow2531 May 12 '11 at 10:23
  • No, if you call `setbuf(stream, NULL)` I'm fairly certain that you will sabotage performance by forcing IO for every stdio call. – Dietrich Epp May 12 '11 at 11:05
  • Understood. I made some bad assumptions about fwrite. – Shadow2531 May 12 '11 at 13:21