コンピュータは、基本的に「数値」しか扱えません。でも、文字も扱いたい、どうしましょう。
一つ一つの文字に数値を割り当てて、文字として扱いたいときにはその約束のもとに「割当表」に基づいて数値と文字を置き換えて扱うことにしました。
半角文字について事実上ほとんどのCの処理系が採用しているASCIIコードという割当表によれば、文字'0'は数値48, '1'は数値49,...'9'は数値57, 'A'は数値65,として扱われます。
(その意味で、ソフトウェアの中身の話をするときは「数値」と「数字」を厳密に区別して考えるべきです。数値というのは値そのもの、数字は数値を表す単独の文字あるいは文字の並びです。)
fgetsでは(あるいは、scanf/scanf_sの"%s"書式指定では)、文字列を取り込みます。つまり、文字'0'が与えられたらそれは数値48を意味します。
また、改行文字は(あなたのシステムでは)数値10だったのでしょう。fgetsでは指定文字数以内なら改行までを取り込みますから、それが結果にあらわれています。
以上「➀これは何が起きているのでしょうか?」
そして、48とか49がそれぞれ1文字です。1文字ずつ取得できています。これが「➁キーボードからの入力を1文字ずつ取得することはできないのでしょうか?」の回答になりますでしょうか。
➂16進数に直す方法は他にもありますか?
「他」というのは一つできてから考えることと思いますが。
「16進数に直す」ですか?
先程の「数値」の話ですが、例えば0b11001==0x19は真ですし、0x19==25も真です。数値は、その表記によらず同じ「値」を意味します。百と言おうとone handredと言おうと数は変わらないのと同様。では、「16進数に直す」とは何を意味するのでしょう?
例えば「16進数表記で表示したい」のだとすると、
数値として取り込んであれば、printf("%x",数値);で16進数として表示されます。これが一番簡単かと思いますし、これ以外の何かをする理由もないでしょう(お勉強として、以外は)。
あるいは、数値を経由せずに、文字列を下から4桁ずつ区切って、"0000"だったら'0'、'0001'だったら'1',...'1111'だったら'f'と置き換える、なんていう方法も考えられます。たった16種しかパターンがないので。
そもそものお題も読み返すと結構悩ましいですね。
キーボードから1,0で表したデータを入力してもらい(例えば11001など)、入力されたデータを16進数に変えて、ビット演算を行いたいです。
まず「1,0で表したデータ(例えば11001など)」これは、2進数表記であることを意図している、と思っていいですか?
「16進数に変えて」は上述の「16進数に直す」と同じ話ですが、しかし「入力されたデータを0x11001と解釈したかったのでは、という疑念がわずかに出たりもします。
そしてさらにビット演算を行いたい? ビット演算は、コンピュータの内部で数値が2進数で保存されていることが前提で行われるものです。16進数とか関係ありません。どういう結果が得られれば満足なのでしょう?