0

So I'm trying to write this code that displays ASCII code in perfect columns, but the columns are perfectly lined up right know. What am I doing wrong?

#include <iostream>   // cout
#include <iomanip>    // setw

using namespace std;
int main ()
{
    int a;                                                                    
    for(a=32;a<=255;++a)
    {
        cout << a << setw(2) <<static_cast<char>(a)<< setw(20);              
    }

    return 0;
}

This is how I want it to look like, http://www.asciitable.com/index/extend.gif

4 Answers4

2

This is going to be a bit long, so... working code is at the bottom, everything before it is an explanation.

  1. Columns: A simple approach to having n columns in the same line is to conditionally insert a newline after every n entries. The easiest way to do this is to use modulo arithmetic, treating the first entry as 1 and checking if the remainder when dividing by n is 0.

        const int NUMBER_OF_COLUMNS = 5;
    
        // ...
    
        for(a=32;a<=255;++a)
        {
            cout << /* output... */
                 << ((a - 31) % NUMBER_OF_COLUMNS == 0 ? "\n" : "");
        }
    

    How this works: We add or subtract from the loop's to treat it as if it started at 1 (in this case, by subtracting 31 because it starts at 32), then use modulo on that value to determine whether it's cleanly divisible by n. If it is, we insert "\n" (newline); if it's not, we insert "" (nothing).

    This can also be modified to always output a newline at the end of the loop, without placing cout << endl; or cout << '\n'; outside the loop.

    // Change...
    << ((a - 31) % NUMBER_OF_COLUMNS == 0 ? "\n" : "");
    // To...
    << ((a - 31) % NUMBER_OF_COLUMNS == 0 || a == 255 ? "\n" : "");
    // Inserts "\n" every n columns, OR when a is 255.
    

    Alternatively, you can place the check at the start of the output, and treat the loop's counter as if it started with 0; in this case, we would subtract 32.

        const int NUMBER_OF_COLUMNS = 5;
    
        // ...
    
        for(a=32;a<=255;++a)
        {
            cout << ((a - 32) % NUMBER_OF_COLUMNS == 0 ? "\n" : "")
                 << /* output... */;
        }
    

    This will place a newline at the very start of the output, although if that isn't desired, it can be avoided by specifically checking that a isn't actually its starting value.

    // Change...
    ((a - 32) % NUMBER_OF_COLUMNS == 0 ? "\n" : "")
    // To...
    ((a - 32) % NUMBER_OF_COLUMNS == 0 && a != 32 ? "\n" : "")
    // Inserts "\n" every n columns, unless a is 32.
    

    You can also modify this approach to let the user specify how many columns they want to display, if you so desire.

  2. Spacing: If you pass std::setw() a constant value, it can mess up your formatting in certain places. As it stands, there are two issues with the spacing.

    for(a=32;a<=255;++a)
    {
        cout << a
             << setw(2)   // Doesn't take into account the number of digits in a.
             <<static_cast<char>(a)
             << setw(20); // Doesn't take into account character 127 not being a graphical
                          //  character.
    }
    

    As an alternative, you can output tabs with \t, change which output you apply std::setw() to, or use a little logic to determine what value to pass std::setw().

    1. The first one won't properly line up if the width is a constant. This is because std::setw() affects the next output after it, and casting to char guarantees that this output will always be exactly one character (and therefore, that if you specify width x, it will be padded with x - 1 spaces). There are two ways to solve this: Use std::setw() and std::left before outputting a...

      cout << setw(4) << left // Tells cout to make sure a is at least 4 characters,
                              //  padding it at the end if necessary.
                              // 4 characters are used to account for 3 digits + a space.
           << a
           << /* output... */;
      

      Or apply std::setw() to static_cast<char>(a), as you currently are, but use a little logic to determine the value...

      cout << a
           << setw(a < 100 ? 3 : 2)           // Set width to 3 if a < 100, or 2 otherwise.
           << static_cast<char>(a)
           << /* output... */;
      

      If we go with the first one, it may be better to move std::left outside the loop, as so:

      cout << left;
      for(a=32;a<=255;++a)
      {
          cout << setw(4)
               << /* output.. */;
      }
      cout << right; // Reset to default.
      

      Since we're not passing std::right or std::internal inside the loop, there's no reason to pass std::left every single time.

    2. On some platforms, character 127 will break the formatting of everything after it, until the end of the line; this is because it isn't actually a graphical character, and thus won't actually be displayed (Unicode has "DEL", and Win32 console fonts have a house, though, so they can display it graphically). The simplest way to work around this is to output one or more tab stops, or \ts, after static_cast<char>(a).

      cout << /* output... */
           << static_cast<char>(a)
           << "\t\t"
           << /* output... */;
      
  3. Wait, what's that ?: thing?: That would be the conditional operator, unofficially known as the "ternary operator". This operator takes 3 operands, and acts like a miniature if ... else statement that can be used as an expression. It is used as:

    condition ? true-result : false-result

    condition is converted to bool, and can be anything that can evaluate to a boolean value. If true, the operator evaluates to true-result; if false, it evaluates to false-result. This operator looks a bit weird, but is incredibly useful, since it allows conditional logic to be applied in situations where if statements can't be used (such as during variable assignment).

    Here, I used it twice:

    • To conditionally insert a newline into std::cout, after every n columns. Note that it is enclosed in parentheses; this is because it has lower precedence than the << operator. It evaluates to either "\n" or the empty string "", depending on the value of a.
    • To determine the value to pass std::setw(), if it's applied to static_cast<char>(a) instead of a. It evaluates to 3 if a is less than 100, or 2 otherwise.

