As I write my code, I am realizing there are numerous places where a type int could easily be substituted with a type char. Because type char uses less memory than its int counterpart, I am curious why people don't prefer the former more often. for example, it's not uncommon to see a for statement that looks like for(int i, i <10, i++). Why would you use a type int in this statement as opposed to a type char if char consumes less memory and the value of i never exceeds 10?

EDIT: ehh.. is char not able to hold number values?

I think I answered my question. If I try to display a char value, a character as opposed to a number will be returned.

> Because type char uses less memory than its int counterpart, I am curious why people don't prefer the former more often.
Edward has come up with 4 reasons:

  1. int is the default integer type.
  2. int is usually the same as the machine's word size.
  3. Micro-optimizing storage is usually counter-productive.
  4. char is usually treated as a character rather than a small int.

For #2, it's a trade off of size for speed. The variable of the native word size can be faster than a smaller or larger variable.

char in particular is troublesome because it can be either signed or unsigned depending on your compiler. At least with int you know that it's signed, but you can use a smaller type if you really want to:

for (char i = 0; i < 10; ++i)
  std::cout << (int)i << '\n';

cout will treat i as a char without the cast and print a character instead of the integer value, but that's completely the display representation and not the internal value. At the cost of a little more memory you can fix that annoyance by using short instead of char:

for (short i = 0; i < 10; ++i)
  std::cout << i << '\n';

In general, micro-optimizing storage like this is really only beneficial on heavily constrained hardware like embedded systems.

One of the reasons I asked this question is because in my Sudoku program I need to be able to display blank spaces. Currently, the numbers are stored in an array type int; however, I can't display a blank space in here. Would you recommend that I store the values in a string array instead? But isn't a string simply an array of characters....? Now I'm just confusing myself.

I thought type integer only accepted numbers.... Am I allowed to put things in there besides numbers?

For example, something like this won't compile:

#include <iostream>
using namespace std;

main()
{
      int i;
      i = " ";
      cout << i;
      i = "P";
      cout << i;
      return 0;
}

and something like this won't display charatcers but only integers.

#include <iostream>
using namespace std;

main()
{
      int i[] = {' ', 'a'};
      cout << i[0] << endl <<  i[1];
      cin.ignore();
      return 0;
}

Do I need to run a check to see if the integer value of a space is being display and if it is display it as a character instead?

The char type only accepts numbers too. It's not the data that changes, it's how the data is displayed.

> For example, something like this won't compile:
Because a string literal isn't an integer, it's a pointer. This compiles fine because a character literal is syntactic sugar for the underlying integer value:

#include <iostream>

int main()
{
  int i = 'P';
  
  std::cout << i << '\t' << (char)i << '\n';
}

Remember that cout guesses what you want to happen by using the type. int types will be printed as numbers and char types will be printed as characters, so you have to cast.

Edward's question was focused more on why you can't have anything but super simple output. If the problem is storing a blank value, that's not a problem at all. You can just use a value that isn't valid and print a space when you encounter it:

#include <iostream>

void PrintValue(int value)
{
  if (value == -1)
    std::cout << ' ';
  else
    std::cout << value;
}

int main()
{
  int block[3][3] = {
    {-1, 1, -1},
    {-1, 4,  2},
    {8,  7, -1},
  };

  for (int i = 0; i < 3; ++i) {
    PrintValue(block[i][0]);

    for (int j = 1; j < 3; ++j) {
      std::cout << '|';

      PrintValue(block[i][j]);
    }

    if (i < 2)
      std::cout << "\n-+-+-";

    std::cout << '\n';
  }
}

The char datatype is not guaranteed to be stored in a single byte, either.


I would also like to expand somewhat on Ed's response. Typically you don't want to directly print your data, but you want to transform it when you read and write it.

That's what cin and cout do. If you give cout an int, it doesn't actually print an integer to the screen, it prints a string to the screen which represents the integer in a way that humans like to read.

