Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to get rid of errors even after using the right headers

Tags:

c

c-strings

I've just started learning how to program in C, I'm not able get rid of the error. Here's my program:

/* This program rolls two dice and presents the total. It then asks the user 
to guess if the next total will be higher, lower, or equal. It then rolls 
two more dice and tells the user how they did. */

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

int main(void)
{
    int  dice1, dice2, total, total1= 0;
    char ans[25], dans[25];
    char higher[] = "HIGHER", lower[] = "LOWER", equal[] = "EQUAL";

    //the following 3 lines, throws the dice and adds them. 
    dice1 = (rand() % 5) + 1;
    dice2 = (rand() % 5) + 1;
    total = dice1 + dice2;

    //the next few ask the question. 
    printf("Will the next number be higher, lower or equal to %d ?\n", total);
    puts("Type higher, lower or equal.");
    // scanf("&s", ans); //had to remove this line, because apparently we can't use &s to get the string input

    fgets(ans, 25, stdin);
    strcpy(dans, strupr(ans));

    //the next few throw the dice two more times
    dice1 = (rand() % 5) + 1;
    dice2 = (rand() % 5) + 1;
    total1 = dice1 + dice2;

    /*All of these check if the user input matches the actual output and 
    then tells the user if he/she was right.*/
    printf("The upper string is %s.\n", ans);
    if ((ans == higher) && (total1 > total))
    {
        printf("You're right, it is higher!\n");
    }
    else if ((ans == lower) && (total1 < total))
    {
        printf("You're right, it is lower!\n");
    }
    else if ((ans == equal) && (total1 = total))
    {
        printf("You're right. they are equal!\n");
    }
    else
    {
        printf("Your prediction was wrong.\n");
    }



}

The errors which I'm getting:

test.c:25:22: error: implicit declaration of function 'strupr' is invalid in C99 [-Werror,-Wimplicit-function-declaration]

   strcpy(dans, strupr(ans));

                 ^

test.c:25:22: error: incompatible integer to pointer conversion passing 'int' to parameter of type 'const char *' [-Werror,-Wint-conversion]

   strcpy(dans, strupr(ans));

                 ^~~~~~~~~~~

/usr/include/string.h:129:70: note: passing argument to parameter '__src' here extern char *strcpy (char *__restrict __dest, const char *__restrict __src)

                                                                ^

test.c:33:18: error: array comparison always evaluates to false [-Werror,-Wtautological-compare]

   if ((ans == higher) && (total1 > total))

           ^

test.c:37:23: error: array comparison always evaluates to false [-Werror,-Wtautological-compare]

   else if ((ans == lower) && (total1 < total))

              ^

test.c:41:23: error: array comparison always evaluates to false [-Werror,-Wtautological-compare]

   else if ((ans == equal) && (total1 = total))

Please help me with the errors.

Also,

  1. strupr is supposed to be there in stdlib, why am I still getting an error?

  2. When I convert a string to an uppercase string how does it change to int?

  3. Why am I not able to use %s in scanf? (I have used this before)

Thank you.

like image 266
Krishna Avatar asked Mar 06 '23 20:03

Krishna


2 Answers

[answering one question of the this multi-question question]

Why am I not able to use %s in scanf?

You can, but in fact you use &s

  // scanf("&s", ans); //had to remove this lin

which not the same as %s.

like image 150
alk Avatar answered Mar 09 '23 09:03

alk


You have a number of issues to address. Your use of strupr is not a standard C function and may only be available on windoze. Your alternative that are standard are to write a short function and either use the functions isupper() or islower() from the header <ctype.h> to loop over each character and calling toupper() if a change from lower-case to upper-case is required.

A short function can do all of that for you in a very efficient manner. Something like:

/** convert string to uppercase.
 *  returns string with all chars converted to uppercase.
 */
char *str2upper (char *str)
{
    if (!str) return NULL;

    char *p = str;

    for ( ; *p; p++)
        if ('a' <= *p && *p <= 'z')
            *p += 'A' - 'a';

    return str;
}

is all you need. It simply walks the string provided as input and if the character is lowercase, converts it to uppercase.

Your next problem is how you handle the buffer filled by fgets. Being a line-oriented input function, it will read up to and including the '\n' at the end of the input, including that as your final character in asn. Now no matter what you do with your conversion, dans will never match higher or lower or equal -- you figure out why yet?

Let's look at your `higher'

'H','I','G','H','E','R'

Now lets look at dans if it contained the same word (but with the '\n' character still dangling off the end):