So, combining these, we get a final result that looks like this:

#include <iostream>   // cout
#include <iomanip>    // setw, left, right

using namespace std;
int main ()
{
    const int NUMBER_OF_COLUMNS = 8; // Number of columns per line.

    cout << left; // Append padding after output.
    int a;
    for(a=32;a<=255;++a)
    {
        cout << setw(4)                         // Pad until 4 characters.
             << a
             << static_cast<char>(a)
             << "\t\t"                          // Use tabs for spacing.
             << ((a - 31) % NUMBER_OF_COLUMNS == 0 || a == 255 ? "\n" : "");
               // Insert newline when specified, and after outputting the last entry.
    }
    // This isn't necessary since you exit right after, but it's a useful habit to develop
    //  if you format text for console output frequently.
    // Remove if desired.
    cout << right; // Reset to default.

    return 0;
}

I would also suggest:
1) Moving the using namespace std; inside main() itself, and/or replacing it with:
using std::cout; using std::left; using std::right; using std::setw;
2) Declaring a inside the for loop's condition, as for(int a=32;a<=255;++1).

Community
  • 1
  • 1
0

Try this:

#include <iostream>   // cout
#include <iomanip>    // setw

using namespace std;
int main()
{
    int a;
    int count = 0;
    for (a = 32; a <= 255; ++a)
    {
        cout << a << setw(2) << static_cast<char>(a);
        if (count != 3)
        {
            cout << setw(20);
            count++;
        }
        else
        {
            count = 0;
            cout << endl;
        }
    }
    cout << endl;

    return 0;
}

PS: if you want to have more columns that are equally long try to change this if (count != 3) and this cout << setw(20); to something like if (count != 6) and cout << setw(9);

yahiheb
  • 147
  • 9
-1

I think that you are looking for something like this:

#include <iostream>   // cout
#include <iomanip>    // setw

using namespace std;
int main ()
{
    int a;                                                                    
    for(a=32;a<=255;++a)
    {
        cout << setw(3) << a << setw(20) <<static_cast<char>(a) << std::endl;              
    }

    return 0;
}

setw(3) comes before the character, and you want 3 instead of 2 as mentioned in the comments. And you also forgot to print a newline at the end.

To get something that looks like the link, you can do something like this:

#include <iostream>   // cout
#include <iomanip>    // setw

using namespace std;
int main ()
{
    int a;
    int nColumns = 14;
    for(a=32;a<=255;++a)
    {
        cout << setw(10) << a << setw(8) <<static_cast<char>(a);
        if((a-31)%nColumns == 0)
        {
            cout<<endl;    
        }
    }
    return 0;
}

