Невозможно избавиться от ошибок даже после использования правильных заголовков

Я только начал учиться программировать на C, не могу избавиться от ошибки. Вот моя программа:

/* 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");
    }



}

Ошибки, которые я получаю:

test.c: 25: 22: ошибка: неявное объявление функции 'Strupr' недопустимо в C99 [-Werror, -Wimplicit-function-декларация]

   strcpy(dans, strupr(ans));

                 ^

test.c: 25: 22: ошибка: несовместимое целое число с преобразованием указателя с передачей 'int' параметру типа 'const char *' [-Werror, -Wint-conversion]

   strcpy(dans, strupr(ans));

                 ^~~~~~~~~~~

/usr/include/string.h:129:70: примечание: передача аргумента параметру '__src' здесь extern char * strcpy (char * __ restrict __dest, const char * __ restrict __src)

                                                                ^

test.c: 33: 18: error: сравнение массивов всегда возвращает false [-Werror, -Wtautological-compare]

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

           ^

test.c: 37: 23: error: сравнение массивов всегда возвращает false [-Werror, -Wtautological-compare]

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

              ^

test.c: 41: 23: error: сравнение массивов всегда возвращает false [-Werror, -Wtautological-compare]

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

Пожалуйста, помогите мне с ошибками.

Также,

  1. Strupr должен находиться в stdlib, почему я все еще получаю сообщение об ошибке?

  2. Когда я конвертирую строку в строку в верхнем регистре, как она меняется на int?

  3. Почему я не могу использовать %s в scanf? (Я использовал это раньше)

Спасибо.


person Krishna    schedule 22.02.2018    source источник
comment
strupr() не является стандартной функцией C, хотя, как мне кажется, она находится в MS C. Поскольку она не объявлена, компилятор C предполагает, что она возвращает int, что не подходит для аргументов strcpy(). А остальные проблемы, похоже, связаны с тем, что вы не используете strcmp() для сравнения строк. Вам также нужно будет иметь дело с новой строкой, которую fgets() сохраняет во входных данных.   -  person Jonathan Leffler    schedule 22.02.2018
comment
Возможный дубликат Strupr () и strlwr () в строке string.h соответствуют стандарту ANSI?   -  person DYZ    schedule 22.02.2018
comment
чтобы проверить, равны ли строки, используйте strcmp   -  person yano    schedule 22.02.2018
comment
ans == higher - неправильный способ сравнения строк. ans и higher - указатели на два разных массива. Эти указатели никогда не равны. Вы должны использовать strcmp(ans, higher). И в C нет стандартной функции для преобразования строки в верхний регистр.   -  person DYZ    schedule 22.02.2018
comment
Вы хотели использовать 5 кубиков вместо 6?   -  person MFisherKDX    schedule 22.02.2018
comment
Это выглядит плохо: (total1 = total)). Не причина предупреждений, но, вероятно, не то, что вам нужно. PS: Избавьтесь от лишнего (). if (a ›b || c‹ d) намного читаемее, чем if ((a ›b) || (c‹ d))   -  person Bjorn A.    schedule 22.02.2018
comment
кажется, вы используете пятигранные кости ... должно быть rand()%6+1 rand ()% 6 дать значение в диапазоне [0,5]   -  person AndersK    schedule 22.02.2018


Ответы (3)


Вам нужно решить ряд вопросов. Использование strupr не является стандартной функцией C и может быть доступно только в windoze. Стандартная альтернатива - написать короткую функцию и либо использовать функции isupper() или islower() из заголовка <ctype.h>, чтобы перебирать каждый символ и вызывать toupper(), если требуется переход с нижнего регистра на верхний регистр.

Короткая функция может сделать все это за вас очень эффективно. Что-то вроде:

/** 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;
}

это все, что тебе нужно. Он просто просматривает строку, предоставленную как ввод, и, если символ в нижнем регистре, преобразует его в верхний регистр.

Ваша следующая проблема заключается в том, как вы обрабатываете буфер, заполненный fgets. Поскольку функция ввода ориентирована на строку, она считывает до и включает '\n' в конце ввода, включая его в качестве последнего символа в asn. Теперь, что бы вы ни делали со своей конверсией, dans никогда не будет соответствовать higher, lower или equal - вы еще понимаете, почему?

Посмотрим на твою "высшую"

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

Теперь давайте посмотрим на dans, если оно содержит то же слово (но с символом '\n', который все еще свисает с конца):

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

Поскольку вы читаете с fgets и не удаляли завершающий '\n', это всегда будет препятствовать действительному сравнению между dand и любой из ваших строк. Как это исправить?

Просто проверьте, что последний символ в ans, заполненном fgets, является '\n' и перезапишите '\n' завершающим нулем символом, удалив его. (Кроме того, вы должны убедиться, что пользователь не отменил ввод, сгенерировав вручную EOF, чтобы выйти раньше. Вы можете сделать все это в простом небольшом цикле ввода, требуя, чтобы ваш пользователь вводил допустимую строку, пока он не сделает или не решит отменить, например

    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));

Теперь dans правильно написано в верхнем регистре и не '\n' свисает с конца.

Ваши сравнения - последняя проблемная область. Вы не можете проверить равенство строк с помощью оператора ==. (то есть для сравнения символа за раз, а не строки. Подходящим инструментом здесь является функция strcmp в string.h. Если строки сравниваются одинаково, strcmp возвращает 0. Имея это в виду, вы можете исправить свои сравнения с помощью:

    /*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");
    }

Теперь, сложив все вместе, у вас есть код в форме, которая должна работать, например

#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");
    }
}

Пример использования / вывода

$ ./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!

Просмотрите все и дайте мне знать, если у вас возникнут дополнительные вопросы.

person David C. Rankin    schedule 22.02.2018

[отвечая на один вопрос из этого вопроса с несколькими вопросами]

Почему я не могу использовать% s в scanf?

Можно, но на самом деле вы используете &s

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

что не то же самое, что %s.

person alk    schedule 22.02.2018

[отвечая на другой вопрос из этого вопроса с несколькими вопросами]

error: implicit declaration of function 'strupr' is invalid in C99 [-Werror,-Wimplicit-function-declaration]

В приведенном выше сообщении говорится, что компиляторы впервые увидят strupr в этой строке. Таким образом, он "неявно объявляет это. Не зная, что он предполагает, что эта функция возвращает int. Это предусмотрено стандартом C".

Таким образом, в следующий раз, когда компилятор увидит strupr(), он должен вернуть int и при этом выдает предупреждение

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

сообщая вам, что int, переданный в качестве 2-го параметра в strcpy(), не соответствует ожидаемому.

Все это указывает на то, что используемая вами реализация C не предоставляет функции с именем strupr(). Это нормально, поскольку стандарт C не знает эту функцию.

Вы можете обойти это, раскатав свой собственный, например, так:

char * strupr(char * s)
{
  assert(s);

  char * pc = s;
  while (*pc)
  {
    *pc = toupper(*pc); /* toupper() requires <ctype.h> */
    ++pc;
  }

  return s;
}
person alk    schedule 22.02.2018