counting with char

Discussion in 'C Programming' started by eiaks, May 3, 2006.

  1. eiaks

    eiaks Guest

    Hello,

    I want to print a table of characters and their values for my system like
    65: A
    66: B
    aso.
    starting from 0 to 255.

    Am I rigth that I should use an unsigned char for this,
    incrementing it each time? Using an signed char, or just
    plain char (which is signed on my system) would just make
    things difficult since I need to count with negative values.

    But then the problem is the for loop.
    Both this:

    unsigned char c;
    for (c = 0; c < 256; c++)

    and

    for (c = 0; c <= 255; c++)

    will result in an infinite loop since c can't be larger than 255.

    How can I tackle this? Do I have to use an other datatype than
    char for the counter? Or can I cast it at the comparision somehow?

    Which way is the best to go?
     
    eiaks, May 3, 2006
    #1
    1. Advertising

  2. eiaks said:

    > Hello,
    >
    > I want to print a table of characters and their values for my system like
    > 65: A
    > 66: B
    > aso.
    > starting from 0 to 255.
    >
    > Am I rigth that I should use an unsigned char for this,
    > incrementing it each time? Using an signed char, or just
    > plain char (which is signed on my system) would just make
    > things difficult since I need to count with negative values.


    Just use int. All characters are representable as ints.

    A word of advice: before deciding whether to write a character to your
    standard output stream, shove it through isprint(), like this:

    /* ch is an int */
    if(isprint((unsigned char)ch))
    {
    display the character as a character by all means
    }
    else
    {
    display some kind of indication that the character is not printable
    }

    --
    Richard Heathfield
    "Usenet is a strange place" - dmr 29/7/1999
    http://www.cpax.org.uk
    email: rjh at above domain (but drop the www, obviously)
     
    Richard Heathfield, May 3, 2006
    #2
    1. Advertising

  3. eiaks

    Mike Wahler Guest

    "eiaks" <> wrote in message
    news:xGR5g.55295$...
    > Hello,
    >
    > I want to print a table of characters and their values for my system like
    > 65: A
    > 66: B
    > aso.
    > starting from 0 to 255.
    >
    > Am I rigth that I should use an unsigned char for this,
    > incrementing it each time? Using an signed char, or just
    > plain char (which is signed on my system) would just make
    > things difficult since I need to count with negative values.
    >
    > But then the problem is the for loop.
    > Both this:
    >
    > unsigned char c;
    > for (c = 0; c < 256; c++)
    >
    > and
    >
    > for (c = 0; c <= 255; c++)
    >
    > will result in an infinite loop since c can't be larger than 255.


    You could count backwards:

    #include <ctype.h>
    #include <limits.h>
    #include <stdio.h>

    int main(void)
    {
    unsigned char c = UCHAR_MAX;
    const char unprintable = '#';
    unsigned char tmp = 0;

    while(c)
    {
    tmp = UCHAR_MAX - c;
    printf("%d: %c\n",
    tmp,
    isprint(tmp) ? (char)tmp : unprintable);
    --c;
    }

    return 0;
    }

    > How can I tackle this? Do I have to use an other datatype than
    > char for the counter?


    You must if you need to use a value outside its range:

    int main(void)
    {
    unsigned int c = 0;
    const char unprintable = '#';

    for(c = 0; c < UCHAR_MAX; ++c)
    {
    printf("%3d: %c\n",
    c, isprint(c) ? (char)c : unprintable);
    }

    return 0;
    }


    > Or can I cast it at the comparision somehow?


    Casting cannot change the range of a type.
    Always view a desire to cast with suspicion.

    > Which way is the best to go?


    I'd go with my second example; imo it's more
    'straightforward'.

    -Mike
     
    Mike Wahler, May 3, 2006
    #3
  4. eiaks

    Mike Wahler Guest

    Re: (corr) counting with char

    "Mike Wahler" <> wrote in message
    news:doS5g.6307$...
    >
    > int main(void)
    > {
    > unsigned int c = 0;
    > const char unprintable = '#';
    >
    > for(c = 0; c < UCHAR_MAX; ++c)


    for(c = 0; c <= UCHAR_MAX; ++c)

    -Mike
     
    Mike Wahler, May 3, 2006
    #4
  5. eiaks

    Old Wolf Guest

    Richard Heathfield wrote:
    >
    > All characters are representable as ints.


    Chapter and verse? ;)
     
    Old Wolf, May 3, 2006
    #5
  6. eiaks

    Al Balmer Guest

    On Tue, 02 May 2006 23:11:25 GMT, eiaks <> wrote:

    >Hello,
    >
    >I want to print a table of characters and their values for my system like
    >65: A
    >66: B
    >aso.
    >starting from 0 to 255.
    >
    >Am I rigth that I should use an unsigned char for this,
    >incrementing it each time? Using an signed char, or just
    >plain char (which is signed on my system) would just make
    >things difficult since I need to count with negative values.
    >
    >But then the problem is the for loop.
    >Both this:
    >
    >unsigned char c;
    >for (c = 0; c < 256; c++)
    >
    >and
    >
    >for (c = 0; c <= 255; c++)
    >
    >will result in an infinite loop since c can't be larger than 255.


    Make it an int. An int will hold all char values, and chars change
    into ints whenever you aren't watching them closely anyway <g>.

    One other thing - your printer or screen will likely go nuts when you
    print the output, because of all the non-printable characters. Use
    isprint() to check each character, and substitute something else for
    those that aren't printable (a period is often used.)
    >
    >How can I tackle this? Do I have to use an other datatype than
    >char for the counter? Or can I cast it at the comparision somehow?
    >
    >Which way is the best to go?


    --
    Al Balmer
    Sun City, AZ
     
    Al Balmer, May 3, 2006
    #6
  7. Old Wolf said:

    > Richard Heathfield wrote:
    >>
    >> All characters are representable as ints.

    >
    > Chapter and verse? ;)


    Um, well, okay, what I said is certain to be true on the OP's system.

    I suppose it is possible to construct a scenario where what I said is not
    true, e.g. CHAR_BIT = 16, char is unsigned by default, INT_MAX is 32767,
    and the character set is pretty large.


    --
    Richard Heathfield
    "Usenet is a strange place" - dmr 29/7/1999
    http://www.cpax.org.uk
    email: rjh at above domain (but drop the www, obviously)
     
    Richard Heathfield, May 3, 2006
    #7
  8. eiaks

    Chris Torek Guest

    In article <xGR5g.55295$>
    eiaks <> wrote:
    >Both this:
    > unsigned char c;
    > for (c = 0; c < 256; c++)
    >and
    > for (c = 0; c <= 255; c++)
    >will result in an infinite loop since c can't be larger than 255.


    Indeed: if UCHAR_MAX is 255, then when c==255, c++ has the same
    effect as "c = 0" (because 255+1 is congruent to zero mod 256, as
    the mathematicians say it).

    As others noted, this particular case can be solved by counting in
    "int" (which goes to at least +32767, and often higher). But there
    are some situations in which C's "for" loop simply does not do the
    desired job. For instance, suppose that, in C89 (not C99 hence
    no "long long" type), you wish to iterate over every possible
    "unsigned long" value. An attempt like:

    unsigned long ul;

    for (ul = 0; ul <= ULONG_MAX; ul++)

    is an infinite loop, just as with the example above with unsigned
    char. What is needed is a loop construct with a test-at-bottom.
    C has one, but it is clumsier than a "for" loop. Just as most
    people prefer a "for" loop for iterating through a list:

    for (p = head; p != NULL; p = p->next)

    or looping zero-or-more times through a case that does not hit
    integer boundary problems:

    for (i = 0; i < n; i++)

    we might "prefer" a "for_until_with_test_at_bottom" loop in which
    we could write:

    for_until_test_at_bottom (ul = 0; ul != ULONG_MAX; ul++) {
    ... code ...
    }

    Instead, in C, we have to write, e.g.:

    ul = 0;
    do {
    ... code ...
    continue_here: ;
    } while (ul++ != ULONG_MAX);

    and replace any "continue" statements in the "code" section with
    "goto continue_label". (If there are no such statements, we can
    omit the label and the empty statement that goes with it.) This
    construct *also* depends on the fact that "ul++" is well defined
    even if ul was ULONG_MAX (here ul becomes 0). (We could write this
    as "do { ... } while (++ul != 0);" as well.) If the termination
    condition might overflow -- as is true with signed integers -- we
    have at least a technical problem, as the "++" might trap (even
    though Real C Compilers never do, even on machines on which they
    could -- it is usually more important to produce wrong answers fast
    than to catch the error, after all :) ).

    Fortunately there is a third alternative. Although some purists
    object to it, it neatly implements *all* forms of loops, including
    test-at-top, test-at-bottom, and the occasional test-in-the-middle
    "loop-and-a-half" that comes up now and then:

    for (ul = 0;; ul++) {
    ... some code here ...
    if (should_terminate_loop)
    break;
    ... more code here ...
    }

    where either "code" section can be eliminated. (Of course, if the
    first section is eliminated, we can just move the termination
    condition into the "for" statement, and invert the sense.)
    --
    In-Real-Life: Chris Torek, Wind River Systems
    Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
    email: forget about it http://web.torek.net/torek/index.html
    Reading email is like searching for food in the garbage, thanks to spammers.
     
    Chris Torek, May 3, 2006
    #8
  9. eiaks

    CBFalconer Guest

    Chris Torek wrote:
    >

    .... snip ...
    >
    > Fortunately there is a third alternative. Although some purists
    > object to it, it neatly implements *all* forms of loops, including
    > test-at-top, test-at-bottom, and the occasional test-in-the-middle
    > "loop-and-a-half" that comes up now and then:
    >
    > for (ul = 0;; ul++) {
    > ... some code here ...
    > if (should_terminate_loop)
    > break;
    > ... more code here ...
    > }
    >
    > where either "code" section can be eliminated. (Of course, if the
    > first section is eliminated, we can just move the termination
    > condition into the "for" statement, and invert the sense.)


    In my view, ugly. What is this urge to cast everything into a for
    loop? while and do while are also available, and usually clearer
    IMNSHO. for is best suited for iteration.

    --
    "If you want to post a followup via groups.google.com, don't use
    the broken "Reply" link at the bottom of the article. Click on
    "show options" at the top of the article, then click on the
    "Reply" at the bottom of the article headers." - Keith Thompson
    More details at: <http://cfaj.freeshell.org/google/>
    Also see <http://www.safalra.com/special/googlegroupsreply/>
     
    CBFalconer, May 3, 2006
    #9
  10. eiaks

    Chris Torek Guest

    >Chris Torek wrote:
    >> Fortunately there is a third alternative. Although some purists
    >> object to it, it neatly implements *all* forms of loops, including
    >> test-at-top, test-at-bottom, and the occasional test-in-the-middle
    >> "loop-and-a-half" that comes up now and then:
    >>
    >> for (ul = 0;; ul++) {
    >> ... some code here ...
    >> if (should_terminate_loop)
    >> break;
    >> ... more code here ...
    >> }
    >>
    >> where either "code" section can be eliminated. (Of course, if the
    >> first section is eliminated, we can just move the termination
    >> condition into the "for" statement, and invert the sense.)


    In article <>
    CBFalconer <> wrote:
    >In my view, ugly. What is this urge to cast everything into a for
    >loop? while and do while are also available, and usually clearer
    >IMNSHO. for is best suited for iteration.


    The example *was* iteration.

    Write me a loop that iterates an "int i" from INT_MIN through
    INT_MAX, *inclusive*, with no undefined behavior, and only one copy
    of the loop body. (Make sure that a "continue" within the loop
    "does the right thing" too.) The last constraint rules out these
    two forms:

    i = INT_MIN;

    LOOP_BODY; /* handles INT_MIN case */

    do {
    i++; /* starts at INT_MIN+1 */
    LOOP_BODY; /* handles INT_MIN+1 through INT_MAX */
    } while (i != INT_MAX);

    and:

    i = INT_MIN;
    do {
    LOOP_BODY; /* handles INT_MIN through INT_MAX - 1 */
    } while (++i != INT_MAX);
    LOOP_BODY; /* handles INT_MAX case */

    The "no undefined behavior" constraint rules out this form:

    i = INT_MIN;
    do {
    LOOP_BODY;
    } while (i++ != INT_MAX);

    because "i++" is undefined when i == INT_MAX.
    --
    In-Real-Life: Chris Torek, Wind River Systems
    Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
    email: forget about it http://web.torek.net/torek/index.html
    Reading email is like searching for food in the garbage, thanks to spammers.
     
    Chris Torek, May 4, 2006
    #10
  11. eiaks

    CBFalconer Guest

    Chris Torek wrote:
    >

    .... snip ...
    >
    > Write me a loop that iterates an "int i" from INT_MIN through
    > INT_MAX, *inclusive*, with no undefined behavior, and only one copy
    > of the loop body. (Make sure that a "continue" within the loop
    > "does the right thing" too.) The last constraint rules out these
    > two forms:


    Can't do it in C. However <big grin> my PascalP system could do it
    25 years ago:

    FOR i := -maxint TO maxint DO something(i);

    This was a failing that was discovered, and fixed, by use of the
    Pascal validation suite. Unfortunately C has never had a public
    equivalent.

    --
    "If you want to post a followup via groups.google.com, don't use
    the broken "Reply" link at the bottom of the article. Click on
    "show options" at the top of the article, then click on the
    "Reply" at the bottom of the article headers." - Keith Thompson
    More details at: <http://cfaj.freeshell.org/google/>
    Also see <http://www.safalra.com/special/googlegroupsreply/>
     
    CBFalconer, May 5, 2006
    #11
  12. Chris Torek wrote:
    > Write me a loop that iterates an "int i" from INT_MIN through
    > INT_MAX, *inclusive*, with no undefined behavior, and only one copy
    > of the loop body. (Make sure that a "continue" within the loop
    > "does the right thing" too.)


    int i = INT_MIN;
    do {
    LOOP_BODY;
    } while(i != INT_MAX ? i++, 1 : 0);

    Does that count? :)
     
    =?utf-8?B?SGFyYWxkIHZhbiBExLNr?=, May 5, 2006
    #12
  13. eiaks

    Jordan Abel Guest

    On 2006-05-04, Chris Torek <> wrote:
    > The "no undefined behavior" constraint rules out this form:
    >
    > i = INT_MIN;
    > do {
    > LOOP_BODY;
    > } while (i++ != INT_MAX);
    > because "i++" is undefined when i == INT_MAX.


    int i = INT_MIN;
    do {
    LOOP_BODY;
    } while(i != INT_MAX && (i++,1))
     
    Jordan Abel, May 5, 2006
    #13
  14. eiaks

    Malcolm Guest

    "CBFalconer" <> wrote i
    > Chris Torek wrote:
    >>

    > ... snip ...
    >>
    >> Write me a loop that iterates an "int i" from INT_MIN through
    >> INT_MAX, *inclusive*, with no undefined behavior, and only one copy
    >> of the loop body. (Make sure that a "continue" within the loop
    >> "does the right thing" too.) The last constraint rules out these
    >> two forms:

    >
    > Can't do it in C. However <big grin> my PascalP system could do it
    > 25 years ago:
    >
    > FOR i := -maxint TO maxint DO something(i);
    >
    > This was a failing that was discovered, and fixed, by use of the
    > Pascal validation suite. Unfortunately C has never had a public
    > equivalent.
    >

    int i;

    i = INT_MIN;
    loop:
    do_something(i);
    if(i < INT_MAX)
    {
    i++;
    goto loop;
    }
    /* loop end */
    --
    Homepage: www.personal.leeds.ac.uk/bgy1mm
    Programming goodies
     
    Malcolm, May 7, 2006
    #14
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. wwj
    Replies:
    7
    Views:
    578
  2. wwj
    Replies:
    24
    Views:
    2,548
    Mike Wahler
    Nov 7, 2003
  3. Ben Pfaff
    Replies:
    5
    Views:
    490
    Tristan Miller
    Jan 17, 2004
  4. lovecreatesbeauty
    Replies:
    1
    Views:
    1,098
    Ian Collins
    May 9, 2006
  5. edwardfredriks

    counting up instead of counting down

    edwardfredriks, Sep 6, 2005, in forum: Javascript
    Replies:
    6
    Views:
    213
    Dr John Stockton
    Sep 7, 2005
Loading...

Share This Page