Problem with odd loop when passing float to function 
Author Message
 Problem with odd loop when passing float to function

First of all, I know this code is long and probably inefficient as
hell, but I was just practicing and so didn't take the time to sit
down and plan it out. Anyway, I stumbled on a run time error that I
can't for the life of me figure out. Everything runs smoothly until
the final call to getInput(), which asks for input of type float. When
I input any number, rather than store the value in the variable and
return to main() which should print it, it seems to loop back to the
beginning of main() instead. As in it reprompts for a single character
and then an integer and so on, until it gets to the float, at which
point it loops back again.

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#define INT_NUM         0
#define LONG_NUM                1
#define FLOAT_NUM       2
#define SINGLE_CHAR     3
#define ALPHA_STRING    4
#define ALPHA_NUMERIC   5

typedef enum {clear, error} FLAG;       /* Flag indicates when error
occured */

char buff[128];     /* Universal input buffer */

/* Reset all elements in buffer to NULL ('\0') */
void clear_buff(void) {
        int i;
        for (i = 0; i < (strlen(buff) + 1); i++) {
                buff[i] = '\0';
        }

Quote:
}

void getInput(char prompt[], short in_type, void *ptr) {

        FLAG err_flag = clear; /* Set error flag */
        int i;  /* Loop counter */
        int (*test_type)(char); /* Pointer to function */

        do {
                if (err_flag == error) {        /* Printf error
message if error is encountered */
                        printf("Invalid entry.\n");
                        err_flag = clear;       /* Reset error flag */
                }

                /* Prompt and recieve input */
                printf("%s\n", prompt);
                fgets(buff, 128, stdin);

/* I get warnings for the function pointer test_type saying suspicious
pointer at each case below */
                switch (in_type) {
                        /* If short, int or long test for digits */
                        case INT_NUM: case LONG_NUM:
                                /* Warning here */
                                test_type = isdigit;    
                                break;
                        /* If float or double test for digits and
decimal points. Tested here because it has an extra item to test for
*/
                        case FLOAT_NUM:
                                for (i = 0; i < strlen(buff); i++) {
                                        if ((!test_type(buff[i])) &&
(buff[i] != '\n') && (buff[i] != '.')) {
                                                err_flag = error;
                                        }
                                }
                                break;
                        /* If char test for length (one character) and
alpha (letter...not number) */
                        case SINGLE_CHAR:
                                if (strlen(buff) > 2) {
                                        err_flag = error;
                                        break;
                }
                                else {
                                        /* Warning here */
                                        test_type = isalpha;
                                }
                                break;
                        /* If string test for alpha (no numbers) */
                        case ALPHA_STRING:
                                /* Warning here */
                                test_type = isalpha;
                                break;
                        /* If alpha numeric test for letters and/or
numbers */
                        case ALPHA_NUMERIC:
                                /* Warning here */
                                test_type = isalnum;
                                break;
                }

                /* Float was tested for above. Test for all others
here */
                if (in_type != FLOAT_NUM) {
                        for (i = 0; i < strlen(buff); i++) {

                        /* Test with function pointed to above */
                                if ((!test_type(buff[i])) && (buff[i]
!= '\n')) {
                                        err_flag = error;
                                }
                        }
                }
        }
        while (err_flag == error);      /* Repeat if error is
encountered */

        switch (in_type) {
/* For each, cast pointer and string in buffer, then transfer value
from buffer to variable */
                case INT_NUM:
                        *(int *)ptr = atoi(buff);
                        break;
                case LONG_NUM:
                        *(long *)ptr = atol(buff);
                        break;
                case FLOAT_NUM:
                        *(float *)ptr = atof(buff);
                        break;
                case SINGLE_CHAR:
                        *(char *)ptr = buff[0];
                        break;
                case ALPHA_STRING: case ALPHA_NUMERIC:
                        strcpy((char *)ptr, buff);
                        break;
        }

Quote:
}

int main(void) {
        char love, hate[10];
        int stoopid;
        float crazy;

        /* Test single character input */
        getInput("Enter a single letter: ", SINGLE_CHAR, &love);
        printf("%c\n", love);

        clear_buff();

        /* Test integer input */
        getInput("Enter a whole number: ", INT_NUM, &stoopid);
        printf("%d\n", stoopid);

        clear_buff();

        /* Test string input */
        getInput("Enter a string: ", ALPHA_STRING, &hate);
        printf("%s\n", hate);

        clear_buff();

        /* Test float input */
        /* This one causes it to loop back up to the beginning of
main() for some reason */
        getInput("Enter a floating point number: ", FLOAT_NUM,
&crazy);
        printf("%f\n", crazy);

        return 0;

Quote:
}



