Stroustrup 4.11 exercise 4

A

arnuld

solution runs fine but i was not able to do the "hexadecimal" part .
any help on that ?

--------- PROGRAMME ---------------
/* TC++PL 3e, 4.11 exercise 4

STATEMENT:
write a programme that prints out the letters 'a'...'z',
digits '0' to '9' and their integer values. do the same for
other printable characters. Do the same again but use hexadecimal
notation.
*/

#include<iostream>

int main()
{
for(int i=0; i <= 127; ++i)
{
std::cout << "'"
<< char(i)
<< "' : \t"
<< i
<< std::endl;
}

return 0;
}

--------- OUTPUT -------------

NOTE: here some characters are not displayed properly but on my GNOME-
Terminal they were displayed without any trouble.

[arch@voodo tc++pl]$ ./a.out
'' : 0
'' : 1
'' : 2
'' : 3
'' : 4
'' : 5
'' : 6
'' : 7
' : 8
' ' : 9
'
' : 10
'
' : 11
'
' : 12
' : 13
'' : 14
'' : 15
'' : 16
'' : 17
'' : 18
'' : 19
'' : 20
'' : 21
'' : 22
'' : 23
'' : 24
'' : 25
'' : 26
'' : 27
'' : 28
'' : 29
'' : 30
'' : 31
' ' : 32
'!' : 33
'"' : 34
'#' : 35
'$' : 36
'%' : 37
'&' : 38
''' : 39
'(' : 40
')' : 41
'*' : 42
'+' : 43
',' : 44
'-' : 45
'.' : 46
'/' : 47
'0' : 48
'1' : 49
'2' : 50
'3' : 51
'4' : 52
'5' : 53
'6' : 54
'7' : 55
'8' : 56
'9' : 57
':' : 58
';' : 59
'<' : 60
'=' : 61
'>' : 62
'?' : 63
'@' : 64
'A' : 65
'B' : 66
'C' : 67
'D' : 68
'E' : 69
'F' : 70
'G' : 71
'H' : 72
'I' : 73
'J' : 74
'K' : 75
'L' : 76
'M' : 77
'N' : 78
'O' : 79
'P' : 80
'Q' : 81
'R' : 82
'S' : 83
'T' : 84
'U' : 85
'V' : 86
'W' : 87
'X' : 88
'Y' : 89
'Z' : 90
'[' : 91
'\' : 92
']' : 93
'^' : 94
'_' : 95
'`' : 96
'a' : 97
'b' : 98
'c' : 99
'd' : 100
'e' : 101
'f' : 102
'g' : 103
'h' : 104
'i' : 105
'j' : 106
'k' : 107
'l' : 108
'm' : 109
'n' : 110
'o' : 111
'p' : 112
'q' : 113
'r' : 114
's' : 115
't' : 116
'u' : 117
'v' : 118
'w' : 119
'x' : 120
'y' : 121
'z' : 122
'{' : 123
'|' : 124
'}' : 125
'~' : 126
'' : 127
[arch@voodo tc++pl]$
 
A

Alf P. Steinbach

* arnuld:
solution runs fine but i was not able to do the "hexadecimal" part .
any help on that ?

This prints a number in hexadecimal notation:

cout << hex << 12345 << endl;

Not sure which header 'hex' is defined in.
 
M

Mike Wahler

Alf P. Steinbach said:
* arnuld:

This prints a number in hexadecimal notation:

cout << hex << 12345 << endl;

Not sure which header 'hex' is defined in.

<ios> declares stream manipulators, except those
taking arguments, which are declared by <iomanip>.

-Mike
 
M

Marcus Kwok

arnuld said:
solution runs fine but i was not able to do the "hexadecimal" part .
any help on that ?

Look up the "hex" manipulator in said:
--------- PROGRAMME ---------------
/* TC++PL 3e, 4.11 exercise 4

STATEMENT:
write a programme that prints out the letters 'a'...'z',
digits '0' to '9' and their integer values. do the same for
other printable characters. Do the same again but use hexadecimal
notation.
*/

[code snipped]
--------- OUTPUT -------------

NOTE: here some characters are not displayed properly but on my GNOME-
Terminal they were displayed without any trouble.

In <cctype> there is a function called isprint() that will tell you
whether or not a character is supposed to be printable.
 
I

I V

Your program doesn't quite do what the exercise asks:

STATEMENT:
write a programme that prints out the letters 'a'...'z',
digits '0' to '9' and their integer values. do the same for
other printable characters. Do the same again but use hexadecimal
notation.
*/

The exercise asks you to print the letters a-z and the digits 0-9 but here
for(int i=0; i <= 127; ++i)
{

you are printing all the characters with codes between 0 and 127. Some of
these will be characters which are not letters a-z or numbers 0-9; some of
them will not be printable characters at all (this is why you are getting
odd output).

I'm pretty sure that the C++ standard guarantees that the
character codes for a-z are continuous, as are the codes for the digits
0-9, so you can loop over these two character ranges.
 
A

arnuld

Your program doesn't quite do what the exercise asks:
The exercise asks you to print the letters a-z and the digits 0-9 but here

NO, it also asks you to print the ALL printable characters. read
again.
you are printing all the characters with codes between 0 and 127. Some of
these will be characters which are not letters a-z or numbers 0-9; some of
them will not be printable characters at all (this is why you are getting
odd output).

ok, how do i know which characters are printable or not ?
 
A

arnuld

In <cctype> there is a function called isprint() that will tell you
whether or not a character is supposed to be printable.


great, i used it and here is the resulting programme and output. as
you can see the output contains only the CHARS between 32-126 because
i applied "isprint()".

thanks Marcus

--------- PROGRAMME ------------

#include<iostream>
#include<cctype>

int main()
{
std::cout << "CHAR \tDECIMAL\tHEX" << std::endl;

for(int i=0; i <= 127; ++i)
{
char ic = char(i);

if(isprint(ic))
{
std::cout << "'"
<< ic
<< "' : \t"
<< i
<< std::endl;
}
}

return 0;
}

---------- OUTPUT ----------
CHAR DECIMAL HEX
' ' : 32
'!' : 33
'"' : 34
'#' : 35
'$' : 36
'%' : 37
'&' : 38
''' : 39
'(' : 40
')' : 41
'*' : 42
'+' : 43
',' : 44
'-' : 45
'.' : 46
'/' : 47
'0' : 48
'1' : 49
'2' : 50
'3' : 51
'4' : 52
'5' : 53
'6' : 54
'7' : 55
'8' : 56
'9' : 57
':' : 58
';' : 59
'<' : 60
'=' : 61
'>' : 62
'?' : 63
'@' : 64
'A' : 65
'B' : 66
'C' : 67
'D' : 68
'E' : 69
'F' : 70
'G' : 71
'H' : 72
'I' : 73
'J' : 74
'K' : 75
'L' : 76
'M' : 77
'N' : 78
'O' : 79
'P' : 80
'Q' : 81
'R' : 82
'S' : 83
'T' : 84
'U' : 85
'V' : 86
'W' : 87
'X' : 88
'Y' : 89
'Z' : 90
'[' : 91
'\' : 92
']' : 93
'^' : 94
'_' : 95
'`' : 96
'a' : 97
'b' : 98
'c' : 99
'd' : 100
'e' : 101
'f' : 102
'g' : 103
'h' : 104
'i' : 105
'j' : 106
'k' : 107
'l' : 108
'm' : 109
'n' : 110
'o' : 111
'p' : 112
'q' : 113
'r' : 114
's' : 115
't' : 116
'u' : 117
'v' : 118
'w' : 119
'x' : 120
'y' : 121
'z' : 122
'{' : 123
'|' : 124
'}' : 125
'~' : 126
[arch@voodo tc++pl]$
 