'H','I','G','H','E','R','\n'

Since you read with fgets and did not remove the trailing '\n', it will always prevent a valid comparison between dand and any of your strings. How to fix it?

Simple, just check that the last character in the ans as filled by fgets is the '\n' and overwrite the '\n' with a nul-terminating character removing it. (additionally, you should check that the user didn't cancel the input by generating a manual EOF to quit early. You can do all those things in a simple little input loop while requiring your user to enter a valid string until he does or decides to cancel, e.g.

    if (!fgets (ans, 25, stdin)) {  /* check for user cancle with EOF */
        fprintf (stderr, "user canceled input.\n");
        return 1;
    }
    size_t len = strlen (ans);          /* get string length */
    if (len && ans[len - 1] == '\n')    /* valisate last char is '\n' */
        ans[--len] = 0;                 /* overwrite with nul-character */
    else    /* warn if chars can remain unread (input too long) */
        fprintf (stderr, "unread characters may remain in stdin.\n");

    strcpy(dans, str2upper(ans));

Now dans is properly uppercase and has no '\n' dangling off its tail-end.

Your comparisons are the last problem area. You cannot check string equality with the == operator. (that is for comparing a character at a time, not a string. The strcmp function in string.h is the proper tool here. If the strings compare equally, strcmp returns 0. With that in mind you can fix your comparisons with:

    /*All of these check if the user input matches the actual output and 
    then tells the user if he/she was right.*/
    printf("The upper string is %s.\n", ans);
    if (strcmp (dans, higher) == 0 && (total1 > total))
    {
        printf("You're right, it is higher!\n");
    }
    else if (strcmp (dans, lower) == 0 && (total1 < total))
    {
        printf("You're right, it is lower!\n");
    }
    else if (strcmp (dans, equal) == 0 && (total1 == total))
    {
        printf("You're right. they are equal!\n");
    }
    else
    {
        printf("Your prediction was wrong.\n");
    }

Now putting it altogether, you have your code in a form that should work, e.g.

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

/** convert string to uppercase.
 *  returns string with all chars converted to uppercase.
 */
char *str2upper (char *str)
{
    if (!str) return NULL;

    char *p = str;

    for ( ; *p; p++)
        if ('a' <= *p && *p <= 'z')
            *p += 'A' - 'a';

    return str;
}

int main(void)
{
    int  dice1, dice2, total, total1= 0;
    char ans[25] = {0}, dans[25] = {0};
    char higher[] = "HIGHER", lower[] = "LOWER", equal[] = "EQUAL";

    //the following 3 lines, throws the dice and adds them. 
    dice1 = (rand() % 5) + 1;
    dice2 = (rand() % 5) + 1;
    total = dice1 + dice2;

    //the next few ask the question. 
    printf("Will the next number be higher, lower or equal to %d ?\n", total);
    fputs ("Type higher, lower or equal: ", stdout);

    if (!fgets (ans, 25, stdin)) {  /* check for user cancle with EOF */
        fprintf (stderr, "user canceled input.\n");
        return 1;
    }
    size_t len = strlen (ans);          /* get string length */
    if (len && ans[len - 1] == '\n')    /* valisate last char is '\n' */
        ans[--len] = 0;                 /* overwrite with nul-character */
    else    /* warn if chars can remain unread (input too long) */
        fprintf (stderr, "unread characters may remain in stdin.\n");

    strcpy(dans, str2upper(ans));

    //the next few throw the dice two more times
    dice1 = (rand() % 5) + 1;
    dice2 = (rand() % 5) + 1;
    total1 = dice1 + dice2;

    /*All of these check if the user input matches the actual output and 
    then tells the user if he/she was right.*/
    printf("The upper string is %s.\n", ans);
    if (strcmp (dans, higher) == 0 && (total1 > total))
    {
        printf("You're right, it is higher!\n");
    }
    else if (strcmp (dans, lower) == 0 && (total1 < total))
    {
        printf("You're right, it is lower!\n");
    }
    else if (strcmp (dans, equal) == 0 && (total1 == total))
    {
        printf("You're right. they are equal!\n");
    }
    else
    {
        printf("Your prediction was wrong.\n");
    }
}

Example Use/Output

$ ./bin/rolldice
Will the next number be higher, lower or equal to 6 ?
Type higher, lower or equal: lower
The upper string is LOWER.
You're right, it is lower!

Look things over and let me know if you have additional questions.

like image 33
David C. Rankin Avatar answered Mar 09 '23 10:03

David C. Rankin