-1

I am trying to understand printf() but I am only familiar with C++ cout<< statements, would anyone be able to translate the syntax of the printf() statements below? I am just trying to understand what is happening in this snippet of code.

void print_section(int n, int z){

    char dots[2*n+1];       // this makes a char array
    memset(dots,':',2*n+1); // this is similar to setfill()
    dots[2*n+1] = 0;

    for(int r = 0; r < n+1; r++){
        printf("%*.s|%.*s\\%.*s/%.*s|\n",z-n,"",r,dots,2*(n-r),dots,r,dots);
    }
    for(int r = n; r >= 0; r--){
        printf("%*.s|%.*s/%.*s\\%.*s|\n",z-n,"",r,dots,2*(n-r),dots,r,dots);
    }
}
GeorgiN
  • 21
  • 5

1 Answers1

2

How printf() works?

If you want to fully understand the working of printf() function, then refer this: http://www.cplusplus.com/reference/cstdio/printf/

In simple words, "%*.s|%.*s\\%.*s/%.*s|\n" says that

  1. Set field width dynamically and print required amount of ''
  2. Print |
  3. Set field width dynamically and print required amount of ':'
  4. Print \
  5. Set field width dynamically and print required amount of ':'
  6. Print /
  7. Set field width dynamically and print required amount of ':'
  8. Print |
  9. Print newline character \n to go to the next line in console.

Similarly, you can figure out what "%*.s|%.*s/%.*s\\%.*s|\n" will print.

Code conversion

I assume that you're pretty familiar with C++. It's better if you use string class as you can then easily use substr() member function to extract the required dots substring to print. You can understand how setw() works from here. The converted code is given below.

#include <iostream> // Input.Output
#include <string> // string class
#include <iomanip> // setw() function
int main(){
    const int n=3,z=6;
    std::string _dots(2*n+1,':');
    for(int r = 0; r < n+1; r++){
        std::cout<<std::setw(z-n)<<""<<"|"<<_dots.substr(0,r)<<"\\"<<_dots.substr(0,2*(n-r))<<"/"<<_dots.substr(0,r)<<"|"<<std::endl;
    }
    for(int r = n; r >= 0; r--){
        std::cout<<std::setw(z-n)<<""<<"|"<<_dots.substr(0,r)<<"/"<<_dots.substr(0,2*(n-r))<<"\\"<<_dots.substr(0,r)<<"|"<<std::endl;
    }
    return 0;
}

Output

   |\::::::/|
   |:\::::/:|
   |::\::/::|
   |:::\/:::|
   |:::/\:::|
   |::/::\::|
   |:/::::\:|
   |/::::::\|
Ajay Dabas
  • 1,404
  • 1
  • 5
  • 15
  • 1
    Yep, that's the key. Where the *precision* can be controlled by `printf` with the `"%s"` *conversion specifier* to limit the number of characters output, in C++, you have to control the string size itself with `.substr()`. **Note:** you only need `std::string _dots(2*n,':');` -- no need to reserve space for the *nul-terminating* character `:)` – David C. Rankin Jan 25 '20 at 06:23
  • One bit of extra sneaky worth spending some time on is exactly what happens with the first `"%*.s"`. The associated arguments are `z-n` and `""`, a minimum length to print (padded with spaces because nothing else is specified) and an empty string. `"%s"` would be just print an empty string--basically do nothing--but because of the `*.` that nothing has a minimum width of `z-n` spaces. End result: print `z-n` spaces. I'm not sure that `.` is needed though. I'd love it if anyone could explain if I missed something. – user4581301 Jan 25 '20 at 06:37