Я новичок в C, не понимаю, почему этот код не работает?
void main(){
char userInput = "a";
if (userInput == "a"){
printf("a");
} else printf("b");
getch();
}
returning "b"
но этот работает
void main(){
char userInput;
if ("a" == "a"){
printf("a");
} else printf("b");
getch();
}
returning "a"
В чем разница?
Подсказка: userInput - это единственный char, а не набор char.
"a" - это указатель (адрес памяти) на 2 байта, содержащий символ a и нулевой байт. 'a' - однобайтовая переменная. char - это тип символьной переменной. Если у вас "a" == "a", то вы сравниваете УКАЗАТЕЛИ, т.е. адреса памяти, которые просто так совпадают, поскольку компилятор поместил обе строки "a" в один и тот же адрес памяти.
Ни одна из частей не будет "работать" гарантированно. Строковые литералы могут иметь уникальные адреса. "a" == "a" вполне может быть ложным, AFAIK.
Возможный дубликат Как правильно сравнивать строки?
@toohonestforthissite Первая половина вопроса - это абсолютный обман, а вторая часть - нет. Ответ сводится к оптимизации компилятора.
@Lundin: Обе части - дураки. Собственно вторая часть - это то, что я связал, первая часть - опечатка (char *, тогда она такая же, как вторая часть). Оба являются основами языка Си, которые объясняются очень рано в соответствующих главах книги Си для начинающих. Нет необходимости вдаваться в подробности компилятора. Это UB для сравнения указателей, которые не указывают на / точно на один и тот же объект.
@toohonestforthissite Ну, в этом случае код делает случайно сравнивает два указателя, указывающих на один и тот же объект.
@Lundin: Нет, они этого не делают - судя по языку. Успешное сравнение - результат UB. / Говоря об оптимизации компилятора: компилятор мог полностью заменить условие на 1).
@toohonestforthissite Нет, это чушь. Вы перепутали это с арифметикой указателей на указатели, которые не указывают на один и тот же объект, что здесь не применимо. В языке говорится, C17 6.5.9: Операторы равенства: «Ограничения Должно выполняться одно из следующего: ... - оба операнда являются указателями на квалифицированные или неквалифицированные версии совместимых типов;». Нигде нет плохо определенного поведения - сравнения указателей совершенно четко определены и подробно объяснены в C17 6.5.9 §6.
@Lundin: Черт возьми, я всегда об этом забываю. Простите, да, вы правы. Похоже на недостаток стандарта, позволяющий проводить неоднозначные сравнения, подобные приведенному выше. Но все же должно применяться 6.5.9p6: «Два указателя сравниваются как равные тогда и только тогда, когда… оба являются указателями на один и тот же объект…». Если вы не найдете в стандарте отрывок, утверждающий, что идентичные строковые литералы являются одним и тем же объектом. Если бы они просто «могли быть», это было бы двусмысленно и имо недостатком в стандарте. Я думаю, что этот абзац в любом случае довольно неаккуратный, например с последним предложением.
@KamilCuk: "a" - это массив из 2 символов. В контекстах, используемых OP, он преобразуется в указатель. Указатели и массивы - разные вещи.
относительно: void main(){ Подпись для main() ВСЕГДА имеет тип возврата int, независимо от того, что позволяет Visual Studio
в отношении: char userInput = "a"; это пытается поместить массив в один символ (или адрес массива "a" в один символ. Предложите либо: char userInput[] = "a";, либо char *userInput = "a";. Первый инициализирует массив, второй инициализирует указатель на массив





Литерал, представленный как "a", является строковым литералом. Основной тип - это массив char, например char [size]. Это несовместимый тип с char, поэтому назначение
char userInput = "a";
не действует.
Вы хотите использовать символьную константу, вы пишете что-то вроде
char userInput = 'a';
Тем не менее, if ("a" == "a"), похоже, работает в вашем случае, но он не делает то, что вы думаете. Он не сравнивает содержимое, а сравнивает базовый адрес (адрес первого элемента) строк, и в вашем случае они кажутся одинаковыми. Ваш компилятор использует область памяти тем же для идентичных строковых литералов (оптимизация) - так что вы видите правдивый результат, но это не гарантируется стандартом. Компилятор (ny) может выбирать свою собственную стратегию распределения памяти с процессом оптимизации или без него.
При использовании gcc, если -fno-merge-константы используется как опция компиляции, ожидается, что это условие будет оцениваться как ложное.
Спасибо, друг за знания, не могли бы вы предложить мне какой-нибудь хороший учебник для изучения Си и информатики.
@AbhishekPandey Нет единого источника правды. Попробуйте руки со спецификацией - трудный путь, но лучший способ,
Цитировать символы с помощью ' Так
char userInput = 'a';
if (userInput == 'a'){
С char userInput = "a"; вы инициализируете userInput с char*, а не с символом 'a'. То же самое с сравнением, вы сравниваете char с char*.
И для инициализации, и для сравнения вы должны заключить символ в одинарные кавычки,
void main(){
char userInput = 'a';
if (userInput == 'a'){
printf("a");
} else printf("b");
getch();
}
Если игнорировать неверный синтаксис char userInput = "a" (я так понимаю, вы имели в виду char*), то первый случай очевиден и часто встречается часто задаваемые вопросы: вы сравниваете не содержимое строк, а их адреса. См. Как правильно сравнивать строки?
Та же проблема возникает, когда вы делаете "a" == "a", вы сравниваете адреса строк. Эти доступные только для чтения константы "..." в C формально называются строковые литералы.
Компиляторы используют общепринятый метод оптимизации, известный как «объединение строк». Объединение строк означает, что, встречая один и тот же строковый литерал несколько раз в программе, компилятор выделяет только один из них.
Итак, в вашем случае "a" и "a" оказались одним и тем же адресом памяти, потому что фактически был выделен только один из строковых литералов. Вы можете попробовать распечатать фактические адреса, по которым расположены строковые литералы, и убедиться, что они идентичны:
#include <stdio.h>
int main (void)
{
printf("%p %p", "a", "a");
}
Упрощенный ответ: в C все, что находится внутри двойных кавычек, является строкой, то есть последовательностью символов, оканчивающейся нулем. Одиночная кавычка предназначена для одиночного символа.
Пример :
char c = ‘a’ ;
char *str = “string”;
"a" - это строковый литерал, а не символьный литерал, который следует заключать в одинарные кавычки, как в 'a'.
char userInput = "a";, ваш компилятор должен жаловаться.