
Комментарии 70
Позабавил тэг "разработка игр"
Автор, вот вы когда сами пишете этот хаос из if'ов, у вас ничего не щелкает в голове?
Возможно, немного не в тему, но:
А какой фидбек вы ожидаете?
То, что вы попробовали Си - это классно. В любом случае это новый взгляд на программирование и управление ресурсами.
То, что в программе есть что доделать - это тоже очевидно:
scanf("%s", p_choice); -> scanf("%99s", p_choice);
Результат scanf лучше контролировать, т.к. если вы введёте один пробел, то p_choice рискует остаться неизменным;
p_choice на старте лучше обнулить/очистить. Так-то она мусором заполнена, и если это мусор соответствует букве q, то программа сразу же выйдет;
т.к. в программе нет отработки "мусорного" ввода (на запрос ввели "123"), то можно сделать немного полегче-получше: пользователь что-то вводит и в цикле по трём строкам идёт сравнение: какой из вариантов он ввёл? Если ни одному не соответствует, то просим повторить. А если вариант найден, то дальше идёт сравнение чисел. ЧИСЕЛ, КАРЛ! Лучше сравнивать числа: 0 тупит 1, 1 разрезает 2, 2 обёртывает 0.
// окончание игры
if (strcmp("q", p_choice) == 0) {
printf("\nQuitting...\n");
}
можно заменить на просто printf ... - в этом месте p_choice и так равен "q".
Прим.: в нативных языках Си, C++ строковый тип считается "не простым" типом данных (в общем, то это так и есть для всех языков, просто это стараются скрыть в тумане). И поэтому от строк стараются "отойти": если можно переключиться на числа - то лучше работать с числами.
В C если тело оператора if состоит из одного оператора, то фигурные скобки можно не писать, на 8 строк меньше.
Логика вашей игры на C и на питоне отличается: в C вы формируете случайный выбор компьютера вне игрового цикла, так что будете угадывать один и тот же вариант.
Плюсанул хотя бы даже за то, что статья написана живым человеком.
Меня уже поставили в известие. Насколько я помню, из-за моего просчета (я не заключил "яблоко рандома" в цикле while) выбор выполняется только один раз, так что выбор тоже будет идти только однажды. Благодарю за комментарий.
Для людей экономящих фигурные скобки после ифа в аду предусмотрен отдельный котел. Имхо).
А вот MISRA C:2012 правило 15.6 рекомендует ставить фигурные скобки во всех случаях. Потому что сегодня там одна строка, завтра две. Да и читаемость улучшается
Ожидаю фидбека в комментариях!
Напрашиваетесь, сударь, напрашиваетесь...
Вы там, в Питоне своём, как сыр в масле катаясь расслабились до наивности детской. Хотите приложение под Андроид - Kivy, хотите фронтенд - да хоть Anvil.works, и так со всем - Питон и ещё совсем чуть-чуть дают результат. А на С - стоит выйти за вот такую ножницы-бумагу... Андроид приложение - извольте, SDK, NDK, Native Activity и куча подробностей, с которыми можно разобраться, но изложены они с точки зрения Котлина, а то и Джавы. Фронтенд - а Вам какой, на Emscripten или Clang/LLVM? Ну и кусок JavaScript в придачу.,
То, что Вы увидели на ножницах с бумагой - это парадный фасад, а на деле может быть так, что пока Вы, пытаясь получить реально полезный результат, будете учить С, а на это неделя по вечерам уже много, и всю обвязку что и есть задница, можно будет выучить весь Rust и получить тот же результат от Cargo, потом выучить Go и получить результат ещё раз от Go (замечаете - и того проще чем с Растом), а остаток времени провести в душевных метаниях - может быть надо было сразу отдаться, ну или примкнуть к, Flutter?
С Flutter, кстати, возможен пример. На Python вы берёте Flet и ездите на Flutter фрирайдером. На C - сначала Dart, потом Flutter, потом Dart FFI и только потом вопрос "а ради чего?". Если кто-то поклялся Вам хорошо платить за C, ну знает или думает что знает ради чего, это одно дело, а если нет...
Так что от меня фидбек такой - бросайте эту ерунду, вы знакомитесь с С так, как это делали тогда, когда альтернатив не было. Вы питонист? Отлично, напишите модуль на С. Убедитесь, что он и на Андроид, с тем же Kivy например, тоже работает. Напишите что-нибудь на SDL или Qt. И только после этого у Вас появится право решать - понравился С или нет.
Разве C не учат перед C++? В моем видении C — только промежуточная ступень, чтобы получше разобраться в тех же C++/Rust. Хотя, по такой же логике, перед C стоило бы посмотреть на Go/CSharp.
Если вам интересен C++ или Rust, то для этого совершенно необязательно учить C. В случае с C++ многое из того, что вы освоите в C будет доступно, но категорически не рекомендовано к использованию. Нет ничего плохого в изучении C, если он интересен сам по себе, но врядли полезно, как подготовку к изучению того же C++
Тогда я просто начал бы писать на C++, как на Python. Тогда геморроя было бы в 10 раз больше. Я предпочту сначала понять, как работают системы с минимумом абстракций, чтобы уже потом плавно перетечь в C++.
Ну, писать на C++ как на python у вас всё равно не получилось бы, как не получилось на C. И не стоит ожидать, что C можно плавно "перетечь" в C++. Зная C, можно легко начать писать работающие программы, которые будут компилироваться C++ компилятором. Но для идиоматичного кода придётся учиться заново, местами переучиваясь от привычек из C
Можно знать C и не знать ничего больше, его достаточно для многих применений.
Если очень постараться, то можно и API для бэкенда написать на C.
Я сегодня ради эксперимента взял ИИ (я все еще не умею писать на C, могу только вникать в код) и провел бенчмарк FastAPI-обертки + бэкенда на C против уже существующей этой же обертки на TS. Суть программы была в том, что это была админ-панель (пользователи могли регистрироваться, а админы могли их банить).
Я построил архитектуру так, что Python асинхронно сгребает в батчи (10, 50, 100, 200) запросы и посылает их в C-бэкенд. С количеством обрабатываемых батчей росла и скорость обработки (98× скорости при батче в 200 запросов, и оно шло только вверх по метрике!)
На моем динозавре 2009 года с 6 ГБ ОЗУ оно летало. Я завтра попробую уйти от PostgreSQL и посмотреть в сторону RocksDB, там должно быть еще больше. C++ тоже мне интересен, но я пока не буду его трогать, пусть и знаю несколько прикольных фреймворков для обработки данных
Разве C не учат перед C++?
Наверняка есть и такие случаи, когда учат. Иначе вот такое вот без надобности было бы.