Sat, 18 Aug 2001 03:00:00 GMT  
 Problem with odd loop when passing float to function

Quote:

> First of all, I know this code is long and probably inefficient as
> hell, but I was just practicing and so didn't take the time to sit
> down and plan it out. Anyway, I stumbled on a run time error that I
> can't for the life of me figure out. Everything runs smoothly until
> the final call to getInput(), which asks for input of type float. When
> I input any number, rather than store the value in the variable and
> return to main() which should print it, it seems to loop back to the
> beginning of main() instead. As in it reprompts for a single character
> and then an integer and so on, until it gets to the float, at which
> point it loops back again.

> #include <stdio.h>
> #include <stdlib.h>
> #include <ctype.h>
> #include <string.h>

> #define INT_NUM         0
> #define LONG_NUM           1
> #define FLOAT_NUM       2
> #define SINGLE_CHAR     3
> #define ALPHA_STRING    4
> #define ALPHA_NUMERIC   5

> typedef enum {clear, error} FLAG;  /* Flag indicates when error
> occured */

> char buff[128];     /* Universal input buffer */

> /* Reset all elements in buffer to NULL ('\0') */
> void clear_buff(void) {
>    int i;
>    for (i = 0; i < (strlen(buff) + 1); i++) {
>            buff[i] = '\0';
>    }
> }

Not your error, but this function is totally unnecessary.  Either the
fgets() call you make later will succeed and the contents of buff will
be valid afterward, or the call will fail and if you had included
proper testing of the return value, which you didn't, you would have
known better than to access the contents of buff so it doesn't make
any difference.

Quote:
> void getInput(char prompt[], short in_type, void *ptr) {

>    FLAG err_flag = clear; /* Set error flag */
>    int i;  /* Loop counter */
>    int (*test_type)(char); /* Pointer to function */

There isn't a single function in the standard C library (unless
Lawrence's memory is better than mine) which takes a char parameter.
The isdigit function, which you later try to point test_type to, takes
an int parameter.

Also note that you defined the pointer without initializing it to
point to any function.

Quote:
>    do {
>            if (err_flag == error) {        /* Printf error
> message if error is encountered */
>                    printf("Invalid entry.\n");
>                    err_flag = clear;       /* Reset error flag */
>            }

>            /* Prompt and recieve input */
>            printf("%s\n", prompt);
>            fgets(buff, 128, stdin);

Never, never, NEVER use a buffer after a call to fgets() without
checking the return value for NULL!  If fgets() fails and returns
NULL, the contents of the buffer are indeterminate and using any of
the contents is another source of undefined behavior (see below).

Quote:
> /* I get warnings for the function pointer test_type saying suspicious
> pointer at each case below */
>            switch (in_type) {
>                    /* If short, int or long test for digits */
>                    case INT_NUM: case LONG_NUM:
>                            /* Warning here */
>                            test_type = isdigit;    

If you had your compiler set to strictly conforming ANSI mode, it
would break here.  You are assigning the address of a function
accepting a single int parameter to a pointer to a function which
accepts a single char parameter.  The function types do not match.

Quote:
>                            break;
>                    /* If float or double test for digits and
> decimal points. Tested here because it has an extra item to test for
> */
>                    case FLOAT_NUM:
>                            for (i = 0; i < strlen(buff); i++) {
>                                    if ((!test_type(buff[i])) &&

If in_type has the value FLOAT_NUM, you are calling a function through
an uninitialized function pointer.  Whatever random garbage test_type
contains, it is almost guaranteed not to be the address of a function
you can call.  This is a serious bug which goes by the technical term
"undefined behavior" where anything can go wrong and usually does.

On most operating systems these days this would get your program shut
down almost instantly with some kind of fault.

Quote:
> (buff[i] != '\n') && (buff[i] != '.')) {
>                                            err_flag = error;
>                                    }
>                            }
>                            break;
>                    /* If char test for length (one character) and
> alpha (letter...not number) */
>                    case SINGLE_CHAR:
>                            if (strlen(buff) > 2) {
>                                    err_flag = error;
>                                    break;
>                 }
>                            else {
>                                    /* Warning here */
>                                    test_type = isalpha;

Of course, assigning "int isalpha(int)" to "int (*)(char)".

- Show quoted text -

Quote:
>                            }
>                            break;
>                    /* If string test for alpha (no numbers) */
>                    case ALPHA_STRING:
>                            /* Warning here */
>                            test_type = isalpha;
>                            break;
>                    /* If alpha numeric test for letters and/or
> numbers */
>                    case ALPHA_NUMERIC:
>                            /* Warning here */
>                            test_type = isalnum;
>                            break;
>            }

>            /* Float was tested for above. Test for all others
> here */
>            if (in_type != FLOAT_NUM) {
>                    for (i = 0; i < strlen(buff); i++) {

>                    /* Test with function pointed to above */
>                            if ((!test_type(buff[i])) && (buff[i]
> != '\n')) {
>                                    err_flag = error;
>                            }
>                    }
>            }
>    }
>    while (err_flag == error);      /* Repeat if error is
> encountered */

>    switch (in_type) {
> /* For each, cast pointer and string in buffer, then transfer value
> from buffer to variable */
>            case INT_NUM:
>                    *(int *)ptr = atoi(buff);
>                    break;
>            case LONG_NUM:
>                    *(long *)ptr = atol(buff);
>                    break;
>            case FLOAT_NUM:
>                    *(float *)ptr = atof(buff);
>                    break;
>            case SINGLE_CHAR:
>                    *(char *)ptr = buff[0];
>                    break;
>            case ALPHA_STRING: case ALPHA_NUMERIC:
>                    strcpy((char *)ptr, buff);
>                    break;
>    }
> }

