0

I got code that follows:

char* writeSpace(int i)
{
 fputs("                              " + (30-i), stdout);
}

printf("#%i key: %s%svalue: %s%s value2: %s", id, key, writeSpace(10), value, writeSpace(8), value2);

my output should look something like:

#1 key: foo          value: bar        value2: foobar

but it isn't. it looks like:

                      #1 key: foo(null)value: bar(null)value2: foobar(null)

What's wrong with my code?

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
icepopo
  • 1,617
  • 4
  • 16
  • 13
  • Why are you using these old legacy functions? You have access to the C++ standard library: use it. – Lightness Races in Orbit Jul 10 '11 at 12:08
  • 1
    This looks like it should be tagged with 'C' (and not with 'C++'). – johnsyweb Jul 10 '11 at 12:14
  • Please explain what you want to do: let writeSpace(i) create and return a string of i*whitespace, or do you want a side effect, so that writeSpace(i) writes such a string to a stream? Or even both? – Nico Jul 10 '11 at 12:16

5 Answers5

4

You've declared writeSpace() to return a char*, but you haven't returned anything from it.

MatthewD
  • 2,509
  • 2
  • 23
  • 27
4

Well, you're fputting all those spaces to the console, so you get them first.

Then you're outputting everything else, so you get that next.

Perhaps you meant for writeSpace to return a C-style string, rather than print it to the console.

But be sure that you allocate space for it! Since ownership of memory buffers gets a bit hinky, it's best to allocate space outside of the function.

void writeSpace(char* buf, int i) {
   fputs("                              " + (30-i), buf);
}

char spaceBuf1[30];
writeSpace(spaceBuf1, 10);

char spaceBuf2[30];
writeSpace(spaceBuf2, 8);

printf("#%i key: %s%svalue: %s%s value2: %s",
   id, key, spaceBuf1, value, spaceBuf2, value2);

And consider using actual C++ features like iostreams and std::string. It'll be much easier:

std::cout << "#" << id << " "
          << " key: " << std::setw(30) << key
          << " value: " << std::setw(30) << value
          << " value2: " << value2;

I recommend these resources for learning idiomatic C++.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
0

Your writeSpace function is not returning a new string (even though you've declared it that way) but is writing to the terminal directly. Since you call it as an argument in your printf call, writeSpace gets called first, prints its stuff, and then printf prints its stuff. You should do it like this:

char* writeSpace(int i)
{
    char *ret = NULL;
    asprintf(ret, "                              " + (30-i));
    return ret;
}

Of course, this requires you to free the memory (otherwise you'd have a memory leak). You could do it like this:

char *spaces = writeSpace(10);
printf("%s%i", spaces, 42);
free(spaces);

An alternative is to use a static variable that the function itself cleans up on the next call:

char* writeSpace(int i)
{
    static char *ret = NULL;
    if (ret != NULL) free(ret);
    asprintf(ret, "                              " + (30-i));
    return ret;
}

But this has the disadvantage that you can only use one call to writeSpace in your printf arguments, as the second one will clean up the memory of the previous call. Still might be what you want.

BTW, The + (30-i) part is evil. What you probably want is this instead:

asprintf(ret, "%*s", i, ""); // Prints i spaces
DarkDust
  • 90,870
  • 19
  • 190
  • 224
0

If you want to format variable ws' and you absolutely have to use plain C you might use such format strings (%*c, where * is the count of ws and c represents the char to set (' ' in this case of course)):

sprintf(buffer, "%*cafterspace", 30, ' '); // Will print 30 ws and then "afterspace".
sprintf(buffer, "%*cafterspace", 15, ' '); // Will print 15 ws and then "afterspace".

But you still have to prepare a buffer as Tomalak explained!

Nico
  • 1,554
  • 1
  • 23
  • 35
0

The other Answers provided have the correct answer you are looking for. However, I would like to try and add a little explanation of the symptoms you were seeing so as to help you avoid them in the future.

when your printf statement is executed:

 printf("#%i key: %s%svalue: %s%s value2: %s", id, key, writeSpace(10), value, writeSpace(8), value2);

The two writeSpace() method calls are executed before the printf itself does anything. The reason for this is that the return value of these methods are used as arguments for the printf method. So the sequence of execution for the above line of code is:

  • writeSpace(10) which prints some white spaces to standard out and returns a null pointer.
  • writeSpace(8) which prints some more white spaces to standard out and also returns a null pointer.
  • finally printf is called with the following arguments: printf("#%i key: %s%svalue: %s%s value2: %s", id, key, null, value, null, value2);

This is why you see the white spaces printed at the beginning, but also why you are seeing the "(null)" appear in your output.

So the lesson learn here is that during a program execution the arguments for a method are resolved before the method itself is called.

Rob
  • 2,618
  • 2
  • 22
  • 29