C и C++ языки очень разные. То, что они местами внешне похожи - следствие того, что на момент создания плюсов поголовно все заинтересованные лица знали C. Далее сходство сохраняли как дань традиции, но сами ответственные лица подчёркивают - это ни в какой степени не являлось целью и делалось строго по возможности.
Изучать C ради лучшего последующего изучения плюсов - ошибка. Чтобы C просто не мешал, его нужно не только основательно изучить, но и к нему привыкнуть, чтобы языки не смешивались один с другим. Если хочется и C и C++, тогда хорошо, если только плюсы - двойная работа в лучшем случае.
Ниже Вы пишете
Тогда я просто начал бы писать на C++, как на Python.
и это очень странно. С одной стороны, как писать как на Пайтон если на плюсах половина кода в одном файле, а другая половина - в другом? С другой стороны, на Пайтон можно писать в любом стиле, в том числе как на плюсах с макросами.
Если языки сами по себе, как хобби или предмет любования логическими, да и алогичными тоже, построениями, не интересуют - никакого смысла в полиглотстве нету. А рассказы типа "я выучил ... и стал лучше ..." - это скорее от нежелания признавать собственные ошибки, чем от искренности.
Например, заинтересовала тема функционального программирования (спецом подальше от C). Тогда можно прочитать про функциональное программирование и подумать как это будет на своём Пайтоне. Где именно прочитать, я не знаю, однако. Если Вы тоже не знаете, ну не удалось выяснить, то берёте книгу по функциональному языку, скажем по Лисп, и читаете по диагонали. Далее то же самое - уложить идеи на Пайтон. Ключевое слово - по диагонали, то есть никак не выучить.
Применительно к C или плюсам - посмотрите на Ассемблер и, если не в курсе то обязательно, на архитектуру машины, особенно на систему прерываний.
А что учить легче — C или плюсы? Не по отделению "по какому языку материалов больше", а скорее по именно усвоению материала
На мой скромный взгляд, чистый Си учить намного легче. Вот совсем (и намного) легче. На C++ одни пляски с шаблонами чего стоят!
НО: если рассматривать условно "большие" проекты, то более понятный, чистый, корректный код будет скорее всего на C++ (конечно, если вы на нём умеете). Просто потому, что стандартных средств для типовых задач - их намного больше. И контроль типов лучше. Повторюсь: это всё работает, если вы умеете "в плюсы". Если вы будете на C++ писать как на чистом Си (многие так и делают и это работает) - тогда преимуществ не будет.
Получается, что на C++ в сложности обучения идет кривая до небес, а после этого плато?
Попробую дать другую аналогию (скорость + дистанция) (также: сравнение с Питоном сделано для контраста, не нужно сильно придираться):
== Задаём скорость:
Питон - это как передвижение по просёлочной дороге (утоптано, умято, вполне ровно);
Си - это передвижение по перепаханному полю (вроде не проваливаемся по пояс, но если побежим, то можно и ноги повредить);
C++ - это передвижение по утрамбованному полю (двигаемся медленно, но возможность повредить ноги снижается).
== Включаем дистанцию:
Начинающий разработчик - ну что там говорить - это быстро везде, особенно с ИванИванычем;
Продвинутый разработчик:
на Си - добраться до деревни в 5 км на север;
на Питоне - это обойти 10 полян на севере на расстоянии 10 км;
на C++ - это побывать во всех полянах на севере на расстоянии 10 км.
---
А теперь переходим к исходному вопросу: что легче? По-моему, легче прийти в одну известную недалёкую точку, хоть и по перепаханному полю.
Очевидно, у Вас возможны другие приоритеты. Банально, разный темперамент может повлиять: кто-то не готов "медленно, в одном направлении, а деревни всё ещё не видно".
---
Прим.: по-моему, кривая обучаемости здесь несколько неинформативна, т.к. объём навыков (ордината графика) сильно разная - количество полян отличается очень-очень. Соответственно и сравнивать крутизну некорректно.
Прим.Прим.: В C++ нет как таковой сложности обучения до небес (например, если что-то не знаете - то вообще босса не замочить ничего сделать нельзя): если что-то слишком сложно, то вы такими средствами не пользуетесь (или используете готовые библиотеки) - и всё ок.
Так красиво расписано все... В поэты бы Вам.
Прим.Прим.: В C++ нет как таковой сложности обучения до небес (например, если что-то не знаете - то вообще
босса не замочитьничего сделать нельзя): если что-то слишком сложно, то вы такими средствами не пользуетесь (или используете готовые библиотеки) - и всё ок.
Босс: ты же знаешь С++, у нас на новой платформе проект не собирается, что то с бустом, поправь...
Нет, потом следующая кривая до небес. Первая была еще пологой =)
Сам язык С максимально простой, но при этом и за программиста он ничего не делает. Поэтому за всеми подводными камнями нужно следить самостоятельно.
С++ может взять на себя рутину, но надо знать что написать.
void lower(char *str) {
for (int i = 0; str[i]; i++) {
str[i] = tolower(str[i]);
}А теперь используем:
...
char just_char_array[] = {'e', 'n', 'd', 'l', 'e', 's', 's', ' ', 'F', 'u', 'n'};
lower(just_char_array);
...Наслаждаемся UB.
Напомню две вещи:
Этот код я написал на второй день своего изучения C, причем не обошлось без интенсивного поиска информации по абстрактной логике, не говоря уже о багах и сегфолтах;
Код функции предназначен для строк, а не для массивов со строками
Я ценю и уважаю Ваш профессионализм, но надо же вникать в контекст ситуации.
Я же по этому поводу:
Ожидаю фидбека в комментариях!
Ничего страшного, научитесь еще.
Код функции предназначен для строк, а не для массивов со строками
И про этот "маленький" нюанс узнаете в процессе.
Прозвучало как страшное предзнаменование. Спасибо за предупреждение.
Указатели, массивы и строки, их взаимосвязь и то, как они передаются (или возвращаются) в функции — очень интересные темы и не такие уж сложные, как может показаться с первого взгляда. Вам должно понравиться.
Это и вправду так. scanf() дался мне очень легко, да и строки вида printf("Значение: %d", num) я полюбил даже больше питоновского форматирования строк. Я сам в предвкушении будущей работы с ними.
С "дружелюбным" scanf() Вас тоже ждёт сюрприз. Если Вы свою текущую программу на си будете вызывать на беке с передачей туда пользовательского ввода, то дадите remote code execuition.
Дело в том, что scanf не проверяет размер целевого буфера, т.к. физически не может это делать не зная его размер. В итоге он проедется по стеку, делая типичный buffer overflow. В умелых руках этого достаточно для атаки.
Начните с Столярова, иначе сищность головного мозга не избежна
В его программе все char* заканчиваются нулями (из-за инициализации списком, надо же, сделали такое в C), поэтому UB не будет.
Поправка: scanf формирует null-terminated последовательность char, поэтому в случае p_choice UB тоже не будет.
Хорошо было бы предложить решение, которое бы позволило в данном случае избежать UB. Вопрос только в том, существует ли оно.
Просто решение — разумеется существует, выделите буфер подлиннее, скопируйте туда аргумент, добавьте в конец \0 и работайте с этой безопасной копией. Но так никто не делает, конечно.
Я просто не понял, что @Serpentine предлагает сделать, чтобы избежать UB непосредственно в функции lower. Какой бы тип не был выбран для строки(указатель, указатель+длина), всё равно пользователь функции сможет передать испорченные данные.
Последовательность char just_char_array[] должна обязательно заканчиваться нулем '\0', иначе это некорректная строка C.
А это не строка. Это массив, вообще-то. Сами-то посмотрите, что у вас объявлено - массив char.
Все верно, массив char содержит NUL-terminated строку C, т.е. последовательность символов, которая заканчивается символом NUL (\0).
Омг, ну ты бы ещё на ассемблере пытался это написать - да ещё и изучая язык по ходу.
Я, зная и Си и ассемблер и ещё много других классических языков, точно также буду плеваться от Питона, который не знаю вообще.
В 2026 так на питоне тоже писать не нужно. Объявите пару enum’ов и вперед:
match (player_move, computer_move):
# Draw cases
case (Move.ROCK, Move.ROCK) | (Move.SCISSORS, Move.SCISSORS) | (Move.PAPER, Move.PAPER):
return GameResult.DRAW
# Player wins
case (Move.ROCK, Move.SCISSORS) | (Move.SCISSORS, Move.PAPER) | (Move.PAPER, Move.ROCK):
return GameResult.WIN
# Computer wins
case (Move.ROCK, Move.PAPER) | (Move.SCISSORS, Move.ROCK) | (Move.PAPER, Move.SCISSORS):
return GameResult.LOSE
case _:
return GameResult.INVALID_INPUT
Можно полный код такой версии?
Что-то типа такого:
import random
from enum import Enum
class Move(Enum):
ROCK = "rock"
SCISSORS = "scissors"
PAPER = "paper"
class GameResult(Enum):
WIN = "win"
LOSE = "lose"
DRAW = "draw"
INVALID_INPUT = "invalid input"
def determine_winner(player_move: Move, computer_move: Move) -> GameResult:
"""
Determine the winner using Python 3.10+ pattern matching.
Args:
player_move: The player's move
computer_move: The computer's move
Returns:
GameResult indicating who won
"""
match (player_move, computer_move):
# Draw cases
case (Move.ROCK, Move.ROCK) | (Move.SCISSORS, Move.SCISSORS) | (Move.PAPER, Move.PAPER):
return GameResult.DRAW
# Player wins
case (Move.ROCK, Move.SCISSORS) | (Move.SCISSORS, Move.PAPER) | (Move.PAPER, Move.ROCK):
return GameResult.WIN
# Computer wins
case (Move.ROCK, Move.PAPER) | (Move.SCISSORS, Move.ROCK) | (Move.PAPER, Move.SCISSORS):
return GameResult.LOSE
case _:
return GameResult.INVALID_INPUT
def play_game(player_input: str) -> tuple[GameResult, Move, Move]:
"""
Play a single round of Rock-Scissors-Paper.
Args:
player_input: The player's move as a string ("rock", "scissors", or "paper")
Returns:
A tuple of (result, player_move, computer_move)
"""
# Parse player input
match player_input.lower():
case "rock":
player_move = Move.ROCK
case "scissors":
player_move = Move.SCISSORS
case "paper":
player_move = Move.PAPER
case _:
raise ValueError(f"Invalid move: {player_input}. Use 'rock', 'scissors', or 'paper'.")
# Computer makes a random move
computer_move = random.choice(list(Move))
# Determine the winner
result = determine_winner(player_move, computer_move)
return result, player_move, computer_move
def display_result(result: GameResult, player_move: Move, computer_move: Move) -> None:
"""Display the game result in a user-friendly format."""
print(f"\nYou played: {player_move.value}")
print(f"Computer played: {computer_move.value}")
match result:
case GameResult.WIN:
print("🎉 You win!")
case GameResult.LOSE:
print("😢 You lose!")
case GameResult.DRAW:
print("🤝 It's a draw!")
case GameResult.INVALID_INPUT:
print("✗ Invalid input")
def main():
"""Main game loop."""
print("Welcome to Rock-Scissors-Paper!")
print("Type 'quit' to exit.\n")
while True:
user_input = input("Enter your move (rock/scissors/paper): ").strip()
if user_input.lower() == "quit":
print("Thanks for playing!")
break
try:
result, player_move, computer_move = play_game(user_input)
display_result(result, player_move, computer_move)
except ValueError as e:
print(f"Error: {e}")
if __name__ == "__main__":
main()
Недавно я задумался: Python — не единственный инструмент, которым я хочу оперировать в своих инструментах. Python, понятно, легко освоить и он применяется везде, но язык-то не идеальный!
«Неверная» постановка вопроса! Питон – язык идеальный, но, только для своего класса задач. Это – подготовка и обработка данных. Всё! Для работы с графикой, видео, звуком, ГУИ (графическим интерфейсом пользователя), потоками и много чем еще, выгодней использовать С++ с фреймворками.
Я лично предпочитаю WTL, библиотеку кода, занимающую, в исходниках, менее полутора мегабайт! На базе чего написал свою обучающую систему «Леколь» (см. https://lecole.free.nf/ и мои статьи, здесь).
У меня есть, также, неопубликованная программа для работы с медиа-файлами: «МедиаТекст».

Для загрузки любимых видосиком, написал графическую обёртку «MiniDL» для известной консольной утилиты «yt-dlp.exe» ( https://habr.com/ru/articles/955838/ )

Короче говоря, C++ / WTL – рулит! А вот данные для обучающей программы и видео, с двуязычными субтитрами делал на Питоне. Для подобных задач – ему цены нет!
Но, если надо скачать, допустим, онлайн-словарь, для изучения иностранного языка, то для борьбы с капчей, лучше использовать не Питон (там «дорогое» решение), а расширения для старой версии «Хрома», поддерживающую вторую, а не третью версия манифеста. Ибо, последняя – более ограничительная для подобных целей.
Короче, для разных задач – свое ПО!
А «чистый» Си, это, скорее, для нижнеуровневого и консольного программирования. Например, чтобы реализовать собственные видеоплейер в оконной программе, я взял опенсорсный «FFplay.c», переделал его в классы С++ и спокойно подключил к своему проекту. Кстати, ничего путного, на эту тему, на Гитхабе, я так и не нашел.
Так что, не делайте концептуальных ошибок и будет вас счастье!
А вы C++ с нуля учили?
А вы C++ с нуля учили?
Я все языки учил по принципу: Берешь простой прототип, компилируешь. Либо запускаешь на исполнение, если скрипт. Потом, экспериментируешь с кодом, пока не врубишься, что к чему. Книги по языку и документацию, особо, не читал. Из-за чего много времени приходилось сидеть в Интернете, в поисках подходящего прототипа. Сейчас, благо, есть ИИ-сервисы, которые в части поиска нужной информации представляют собой «Интернет-2.0».
Вообще-то, кормил меня язык «1С77». Проще учетной платформы не существует. Единственный минус – программистов «конфигурастов» никто за программистов не считал. Параллельно, я начал, на работе, осваивать ассемблер и декомпиляцию бинарного кода (см. мой сайт https://erfaren.narod.ru/ ). Этого оказалось мало, поэтому перешел на освоение С++. Сначала с MFC, потом с WTL. Последний прижился, пользуюсь им до сих пор. Затем был Питон и т.п. Для них в Visual Studio С++ существуют мастера, которые генерят различные прототипы кода. С их разбора я и начинал освоение языка. Плюс очень много помогал, в свое время, сайт codeproject.com (сейчас он в упадке). Не говоря уже о Гитхабе.
Мужик, ты задолбал с саморекламой
Мужик, ты задолбал с саморекламой
Мужик, ты не одинок в своих чувствах! Меня тоже достают пустые статьи, где много общих слов и ни одного конкретного примера. Я, конечно, повторяюсь, но по делу. Реплики делаю по существу, а не ради рекламы (смысла в которой нет никакого!). Реагируйте на них тоже по существу – будет предметный разговор. Но, обычно, авторы простых статей, сгенерированных ИИ-ями, хотят только, чтобы их хвалили, какие они молодцы, что научились промпты писать, либо никак не реагировали. Однако, критики боятся – в Интернет не ходить! Здесь все-таки технический форум, а не просто тусовка школьников. Что подразумевает некий уровень в текстах. Удивляет, что многим просто нечего сказать в ответ. Зачем тогда вообще ходить на технический форум? Есть другие площадки, попроще.
В крайнем случае, если нечего сказать по делу, можете переходить на личности, типа: «Сударь! Мне не нравится, что вы говорите, как вы говорите и, вообще, вы сами» (можно в переводе на рабоче-крестьянский язык, я не обижусь), либо, втихоря, минусовать. В итоге, и «волки целы и овцы сыты!». Вы получаете сатисфакцию за то, что демонстрируете свое «фе», кому-то, вроде меня, кто примелькался у вас на глазах, а я внушаю вам простую мысль, что на техническом форуме надо больше писать по сути дела, а не переходить на эмоции, без особой нужды.
Зачем сравнивать строки? Можно изначально присвоить номер для введённого слова и пробросить через switch...
Наконец то хоть кто-то осмелился подобное написать. Это очень забавно со стороны выглядит.
Респект автору!
Я всегда рад когда люди пробуют C. Это замечательный инструмент обучения, который позволяет приблизиться к железу.
Но самое главное преимущество языка C именно для обучения - это возможность выстрелить себе в ногу в каждой строчке. Это позволяет ещё лучше понять железо, а потом писать более эффективный и разумный код на языках, предоставляющих инструменты защиты от утечки памяти. Ведь на самом деле утечку памяти можно прекрасно устроить и на Rust. И та база, которую вам даст боль от C, пригодится вам везде.
Поддеживаю автора в желании изучить C. Язык являается лучшим средством разрбраться в том, как работает компьютер и что делают программы, написанные на языках высокого уровня.
По Моему мнению, любой программист, вне зависимости от используемого ЯП, платформы и фреймворков, должен "уметь в C", иначе компьюер и программы будут касатся непонятным чёрным ящиком, имхо.
Всегда пугало привидение типа.
Первые мысли питониста о Си на примере игры «камень-ножницы-бумага»