My online compiler does not show characters from 130 to 255 so a break appears (columns not lining up after 130). If yours can show correctly every character, you should not see any break.

Example

Jean-Emmanuel
  • 688
  • 8
  • 18
  • Thanks that helps! But that only creates two columns what if I want like 14 columns that are equally long. – Markus Fürst Nov 28 '16 at 18:48
  • @MarkusFürst I'm not sure I understand correctly, can you write a small example ? But I think I would simply add an if statement in the for loop, and look at (a-32)%14 for example. Every time this number is equal to 0, you print the newline – Jean-Emmanuel Nov 28 '16 at 18:52
  • Look at the link I posted in the original question :) – Markus Fürst Nov 28 '16 at 19:01
  • @MarkusFürst Could you explain ? As far as I know, the code compiles and output something coherent. You can have a look [here](http://rextester.com/JMERNN63187). – Jean-Emmanuel Nov 28 '16 at 19:33
  • @MarkusFürst Number of columns might be too big or width to large for your screen, so it might look like it's going on a new line when it should not. Play with these numbers and let me know. – Jean-Emmanuel Nov 28 '16 at 19:35
  • I think the problem is as you said that the columns is too big for my screen or something. The link that you posted, the columns were great until 128. – Markus Fürst Nov 28 '16 at 19:55
  • That's what I said in the post. The online compiler does not know how to print those chars, so the garbage output is bigger than a normal char. I can't verify that, but I believe that a screen outputting the real chars would keep the width just fine. – Jean-Emmanuel Nov 28 '16 at 19:58
  • Thanks for all the help! – Markus Fürst Nov 28 '16 at 20:03
  • 1
    The formatting issue starting at 128 & later is caused by the "delete" control character (ASCII 127), which isn't actually a graphical character (although Unicode displays it as "DEL", and Windows' Win32 console fonts display it as a house). – Justin Time - Reinstate Monica Nov 28 '16 at 21:19
-1

As mentioned before in the comments, you need to ask std::coutfor the correct width before outputting the value, and you need to have a means to output a new line, when you have a certain number of columns. So here is just a small edit to your code (this will have numbers increasing in the row, if you want the values to increase in a column instead of a row, you need to do a bit more math or instead of outputting values directly, have them appended to a string for each line, and then output the values at the end. I'll add the first solution to the end of this answer, since the row-increment answer was already given by someone else :-) ):

#include <iostream>
#include <iomanip>

using namespace std;
int main ()
{
    int nocols = 5;    // number of columns that you want
    for (int a = 32; a < 256; ++a)
    {
        cout << setw(3) << a << setw(20) << static_cast<char>(a);
        if (!((a - 31) % nocols))
            cout << endl;
    }

    return 0;
}

Here is a go at column-increment format:

int nocols = 8;    // number of columns that you want
int norows = 1 + (256 - 32 - 1) / nocols; // number of rows

for (int row = 0; row < norows; ++row)
{
    for (int col = 0; col < nocols; ++col)
    {
        int ch = 32 + norows * col + row;
        if (ch < 256)
            cout << setw(3) << ch << setw(10) << static_cast<char>(ch) << ' ';
    }
    cout << endl;
}
triple_r
  • 1,037
  • 1
  • 8
  • 21
  • Have you tried your code ? The output does not look good. And setw(2) is not enough as he goes up to 255. – Jean-Emmanuel Nov 28 '16 at 19:12
  • @RolandIllig Thanks, fixed it, I also had the formula for `ch` wrong, it was going row by row. Now it should go column by column, and also stop outputting when ch is larger than 255. – triple_r Nov 28 '16 at 19:59
  • It is still wrong. `norows` should be `(256 - 32 + nocols - 1) / nocols`. – Roland Illig Nov 28 '16 at 20:08
  • @RolandIllig I see, mine prints an extra line when number of characters that are being printed is divisible by the number of columns. Thanks, fixed it. – triple_r Nov 28 '16 at 21:00