> int main(void) {
>    char love, hate[10];
>    int stoopid;
>    float crazy;

>    /* Test single character input */
>    getInput("Enter a single letter: ", SINGLE_CHAR, &love);
>    printf("%c\n", love);

>    clear_buff();

>    /* Test integer input */
>    getInput("Enter a whole number: ", INT_NUM, &stoopid);
>    printf("%d\n", stoopid);

>    clear_buff();

>    /* Test string input */
>    getInput("Enter a string: ", ALPHA_STRING, &hate);
>    printf("%s\n", hate);

>    clear_buff();

>    /* Test float input */
>    /* This one causes it to loop back up to the beginning of
> main() for some reason */
>    getInput("Enter a floating point number: ", FLOAT_NUM,
> &crazy);
>    printf("%f\n", crazy);

>    return 0;
> }

<Jack>

Spend a little more time with your C reference book, compiler manual,
online help or man pages.  Pay attention to the exact types of
arguments, so you will know things like the type of argument taken by
isdigit() and isalpha().  Especially pay attention to the return value
when a function has a specific one for indicating an error, like
fgets(), and always test for the error value.

Never ignore warnings, especially about pointer type conversions and
you are going to dereference the pointer.  That is not your problem
here, but it could be in many situations.

And always make sure all variables are initialized before you use
them, including function pointers.

</Jack>
--
Do not email me with questions about programming.
Post them to the appropriate newsgroup.
Followups to my posts are welcome.



Sat, 18 Aug 2001 03:00:00 GMT  
 Problem with odd loop when passing float to function

Quote:

> Thanks, man. This is exactly the kind of reply I like getting. I'm about four
> months ahead of the rest of the class in school, so I can't get criticism
> from my school mates. My teacher barely speaks english, and she usually ends
> up answering your questions with something that has nothing at all to do with
> what you are asking about. The only teacher who is willing to take the time
> to critique my work has only so much time between classes to help me. So
> basically I'm going at it on my own, and need real criticism and pointers on
> what I'm doing wrong and how I can improve.

> Admittedly I made it easy for you by writing some ugly and potentially
> dangerous code, but that's what I get for not planning any part of it out
> before writing it. Especially since I was working with a new concept. Lesson
> learned. Thanx.

<Jack>

Now is the time to get writing ugly and dangerous code out of your
system.  You might work on a project with me some day and if you write
ugly and dangerous code I would have to fire you or do you bodily
harm, or both... :)

</Jack>
--
Do not email me with questions about programming.
Post them to the appropriate newsgroup.
Followups to my posts are welcome.



Tue, 21 Aug 2001 03:00:00 GMT  
 
 [ 4 post ] 

 Relevant Pages 

1. Problem with odd loop when passing float to function

2. Passing float to dll problem

3. Homework Problem --- While Loop Need in a Function

4. FAQ 13.16 (was: Homework Problem --- While Loop Need in a Function)

5. problem passing unmanaged pointer from one managed member function to another

6. problem: conditional argument passing to a function

7. Problems passing arrays of Strings to function.

8. problems about passing struct to functions

9. Anwser: Problems passing a dynamic array of structures to a function

10. Problems passing a dynamic array of structures to a function

11. FAQ: Problems passing results from a function back, gcc and SunOS 4.1.4

12. pointer problem - passing contents back to calling function.

 

 
Powered by phpBB® Forum Software