Q&A¶
ここでは講義中に出た質問に対する回答を載せていきます。随時更新です。
Week1¶
-
来週以降、自分のPCを使ってもいいのか?
- 大丈夫です。具体的には以下です。
- 【場所について】week2以降は、情報教育棟で講義を行います。講義を受ける人は全員情報教育棟に来てください。情報教育棟に入ること自体は、ECCSアカウントを登録していなくても可能です。
- 【PCについて】
- 情報教育棟のマックを使う場合、ECCSアカウントが必要です。この手順に従ってECCSアカウントを登録しておいてください。机に据え置きしてあるマックを使うので、ノートPCを持ち込んだりする必要はありません。
- もし自分のノートPCを持ち込む場合、それでも大丈夫です。ECCSアカウントはいりません。目の前のマックは使わずに、自分のPCを用いて講義をうけます。
- 【プログラミング環境について】
- 据え置きマックを使うにしろ、自分のノートPCを使うにしろ、「ローカル環境」でも「ブラウザオンライン環境」でも大丈夫です。
- 講義で公式にサポートするのは「情報教育棟マックのローカル環境」および「ブラウザオンライン環境」のみです。
-
出席点はあるか?
- ありません。もしC言語を既に全部理解しているなら、講義に出なくても大丈夫です。宿題だけは全部やってください。宿題・最終レポートのみで成績をつけます。
-
他学部・他学科だが履修可能か?
- 履修出来ます。便覧やUTAS/ITC-LMSをよく読んで取得単位等について確認してください。
-
何度リロードしても読み込みが終わらない場合どうすれば良いですか
- 3分ぐらいまってください
-
Main.cの横にある2という数字は何を意味しているのでしょうか
- 警告の数だと思います。ファイルの中身がc言語的に変だよ、と教えてくれています。あまり気にしなくて大丈夫です。
-
ターミナルのところをクリックすると、沢山欄が出てきますが、New terminal というところを押せば良いですか
- それでもOKです。授業では黒ターミナルを使います。
-
homeからのlsのとき、出てくるlost+foundはなんですか。
- ゴミ箱的なものですが、特殊なフォルダなので気にしなくて大丈夫です。
-
ls-1
の詳細にプリントするとはどういうことですかls -l
(エル、エス、スペース、ダッシュ、エル)です
-
a.out にはコンパイルするたびに中身が完全に新しいものに置き換わりますか
- 変わります。ただ、コンパイルに失敗した場合は変わらないので、注意してください。
-
0x7fff9de8af10
と0x7fff9de8af0c
の差はちょうど4でしょうか- そうです。0, 1, ..., 9, a, b, c, d, e, f, 10, 11, 12, ..., 19, 1a, 1b, 1c, 1d, 1e, 1f, 20, ... です。
-
vscodeでデフォルトで設定されているスニペットをいじる方法はありますか?
- VSCodeであれば左下の歯車から「ユーザー スニペット」から編集できます。
-
アドレスは2進数で表された0~(2^64)-1 を16進数で表しているということであっていますか
- あってます
-
以下のように書いたところエラーが出る代わりにaとbの表示される順番が逆になって"600 3.140000"になりました。これでは気づけないままプログラムが意図しない動きをしそうですが仕様でしょうか?
int a = 600; float b = 3.14; printf("%d\t%f\n", b, a);
%d
などと、対応する変数の型が揃わない場合の挙動は未定義のようです。- 【2023/12/1追記】 このような記事がありました。
-
予想される正しく間違った挙動はどうなりますか?
- 私が実行した結果を共有しておきます.
int main() { int i = 123; float v = 123; printf("i=%d\n", i); // i=123 printf("v=%f\n", v); // v=123.000000 printf("i=%f\n", i); // i=123.000000 printf("v=%d\n", v); // v=-1585646944 printf("i=%f\n", (float)i); // i=123.000000 printf("v=%d\n", (int)v); // v=123 }
- 私が実行した結果を共有しておきます.
-
charって文字型ではないんですか?
- characterのことですので、文字の型です。日本語として「文字型」というかはちょっと微妙ですが、英語ではcharacter型と言います。
-
printf("v=%d", v);
と書き換えたところエラー文に、float型で宣言したはずの変数vがdouble型だと表示されたのですがこれはなぜですか?- 暗黙の型変換が起こってdoubleになっているんだと思います。型変換を勉強するときに説明します。
-
doubleも64ビットなのに、longに比べてはるかに大きい数字を表現できるのはどうしてですか?
- long(整数)は数字を正確に表現していますが、double(実数)は「その範囲の数字を近似的に表現」しているだけなので、正確ではありません
-
固定小数と浮動小数の違いはどのように理解したらいいでしょうか
- 原理が違います。アーキテクチャの授業で詳細を習うと思います。みなさんが普段使うのはすべて浮動小数です
-
surfaceはバッテリー持ち良いですか
- 普通じゃないですかねえ
-
surfaceのどういう点が好きですか?
- まずタッチパネルは、使い始めてみると案外いいですね。電車の中で論文をよむときなど、すすすっとスクロールできます。スクロールやピンチに関するUIは、マウス・キーボードよりもタッチのほうがいいんですよね。また、キーボード着脱式は簡易デュアルスクリーンになったりして案外便利です。加えて、ペンが附属しており、そして(Pro8以降のモデルだと)キーボードにスポッとはめて充電まで出来るのがいいですね。ペンはpdf書類へのサインとか、図に対するビジュアルなコメントを付ける際に案外必要になります。意外に知られていませんが、パワポはペン入力をめちゃくちゃしっかりサポートしています。総じて、Microsoftが威信を掛けて作ったUI/UXデザインであり、そしてメインモデルが9代目まで続いているという確かな伝統が感じられます。ただ、Thinkpad X1 Carbon (or Thinkpad X1 Nano)のほうが間違いは無いです。
-
C言語には初期化されていない状態の変数への参照にエラーを吐かせる設定は無いのですか?
gcc main.c -Wall
のように-Wall
オプション(Warning All)をつけると警告を吐いてくれます。エラーにはならないです(安全性よりも、ローレベルに触れること重要視して最高性能を追求できるというのが、C言語の立ち位置です)
-
ソースコードの文字の大きさを大きくする方法を教えてください
- File -> Preferences -> Open settingsからできると思います。
-
先生のページを参考に WSL のインストールをしたら、 Ubuntu が起動するタイミングで
WslRegisterDistribution failed with error: 0x80370114
というエラーが出てしまいました。どうすれば良いのでしょうか? ちなみに使っているのは Surface Pro 8 です- このような記事を参考にするとよいかもしれないです
-
macのctrlはcommandキーに侵略されているような気がしますが、ctrlキーを使うことになるのでしょうか?
- ちょっと今手元にマックのキーボードがないのでわからないのですが、emacs使うときはctrlが必要になると思います
-
個人のWindowsPCでWSLを用いても問題ありませんか?
- 大丈夫です。winノートPCを情報教育等にもっていってください。ローカル環境構築も参考にしてください。松井の書いたこの記事とかも参考にしてください。
-
パソコンが配られるとは!?
- 電気系の3年生にはレンタルで配られます。
-
個人のパソコンはwindowsでなにか困ることはありますか?
- 大丈夫です。ローカル環境構築をよくよんでください。松井の書いたこの記事とかも参考にしてください。
-
mac は Ctrl と Caps Lock が逆なので嫌いです()
- windowsであってもctrlとcaps lockはひっくり返すのがemacs的ということになります(emacsというのは、プロ向け(?)のエディタです)
-
毎週の課題はどのタイミングで公開されますか
- 授業の最後です
-
演習ではコードの最後に
return 0
と書いたのですが、こちらでは必要ないのでしょうか。また、return 0
の意味は何でしょうか。- あるほうが正確です。ここでは省略してもエラーにはならないです。この記述の意味は、このメイン関数(このプログラム)が返すリターンコードは0であるという意味になってます。
./a.out
を実行したあとにecho $?
(直前に実行した操作のリターンコードを表示する) とすると、0が表示されます。return 1
にしておくと1になります。この情報は、プログラムを別のプログラムと組み合わせるときに使ったりします
- あるほうが正確です。ここでは省略してもエラーにはならないです。この記述の意味は、このメイン関数(このプログラム)が返すリターンコードは0であるという意味になってます。
-
a.outをcatしてみるとすごい文字化けが表示されますが、どういった状況なんでしょうか
- a.outはコンピュータが読める形式になっているので、人間が読める形式にはなっていません。そのため、開くと文字化けしているように見えます。
-
terminalを使う場面において、ファイル名を日本語にすると何らかの弊害がありますか?
- ある場合もあります。なので、特に理由がない場合はアルファベットにすることをおすすめします
-
すごい初歩的なことかもしれませんが、コンパイラとは何か教えてください
- ソースコードという、人間が読み書きできるテキストファイルを、機械が読み書きできる形式に変換してくれるものです
-
int main()
のint
を省略した場合、コンパイラはそれを自動で補完いてくれますか?それとも補完しないでそのままコンパイルしますか?- 自動で補完しています
-
clangとgccはCのコンパイラだが、設計が違うコンパイラということですか?
- そうです。clangというのは途中でLLVMというナウい仕組みが挟まる、新しいコンパイラです。マックではデフォルトがclangになっています
-
演習でやったときはmainの前にintがありましたが、なんのためのintだったんですか?
- 関数名の前のintとかは関数が返す値の型を指定するためのものです。main関数はint型を返すと決まっています。
-
Tabキー押しても自動補完されないのですが考えられる理由はありますか?
- カレントディレクトリが違っていたり、そこまでにタイプミスしているかなどだと思います。
-
.bash_history
には、どのくらいの期間の履歴が保存されるのでしょうか?例えば、来週、今日打ったコマンドを復習したい場合には、どうすれば良いか知りたいです.bash_history
に残っているのは今回の環境では直近1000件のようです。
-
bashとはどういう意味でしょうか?
-
ディレクトリとファイルを同時に作成できるコマンドはありますか?
これだとmkdir -p aaa/test.c
で出来るとのことです(教えてくれた人、ありがとうございます)test.c
というフォルダができちゃいますね
-
terminalに書いた内容を保存することはできますか?
~/.bash_history
に自分が打ったコマンドは残っているかもしれません
-
Terminalがキー入力を受け付けなくなったのですが、どうすれば良いでしょうか
- ブラウザをリロードしてみてください
-
cpコマンドでコピーされたファイルは通常どのディレクトリに作成されますか
- 現在位置です
-
pwdで表示されるディレクトリをcd以下に書いて実行するとエラーが起きてしまうのですがなぜでしょうか?
- 最初のスラッシュがcdを打つときに抜けているとかかもしれません
-
terminal上で、for文を作ることはできますか?main1.c main2.c main3.c main4.cを同時に作ったりはできますか?
- ブレース展開を使えばできます
touch main{1..4}.c
- ブレース展開を使えばできます
-
cloud shell のターミナルはどのOSに基づいていますか?
- Debianです。詳しくはオンライン環境構築の下のほうを参照してください。
-
hoge
には何か意味があるのでしょうか- メタ構文変数と呼ばれています。英語だとfoo, barとかがあります。
-
フォルダに
main.c
入れてcatしたらcat: main.c: No such file or directory
が表示されたですけどフォルダから出す以外解決策ありますか?- そのフォルダの中に
cd
出来ていないと思われます。
- そのフォルダの中に
-
cd home/matsui528
のように打つとうまくいくのですが,cd matsui528
と打つとうまく行きません.後者のコードは現在地が「matsui528」の一つ上でないと行かないのでしょうか?- 相対パスを指定すると、カレントディレクトリから見た相対的な位置を指定することになります。カレントディレクトリが
/
であれば、/matsui528
というフォルダが存在しないので、cd matsui528
では移動できないことになります。
- 相対パスを指定すると、カレントディレクトリから見た相対的な位置を指定することになります。カレントディレクトリが
-
ls コマンドを実行したときの文字の色の違いは何を表しているのでしょうか?
- 白はファイルです。青はディレクトリです。他にパーミッションという概念などでも色分けされていると思います。
-
UNIXとLinuxでどちらの方がプログラミングに向いてるといった優劣はあるのでしょうか?
- まずUnixのほうが大きな概念です。Unixの一種として、LinuxやMac OSがあります。また、Linuxにも色々あり、UbuntuやCent OSなどが人気です。プログラミングの学習や計算機科学の研究では、いわゆるwindows系列を直接使うことに比べ、Unix系列を使う場面は多いと思います。また、最近はWindows Subsystem for Linux (WSL)という技術を用いて、windows上でもLinux的なものを使えます(便利)
-
/ のてっぺんで ls をするとたくさんモノが出てきましたが,そこに cd で移動するのは危険ですか?
- 探検してみるのは勉強になります。cdとlsをするぶんにはコンピュータに害を与えることはないです。
-
よく耳にするLinuxとは何のことなのでしょうか
- OSの種類だと思ってください。上でも書いたように、計算機科学ではLinuxをよく使います
-
passを探検していたらflutterのファイルなどもあったのですが、cloud shellで実行できるのですか
- 出来るんだろうと思います(未確認)
-
cd..と打ってもcommand not found となってしまうのですが、どうすればいいですか
- cd の後にスペースを入れてもう一回試してみてください。
-
ホーム位置はどの様に決まっていますか
- Linuxだと
/home/YOUR_NAME
です。Macだと/Users/YOUR_NAME
です
- Linuxだと
-
ホーム位置が複数存在する場合はあるのでしょうか?
- 一人のユーザについては、無いと思います。
-
プログラムと数学は密接な気がしますが,入試数学20点台ですが生き残れますか!!?
- 大丈夫です
-
macの場合どのボタンを押せばtab補完できますか
- Controlの上にある ->| こんなマークのボタンだと思います。
-
ロードに凄い時間がかかってしまい、main.cの作り方を教えて頂けないでしょうか
- 左側のファイルエクスプローラを左クリックして"New File"を押してください。ファイル名を指定する画面が出てくるので、main.cと打ち込んでみてください。
-
本筋には関係ないですが、EEIC生のプログラミング経験率ってどのぐらいなのでしょうか
- どうなんでしょうね?例年、ほとんどしたことが無いという人はたくさんいます。
-
エディター部分とターミナル部分を切り替えるキーボードショートカットはありますか?
- わからないです。。。誰かわかったら教えてください。
-
google cloud shell には、ターミナルが二つあるみたいなお話があったかと思いますが、違いは何でしょうか?
- よくわかんないのです。気にしなくて大丈夫です
Week2¶
-
値渡しをせずに関数で値を変更させたいのですがそういったことは可能ですか?
- グローバル変数を使えば可能です。ただ、C言語の思想としては、関数の呼び出し元の値を変更する際は、単純な戻り値あるいはポインタを使うということが基本になります。ポインタについてはweek4で勉強します。
-
return 0の正常に終了したら0を返すというのはどこに返されているのですか?
- ./a.outを実行したときにターミナルに返されていると思ってください
-
関数は引数の種類で区別されますか?同じ名前で引数の種類の異なる関数を複数定義できますか?
- 同じ名前の関数を定義すると引数型が違ってもエラーになります。
-
関数の戻り値に配列を指定する事はできますか?
- 配列を直接返すことはできません。配列を返したいならポインタを返すことになります。
-
先ほどの解説でi = 4になったのはなぜですか?
- 非常に重要なので改めて見てましょうか。week2のfor文の定義の解説部分をじっくり眺めながら、以下を見てください。
上記を実行すると次のようになります。
int i = 100; printf("before loop: i = %d\n", i); for (i = 0; i < 4; ++i) { printf("i = %d\n", i); } printf("after loop: i = %d\n", i);
ここでループの最後のbefore loop: i = 100 i = 0 i = 1 i = 2 i = 3 after loop: i = 4
i = 3
を表示したあとにどうなる確認しましょう。 - ループが終わったので、ループ更新である「式3」にあたる部分、すなわち
++i
を実行します。これによりi
は4になります。 - その後、ループを続ける条件である「式2」にあたる部分、すなわち
i < 4
を確認します。これは偽になります。 - なので、終了してループを抜けます。ループの外側では、
i
は4になります。
- 非常に重要なので改めて見てましょうか。week2のfor文の定義の解説部分をじっくり眺めながら、以下を見てください。
-
課題の出来は成績評価にどの程度影響しますか?
- 毎週の宿題ですね?毎週の宿題+最終課題で評価しますが、提出して最低限のことができていればそれ以上はあまり差をつけない予定です(全員が基礎が出来るようになるというのが目標なので)
-
外で宣言した変数の値を、while文やfor文の中で変えたとき、ループが終わりwhile文やfor文の外に出たあと、その変数の値は外で宣言した値に戻りますか?
- いいえ。戻りません。変更されたままです。是非試してみてください。ここは非常に重要な点です
-
プログラミング初心者の電電内定者でも,ソフ2は理解可能ですか? 重要であることはわかってますが,オーバーにならないか心配です。
- 個人的にはとることをオススメします。mallocといった重要な概念はソフ2でしっかりやります。ですが、もしソフ1終了時点で既にいっぱいいっぱいでもうヤバいと思う場合は無しでいいと思います。
-
先週の内容なのですが、アドレスが14桁なのはなぜですか?64bit だと16桁になるように思うのですが
- 64bitですが、12桁分しか使わないというだけです。先頭の0xは16進数であることを示す記号です。
-
C言語に三項演算子みたいなものってありますか?
- あります。ソフ1の後ろのほうかソフ2かで紹介すると思います
-
ソフ1の前にプログラミング基礎演習がある
- 曜日の関係で演習のほうが前になってしまうことが多いんですよね。。。。
-
switch で 一致する case も default もない場合にはどこにジャンプしますか?
- 何も実行しません。
-
字下げ幅2派閥以外を認めたほうがいいのでしょうか?
- 初期設定だと4個の場合が多いと思います。emacsだと初期で2個かもしれないです。どっちでもいいですが、4か2が多いかと思います。とにかく「字下げしない」というのはやめましょう
-
terminalで code . としても、command not found になるのですが、改善策はありますか?
- この辺りが参考になりそうです。ただし、ECCSの場合は管理者パスワードが求められるため、できないと思います。
-
xcode 開けないんですけど、どうにかなりませんか?
- xcodeはサポートしないので、ちょっとわからないです
-
linker command failed with exit code 1 というエラーが出たのですが、どういう内容のエラーですか?
- 一番頭に #include が正しく打てているかどうかや、ファイルの保存が出来ているかどうかを確認してください
-
Cにおいてよく使われる変数の命名法は何でしょうか?(例えばhogeHogeなのかhogehogeなのかHogeHogeなのか)
- これはコーディング規則に関する話で、色々な流儀があります。これとかを読んでみると面白いです。どのような流儀でもいいですが、一つのソースコード中では同じ流儀で統一することをおすすめします。
-
vscodeでCを書く時に、Google cloud editorを使用しているときのように、自動でインデントなどを行ってくれるようにできますか?
- 「Editor: Auto Indent」の設定が怪しいような気がします... 「設定」を開き「設定の検索」から「Editor: Auto Indent」を検索し,「full」になってるか確認してみてください...
-
Vs codeでコンパイルできません。原因はなんでしょうか
- セーブしていない、というのが主な原因だと思います。わからなければ手をあげてみてください
-
&& は左側が偽だった場合短絡評価されますか?
- されます。左側が偽だった場合、右側は評価されません。
-
|| についてですが、左辺が偽だった時に右辺の関数を実行するみたいな使い方ができたりしますか?
- たしかにできます。少し読みにくいと思いますが...
-
JSDockのようなコメントの記法はC言語にもありますか?
- 他の言語ではコメントにおける記法方式がプログラミングそのものと関係するようなものもありますが、C言語ではそういうものはありません。その上で、コメントで変数内容を説明させてドキュメントに反映させるためにはDoxygenなどが使われます。
-
VSCodeの言語を日本語にするのも拡張機能のインストールが必要ですか?
- Japanese Language Pack for VS Codeという拡張機能を入れると日本語になります
Week3¶
-
宿題の「ライブラリは何もincludeせずに」というのは、
も含まれますか? - ファイルを見ればわかりますがstdio.hとstdlib.hはincludeしても大丈夫です
-
リダイレクト用のファイルの作り方がわからないのですが・・
- 「./a.out > hoge.txt」と実行したときに、hoge.txtが存在しなければ、hoge.txtが作られて、その中に./a.outの出力が書き込まれます。hoge.txtが存在していたら、hoge.txtの中身は全て消えた上で、./a.outの内容が書き込まれます。
-
リダイレクトするファイルの最後で改行しなくても最後の行がputcharに入力されるのはなぜでしょうか?
- ファイルの最後に自動的にEOFがつく(end-of-file、すなわちファイルの最後を意味する)から、で答えになると思います(もしそれでも挙動が変だと思ったら、もう少し詳しく教えてください)
-
getcharで入力を受け取るとき、キーボードでNULL文字'\0'を打ち込むことは可能ですか?
- 今ばっと調べたところ、出来ない、、、と思います(出来るやり方知ってる人がいたら教えてください)
-
バッファに何か溜まっている状態でCtrl Dを押したらその後Enterを押した時に、このプログラムが終了しそうに思うのですが、しないのはなぜですか?
- バッファが溜まっている状態でctrl+dをすると、コラムで書いた通り、EOFは発生せずに、単にバッファの内容をドドドッと流し込むだけになります。その後エンターを押すと、「改行のみ」が入力されます。なので、EOFはどこにも存在しません。よって、プログラム中でEOFが出れば終了というふうになっている場合、プログラムは終了しません
-
Putcharとprinted はどう違うのでしょうか?putcharはprintfの一文字かつ文字のみを出すものということですか?
- 先ほど言った通りprintの関数はめちゃくちゃたくさんあって、printfは高機能版という感じです。
-
以下をコンパイルするとwarningが出る理由を教えて下さい。
#include <stdio.h> int main() { char s[5] = "hello"; s[3] = "a"; printf("%c\n", s[3]); }
- なぜでしょうか?今日まさにやったことになってます。warningをよく読んでみてください。-Wallオプションをつけると詳細に教えてくれるかもしれません
-
int cの部分について、文字にもintを使うのですか?
- 文字は単なる整数なので、実は文字一つをintで表現しても何も問題ないです(intの配列が文字列というわけではありませんが)
-
関数の引数に配列を渡すと、その先頭アドレスのみが渡されるとのことでしたが、sizeof()に配列を入れることでその中身のビット数が表示されることが特殊な例なのでしょうか?
- 関数の引数に配列を渡すと云々と言う話があったのに、sizeofという関数だけは、その引数に配列をいれるときに挙動が特殊じゃないのか、という意味でしょうか。であれば、実はsizeofは普通の関数ではない、というのが答えになります。sizeof演算子とか呼ばれます
-
パイプ機能がどういうふうに役立つのか全く想像できないのですが、どういう場面で輝くのでしょうか
- たくさんのことが出来ます。例えば
ls -al
でファイル情報一覧を表示して、そこからgrep
コマンドで必要な行だけ抜き取る、とかが出来ます
- たくさんのことが出来ます。例えば
-
文字列の場合は、それを関数に渡しても先頭のアドレスとして認識されることはないのでしょうか?
- 先頭のアドレスとして認識されます
-
count_space関数のところで、s[i] != '\0'の条件式をs[i] != 0と、リテラルの0を用いて書き換えることは可能ですか?
- 可能です
-
授業サイトのstrcmpの紹介例で-100が出力されるのはなぜですか?
- 参照実装としては以下のような感じになっています(あくまで参考です)
King, p306
int mystrcmp(char s[], char t[]) { int i; for(i= 0; s[i] == t[i]; i++) { if (s[i] == '\0') { return 0; } } return s[i] - t[i]; }
- 参照実装としては以下のような感じになっています(あくまで参考です)
-
以下のようにしたときに情報の損失がないのはなぜですか?
unsigned int a = (int)(-4); int a2 = (unsigned int)(a); printf("a : %u\n", a); // 4294967292 printf("a2 : %d\n", a2); // -4
- intもunsigned intも32bitなので、無理やり値をいれてもビット系列として情報が落ちることはないというだけです。
- まず、キャスト部分は無くても同じなので、上記は以下と同じです
unsigned int a = -4; int a2 = a;
- 最初の代入のとき、intでいう-4(2進数でいうと
11111111|11111111|11111111|11111100
)がunsigned intに無理やりいれられるので、aは424967292になります(これはusigned intにおいて2進数でいう11111111|11111111|11111111|11111100
)。次の代入では、そのaが無理やりintであるa2にいれられます。これはa2が2進数でいう11111111|11111111|11111111|11111100
になることを意味します。それはintでは-4です。
-
「キャストは単項の演算子」というのは、どういうことでしょうか?
- 「+」は二項の演算子(対象が2つ必要)です。単項の演算子というのは対象が1つだけのもので、演算子の直後のものにのみ作用します !a で否定、とかです。(今改めて質問をうけて思ったのですが、キャストが式全体に作用しないというのは単項だからというよりも、四則演算よりも演算の優先度が高いから、というのが直接的な理由でした)
-
「入出力」の「文字の読み書き」の項についての質問です。日本語を表示させるとき、1文字につきYou entered 置換文字(黒い菱形に「?」と書かれた文字)が3行表示されました。ひらがなは2バイトのはずなので2行表示されるのかなと思ったのですが、なぜ3行なのでしょうか?また、単に日本語を複写させたときに文字化けせずに(置換文字が表示されるのではなく、)入力のままに表示されるのは、どのような内部処理によるものなのでしょうか?
- Unicodeで考えるとひらがなは3バイトですね
-
math.h を include するときにはコンパイル時に -lm をつけると習ったのですが、 string.h を include するときには何もつけなくていいのはなぜですか?
#include <hoge>
というのは、hogeというファイルをそこに展開しろというだけの意味です。なので、-lmをつけるかどうかは、インクルードするものによります。stringの場合は無しで大丈夫です
-
引数が(char s[])の関数のプロトタイプ宣言をする際には、引数の型は(char)でいいのですか? (charは同じ型名で文字と文字列の両方を表しているのがよく分かりません)
char *
(char型のポインタ)またはchar []
で大丈夫です。「文字」を指すのがcharで、「文字列」を指すのはcharの配列です。なので、charが文字も文字列も指すわけではないです。
-
なぜ0ではなく\0とするんでしょうか?何か理由があれば教えていただきたいです。
- 実際のところは歴史的経緯によると思うのでわかりませんが、文字の世界と、その文字にどのような数字が割り振られるかとは、別の話になります。なので、終端を表すなんらかのシンボルを準備すること自体は自然です。なので、「\END」みたいな特殊なシンボルを割り当て、そしてその実態は999という数、とかでも成り立つとは思います。それに対し (1) なぜ\0という「ゼロ」という記号を使ったのか、そして(2) 対応する数字がなぜゼロなのか、というのは、歴史的経緯や実装の要請によってだと思います。
Week4¶
-
(*s1 = *s2) != 0
のところの0は'\0'
じゃなくていいのでしょうか、、?'\0'
(NULL文字)は0
と等価なので、これでも動作します。
-
{char* pmsg1 = "abc";}{char* pmsg2="def";} {pmsg1 = pmsg2;}
のように上書きした時に、abcにアクセスする術がなくなってしまうように思うのですが、この時点で"abc"に割り当てられたメモリは解放されますか?- ここではメモリはコンパイルがよしなに扱います。ユーザはコントロールできません。すぐに開放されるかどうかはわからないです。
-
const char *s2 のconstはs2に入っているポインタを定数とするのではなく、s2に入ってるポインタ先の配列を固定するものという認識でよろしいでしょうか
- そうです。ポインタ自身を固定するときはchar * const sとなります。まとめると以下になります。これは重要なのでweek4の本文中にも追記しておきました。
void f1(const int *p) { // !!!! ダメ !!!! *p = 3; // ポイント先の値の変更 *(p + 2) = 5; // ポインタ経由での配列要素の変更 // OK int a; p = &a; // ポインタそのものの変更 } void f2(int * const p) { // OK *p = 3; // ポイント先の値の変更 *(p + 2) = 5; // ポインタ経由での配列要素の変更 // !!!! ダメ !!!! int a; p = &a; // ポインタそのものの変更 } void f3(const int * const p) { // !!!! ダメ !!!! *p = 3; // ポイント先の値の変更 *(p + 2) = 5; // ポインタ経由での配列要素の変更 // !!!! ダメ !!!! int a; p = &a; // ポインタそのものの変更 }
- そうです。ポインタ自身を固定するときはchar * const sとなります。まとめると以下になります。これは重要なのでweek4の本文中にも追記しておきました。
-
for文のはじめを;と書いて良いのは、単に配列名を書くだけでその初めの要素を指すことになるから、という理解で大丈夫でしょうか?
- for(A; B; C)のときにA, B, Cには何を書いてもいいし、書かなくてもいいです。これは配列とかとは関係ないです。今回の例題では初期化操作が必要ない(関数目線からいうと、やってきたsというポインタの位置からスタートして、NULL文字までの距離を返すだけ)というだけです。ちなみに、s[] = "abcde" としたときにstrlen(s+2)とかいうように文字列の途中から後ろ側ぶんの長さを見ることもできます
-
これまで、for文の時に、++iと書いていたことが多かったと思いますが、ポインタになってから、++pでなく、p++という表記が増えたのは、なぜでしょうか?
- これは特に意味はないです。今日のポインタ周りの関数の例題は、表記してある通りKingの教科書からの引用があり、Kingさんはp++スタイルを使っていたというだけです
-
forの中身の最初が;となっているのは、どのような挙動のためかもう一度お聞きしたいです
- これは単にfor (i = 0; i < N; ++i) みたいに書くときに、最初のi = 0のような初期化動作を何もせずに、for ( ; i < N; ++i) のようにしているというだけです。つまり最初に何もしないというだけです
-
char *p = s; の s(配列) は int の時と違って &s[0] とはならないのですか (edited)
- &s[0]はsと等価なのでどっちで書いても問題ないかと思います。
-
for (; *s != '\0'; ++s)
という操作は、sの要素として0が入っていると(例えば"a0c"
の場合)ストップしてしまうのでしょうか?- ここは重要なので是非理解しておいてください。
- sの要素として0が入っているとストップします。しかし、
"a0c"
では真ん中のゼロでストップしません。なぜなら、"a0c"
は{'a', '0', 'c', '\0'}
であり、それはすなわち{97, 48, 99, 0}
だからです。なので、ストップするのは一番後ろのNULL文字になります
-
配列に要素として0が入っていたらNULLとは判定されないのでしょうか?
- char配列に0が入っていたら、それはNULL文字として扱われます。
*p == 0
であり、*p == '\0'
でもあります。上の質問解答を参照してください。あるいは、「ポインタにアドレスを設定していないNULL代入と勘違いされないか?」ということが質問の意図だとすれば、それはp == 0
であり、p == NULL
ですね。なのでNULL文字をpで指すことと、pの中身がNULLであることは、違います。
- char配列に0が入っていたら、それはNULL文字として扱われます。
-
クイズのmy_strcpy3のwhile文の条件の処理順序がよくわかりません。代入の後にインクリメントが行われるという認識で良いですか?これは、全てのコンパイラで共通の挙動を示すのでしょうか。
- これは完全にOKな式になっていて、全てのコンパイラで共通の挙動を示します。演算子の優先順位に従って処理されているだけです。
-
C言語で、関数に配列を渡す場合、その長さも同時に与えるしかないのでしょうか?ポインタからでは、配列の長さは知りようがないですよね?
- 基本的に、長さも同時に与えるしかないです。仰る通り、ポインタからは配列の長さはわからないです。ただ、いまからやりますが、例えば文字列だと終端がNULL文字であるというルールが決まっているので、その情報を用いることで明示的に長さを渡さなくても処理できます。
-
セグフォはなぜそんなに危険なのですか?
- 色々と危険ですが、例えば配列の外にアクセスするようなプログラムを書いていて、たまたま今日はうまくいったものが、別のPCで実行するとセグフォになって落ちたりします。そうすると、プログラムのどこにバグがあるのかわからなくなってつらくなったりします(みなさんの例でいうと、手元では宿題がうまく動くのに、自動採点ではセグフォになったりすると、つらいです)
-
逆に引数のコピーではなく、そのものを受け渡すような言語はあるのでしょうか?
- 「参照渡し」という操作になります。pythonやc++を含め多くの言語に存在します
-
宿題にある、「便利な関数」は使わないという制限は「授業で扱った関数」の範囲でおさめるべき、といった意味でしょうか。 例えば continueはどうでしょうか。
- 例えば数学関数とかをインクルードして使わないでほしいという意味でした。continueというのは何を指していっていますか?for文の中でcontinueを使うというのはもちろんOKです
-
(long)xは、longのキャストをしているのでしょうか?その場合、小数点以下が切り捨てられる?
- そうですね。week2とかでやったように、小数を整数に無理やり変換したり代入しようとすると、小数点以下が切り捨てられます。ここでは明示的に右側でキャストしてその時点で小数以下を消していますが、ここはキャストがなくても、代入時に小数点以下が切り捨てられます(厳密にはその場合は意図していない処理なんじゃないの?と警告が出ると思います)
-
ポインタを初期化する前に値を参照するコードを実行したら、 Segmentation fault と表示されたのですが、これはどういう状況なのでしょうか?
- いわゆるセグフォというやつで、ポインタ操作で変なことをしてしまった場合に発動します。これが出てくるときは、間違ったポインタ操作をしてしまっています。
-
ポインタで指すのも先頭アドレスですか?
- 配列を考えた時はそうです。
-
ポインタ自体が変数に格納できるならポインタのポインタも変数に入れられるということですか?
- はい。ポインタのポインタというやつです。来週やります。
-
ポインタ変数はメモリアドレスを格納することから、ポイントする先の変数型関わらず長さは一定だと思いますが、ポインタ変数を宣言するときに変数で分けるのはなぜでしょうか?
- 結局同じサイズなのに、intのポインタは
int*
として、charのポインタはchar*
と宣言するのはなぜか? という質問と理解して回答します。 一つの理由として、「ポインタに対し、整数の加算と減算」をする際に便利、というものがあると思います(ポインタに対する操作の節で紹介されます)。intのポインタに+1すると4バイト後ろのアドレスを指すようになるのに対し、charのポインタに+1すると1バイト後ろのアドレスを指すようになります。 - また、単純に、バナナ機能を使うときは元の変数の型を明示しておく必要があります
- 結局同じサイズなのに、intのポインタは
Week5¶
-
最終課題に関して、友人がいないと不利になりますか?
- なりません
-
メイン関数の記法についてですが、int main(int argc, char *argv)のかっこの中身のint argcを省略するとsegmentation faultになるのはなぜですか?
- これは単純にmain関数というものが最初にint, 次にcharポインタ配列、を引数にとると決まっているからです。c言語は引数の種類や順番について厳密です(例えばpythonとかだともっと緩く書ける場合があります)
-
「ポインタの配列」で各要素にアドレスを代入しているのに、その要素をプリントするとアドレスが表示されるのではなく、そのアドレスの中身の文字列が表示されるのはなぜですか?
- これは逆で、「もともと
%s
で表示してたものは、アドレス。すなわち、char配列の変数名そのもの(=char配列の先頭アドレス)あるいは文字列リテラル(=どこかに確保されたchar配列の先頭アドレス)」というだけです。以下をみてください。ここからわかるように、もともとchar *arr[3]; char s1[] = "hoge"; char s2[] = "fuga"; char s3[] = "piyo"; arr[0] = s1; arr[1] = s2; arr[2] = s3; printf("%s\n", arr[0]); // hoge printf("%s\n", s1); // hoge printf("%p\n", arr[0]); // 0x7ff... printf("%p\n", s1); // 0x7ff...
printf("%s\n", s1)
のように書いていたものは、%s
にアドレスを与えています。なので、printf("%s\n", arr[0])
と書いても、同じようにアドレスを与えています。なので文字列が表示されます。これらは%p
で表示するとどちらもアドレスであることがわかります。
- これは逆で、「もともと
-
hogehoge.hみたいなファイルって自作できるんですか??
- できます。普通に作るだけです。
-
C言語はどのように文字列リテラルのメモリ上の配置場所を決めているのでしょうか?
- C言語的にはルールが決まっておらず、gccが決めているような気がします。いずれにせよ、ユーザは関与できません
-
find_largest1ではなくて、find_largest2を使う性能上のメリットはありますか?
- もしこれがint配列ではなく巨大な構造体(week6で習います)の配列で、コピーを発生させたくない場合は、find_largest2のほうにポインタを変更するほうが速い場面があるかもしれないです。
Week6¶
-
タッチタイピングのいい練習法ありますか?特に記号類と数字キーが苦手です
- TAさんによるオススメ:ホームポジションが身についていなければ人差し指をFとJキーに置くのを常に意識するのもいいと思います。
-
math.hに整数入れたらバグが起きることはありますか?
- math.hの何らかの関数に、と言う意味ですか?関数によります(charなどを引数に取る関数にintをいれたらもちろんおかしいことになります)
-
再現性があるのに、乱数と言えるのでしょうか?
- seedを同じにすると再現性があること自体は、望まれる特性です。
-
0でなければ何でも真になるのはビット演算のためですか?
- ビット演算のためというわけではないような気がしますが、わかりません
-
void print_bit_uchar(unsigned char c) でのcは2進数で扱われるのですか?このコラムの挙動かよくわかりませんでした
- 全ての変数はただのbit列なので、2進数かどうかなどはないです(しいていえば全て0/1なので、全て2進数です) bit演算というのはある変数を2進数と言う風に特別に扱うとかではなくて、ただ単に普通のintとかの変数に、何らかの処理をしているというだけです
-
int ramen_flagでは32ビット使うのですか?
- intなので、ramen_flagを作成した時点で32bit使うのは確定です
-
構造体とポイントのクイズにおいて、ptinrectという関数がなぜうまく行くのかがわからなかったので、解説していただけませんでしょうか?
- どの部分が分からなかったのかが少し分からないので繰り返しになってしまうかもしれませんが... ここでは ptinrectの入力として与えられるRect rについて、「r.pt1は必ず左上(xもyも値が小さい)、r.pt2は必ず右下(xもyも値が大きい)」が成り立つものとしています。このとき「Point p が Rect r の中に含まれていること」は「p.x >= r.pt1.x && p.x < r.pt2.x && p.y >= r.pt1.y && p.y < r.pt2.y」と同じなのでこの関数はうまく行きます(今回、長方形の境界については右と下の辺は含まないものとしているようです)。
-
ビット数が異なるもの(たとえばcharとint)にビット演算を行うとどうなりますか?
- ビット演算そのものは一般的な演算子なので、二項演算で型が違う場合は、一般的な型変換に従うと思います。
-
変数のビットをシフトした時、その変数のとなりのメモリ領域に変数が隣接していた場合、隣接している変数の値は書き換わってしまいますか?
- 変わらないです(シフトは変数単位の操作です)
-
1の補数、2の補数の名前の意味がよくわかりません。なぜ「1の」「2の」という名前なんでしょう?どこに「1」や「2」が現れているのですか?
- なんでなんでしょうね。。。。松井もよくわかっていません。
-
実装依存とは何ですか?
- 例えば「C言語のルールとしては決まっていない。コンパイラによる実装依存だ」とした場合、gccやclangやインテルコンパイラやmsvcがそれをどう実装しているかに依存して結果がかわりうるということです(みなさんはこれまでgccしか使っていませんが、C言語を実現するコンパイラとして色々なものがあります)
-
自作コンパイラを作成するのにおすすめなサイトや書籍はありますか?
- 松井は全然わからないので、田浦先生のOSの講義などを是非ごらんください https://taura.github.io/operating-systems/
-
以下のように
とした時点ではy1とy2のポインタは同じなのに、y2.s = "world";とすると、異なるポインタを指すのはどうしてですか?StrByPtr y1 = { .s = s }; StrByPtr y2 = y1;
- これはy2.sが別のものである"world"の先頭アドレスを指すようになった、というだけです。
のあとに
char *s1 = "hoge"; char *s2 = s1;
しただけですs2 = "fuga"
- これはy2.sが別のものである"world"の先頭アドレスを指すようになった、というだけです。
-
struct pointをmain関数の中で定義しないのはなぜですか?
- 定義することは可能みたいです。どちらかということ構造体というのはプログラム全体を通して使う基礎的なものを定義するという感じなので、main関数という「実際に使う部分」ではなく、その外側で準備されることが多いと思います。main内でしか使わない小さなものならmain内で定義しても大丈夫かもしれないです(ただその場合他の関数の引数にできないとかがあると思います)
-
ディープコピーとシャローコピーの違いをもう一度説明いただけると助かります
- aとbがあって、
b = a
としたあとに、aを変更したときにbも変更されるのがシャローコピーです。シャローというだけあって完全にコピーされておらず、ポインタで同じものを指しているイメージです。C言語でいうと関数に配列を渡すときはシャローです(実際はポインタを渡しているので) - 一方、
b = a
したあとにaを変更したときにbは変更されないのがディープコピーです。ディープというとおり、全ての内容を完全にコピーしているので、aとbは関係がなくなります。cの構造体の代入はそれです。 - 注意として、「ポインタのディープコピー」がシャローコピーそのものなので、それは注意が必要です。つまり、構造体のコピーはディープコピーですが、ポインタが含まれていればそこはシャローになります。今回のStrByPtrはシャローな挙動になっています
- aとbがあって、
-
最終課題は授業内でペアプロやった人とやるのですか?それとも授業一回きりですか?
- ペアプロと最終課題は全然関係ないです
-
今まで提出した課題は手元に持っておかないと削除されるんですか?
- 削除されないですが、ずっと残しておきたい場合は手元にバックアップをとっておくことをオススメします。
Week7¶
-
'a'のような文字にはcharを使ってきましたが、charは単なる小さな整数なので、intで表現しても問題ありません。とありましたが、文字列の配列を作る場合にはint[]ではなくchar[]でないとダメなのでしょうか?
- 文字の定義は「小さな整数」なので、intに入れても表現できます。文字列の定義は「char配列で最後にNULL文字」なので、int配列はダメです。この2つは全然別のことです。
-
松井先生の研究室で,フォントファイルそのもの,または機械学習などと絡めて周辺技術を扱う研究はありますか?
-
create pull requestをターミナル上からすることはできますか?
- pull requestはgitの機能ではなくgithubのものなので、gitコマンドでは出来ないのですが、さっきからちょくちょく言っているghというコマンド(GitHub CLI)を使うとできます https://zenn.dev/fusic/articles/336c5192d2f162
-
トークンを作成したのですが、トークンやユーザーネームをターミナルに入力することなくgithubとvscodeが連携されたのですが、大丈夫でしょうか?
- あんまり気にしなくて気合で大丈夫な気がします。将来的にはsshという方式を使うほうがいいです
-
コミットとプッシュの2つの作業が必要なのはなぜですか?一発でできてもいいように思うのですが
- commitは手元の更新をまとめるもので、pushはそれをGitHub等に送信するものなので、この両者に概念的な違いはあります。一方、addとcommitは確かに本当に二段階必要なのか、だんだん気になってくる気持ちはわかります。いずれにせよ、GUIのクライアントによっては、syncといったボタンで1クリックで全てまとめてやってくれるものもあるかと思います。
-
ソフ2は予習した方がいいですか?
- ソフ1に比べると難しいと思いますので、予習してもいいかもしれないですね。齋藤先生もソフ1と同じくHPを公開する形にしているので、既に見れるかもしれません。あるいは去年のものは確実に見えます
-
GitHubの機能を学ぶのにおすすめの本やサイトはありますか?
- 講義のGitのページの最初のほうのリンクを見てみてください。
-
githubの機能がなかった時代は、hpを作るのはどのような点が難しかったのですか?
- HPを手動で構築するには、(1) 恒久的に動くマシンを準備する、(2) ドメインを取得する、(3) マシン上でウェブサーバのプログラムを起動させ続ける、という、物理的な作業・契約が必要な作業・メンテナンスが必要な作業が必要でした。これらを委託するには、「HP開設サービス」みたいなものを契約する必要がありました。また、必ずどこかでお金がかかるというのが普通でした。GitHub Actionはこれらの全てのステップをすっ飛ばしてくれるので、便利です。
-
メモや論文などのテキストを編集するために,ぎっとを使うのは,どんな良い点がありますか。
- 「ソースコード編集に対してテキスト編集はどういうメリットが?」という意味ですかね。ソースコードの場合と同じように、更新履歴確認とかバックアップはメリットになります。gitがないと、論文を書く際に、「ここはあとでまた必要になるかもしれないけど今は消しとこう」みたいな部分がコメントアウトだらけになります
-
gitって差分ですか?スナップショットですか?
- イメージとしては差分を管理するのですが、正確にはスナップショットを保存しているようです。詳しくはここを参照