A

Alf P. Steinbach

* arnuld:
ok, how do i know which characters are printable or not ?

You can use the iscntrl function.

This function, from the old C library, is designed so that it almost
invites you to use it incorrectly.

The argument type is 'int', but it expects a /non-negative/ character code.

Hence if you pass a 'char', and with your compiler or compiler options
'char' is a signed type, you might end up passing in a negative value.

To avoid that the actual argument should be cast to 'unsigned char'
(it's perhaps best to write a function that in turn calls iscntrl).
 
A

arnuld

<ios> declares stream manipulators, except those
taking arguments, which are declared by <iomanip>.

i tried this:

------------ PROGRAMME -----------
#include<iostream>
#include<cctype>
#include<ios>


int main()
{
std::cout << "CHAR \tDECIMAL\tHEX" << std::endl;

for(int i=0; i <= 127; ++i)
{
char ic = char(i);

if(isprint(ic))
{
std::cout << "'"
<< ic
<< "' : \t"
<< i
<< '\t'
<< std::ios::hex
<< i
<< std::endl;
}
}

return 0;
}

--------- OUTPUT ----------
[arch@voodo tc++pl]$ g++ -ansi -pedantic -Wall -Wextra 4.11_4.cpp
[arch@voodo tc++pl]$ ./a.out
CHAR DECIMAL HEX
' ' : 32 832
'!' : 33 833
'"' : 34 834
---------------------

i only USED some part of OUTPUT of here to make post shorter. you can
see the 1st line: DECIMAL "32" equals "832" in HEX. but it does not,
see:

HEX 832 = 8*16^2 + 3*16^1 + 2*16^0
= 2048 + 48 + 2
= 2098 IN DECIMAL

what is wrong with my programme ?
 
A

Alf P. Steinbach

* arnuld:
<ios> declares stream manipulators, except those
taking arguments, which are declared by <iomanip>.

i tried this:

------------ PROGRAMME -----------
#include<iostream>
#include<cctype>
#include<ios>


int main()
{
std::cout << "CHAR \tDECIMAL\tHEX" << std::endl;

for(int i=0; i <= 127; ++i)
{
char ic = char(i);

if(isprint(ic))
{
std::cout << "'"
<< ic
<< "' : \t"
<< i
<< '\t'
<< std::ios::hex
<< i
<< std::endl;
}
}

return 0;
}

--------- OUTPUT ----------
[arch@voodo tc++pl]$ g++ -ansi -pedantic -Wall -Wextra 4.11_4.cpp
[arch@voodo tc++pl]$ ./a.out
CHAR DECIMAL HEX
' ' : 32 832
'!' : 33 833
'"' : 34 834
---------------------

i only USED some part of OUTPUT of here to make post shorter. you can
see the 1st line: DECIMAL "32" equals "832" in HEX. but it does not,
see:

HEX 832 = 8*16^2 + 3*16^1 + 2*16^0
= 2048 + 48 + 2
= 2098 IN DECIMAL

what is wrong with my programme ?

A number of things.

First, unrelated to the hex, the conversion of 'i' to 'ic', to serve as
argument to 'isprint', does exactly the Wrong Thing. For the range you
have chosen, 0 through 127, it doesn't matter. But if increased that
range to say 0 through 255, then the conversion would introduce a
possible bug whereas all would be OK if you just used 'i' directly.

Second, regarding the hex. It's evident from the output that
std::ios::hex is display as '8', then 'i' is displayed in decimal. And
the reason is that the program is using the wrong 'hex', again because
it does to much: simply write 'std::hex', not 'std::ios::hex'.

Third, still regarding the hex. It sets the stream to a persistent
"display as hex" mode. Thus, when the code has been fixed as explained
above, only the first line of output will show any decimal number, the
rest will all be in hex.

I leave it to you to figure out a solution to that. ;-)
 
