#c #cs50
Вопрос:
Я выполнял набор задач CS50 «Цезарь», и когда я попытался сдвинуть заглавные буквы, используя if (isupper(argument) == true)
для проверки, был ли символ, который я хотел переместить, прописным, это не сработало, он подумал, что заглавные буквы на самом деле не были прописными. Когда я включил его if (isupper(argument))
, программа правильно сдвинула заглавные буквы. Есть ли какая — то разница между этими двумя форматами? Вот код, который я использовал (я имею в виду код в цикле for):
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
//Check wether there is only 1 command line argument
if (argc == 2)
{
//Check if there is any character that's not a digit
for (int i = 0; i < strlen(argv[1]); i )
{
if (isdigit(argv[1][i]) == false)
{
printf("Usage: ./caesar keyn");
return 1;
}
}
}
else
{
printf("Usage: ./caesar keyn");
return 1;
}
//Convert key to an int
int key = atoi(argv[1]);
//Prompt plaintext
string plaintext = get_string("plaintext: ");
string ciphertext = plaintext;
//Shift ciphertext's characters by the amount of "key"
for (int i = 0; i < strlen(plaintext); i )
{
//If it isn't a letter, do nothing
if (isalpha(plaintext[i]) == false)
{
ciphertext[i] = plaintext[i];
}
else
{
//If it's uppercase
if (isupper(plaintext[i]) == true)
{
//Convert ASCII to alphabetical index
plaintext[i] -= 'A';
//Shift alphabetical index
ciphertext[i] = (plaintext[i] key) % 26;
//Convert alphabetical index to ASCII
ciphertext[i] = 'A';
}
//If it's lowercase
else if (islower(plaintext[i]))
{
//Convert ASCII to alphabetical index
plaintext[i] -= 'a';
//Shift alphabetical index
ciphertext[i] = (plaintext[i] key) % 26;
//Convert alphabetical index to ASCII
ciphertext[i] = 'a';
}
}
}
//Print ciphertext
printf("ciphertext: %sn", ciphertext);
}
Комментарии:
1. Сначала сохраните результат в переменной, прежде чем делать свое предположение, потому что функция должна сначала вернуть результат, а затем выполнить результирующие сравнения. Например, int result = isupper(аргумент); затем просмотрите содержимое «результата» с помощью отладки/точки останова. Я не говорю, что это правильный способ кодирования, но в данной ситуации это дает вам дополнительное представление, которое, я думаю, будет ценным.
2.
true
это одна из ценностей, которая обладает правдивостью.3. @rici так и есть, хороший улов.
4. @rici, в котором они находятся ,
stdbool.h
но если бы было допустимо/рекомендовано использовать их сisupper
et. al., не следовало бы/неctype.h
должно было бы включатьstdbool.h
само по себе, и макросы должны были бы обеспечивать истинное логическое значение 1/0?5.@крейг: если
isupper
бы вернулиbool
или даже_Bool
, это было бы приемлемо для сравненияtrue
. Даже тогда я бы этого не сделал, и я не думаю, что ты бы тоже этого сделал.if (booleanValue == true)
это шум. Но неуместно говорить (как это сделал отредактированный комментарий), что вы не должны использоватьtrue
иfalse
потому, что они не являются стандартными. Они стандартны, и у них есть применение. Это не один из них, и необходимо объяснить, почему это так. (И так оно и было.)
Ответ №1:
int isupper(int) не возвращает логическое значение (значение 0 или 1). Он возвращает ненулевое значение int, если аргумент в верхнем регистре.
разница между этими двумя условиями заключается в том, что одно сравнивает возвращаемое значение с одним, а другое сравнивает возвращаемое значение с ненулевым.
Комментарии:
1. О, в этом есть смысл! Спасибо за вклад! 😀
Ответ №2:
Когда у вас есть что-то, что вы считаете правдой/ложью, никогда не пишите
if(thing == true)
или
if(thing == false)
Просто напиши
if(thing)
или
if(!thing)
Оказывается, что isupper()
и islower()
и остальные функции <ctype.h>
isxxx возвращают ноль/ненулевое значение для false/true, но не обязательно 0/1. Если isupper('A')
вернется, скажем, 4, то if(isupper(argument))
будет работать так, как вы ожидаете, но if(isupper(argument) == true)
всегда будет терпеть неудачу.
См.также вопрос 9.2 в списке часто задаваемых вопросов C.
Комментарии:
1. Хорошая практика. Однако, хотя
true
тест плохой,false
тест в порядке [возможно, плохой стиль] (например(thing == 0) === (! thing)
). Лично я никогда не используюtrue/false
определения, но второе [всегда] будет работать.2. Хорошая рекомендация.
3. О, ух ты, теперь мне все так ясно! Это было действительно хорошо сказано, спасибо 🙂
4. Некоторая досадная деталь: если вы запустите cppcheck, он выдаст предупреждения: «[misra-c2012-14.4] Управляющее выражение оператора if и управляющее выражение оператора итерации должны иметь по существу логический тип» даже для кода, подобного
if (function_returning_bool())
. Насколько более «по существу буланов», чем тип возвратаbool
, он может получить?
Ответ №3:
Это плохой стиль-сравнивать значение истинности (логическое выражение) с константой истинности
if (isdigit(argv[1][i]) == false) // Bad style
if (!isdigit(argv[1][i])) // Better
if (isupper(argument) == true) // Bad style
if (isupper(argument)) // Better
В случае isupper
наличия скрытой ошибки. Чтобы быть «истинным», в C достаточно быть ненулевым. Но true
определяется как 1 в C.
==/!= true/false
Также отображаются логические значения второго рейтинга, которые вы могли бы с таким же успехом сделать (X == true) == true
. Избыточен и скрывает исходное состояние как гражданин первого ранга. Это показывает отсутствие некоторых знаний в области программирования (хотя и несерьезных).
Ответ №4:
Из стандарта C (7.4.1 Функции классификации символов)
1 Функции в этом подпункте возвращают ненулевое значение (true) тогда и только тогда, когда значение аргумента c соответствует значению в описании функции.
То есть в C любое ненулевое значение, используемое в условии, считается логическим истинным. Это не то же самое, что константа true
, определенная в заголовке <stdbool.h>
. Это любая из функций isdigit
, isalpha
или isupper
может возвращать любое ненулевое значение в качестве истинного значения. Но это не означает, что функция вернет именно ту константу 1
, которая определена в заголовке <stdbool.h>
как макрос true
. Поэтому вместо этого, например, это утверждение if
if (isupper(plaintext[i]) == true)
вы должны написать либо
if (isupper(plaintext[i]) )
или, например,
if (isupper(plaintext[i]) != false)
потому что константа false
эквивалентна значению 0
.