Newbie Q: Interactive program eats up CPU

Discussion in 'C Programming' started by Pan Yongzhi, Dec 12, 2005.

  1. Pan Yongzhi

    Pan Yongzhi Guest

    Hi all,

    I wrote a simple C program, exactly at the bottom of this post. It's an
    interactively game, needing user's input. When invoked at the Linux
    shell, it works OK. But if I click in my ROX-Filer, nothing popups
    since no GUI, but it then cosume almost 100% of my CPU time. I have to
    kill it. I'd like to know if I can make it quit silently when It's
    clicked. Thank you very much. Below is the whole source.

    Pan

    ------------------------------------- start of source
    ---------------------------------------
    /*
    * 4digits - This program make the interactive game Guess-the-Number
    game
    * available on PC and other architectures.
    *
    * Copyright (C) 2005 Pan Yongzhi
    * Reach me: http://pan.cdut.cn or fossilet@@163..com
    *
    * This program is free software; you can redistribute it and/or
    * modify it under the terms of the GNU General Public License
    * as published by the Free Software Foundation; either version 2
    * of the License, or (at your option) any later version.
    *
    * This program is distributed in the hope that it will be useful,
    * but WITHOUT ANY WARRANTY; without even the implied warranty of
    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    * GNU General Public License for more details.
    *
    * You should have received a copy of the GNU General Public License
    * along with this program; if not, write to the Free Software
    * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
    02111-1307, USA
    * or see http://www.gnu.org/copyleft/gpl.html.
    *
    */
    # include <stdio.h>
    # include <stdlib.h>
    # include <math.h>
    # include <time.h>
    # include <ctype.h>
    # define VERSION_STRING "4digits-0.1"
    # define COPYRIGHT \
    "4digits 0.1, Dec 2005\n\
    Copyright (C) 2004, 2005 Pan Yongzhi\n\
    4digits comes with NO WARRANTY to the extent permitted by law. This
    program\n\
    is free software; you can redistribute it and/or modify it under the
    terms\n\
    of the GNU General Public License as published by the Free Software\n\
    Foundation - version 2. For more information about these matters, see
    the\n\
    file named COPYING.\n\n"

    int main(void)
    {
    int n; /* the 4-digit number to be guessed*/
    char mstr[4]; /* string for the 4-digit number */
    int m; /* the 4-digit number inputted */
    int i,j; /* counters for the 4 digits, <=4*/
    int cnt; /* counter for the time of guess, <=8*/
    int A; /* number of digits both value and place is right*/
    int B; /* number of digits only vaule but place is right*/
    int nd[4]= {0,0,0,0}; /* 4x1 array for the 4 digits of n*/
    int md[4]={0,0,0,0}; /* 4x1 arrays for the 4 digits of m*/
    time_t t; /* time_t type variable, to be seed for random n*/
    printf(COPYRIGHT);
    cnt = 0;

    srand((int) time(&t));
    n = 1000 + (int) ( 8999.0 * rand() / RAND_MAX );

    /* generate a random 4-digit number*/
    /* if the digits of n is not different from each other, regenerate
    it*/
    while(nd[0]==nd[1] || nd[1]==nd[2] || nd[2]==nd[3] || nd[0]==nd[2] ||
    nd[0]==nd[3] || nd[1]==nd[3])
    {
    srand(n);
    n = 1000 + (int) ( 8999.0 * rand() / RAND_MAX );
    for(i=0;i<4;i++)
    nd=(int) ( n / pow(10,3-i) )%10;
    }

    do
    {
    printf("Input a 4-digit number:");
    fflush(NULL);
    scanf("%s", mstr);
    m = atoi(mstr);
    if ((m < 1000) | (m > 9999))
    {
    printf("%d: input error!\n", m);
    cnt--;
    continue;
    }
    for(i=0;i<4;i++)
    md=(int) ( m / pow(10,3-i) )%10;
    /*comparision of nd & md*/
    A=0, B=0;
    for(i=0;i<4;i++)
    for(j=0;j<4;j++)
    if(md==nd[j])
    (i==j) ? A++:B++;
    printf("%dA%dB ",A,B);
    printf("\t %d times left.\n", 7-cnt);
    if(A==4)
    printf("You win!\n"), exit(0);
    }while(cnt++<=7);

    printf("Hahah, you lose. It is %d.\n", n);
    return 0;
    }
    ------------------------------------- end of source
    ---------------------------------------
    Pan Yongzhi, Dec 12, 2005
    #1
    1. Advertising

  2. In article <>,
    Pan Yongzhi <> wrote:
    >I wrote a simple C program, exactly at the bottom of this post. It's an
    >interactively game, needing user's input. When invoked at the Linux
    >shell, it works OK. But if I click in my ROX-Filer, nothing popups
    >since no GUI, but it then cosume almost 100% of my CPU time.


    > srand((int) time(&t));
    > n = 1000 + (int) ( 8999.0 * rand() / RAND_MAX );
    >
    > /* generate a random 4-digit number*/
    > /* if the digits of n is not different from each other, regenerate
    >it*/
    > while(nd[0]==nd[1] || nd[1]==nd[2] || nd[2]==nd[3] || nd[0]==nd[2] ||
    >nd[0]==nd[3] || nd[1]==nd[3])
    > {
    > srand(n);


    You should only rarely reseed your random number generator.

    First you seed it with the time. Once that seed is set, the rand()
    call in calculating n will follow a fixed formula to produce the
    next random number based upon the current seed.

    You then take that possibly-large result and multiply it by ~8999,
    converting to double in the process, and divide that by RAND_MAX.
    You would be safer off using 8999.0 * ((double)rand() / RAND_MAX)
    as that prevents the possibility that 8999.0 * rand loses
    precision.

    There is only one possible value of n for any given original
    seed (the seed based upon the time), and you re-seed the random
    number generator with it, which can only produce one possible result
    from the original time.

    > n = 1000 + (int) ( 8999.0 * rand() / RAND_MAX );


    Again, once that time() was determined, there is only one
    possible rand() that can can make it to the here the first
    time through, and each iteration after that is fixed by the
    srand()... so all the way back, your results will depend
    solely upon that original time.


    > for(i=0;i<4;i++)
    > nd=(int) ( n / pow(10,3-i) )%10;
    > }


    Those values are going to depend solely upon the calculated n,
    by you are unnecessarily working with floating point in
    this loop. You can do the same thing with:

    for(i=0;i<4;i++) { nd[3-i] = n % 10; n /= 10; }

    > do
    > {
    > printf("Input a 4-digit number:");
    > fflush(NULL);


    There is no certainty that that will appear on the screen.
    You do fflush(), which is good, but the behaviour is
    operating system defined when your output line does not end
    with \n .

    scanf("%s", mstr);

    If scanf() fails, then mstr will be left with an indefinite
    value, since you do not initialize mstr . That indefinite value
    likely does not fall into the right range, so your program
    probably ends up looping around printing errors about
    bad input, then failing on the next scanf, failing again
    the same way, and so on. You really need to check the result
    of scanf().

    Speaking of scanf(), you have:

    char mstr[4]; /* string for the 4-digit number */

    but if the user actually enters 4 digits, then the null that scanf()
    is going to write afterwards is going to get written to some
    indeterminate location in memory, scribbling over top of whatever
    was there. If you want to allow for 4 digits of input, you need
    at least char [5], with the 5th holding the null. And you need to
    adjust your arguments to scanf() to prevent the possibility that the
    user accidently entered too many characters... and you need to
    adjust the logic about what you do after that because if the user
    did happen to type in too many characters, the remainder are going
    to be left in the input buffer for the next scanf(), but you
    probably want to some out get them out of that input buffer until
    the end of the input line...
    --
    I was very young in those days, but I was also rather dim.
    -- Christopher Priest
    Walter Roberson, Dec 12, 2005
    #2
    1. Advertising

  3. Pan Yongzhi

    ionshift Guest

    As a little tip, you don't really need to create a time_t variable to
    seed the random number generator of the standard library function
    srand(). You can can just call it as srand(time(NULL)), which actually
    works the same way.
    ionshift, Dec 12, 2005
    #3
  4. "ionshift" <> writes:
    > As a little tip, you don't really need to create a time_t variable to
    > seed the random number generator of the standard library function
    > srand(). You can can just call it as srand(time(NULL)), which actually
    > works the same way.


    As another little tip, please read <http://cfaj.freeshell.org/google/>.
    Thank you.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
    Keith Thompson, Dec 12, 2005
    #4
  5. Pan Yongzhi wrote:
    > Hi all,
    >
    > I wrote a simple C program, exactly at the bottom of this post. It's an
    > interactively game, needing user's input. When invoked at the Linux
    > shell, it works OK. But if I click in my ROX-Filer, nothing popups
    > since no GUI, but it then cosume almost 100% of my CPU time. I have to
    > kill it. I'd like to know if I can make it quit silently when It's
    > clicked. Thank you very much. Below is the whole source.
    >
    > Pan

    You should probably ask about this in a linux programming newsgroup,
    since you can't really do what you want with standard C functions. Or
    try your luck at the ROX web site.

    >
    > ------------------------------------- start of source
    > ---------------------------------------
    > /*
    > * 4digits - This program make the interactive game Guess-the-Number
    > game
    > * available on PC and other architectures.
    > *
    > * Copyright (C) 2005 Pan Yongzhi
    > * Reach me: http://pan.cdut.cn or fossilet@@163..com
    > *
    > * This program is free software; you can redistribute it and/or
    > * modify it under the terms of the GNU General Public License
    > * as published by the Free Software Foundation; either version 2
    > * of the License, or (at your option) any later version.
    > *
    > * This program is distributed in the hope that it will be useful,
    > * but WITHOUT ANY WARRANTY; without even the implied warranty of
    > * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    > * GNU General Public License for more details.
    > *
    > * You should have received a copy of the GNU General Public License
    > * along with this program; if not, write to the Free Software
    > * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
    > 02111-1307, USA
    > * or see http://www.gnu.org/copyleft/gpl.html.
    > *
    > */
    > # include <stdio.h>
    > # include <stdlib.h>
    > # include <math.h>
    > # include <time.h>
    > # include <ctype.h>
    > # define VERSION_STRING "4digits-0.1"
    > # define COPYRIGHT \
    > "4digits 0.1, Dec 2005\n\
    > Copyright (C) 2004, 2005 Pan Yongzhi\n\
    > 4digits comes with NO WARRANTY to the extent permitted by law. This
    > program\n\
    > is free software; you can redistribute it and/or modify it under the
    > terms\n\
    > of the GNU General Public License as published by the Free Software\n\
    > Foundation - version 2. For more information about these matters, see
    > the\n\
    > file named COPYING.\n\n"
    >

    You could make the copyright string just a char array, and put the
    version string into it like this:

    #define VERSION_STRING "0.1, Dec 2005"
    const char copyright[] = "4digits " VERSION_STRING "\n"
    "Copyright (C) 2004, 2005 Pan Yongzhi\n"
    "etcetera...\n\n"

    Then you won't have to remember to update the version in two places.

    > int main(void)
    > {
    > int n; /* the 4-digit number to be guessed*/
    > char mstr[4]; /* string for the 4-digit number */
    > int m; /* the 4-digit number inputted */
    > int i,j; /* counters for the 4 digits, <=4*/
    > int cnt; /* counter for the time of guess, <=8*/
    > int A; /* number of digits both value and place is right*/
    > int B; /* number of digits only vaule but place is right*/
    > int nd[4]= {0,0,0,0}; /* 4x1 array for the 4 digits of n*/
    > int md[4]={0,0,0,0}; /* 4x1 arrays for the 4 digits of m*/
    > time_t t; /* time_t type variable, to be seed for random n*/

    If you use more descriptive names, you don't need the comments, and your
    code is easier to understand. Like this:

    int answer;
    char guess_str[] = "0000";
    int guess;
    int i, j;
    int num_guesses;
    int num_correct;
    int num_wrong;

    I also changed guess_str to 4 zero-initialized digits, that's a good
    starting point. And it has space for a null terminator, which it needs
    if you're going to fill it with a string of four digits.

    > printf(COPYRIGHT);

    printf("%s", COPYRIGHT); might be better. That way you don't get
    problems if COPYRIGHT contains something that looks like a format specifier.

    > cnt = 0;
    >
    > srand((int) time(&t));
    > n = 1000 + (int) ( 8999.0 * rand() / RAND_MAX );

    The simplest way is just n = 1000 + rand()%9000;
    But I'm not sure if one way gives better results than the other.

    >
    > /* generate a random 4-digit number*/
    > /* if the digits of n is not different from each other, regenerate
    > it*/
    > while(nd[0]==nd[1] || nd[1]==nd[2] || nd[2]==nd[3] || nd[0]==nd[2] ||
    > nd[0]==nd[3] || nd[1]==nd[3])
    > {
    > srand(n);
    > n = 1000 + (int) ( 8999.0 * rand() / RAND_MAX );
    > for(i=0;i<4;i++)
    > nd=(int) ( n / pow(10,3-i) )%10;

    If you just need n as a string, do this:
    sprintf(nd, "%d", n);

    > }
    >
    > do
    > {
    > printf("Input a 4-digit number:");
    > fflush(NULL);
    > scanf("%s", mstr);

    This will cause a buffer overflow if the user types something like
    "12345678", because scanf reads the whole thing. You can limit how much
    scanf reads by using a format string like "%4s" instead.

    scanf can also read the number directly with "%d".

    if (scanf("%d", n) != 1)
    /* if scanf didn't return 1, it was unable to find a number */

    To skip any remaining characters after the ones you want, you can use a
    while loop and getchar:

    while (getchar() != EOF);

    You can also try fflush(stdin), but that's not portable.

    > m = atoi(mstr);
    > if ((m < 1000) | (m > 9999))
    > {
    > printf("%d: input error!\n", m);
    > cnt--;
    > continue;
    > }
    > for(i=0;i<4;i++)
    > md=(int) ( m / pow(10,3-i) )%10;
    > /*comparision of nd & md*/
    > A=0, B=0;
    > for(i=0;i<4;i++)
    > for(j=0;j<4;j++)
    > if(md==nd[j])
    > (i==j) ? A++:B++;
    > printf("%dA%dB ",A,B);
    > printf("\t %d times left.\n", 7-cnt);
    > if(A==4)
    > printf("You win!\n"), exit(0);

    It's not very common to use the comma operator like this, just put
    exit(0) on its on line instead. Best not to hide important stuff at the
    end of the line. ;)

    > }while(cnt++<=7);
    >
    > printf("Hahah, you lose. It is %d.\n", n);
    > return 0;
    > }
    > ------------------------------------- end of source
    > ---------------------------------------
    >
    Tydr Schnubbis, Dec 12, 2005
    #5
  6. Tydr Schnubbis wrote:
    > Pan Yongzhi wrote:


    [snip]

    >> /* generate a random 4-digit number*/
    >> /* if the digits of n is not different from each other, regenerate
    >> it*/
    >> while(nd[0]==nd[1] || nd[1]==nd[2] || nd[2]==nd[3] || nd[0]==nd[2] ||
    >> nd[0]==nd[3] || nd[1]==nd[3])
    >> {
    >> srand(n);
    >> n = 1000 + (int) ( 8999.0 * rand() / RAND_MAX );
    >> for(i=0;i<4;i++)
    >> nd=(int) ( n / pow(10,3-i) )%10;

    > If you just need n as a string, do this:
    > sprintf(nd, "%d", n);

    Seems I was a little too quick there, since nd is an array of ints, not
    chars. But if you have char nd[5], you can do the same thing and it
    should work. You can compare the chars directly, since you don't need
    to know which numbers they are, just if they are the same or not. But
    since you've already written the conversion...

    >
    >> }
    >>
    >> do
    >> {
    >> printf("Input a 4-digit number:");
    >> fflush(NULL);
    >> scanf("%s", mstr);

    > This will cause a buffer overflow if the user types something like
    > "12345678", because scanf reads the whole thing. You can limit how much
    > scanf reads by using a format string like "%4s" instead.
    >
    > scanf can also read the number directly with "%d".
    >
    > if (scanf("%d", n) != 1)
    > /* if scanf didn't return 1, it was unable to find a number */
    >
    > To skip any remaining characters after the ones you want, you can use a
    > while loop and getchar:
    >
    > while (getchar() != EOF);
    >
    > You can also try fflush(stdin), but that's not portable.
    >
    >> m = atoi(mstr);
    >> if ((m < 1000) | (m > 9999))
    >> {
    >> printf("%d: input error!\n", m);
    >> cnt--;
    >> continue;
    >> }
    >> for(i=0;i<4;i++)
    >> md=(int) ( m / pow(10,3-i) )%10;
    >> /*comparision of nd & md*/
    >> A=0, B=0;
    >> for(i=0;i<4;i++)
    >> for(j=0;j<4;j++)
    >> if(md==nd[j])
    >> (i==j) ? A++:B++;
    >> printf("%dA%dB ",A,B);
    >> printf("\t %d times left.\n", 7-cnt);
    >> if(A==4)
    >> printf("You win!\n"), exit(0);

    > It's not very common to use the comma operator like this, just put
    > exit(0) on its on line instead. Best not to hide important stuff at the
    > end of the line. ;)
    >
    >> }while(cnt++<=7);
    >>
    >> printf("Hahah, you lose. It is %d.\n", n);
    >> return 0;
    >> }
    >> ------------------------------------- end of source
    >> ---------------------------------------
    >>
    Tydr Schnubbis, Dec 12, 2005
    #6
  7. Pan Yongzhi

    Pan Yongzhi Guest

    Walter Roberson wrote:

    > > srand((int) time(&t));
    > > n = 1000 + (int) ( 8999.0 * rand() / RAND_MAX );
    > >
    > > /* generate a random 4-digit number*/
    > > /* if the digits of n is not different from each other, regenerate
    > >it*/
    > > while(nd[0]==nd[1] || nd[1]==nd[2] || nd[2]==nd[3] || nd[0]==nd[2] ||
    > >nd[0]==nd[3] || nd[1]==nd[3])
    > > {
    > > srand(n);

    >
    > You should only rarely reseed your random number generator.
    >
    > First you seed it with the time. Once that seed is set, the rand()
    > call in calculating n will follow a fixed formula to produce the
    > next random number based upon the current seed.
    >
    > You then take that possibly-large result and multiply it by ~8999,
    > converting to double in the process, and divide that by RAND_MAX.
    > You would be safer off using 8999.0 * ((double)rand() / RAND_MAX)
    > as that prevents the possibility that 8999.0 * rand loses
    > precision.


    Thank you. I get it! I read `man 3 rand` but missed a pair of brackets.

    > > do
    > > {
    > > printf("Input a 4-digit number:");
    > > fflush(NULL);

    >
    > There is no certainty that that will appear on the screen.
    > You do fflush(), which is good, but the behaviour is
    > operating system defined when your output line does not end
    > with \n .
    >
    > scanf("%s", mstr);
    >
    > If scanf() fails, then mstr will be left with an indefinite
    > value, since you do not initialize mstr . That indefinite value
    > likely does not fall into the right range, so your program
    > probably ends up looping around printing errors about
    > bad input, then failing on the next scanf, failing again
    > the same way, and so on. You really need to check the result
    > of scanf().
    >



    > Speaking of scanf(), you have:
    >
    > char mstr[4]; /* string for the 4-digit number */
    >
    > but if the user actually enters 4 digits, then the null that scanf()
    > is going to write afterwards is going to get written to some
    > indeterminate location in memory, scribbling over top of whatever
    > was there. If you want to allow for 4 digits of input, you need
    > at least char [5], with the 5th holding the null. And you need to
    > adjust your arguments to scanf() to prevent the possibility that the
    > user accidently entered too many characters... and you need to
    > adjust the logic about what you do after that because if the user
    > did happen to type in too many characters, the remainder are going
    > to be left in the input buffer for the next scanf(), but you
    > probably want to some out get them out of that input buffer until
    > the end of the input line...


    So I better off use scanf("%4s", mstr)? This will not overwrite unknow
    memory when the input is longer than 4 bytes? But why my original code
    runs OK? But another problem occurs when the input is longer than 4:
    next scanf does not pause for my input and skips with possibly wrong
    data. The longer the input, the more scanf's skipped. It seems a mess
    to correctly and safely deal with scanf input. I once tried gets, but
    gcc told me it's dangerous. Can you be a little more elaborate on this?
    It's really kind of you.
    Pan Yongzhi, Dec 12, 2005
    #7
  8. Pan Yongzhi

    Pan Yongzhi Guest

    Walter Roberson wrote:

    > > srand((int) time(&t));
    > > n = 1000 + (int) ( 8999.0 * rand() / RAND_MAX );
    > >
    > > /* generate a random 4-digit number*/
    > > /* if the digits of n is not different from each other, regenerate
    > >it*/
    > > while(nd[0]==nd[1] || nd[1]==nd[2] || nd[2]==nd[3] || nd[0]==nd[2] ||
    > >nd[0]==nd[3] || nd[1]==nd[3])
    > > {
    > > srand(n);

    >
    > You should only rarely reseed your random number generator.
    >
    > First you seed it with the time. Once that seed is set, the rand()
    > call in calculating n will follow a fixed formula to produce the
    > next random number based upon the current seed.
    >
    > You then take that possibly-large result and multiply it by ~8999,
    > converting to double in the process, and divide that by RAND_MAX.
    > You would be safer off using 8999.0 * ((double)rand() / RAND_MAX)
    > as that prevents the possibility that 8999.0 * rand loses
    > precision.


    Thank you. I get it! I read `man 3 rand` but missed a pair of brackets.

    > > do
    > > {
    > > printf("Input a 4-digit number:");
    > > fflush(NULL);

    >
    > There is no certainty that that will appear on the screen.
    > You do fflush(), which is good, but the behaviour is
    > operating system defined when your output line does not end
    > with \n .
    >
    > scanf("%s", mstr);
    >
    > If scanf() fails, then mstr will be left with an indefinite
    > value, since you do not initialize mstr . That indefinite value
    > likely does not fall into the right range, so your program
    > probably ends up looping around printing errors about
    > bad input, then failing on the next scanf, failing again
    > the same way, and so on. You really need to check the result
    > of scanf().
    >



    > Speaking of scanf(), you have:
    >
    > char mstr[4]; /* string for the 4-digit number */
    >
    > but if the user actually enters 4 digits, then the null that scanf()
    > is going to write afterwards is going to get written to some
    > indeterminate location in memory, scribbling over top of whatever
    > was there. If you want to allow for 4 digits of input, you need
    > at least char [5], with the 5th holding the null. And you need to
    > adjust your arguments to scanf() to prevent the possibility that the
    > user accidently entered too many characters... and you need to
    > adjust the logic about what you do after that because if the user
    > did happen to type in too many characters, the remainder are going
    > to be left in the input buffer for the next scanf(), but you
    > probably want to some out get them out of that input buffer until
    > the end of the input line...


    So I better off use scanf("%4s", mstr)? This will not overwrite unknow
    memory when the input is longer than 4 bytes? But why my original code
    runs OK? But another problem occurs when the input is longer than 4:
    next scanf does not pause for my input and skips with possibly wrong
    data. The longer the input, the more scanf's skipped. It seems hard to
    correctly and safely deal with scanf input. I once tried gets, but gcc
    told me it's dangerous. Can you be a little more elaborate on this?
    It's really kind of you.
    Pan Yongzhi, Dec 12, 2005
    #8
  9. Pan Yongzhi

    Pan Yongzhi Guest

    Tydr Schnubbis wrote:
    > Pan Yongzhi wrote:
    > > Hi all,
    > >
    > > I wrote a simple C program, exactly at the bottom of this post. It's an


    > > interactively game, needing user's input. When invoked at the

    Linux
    > > shell, it works OK. But if I click in my ROX-Filer, nothing popups
    > > since no GUI, but it then cosume almost 100% of my CPU time. I have to
    > > kill it. I'd like to know if I can make it quit silently when It's
    > > clicked. Thank you very much. Below is the whole source.
    > >
    > > Pan

    > You should probably ask about this in a linux programming newsgroup,
    > since you can't really do what you want with standard C functions. Or
    > try your luck at the ROX web site.


    I open a Konqueror in my shell, and click 4digits in Konqueror, thus I
    can see what's outputed. On the shell it shows:

    Input a 4-digit number:0: input error!
    Input a 4-digit number:0: input error!
    Input a 4-digit number:0: input error!
    Input a 4-digit number:0: input error!
    .......

    And it never ends and my CPU is eaten up. Why is it get out of control?
    I just want it to quit, like when I click on /bin/cat.

    > > srand((int) time(&t));
    > > n = 1000 + (int) ( 8999.0 * rand() / RAND_MAX );

    > The simplest way is just n = 1000 + rand()%9000;
    > But I'm not sure if one way gives better results than the other.


    Paragraphs from man 3 rand:
    In Numerical Recipes in C: The Art of Scientific Computing
    (William H.
    Press, Brian P. Flannery, Saul A. Teukolsky, William T.
    Vetterling; New
    York: Cambridge University Press, 1992 (2nd ed., p. 277)), the
    follow-
    ing comments are made:
    "If you want to generate a random integer between 1 and
    10, you
    should always do it by using high-order bits, as in

    j = 1 + (int) (10.0 * (rand() / (RAND_MAX +
    1.0)));

    and never by anything resembling

    j = 1 + (rand() % 10);

    (which uses lower-order bits)."

    > > printf("Input a 4-digit number:");
    > > fflush(NULL);
    > > scanf("%s", mstr);

    > This will cause a buffer overflow if the user types something like
    > "12345678", because scanf reads the whole thing. You can limit how much
    > scanf reads by using a format string like "%4s" instead.
    >
    > scanf can also read the number directly with "%d".
    >
    > if (scanf("%d", n) != 1)
    > /* if scanf didn't return 1, it was unable to find a number */
    >
    > To skip any remaining characters after the ones you want, you can use a
    > while loop and getchar:
    >
    > while (getchar() != EOF);


    Seems scanf is for experts?

    > You can also try fflush(stdin), but that's not portable.
    Pan Yongzhi, Dec 12, 2005
    #9
  10. Pan Yongzhi

    Simon Biber Guest

    Pan Yongzhi wrote:
    > Hi all,
    >
    > I wrote a simple C program, exactly at the bottom of this post. It's an
    > interactively game, needing user's input. When invoked at the Linux
    > shell, it works OK. But if I click in my ROX-Filer, nothing popups
    > since no GUI, but it then cosume almost 100% of my CPU time. I have to
    > kill it. I'd like to know if I can make it quit silently when It's
    > clicked. Thank you very much. Below is the whole source.


    You should check the result any input functions. If the first time you
    try to read input, you are not successful at reading any input, call
    exit(EXIT_FAILURE); or something like that.

    For example:

    ....
    printf("Input a 4-digit number:");
    fflush(NULL);
    if(scanf("%s", mstr) <= 0)
    {
    fprintf(stderr,
    "This program requires interactive input from a terminal\n");
    exit(EXIT_FAILURE);
    }
    ....

    --
    Simon.
    Simon Biber, Dec 12, 2005
    #10
  11. Pan Yongzhi

    Old Wolf Guest

    Pan Yongzhi wrote:
    >>
    >> char mstr[4]; /* string for the 4-digit number */

    >
    > So I better off use scanf("%4s", mstr)?


    No. This reads a string of /at least/ 4 characters, so will always
    overflow the buffer. You need:

    int result = scanf("%.3s", mstr);

    which reads /at most/ 3 characters, so uses up at most 4 bytes
    of the buffer (don't forget about the terminating '\0').

    > But why my original code runs OK?


    It doesn't run OK -- isn't that why you were posting in the first
    place?

    > But another problem occurs when the input is longer than 4:
    > next scanf does not pause for my input and skips with possibly
    > wrong data.


    Actually it gets all the data you didn't read the first time.

    > The longer the input, the more scanf's skipped. It seems hard to
    > correctly and safely deal with scanf input.


    That's right.

    > I once tried gets, but gcc told me it's dangerous.


    Use fgets .
    Old Wolf, Dec 13, 2005
    #11
  12. Pan Yongzhi

    Chris Torek Guest

    >>> char mstr[4]; /* string for the 4-digit number */

    >Pan Yongzhi wrote:
    >> So I better off use scanf("%4s", mstr)?


    In article <>
    Old Wolf <> wrote:
    >No. This reads a string of /at least/ 4 characters, so will always
    >overflow the buffer. You need:
    >
    > int result = scanf("%.3s", mstr);
    >
    >which reads /at most/ 3 characters, so uses up at most 4 bytes
    >of the buffer (don't forget about the terminating '\0').


    I think you are mixing up the printf and scanf engines here. In
    the printf family, "%4s" gives you a minimum field width of four
    but puts no limit on the actual length of the string and will use
    more than four positions if needed:

    printf("|%4s|\n", "");
    printf("|%4s|\n", "123");
    printf("|%4s|\n", "123456");

    produces:

    | |
    | 123|
    |123456|

    for instance. Using "%.4s" in printf limits the "implied" length
    of the string (which now no longer even needs to be a string) to 4.
    Internally, inside the printf() engine, the effect works out to
    the equivalent of the following pseudo-C code:

    /* for %s, not for %ls */
    str = va_arg(ap, char *);
    if (a precision was given) {
    p = memchr(str, '\0', prec); /* where prec is the precision */
    len = p ? p - str : prec;
    } else
    len = strlen(str);

    /* handle padding for %4s or %-4s */
    pad_characters = 0;
    if (a width was given && width > len) {
    pad_characters = width - len;
    if (not-doing-left-adjust) { /* %4s */
    for (; pad_characters > 0; pad_characters--)
    putc(' ', the_file);
    }
    }
    while (len--)
    putc(*str++, the_file);
    /* now handle %-4s case, where pad comes after string */
    for (; pad_characters > 0; pad_characters--)
    putc(' ', the_file);

    to print the string. (Note that this same code works for other
    conversions like %d, once the number is converted to a string and
    its length calculated, but %d needs to be able to zero-pad as well
    as blank-pad, and numeric conversions must handle signs and so on.)

    In the scanf family, however, "%4s" gives you a *maximum* field
    width of four, and "%.4s" has no meaning -- precisions do not apply
    in scanf. (And as you note, it requires an array of at least five
    characters to hold a four-character field scanned via scanf().)

    There is a false appearance of symmetry between printf() and scanf(),
    but in reality, the two functions are quite different. I sometimes
    think it would have been better if the names were not so similar.
    --
    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, Dec 16, 2005
    #12
  13. Pan Yongzhi

    Old Wolf Guest

    Chris Torek wrote:

    > I think you are mixing up the printf and scanf engines here.


    You're right.

    > There is a false appearance of symmetry between printf() and scanf(),
    > but in reality, the two functions are quite different. I sometimes
    > think it would have been better if the names were not so similar.


    It might have been better if scanf had never existed..
    Old Wolf, Dec 18, 2005
    #13
    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. Casper Hornstrup

    ASP.NET process eats all CPU time

    Casper Hornstrup, May 10, 2004, in forum: ASP .Net
    Replies:
    2
    Views:
    443
    Steven Cheng[MSFT]
    May 13, 2004
  2. Dale
    Replies:
    4
    Views:
    354
  3. Iñaki Baz Castillo
    Replies:
    5
    Views:
    114
    Marcelo
    Mar 27, 2008
  4. Axel Bock
    Replies:
    3
    Views:
    102
    David Masover
    Jul 19, 2008
  5. Laszlo Nagy

    tornado.web ioloop add_timeout eats CPU

    Laszlo Nagy, Sep 3, 2012, in forum: Python
    Replies:
    3
    Views:
    426
    Paul Rubin
    Sep 4, 2012
Loading...

Share This Page