A

Alf P. Steinbach

* Michael DOUBEZ:
Alf P. Steinbach a écrit :

Or simply the isprint function of the same header (cctype).

Not that it matters much, but you can assume there was a reason why I
didn't select that more "obvious" function in my answer.
 
A

arnuld

A number of things.

First, unrelated to the hex, the conversion of 'i' to 'ic', to serve as
argument to 'isprint', does exactly the Wrong Thing. For the range you
have chosen, 0 through 127, it doesn't matter. But if increased that
range to say 0 through 255, then the conversion would introduce a
possible bug whereas all would be OK if you just used 'i' directly.

OK, if I use "i" directly then in "isprint(i)" will always be
printable whereas corresponding "char(i)" will not. i have also
removed some magic numbers. this i what i have done now:

#include<iostream>
#include<cctype>

int main()
{
std::cout << "CHAR \tDECIMAL\tHEX" << std::endl;

const int lower_range = 0;
const int upper_range = 127;

for(int i = lower_range; i <= upper_range; ++i)
{
if(isprint((char(i))))
// i think it is same as using "char ic = char(i)
{
std::cout << "'"
<< char(i)
<< "' : \t"
<< i
<< "\t0x"
<< std::hex
<< i
<< std::endl;
}
}

return 0;
}

Second, regarding the hex. It's evident from the output that
std::ios::hex is display as '8', then 'i' is displayed in decimal. And
the reason is that the program is using the wrong 'hex', again because
it does to much: simply write 'std::hex', not 'std::ios::hex'.
done

Third, still regarding the hex. It sets the stream to a persistent
"display as hex" mode. Thus, when the code has been fixed as explained
above, only the first line of output will show any decimal number, the
rest will all be in hex.


YES, you are right:

[arch@voodo tc++pl]$ ./a.out
CHAR DECIMAL HEX
' ' : 32 0x20
'!' : 21 0x21
'"' : 22 0x22
'#' : 23 0x23


:-(

I leave it to you to figure out a solution to that. ;-)

all i can guess is "std::hex" works in both directions, left and right
BUT if that is true why do i get CORRECT values in 1st line? "32
0x20". i don't have any answer to this question.