The same is true for the cells of your Sudoku board. Use a function (like Ed's PrintValue()) to write the appropriate thing to screen.

Hope this helps.

alright. That makes sense to me. I'll create my own output function then that slightly modifies cout. also, under what circumstances does a type char exceed the size of one byte, just out of curiosity?

The data type char is simply a one-byte integer. The maximum and minimum values for your machine and compiler are stored in the header file limits.h. Typically the maximum value is 127 and minimum value is -126. An unsigned char data type can store values in the range 0 to 255.

There really is no such thing as a character in C or C++ because the char data type is just a small integer. When you assign the letter 'A' to a char data type you are assigning the integer value that can be found in any ascii chart. For 'A' the decimal equivalent is 65. The only reason you see an 'A' when you display it using cout is because cout uses some complicated processes to transform the number 65 to a printable character. If you have a non-English computer, such as German, French, Chinese, etc the value 65 will be displayed as something else because they do not use standard American ascii tables. It all depends on what fonts are installed on the computer and what language(s) is/are installed.

> The char datatype is not guaranteed to be stored in a single byte, either.
char is guaranteed to equate to a byte, but a byte isn't guaranteed to be 8 bits. I think that's what you meant.

Comments
Yes, thanks for the correction.

A char is guaranteed to contain 8 bits, at least. (And unless you are playing with really old hardware, like ancient vaxen, a byte is also 8 bits.) But the compiler is not required to store individual chars in 8-bit entities.

So, yes, that's what I meant.

@zoner7
Don't modify cout. Just write a routine to do stuff for you.

I'm writing a Sudoku solver too... :)

The basic cell type can overload the shift operators for I/O:

struct cell_t
  {
  int value;
  // Whatever else I store in a single cell goes here
  };

std::istream& operator >> ( std::istream& ins, cell_t& cell )
  {
  // Get a cell. For example, if each cell is just one char, '1'..'9' and ' ':
  int c = ins.get();
  if (std::isdigit( c ) and (c != '0')) cell.value = c -'0';
  else                                  cell.value = -1;
  return ins;
  }

std::ostream& operator << ( std::ostream& outs, const cell_t& cell )
  {
  // This is the same as Ed's PrintValue() function,
  // with just a little extra error checking...
  if ((cell.value %10) == cell.value) outs << (char)(cell.value +'0');
  else                                outs << ' ';
  return outs;
  }

Hope this helps.

A char is guaranteed to contain 8 bits, at least. (And unless you are playing with really old hardware, like ancient vaxen, a byte is also 8 bits.) But the compiler is not required to store individual chars in 8-bit entities.

So, yes, that's what I meant.

@zoner7
Don't modify cout. Just write a routine to do stuff for you.

I'm writing a Sudoku solver too... :)

The basic cell type can overload the shift operators for I/O:

struct cell_t
  {
  int value;
  // Whatever else I store in a single cell goes here
  };

std::istream& operator >> ( std::istream& ins, cell_t& cell )
  {
  // Get a cell. For example, if each cell is just one char, '1'..'9' and ' ':
  int c = ins.get();
  if (std::isdigit( c ) and (c != '0')) cell.value = c -'0';
  else                                  cell.value = -1;
  return ins;
  }

std::ostream& operator << ( std::ostream& outs, const cell_t& cell )
  {
  // This is the same as Ed's PrintValue() function,
  // with just a little extra error checking...
  if ((cell.value %10) == cell.value) outs << (char)(cell.value +'0');
  else                                outs << ' ';
  return outs;
  }

Hope this helps.

I am just curious what topic matter of C++ that this code uses. Meaning, if I opened up a table of contents, what would I look under to learn more about this subject. I only ask, because I have never encountered a lot of the syntax and phrases that are being used above.

> Meaning, if I opened up a table of contents, what would I look under to learn more about this subject.
Operator overloading, and probably stream I/O too. The exactly thing is overloading the insertion and extraction operators.

This article has been dead for over six months. Start a new discussion instead.