i can create an "if-else" loop, where it will ask the user whether to
print the output in DEC format or in HEX but i don't want to do this.
i want both DEC and HEX on the same line. i am unable to figure any
way out.
 
A

Alf P. Steinbach

* arnuld:
OK, if I use "i" directly then in "isprint(i)" will always be
printable whereas corresponding "char(i)" will not.

No. If you use isprint(i) then the function will work correctly. If
you use isprint(char(i)) then, if char is a signed type and the
character code is negative, isprint has Undefined Behavior, which means
it may crash or give an incorrect result or, for that matter, a correct
one. Don't ever give isprint a negative number as argument. That also
goes for its family functions.

i have also
removed some magic numbers. this i what i have done now:

#include<iostream>
#include<cctype>

int main()
{
std::cout << "CHAR \tDECIMAL\tHEX" << std::endl;

const int lower_range = 0;
const int upper_range = 127;

for(int i = lower_range; i <= upper_range; ++i)

This is good.

{
if(isprint((char(i))))

This is in-principle bad (although with the given range it doesn't do
anything bad): just write 'isprint(i)'.

// i think it is same as using "char ic = char(i)
{
std::cout << "'"
<< char(i)
<< "' : \t"
<< i
<< "\t0x"
<< std::hex
<< i
<< std::endl;
}
}

return 0;
}

[snip]
Third, still regarding the hex. It sets the stream to a persistent
"display as hex" mode. Thus, when the code has been fixed as explained
above, only the first line of output will show any decimal number, the
rest will all be in hex.


YES, you are right:

[arch@voodo tc++pl]$ ./a.out
CHAR DECIMAL HEX
' ' : 32 0x20
'!' : 21 0x21
'"' : 22 0x22
'#' : 23 0x23


:-(

I leave it to you to figure out a solution to that. ;-)

all i can guess is "std::hex" works in both directions, left and right
BUT if that is true why do i get CORRECT values in 1st line? "32
0x20". i don't have any answer to this question.

No, it doesn't work in both directions. It doesn't affect earlier
output. It causes cout to /remember/ that the numbers should be display
in hexadecimal notation.

Initially cout remembers that numbers should be displayed in decimal
notation, and you changed that by using hex.

Now, after a little hex, cout remembers that numbers should be displayed
in hexadecimal notation, and you change that by ...?
 
A

arnuld

No. If you use isprint(i) then the function will work correctly. If
you use isprint(char(i)) then, if char is a signed type and the

i dont understand the behaviour of "isprint()". does it understand its
input as merely an "int" or an "int for ASCII". to be exact:

isprint(68) == int 68
isprint(68) == ASCII representation of 'A'

character code is negative, isprint has Undefined Behavior, which means
it may crash or give an incorrect result or, for that matter, a correct
one. Don't ever give isprint a negative number as argument. That also
goes for its family functions.

ok... i will take it as my 1st "good coding practice" advice from
Alf ;-)


No, it doesn't work in both directions. It doesn't affect earlier
output. It causes cout to /remember/ that the numbers should be display
in hexadecimal notation.

Initially cout remembers that numbers should be displayed in decimal
notation, and you changed that by using hex.

Now, after a little hex, cout remembers that numbers should be displayed
in hexadecimal notation, and you change that by ...?

ok.. what "function" i can use that converts only the given DEC int to
a HEX int. IOW, is it possible to make it NOT to REMEMBER ?
 
M

Michael DOUBEZ

Alf P. Steinbach a écrit :
* Michael DOUBEZ:

Not that it matters much, but you can assume there was a reason why I
didn't select that more "obvious" function in my answer.

Which without explaination only confuse the matter since the OP question
was to know wether a charater is printable or not.

Michael
 
D

Default User

Alf P. Steinbach wrote:

No. If you use isprint(i) then the function will work correctly. If
you use isprint(char(i)) then, if char is a signed type and the
character code is negative, isprint has Undefined Behavior, which
means it may crash or give an incorrect result or, for that matter, a
correct one. Don't ever give isprint a negative number as argument.
That also goes for its family functions.

A slight nitpick. It's ok to pass EOF to isprint() and the other
"character handling" functions. Presumably that's for the case of using
them in conjunction with getchar() or the like, that return an int
that's either an unsigned char converted to int or EOF.




Brian
 
M

Marcus Kwok

I V said:
I'm pretty sure that the C++ standard guarantees that the
character codes for a-z are continuous, as are the codes for the digits
0-9, so you can loop over these two character ranges.

IIRC, only the digits are guaranteed to be contiguous. The letters, not
necessarily so (see EBCDIC).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,039
Messages
2,570,376
Members
47,029
Latest member
EmiliaSton

Latest Threads

Top