Q&A¶
ここでは講義中に出た質問に対する回答を載せていきます。随時更新です。
Week1¶
-
10/10追記 来週以降、自分のPCを使ってもいいのか?
- 大丈夫です。具体的には以下です。
- 【場所について】week2以降は、情報教育棟で講義を行います。講義を受ける人は全員情報教育棟に来てください。情報教育棟に入ること自体は、ECCSアカウントを登録していなくても可能です。
- 【PCについて】
- 情報教育棟のマックを使う場合、ECCSアカウントが必要です。この手順に従ってECCSアカウントを登録しておいてください。机に据え置きしてあるマックを使うので、ノートPCを持ち込んだりする必要はありません。
- もし自分のノートPCを持ち込む場合、それでも大丈夫です。ECCSアカウントはいりません。目の前のマックは使わずに、自分のPCを用いて講義をうけます。
- 【プログラミング環境について】
- 据え置きマックを使うにしろ、自分のノートPCを使うにしろ、「ローカル環境」でも「ブラウザオンライン環境」でも大丈夫です。
- 講義で公式にサポートするのは「情報教育棟マックのローカル環境」および「ブラウザオンライン環境」のみです。
-
10/10追記 UTokyo VPNが使用禁止になってしまっているが、ECCSは使えるのか?
- UTokyo VPNが使用禁止でも、ECCSは使えるはずです。この手順に従ってください。
-
10/10追記 出席点はあるか?
- ありません。もしC言語を既に全部理解しているなら、講義に出なくても大丈夫です。宿題だけは全部やってください。宿題・最終レポートのみで成績をつけます。
-
他学部・他学科だが履修可能か?
- 履修出来ます。便覧やUTAS/ITC-LMSをよく読んで取得単位等について確認してください。
-
We can't load the code editor here because third-party cookies are disabled.
と出るのですがどうすればよろしいでしょうか?- プライベートモードで試すか、別のブラウザでやってみてください
-
画面上部のターミナルを開く部分がないのですがどうしたらよいでしょうか?
- メニューバーの「ターミナル」をクリックして出てくる白いターミナルでもOKです。Google Cloud Shell Editorには白いものと黒いものの二種類のターミナルがあるようですが、どちらでも大丈夫です。
-
cloud shell を立ち上げてNew file を作ろうとすると勝手にファイル名が
Untitled_0
にされて名前がmain.cに設定できないのですがどうすれば名前を変えられますか?- ファイルを右クリックで名前を変えられると思います(Rename)
- メニューバーのFile->Saveを選ぶと名前をつけて保存することができます
-
新しいファイルを作る際に名前を求められるようにするにはどうすればよいですか?
- 右クリックしてNew Fileすれば良いです
-
ClousShellのコマンドラインに文字を入力できないのですが….どうすれば良いでしょうか?
- ブラウザを変えてみてもらえますか?
-
ホーム位置というのはターミナルを開いた時点でいる位置を意味するのですか
- 正確には
$HOME
という環境変数で指定されている位置です。これは$ echo $HOME
とすると確認できます。Ubuntu系では/home/ユーザ名
になってると思います。
- 正確には
-
ターミナル上でファイルを開くにはどうすればいいんですか?
cat
コマンドで確認できます。編集するには、nano
やvim
やemacs
といったエディタを使います。
-
nano はどのようにして終わらせますか?
Ctrl + X
,Yes
, Enter, で「保存して終了」になります。(nanoは立ち上げると下にいくつかコマンドが表示されるのでそれ見ると良いです)
-
二回層上を表す../../の具体例を教えていただきたいです。
- たとえば
とすると一番最初の位置に戻ります。
$ mkdir ishikawa $ cd ishikawa $ mkdir kanazawa $ cd kanazawa $ cd ../../
- たとえば
-
「^」はCtrlの略と捉えていいのでしょうか
- いいと思います。参考。
-
ls
してもmain.c
が出てこないんですが原因はなんでしょうか?cat
ができません、、- ファイルが存在しないかもしないだけかもしれないので、その場合は右クリックして作ってください
- Google Cloud Shell Editor上で適切なディレクトリを開いていないだけかもしれません。その場合、自分の名前のディレクトリを開いているか確認してみてください。
-
rm
の注意について質問ですrm /
とかを実行したら危ないということですよね(真似する人がいるといけないのでダイレクトメッセージで質問しました)- 最近のOSでは警告がでると思います。でも危ないのでやめましょう。
-
mv fuga.c sample_directory/fuga.c
の代わりにmv fuga.c sample_directory
と書いても同じ操作がされると思うのですが、何か細かい違いはありますか?- 基本は同じだと思いますが、コーナーケースは色々あると思います。例えば、
samle_directory
がディレクトリではなくうっかりファイルであった場合は、挙動が違います。一方、$ touch fuga.c sample_directory $ mv fuga.c sample_directory/fuga.c mv: failed to access 'sample_directory/fuga.c': Not a directory <- エラーになる
$ touch fuga.c sample_directory $ mv fuga.c sample_directory $ ls sample_directory <- エラーにならない。sample_directoryがfugaで上書きされる
- 基本は同じだと思いますが、コーナーケースは色々あると思います。例えば、
-
ターミナルとエディタ間の移動のショートカットはありますか?
- 調べたのですがわかりませんでした。知っている人がいたら共有してもらえると助かります。
-
現在ターミナルでenterを押すたびに改行されて>が続くだけの状態に陥ってしまったのですがどうやって通常に戻ればいいでしょうか
- どのような状態になっているかで対処が異なりますが、以下を試してみてください。
- 終了させる方法1: 「exit」と打ってエンターで消える場合もあります。
- 終了させる方法2: コントロールキーを押しながらCを押すと終わる場合が多いです。(強制終了コマンド)
- 終了させる方法2: 「q」を押すと抜けられる時もあります(quitのq)
- ターミナルを終了する方法:ターミナルの上側のプラス記号を押して、新しいタブを開きます。古いタブはバツをクリックして消します。これで綺麗になります。
-
バックスラッシュを文字から変換せずに打つ方法はありますか?
- マックの場合は設定が必要なようです。システム環境設定→キーボード→入力ソース→"¥"キーで入力する文字)で円記号をバックスラッシュに変更するとよいと思います。
- 参考
-
実行時「./」をコマンドの先頭に付記する必要があるのはなぜですか?そうしないとターミナルがa.outを実行すべきファイルと認識してくれないからですか?(そうだとしても「カレントディレクトリ」を意味する“.”と「一番上のディレクトリ」を意味する“/”の組み合わせがどうして「次に示すファイルを実行せよ」という意味になるのか、ちょっと疑問です)
- 授業では答えがあいまいだったので、詳細に追記しました。 まずターミナルでコマンドを実行する際のルールについて説明し、その後
a.out
ではなぜダメかを説明し、そして./a.out
ではなぜOKなのか説明します。ちなみにこの解説が詳しいです。 - ターミナルでコマンドを実行する際のルール
- ターミナルでコマンドを実行する際、何が起こっているのでしょうか。例えば
ls
と打つとファイル一覧が見れるわけですが、これはコンピュータのどこかにある「ls
プログラム」を実行しているからです。ではそれはどこにあるのでしょうか? - これは、
which ls
のようにwhichコマンドで確認できます。例えば私の環境ですと次のようになります。つまり、$ which ls /usr/bin/ls
ls
プログラムは/usr/bin/
にあります。 - それでは、なぜターミナルで
ls
と打つと/usr/bin/
の中のプログラムを実行してくれるのでしょうか?これは、「ターミナルでコマンドを実行しようとするときに、そのコマンドを探す場所一覧」が指定されているからです。これは$PATH
という環境変数の中に記載されています。これを見てみましょう。ここではコロン区切りでディレクトリの一覧が記載されています。一番最初に$ echo $PATH /home/matsui/usr/bin:/home/matsui/.vscode-server/bin/74b1f979648cc44d385a2286793c226e611... (以下、続く)... :/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/s ... (以下、続く)...
/home/matsui/usr/bin
とあります。また、途中には/usr/local/sbin
や/usr/bin
もあります。 - よって、
ls
のようなコマンドを実行しようとする場合、上記の$PATH
の中のディレクトリたちの中にls
プログラムを見つけることができたなら、それを実行します。
- ターミナルでコマンドを実行する際、何が起こっているのでしょうか。例えば
- なぜ
a.out
はダメか?- 上記のルールを元に考えると、
a.out
を実行しようとすると次のようになります。まず$PATH
で指定されるディレクトリたちの中にa.out
がないかどうか探します。 - ですが、実は現在のワーキングディレクトリは
$PATH
で指定されていません。 - なので、
a.out
プログラムを発見できず、実行することが出来ません。 - ちなみに、これはセキュリティ的に安全ではない処理ですが、
$PATH
に無理やり現在のディレクトリを追加すると実行できるようになります。たとえば上記をやったあとは、いったんターミナルを終了してください。そうると$ a.out <- a.outだけだと普通はエラー a.out: command not found $ export PATH="$PATH:./" <- 一次的に$PATHに現在位置である「./」を追加するコマンド $ echo $PATH <- 確認すると、最後に「./」が追加されている /home/matsui/usr/bin:/ ..... :/snap/bin:./ $ a.out <- 実行できる! Hello World!
$PATH
への追加も消えます。
- 上記のルールを元に考えると、
- なぜ
./a.out
はOKなのか?- 次に、それではなぜ
./a.out
ではOKなのかを説明します。 ./a.out
のように、「/
」を含んだコマンドは、自動的に「$PATH
は探さず、それ自身を実行する」というルールになっています- そのため、
./a.out
の場合は、$PATH
に関係なくそれ自身を実行します。 - ちなみに、
.
が現在位置を示すので、./
は現在位置の直下すなわち現在位置そのものを指し、./a.out
は現在位置に存在するa.out
を一意に特定できます。 - スラッシュ入りであれば別の状況でも大丈夫なので、例えば以下のように別の位置から実行することもできます。
$ ls a.out $ ./a.out Hello World! $ mkdir xxx $ cd xxx $ ../a.out Hello World! $ mkdir yyy $ cd yyy $ ../../a.out Hello World!
- 次に、それではなぜ
- 授業では答えがあいまいだったので、詳細に追記しました。 まずターミナルでコマンドを実行する際のルールについて説明し、その後
-
#include <stdio.h>
を書く意味はなんですか?試しになしで書いてみても同じ結果が得られました。- 授業での答えはあいまいだったので、詳細に追記しました まず、上記のincludeを書かない場合、コンパイラは次のような警告を出します。
すなわち、「prinfはちゃんと宣言されていないよ」と言ってきます。この点を掘り下げましょう。
main.c:4:5: warning: implicit declaration of function ‘printf’ [-Wimplicit-function-declaration] 4 | printf("hoge\n"); | ^~~~~~ main.c:4:5: warning: incompatible implicit declaration of built-in function ‘printf’
- cにおいては、
printf
の関数の本体はlibc.so
という共有ライブラリに記述されています。コンパイル時に、このファイルは自動的に読み込まれます(dynamic link)。この意味において、#include <stdion.h>
は「printfを使います」ということを述べているだけです。実体はincludeを書かなくても読み込まれています。なので、コンパイラは警告は出すものの、printfを使うことが出来ます。 こちらも参考 - これは、「偶然使えている」といった状態です。例えば上記の話はc++では適用されないので、上記をg++でコンパイルするとエラーになります。
$ g++ main.c <- g++はc++コンパイラです。多くのcプログラムはg++でもコンパイルできます。 main.c: In function ‘int main()’: main.c:4:5: error: ‘printf’ was not declared in this scope 4 | printf("hoge\n"); | ^~~~~~ main.c:1:1: note: ‘printf’ is defined in header ‘<cstdio>’; did you forget to ‘#include <cstdio>’? +++ |+#include <cstdio> 1 |
- よって、基本的に、「
#include <stdio.h>
をつけなくてもコンパイルが通るのは偶然のようなもの。基本的に必ずつける」としてください。
- 授業での答えはあいまいだったので、詳細に追記しました まず、上記のincludeを書かない場合、コンパイラは次のような警告を出します。
- mainの行にセミコロンがないのはなぜですか
- セミコロンが必要なのは「文」の直後です。
main
の行は本来はmain () { ... }
であるものを改行しているだけで、ここは「文」ではないからです。このあたりはweek2で解説します。
- セミコロンが必要なのは「文」の直後です。
-
カレントディレクトリ以下に、以下のような構造のディレクトリおよびファイルを作ってみましょう:./aaa/bbb.py, ./aaa/ccc.py, ./aaa/ddd/fff.pyのやり方がわからないです。前の質問になってすみません
- 以下のように1個ずつやっていってみましょう
すわなち、存在しないディレクトリ配下に直接ファイルを作ろうとせずに,先にディレクトリを作りましょう。
cd ~ mkdir aaa cd aaa touch bbb.py
- 以下のように1個ずつやっていってみましょう
-
以下のようなエラーが出てきてしまいます。
main.c:one:10: fatal error: stidio.h: No such file or directory 1 | #include "stidio.h" | ^~~~~~~~~~ compilation terminated.
stdio.h
ですね。タイポですまた、正確には<stdio.h>
ですね。ダブルクオーテーションではなくブラケットです。
-
プログラミング演習の方では
gcc -o 名前
としていたのですが、-oは後においても大丈夫ということですか?- 大丈夫です
-
Pythonがコンパイルいらないのは自動でやってくれるからですか?
- 講義中の答えはあいまいだったので、調べました 詳しく述べると、Pythonを実行する場合、そのコードはbytecodeという中間形態に即座にコンパイルされ、それがVirtual Machine上で実行されるそうです。詳しい解説
- このプロセスは即座に行われ、また、インタラクティブに実行できる(ソースコード全体ではなく、ある部分に関しても実行できる)ため、pythonはインタプリンタ言語(コンパイルがいらない言語)と呼ばれます。
- ですが、実際に
python hoge.py
などと実行した場合は、最初にhoge.py
の全体がパースされ全体がbytecodeに変換されます。なので、その意味では「一瞬で全てがコンパイルされる」というような理解で良いと思います。面白い記事。
-
CとC++にはどのような関係がありますか
- ショートアンサー:C++はCにたくさん機能がついたものです。
- ロングアンサー:CはC++のサブセットに近いです。なので、多くのCプログラムはC++としてコンパイル可能です(gccをg++に書き換えてもコンパイルできる)。ですが、最新のCの規格はそのすべてがC++に含まれているわけではありません。また、細かい点で違いもあります(例えば上のほうの質問であったように、ヘッダが無い場合c++ではコンパイルできませんがcではコンパイルできる)
-
int widthとかは整数なのでintをつける理由が分かるのですが、mainは文字列とか返しているので整数でなさそうなのにintをつけるのはなぜですか?
- 実は整数を返しています (本当は
return 0;
とかを最後につけます)
- 実は整数を返しています (本当は
-
実行しようとするとpermission denied と表示されるようになったのですが,何が問題になってるのでしょうか
- これはいろいろな理由が考えられます(実行するファイルは間違っていないか,サーバー上で何かしているときなら変なディレクトリにいないか,など色々検証してみると良いと思います)
-
widthの先頭アドレスははheightの直後のメモリということはわかったのですが、heightの先頭アドレスはどのようにして決まるのでしょうか?
- まず、「直後かどうか」はわかりません。また、先頭アドレスは、普通はコンパイラが決めます(人間が決めるものではありません)
-
アドレス同士を引くと1を返すのですが、直接アドレス同士を足し引きすることはできないんですか?
- アドレスの足し引きはOKです。これはポインタを勉強するときにやります。
-
アンケートからGitHubアカウント名を入力しようとするとそのウィンドウが固まってしまいます。
- これはちょっとわからないので、うまくいかなければ、松井までDMしてGitHubアカウント名をおしえてください
-
確認です。今回アカウントを新規作成するのですが、Githubのusernameは本名でなくても良いのですか?
- 本名じゃなくてもいいです。
-
今までずっとwindows使ってましたので、macの操作は全くわからない状態ですが。来週からは自分のパソコンを使っても大丈夫でしょうか?
- 情報教育棟に自分のwindowsのノートPCをもっていくのはOKです。また、情報教育棟にもwindowsがある?かもしれません。いずれにせよ、環境設定は自分で行ってください(google cloud shell editorを使うか、WSL2を使う)
Week2¶
-
よくわからないがvscodeの挙動がおかしい
- vscodeはデフォルトで「auto save」がオフです。すなわち、毎回ファイルを保存する必要があります。タブの部分で●がついている場合はまだそのファイルは上書き保存されていません。●を消してから実行してみてください。auto saveをオンにすることもできます。
- また、vscodeはファイルを作成しても左側のファイルウインドウ部分が更新されないことがあります。その場合は、左側の丸い矢印のアイコン (Refresh Explore)を押すと最新の内容に更新されます。
-
コードを写経してもコンパイルが通らない。
- 以下のような
int main
といった雛形部分は書く必要があります。#include <stdio.h> int main () { // ここに記載。 return 0; }
- 以下のような
-
宿題でmath.hなどのライブラリを使っても構いませんか?
- 指示がないときは使わないでください.使っていい時は指示します.
-
今更な質問なのですがプログラミング言語でよくv=0.4と書かず、v = 0.4のように半スペース入れる理由とはなんでしょうか?
- これは見やすさのためなのです。こういう風に「こう書いたほうが良いという規範」みたいなものが各言語でいろいろ作られていたりします。
- C言語に関しては、参考文献であげた「組込みソフトウェア開発向け コーディング作法ガイド」が詳しいです。
- とりあえずHPのコードのような感じで半角スペースや改行をいれていくといいです
-
先生がメモリに関しての話を強調されるのはなぜでしょうか。どういう面でメモリが重要になってくるのか知りたいです。
- コンピュータの動作を本当に細かく理解するためには、メモリ上で変数がどのように配置されているか知る必要があるからです。もしみなさんがメモリのことを知らずにpythonだけを使っている場合、メモリを考慮しないレベルでしかものごとを理解することができず、たとえば「なぜかすごく遅い」とかいうときに対処できないことになってしまいます。なので、本講義ではローレベルなメモリの面を強調しています。
-
エアコンの風が寒いので調節してくださると嬉しいです
- 調整できないみたいです。。。すいません。。
-
やってみようにある
if (flag != 0) { ... }
やif (!flag) { ... }
の表記中にある!はどのような意味があるのでしょうかflag != 0
の!
は関係演算子の!=
です。!flag
の!
は否定の論理演算子です。これらは違うものです。
-
以下のようにすると、
以下のように出力されます。int a=3; printf("a: %d, a++: %d, a: %d, ++a: %d\n", a, a++, a, ++a);
これはおかしいのではないでしょうか?a: 5, a++: 4, a: 5, ++a: 5
- 「関数の引数が評価される順番は未定義」というルールになっています。なので、
a
,a++
,a
,++a
がどのような順番で実行されるかは未定義です。よって、printfの結果がどのようになるかも未定義になります。 - 参考:
Order of evaluation of the operands of any C operator, including the order of evaluation of function arguments in a function-call expression, ... is unspecified (except where noted below)
Order of evaluation, cppreference.com また、上記リンクの「Undefined behavior」も参考- 実例はこちら
- 「関数の引数が評価される順番は未定義」というルールになっています。なので、
-
大学のマックのデータに家からアクセスするにはどうすればよいか?
- WebDAVというのが便利のようです(教えてくださった方、ありがとうございます!)
- 大学のデータを家のPCにもっていっても、家のPCで環境を整えていなければc言語を実行できないかもしれません。その場合、ローカル環境構築を参考にしてください。簡単なのは家のPCでGoogle Cloud Shell Editorを使うことです。
-
関数の引数は値渡しとありますが、つまり引数として渡した時点でメモリのどこかに同じ内容がコピーされると解釈しています。この解釈は正しいでしょうか?また、そうであれば、コピーされた先のメモリのアドレスはどのように知ることができるのでしょうか
- その通りです。呼び出し前と関数内の変数それぞれに
&
をつけるとアドレスを確認できます。このあたりはWeek5に詳細に解説します。
- その通りです。呼び出し前と関数内の変数それぞれに
-
implicit declaration of function 'sleep' is invalid in C99と出ました
#include <unistd.h>
を最初に書いてみてください。
-
宿題のgithubはいつごろ見れるようになりますか?
- 毎週、授業の最後に配ります
-
for文においてi++ではなくて++iとしているのにはなにか理由があるのでしょうか
- ここのコラムを参照してください。
-
「0が正常終了」の方にはすこし馴染みがあるので逆に「0が偽」の方で意外な気持ちになってしまった
-
返り値は0が正常なのに真偽は0が偽になるのちょっと矛盾感ありますね
- はい、このあたりは不思議な点なのです。一般に、プログラミング言語の中の真偽の判定では1などが「正」で、0などが「負」のことが多いと思います。
-
vscodeのターミナルで色付き文字になっているのはどうやっているのですか?
- 詳細に書きました
cd ~
したホーム位置で、以下のようなファイルを作るといいです。.bashrc
というファイル。中身は以下。alias ls='ls -G'
.bash_profile
というファイル。中身は以下。if [ -f ~/.bashrc ]; then . ~/.bashrc fi
- この説明は以下です。
- まず、マックの場合、
ls
ではなくls -G
とするとls
に色がつきます。これでおしまいです。 - ですが、毎回
ls -G
と打つのはめんどくさいです。ここで、ターミナルでalias ls='ls -G'
と打つと、「ls
と打った場合にそれを自動的にls -G
に変換してくれる」という状態になります。これは、エイリアスという機能で、コマンドを新しく定義することにより実現されています。一度このエイリアスを実行しておけば、そのターミナルではls
と打つだけで自動的にls -G
になってくれます。- ちなみに、エイリアスは便利な機能なのでいろいろと使えます。例えば以下のようにすると、
ramen
と打つとtabetai
と表示してくれます。alias ramen='echo tabeta'
ここでecho
というのはただ単に引数の内容を表示するというだけのコマンドです。
- ちなみに、エイリアスは便利な機能なのでいろいろと使えます。例えば以下のようにすると、
- さて、これで良いのですが、実はエイリアスはターミナルを閉じるとその効果が消えてしまいます。上記の
ls
で色がつくのを設定したあとターミナルを閉じてみましょう。そして再度起動すると、再びls
に色がつかなくなってしまいます。 - よって、「ターミナルを起動するたびに、毎回エイリアスコマンドを自動的に実行したい」ということになります。それを実現するのが上記のファイルです。
- ホーム位置以下には
.vscode
や.conda
のように「隠し設定ファイル」「隠し設定ディレクトリ」が実はたくさん存在しています。これらはcd ~
したあとls -al
とすることで確認できます。これらのファイルには、自分のための色々な設定が記述されています。 - ここで、
.bashrc
というファイルを作りましょう。この中にコマンドを書いておくと、それは「ターミナルを実行時に毎回起動するもの」ということになります。今回のlsに色を付ける話以外にも、自分のオリジナルコマンドなどをここに定義しておいたりできます。 - また、色々あって
.bashrc
ではなく.bash_profile
というファイルが起動時に呼ばれることもあります。その場合、.bash_profile
にも.bashrc
と同様の記載をしてもいいのですが、情報はまとめて一括管理するほうがいいので、.bash_profile
には「.bashrc
を読み込め」という記載をしておきます。それが上記です。 - 以上により、起動時に自動的に「lsをカラー化する」エイリアスが設定されて、ls結果に色がつきます。
-
文字列の長さ取得、比較、コピー、結合などのためにstring.hのstrlen, strcmp, strcpy, strcatなどの関数を使いたいのですが、こちらも1から自作しますか?
- 今回は自作でお願いします。。。ただ、それらはまだ教えていないので、今回の課題の範囲では文字列操作を行わずに実現してもらう(week1, 2の範囲の知識で実現する)というのが狙いではあります。
Week3¶
-
buff[1000]て何に使うんですか
- ヒントになってしまいますが、入力単語を一度どこかに保存する必要があります
-
week3_2(自由課題)でファイルioやmallocは使っていいでしょうか?
- OKです。c言語でさえあれば何でもOKです。松井の環境(無改造のGoogle Cloud Shell Editor)で実行できるようにしてください。
-
入力の単語数を表示するプログラムで最後Ctrl+Dを入力すると5Dと表示されるのですがこれはなぜですか
- macの仕様かもしれないです。以下の二年前のQAのweek3の最後を見てみてください
-
自由課題で、自作ヘッダーファイルをつけて提出してもいいですか?
- OKです。ちゃんとリポジトリに含めることを忘れないようにしてください
-
Week3_1の課題はenterキーを押したら即座に出力がないとダメですか?cotrol+dを押せば正しく動作するプログラムはできたのですがそれでは不十分でしょうか。
- 自動採点が通ればOKです。自動採点が通らなければダメです。
-
パイプは一度に重ねて使えないのでしょうか。試してみたところできなかったです。コマンド1 | コマンド2 | コマンド3 みたいな事です -可能です
-
Week3_1の課題でscanfは使用可能ですか
- 「使用しない」でおねがいします。。今回は一文字ずつ処理する練習をするのが題意です(ひょっとしたら演習の授業でもう習ってるかもしれないので申し訳ないですが。。。) Week3_2の自由課題のほうはなんでもいいです。
-
putcharとprintfの違いがよくわかりません。
- putcharは文字1つを受け取って文字を出力するシンプルな関数です。printfは文字列を受け取り、文字列を出力する関数で、また変数を文字列に埋め込む機能などもあります。ようは、入出力に関していろいろな関数が準備されているというだけです
-
EOFはリテラルといえますか?
- 「EOFそのものはリテラルとは呼ばない」「EOFが意味するところである「-1」はリテラル」という言い方がしっくりくる気がします(間違っているかもしれません)
-
strcat("abc", "def");
と書くと一瞬"abcdef"
という文字列が生成されたうえでどの変数にも格納されず闇に消えるということですか?- 生成されるわけではないと言えます。
-
cでは1文書き終えるたびに ; を入力するルールを守れば長い文を軽率に改行しちゃって大丈夫ですか?仕様というよりお行儀の観点から知りたいです
- 例えば
int x = a + b + c + ... + z;
みたいなときにどこでどのように改行すべきか、ということですよね。文法的にはコンパイルが通れば大丈夫です。お行儀的には、任意性があると思います。どういう方向でもいいのですが、コード全体を通してやり方を統一することが重要です。参考文献で紹介した【改訂版】組込みソフトウェア開発向け コーディング作法ガイド[C言語版]ESCR Ver.3.0, IPA, 2018.のp107「コーディングスタイルを統一する」などを読んでみてください - プログラミング全般のお行儀の話だと,リーダブルコードという本もおすすめです
- 例えば
-
一度cloud shellで書いたコードをGithubにコピペして提出したのですが、減点対象になっていますか?
- 全然問題ないです。宿題リポジトリ上で自動採点がちゃんと実行されてパスしていることを確認することを忘れないでください
-
最初の方の数字の制御コードがうまく出力できないです
- 表示されなかったりします。それを是非確認してみてほしいです
-
脇道ですがqiitaに真面目な文体で書いてあることはざっくりどれくらいの信頼度ですか?wikipediaくらいの感じですか?
- qiitaそのものはコミュニティサイトなので、間違った情報が含まれていることはあると思います。qiita記事の文中で、言語仕様などの出典を明らかにしている記述は当然ながら信頼度はあがると思います。その意味ではstack overflowもコミュニティサイトですね。。。
-
s[] = "%d"; printf("%lu", sizeof(s))
とすると3が出力されたのですが%dとかは2バイト分使うのでしょうか- ここでも文字列
s
そのものは、'%', 'd', '\0'
の3つのcharになっています。
- ここでも文字列
-
mainの中で関数を宣言するとエラーになるのはなぜですか?そうする必要がないといえばそれはそうなのですが
- あまり納得いかないかもしれないですが、ルールだからというのが返答になってしまいます
-
char, sighned char, unsigned charは全て別物らしいです https://qiita.com/mizcii/items/a5adb7a56b1c4a31951a
- これは知りませんでした。C standardによるとcharが符号付か符号無しかは決まっていないとのことです。皆さんが触れる環境では普通は符号付なので大丈夫です。
King, p136
The C standard doesn't specify whether ordinary char is a signed or an unsigned type; some compilers treat it as a signed type, while others treat it as an unsigned type.
- 【10/25更新】 ARMアーキテクチャでは
char
は符号無しとのことでした!これは知りませんでした。ARMマシンは皆さんが普段使うことが全然ありえますので、注意してください。
- これは知りませんでした。C standardによるとcharが符号付か符号無しかは決まっていないとのことです。皆さんが触れる環境では普通は符号付なので大丈夫です。
-
printfするときは予め適当な変数に代入しておいて、printfの中ではダブルクォーテーションのあとでその変数を書いていますが、代わりにprintfの中のダブルクォーテーションのあとでリテラルを書いても問題ありませんか?(試したところ普通に動きましたが、言語仕様的に問題なくてもお行儀が悪かったりしますか?)
printf("2 + 3 = %d", 5);
こういうことですか?問題ないです。
-
for文でいくつかの変数を順に処理することって(これまでに習ったことで)できますか?具体的にはs1, s2, s3, ...があってそのそれぞれをstrlen関数に入れて何か同じ計算するようなことを、for文で楽したいです。
int s1; int s2;
があったときに、これをfor文で周回したいということでね?これは今まで習っている知識では出来ないですね。
Week4¶
-
int getchar()は、charを受け取るときはchar getchar()にしてはダメなんでしょうか。先週の課題では、char getchar()にしてもうまく挙動していました。
- 先週はうまくいったけど今週はうまくいかないという意味ですか?今週の宿題はgetcharは使わないです(入出力部分は既にかいてあります)そうではなく一般的にそれでいいのかという質問だと、先週やったキーボードから普通に入力を受け付ける範囲であればchar c = getchar()で大丈夫だと思います
-
本日の課題について、Cloud shell上では動くのですが、Github上で動きません。コピペでミスをした可能性があるのでmain.cを初期化してやり直したいのですが、編集前(宿題として配布されたまっさらな状態)のmain.cを確認する方法はありますか?
- コミット履歴をクリックして、一番下の「Initial commit」のところを押すと、一番最初の状態のファイルたちが見えます
-
リテラルはどのように文字列と異なる方法でメモリ上で記憶されているのですか?
- 「リテラルプールに記憶される文字列リテラル」と違い、「整数リテラル」とかはどこに保存されるのか、という意味ですかね?整数リテラルなどはどこかに保存されるわけではなく、使われるときに単純にメモリ上に登場するだけです。
-
int *r = NULL;
としているのですが、これはポインタにnullを代入しているので、printf("%p",r);
とすると何も出力されないのが正しい挙動だと思いました。しかし実際には0x0
と表示されてしまいます。これはどうしてでしょうか- NULLは0であるため16進数での0x0が表示されると思います。
-
今回の授業内容にはあまり関係ない質問なのですが、C言語という言語は具体的にどういう場面で利用されているのでしょうか。
- 組み込みとか、OSとか、速度やメモリが重要なものだと思います。そのうえで、いろいろなプラットフォームで動く必要があるものですかね。cpythonとか、linuxそのものとか。GitHub中でスターが多い、c言語のリポとかを見てみると面白いかもです。
-
int *p; f(p)
のように関数の引数に直接ポインタ変数を入れるとエラーが起こるのはなぜですか?int a =10; f(&a)
のように値を経由しないといけないみたいですが。- 直接ポインタ変数を入れてもOKです。たぶんもとの
int *p
がどこも指していないので、そのせいでエラーになっているきがします
- 直接ポインタ変数を入れてもOKです。たぶんもとの
-
なぜ
sizeof(p)
が8になるか分からないです。intの分の4baitが出力されるのでは、と思いました。- ポインタそのものは64bitの数(アドレス)を保持するので、8バイト必要です(64bitマシンの場合) ポインタは、intを指すポインタもdoubleを指すポインタもcharを指すポインタも、すべて8バイトです。
-
p = &a;
という表記をするなら、*p = a;
という表記もできると思うのですが、どうでしょうか?- その2つは別の操作になります。
p = &a;
ポインタに変数a
のアドレスをいれる。すなわち、p
は新しい変数をポイントする。*p = a;
ポインタが指す変数の値をa
に更新する。この操作を行う前に、ポインタはなんらかの変数を指していなくてはならない。
- その2つは別の操作になります。
-
int a
のアドレス(&a
)とそれを表示した文字列(例えば0x7ffee14b576c
)は全く同じものとして扱ってよいのですか?良いのなら(*&a
)の代わりに(*0x7ffee14b576c
)を使っても良いと思うのですが。- それはダメです。
0x111...
のようなものは、単なる16進数の整数リテラルになります。ここでは0x7ffee14b576c
は140732678231916
と全く同じなので、*0x7ffee14b576c
というのは*140732678231916
と同じ意味になり、「整数の先頭に*
をつけているだけ」になります。
- それはダメです。
-
早めに宿題リポジトリいただけませんか
- 宿題リンクは最後に渡します
-
int *q, q=p
とし、*p=13
とするとa
や*q
の値も変わっていますが、int b=13, p =&b
とするとq
やa
の値は変わりませんでした。これは何故なのでしょうか? -ですね? qに入っていたのはpの値、すなわち「aのアドレス」という単なる値です。p = &bとしても、qが「aのアドレスという単なる値を保持している = aを指している」ことはかわりませんint a = 10; int *p = &a; int *q = p; int b = 13; p = &b;
Week5¶
-
2次元配列のポインタ
p
を作って*(p+1)
とするとエラーになるのですが、この場合は要素を指せないのでしょうか。- 講義中の回答が間違っていました。以下が正しい解説です 指せます。
*(p+1)
はp[1]
に等しいことを思い出すと、*(p+1)
は二次元配列の二行目そのものになります。以下を参考にしてください。#include <stdio.h> void show_intarray(int v[], int n) { printf("["); for (int i = 0; i < n; ++i) { printf("%d, ", v[i]); } printf("]\n"); } int main() { int a[2][3] = { {0, 1, 2}, {3, 4, 5} }; printf("==== print the original array ====\n"); show_intarray(a[0], 3); // [0, 1, 2, ] show_intarray(a[1], 3); // [3, 4, 5, ] int (*p)[3] = a; printf("==== print the pointer as an array ====\n"); show_intarray(p[0], 3); // [0, 1, 2, ] show_intarray(p[1], 3); // [3, 4, 5, ] printf("==== print the pointer as a pointer ====\n"); show_intarray(*p, 3); // [0, 1, 2, ] show_intarray(*(p + 1), 3); // [3, 4, 5, ] }
- 講義中の回答が間違っていました。以下が正しい解説です 指せます。
-
以下が動くのは何故か?
char hokuriku2[][9] = {"toyama", "ishikawa", "fukui"}; char (*p)[9] = hokuriku2; printf("%s\n", *hokuriku2); // エラーなしにtoyamaと表示される
- 講義中に質問をうけたときにちゃんと答えられなかったので回答します これも上の質問への回答と同じです。
*hokuriku2
はhokuriku2[0]
と同じというだけでした。#include <stdio.h> int main () { char hokuriku2[][9] = {"toyama", "ishikawa", "fukui"}; char (*p)[9] = hokuriku2; printf("%s\n", *hokuriku2); // toyama printf("%s\n", *(hokuriku2 + 0)); // toyama printf("%s\n", hokuriku2[0]); // toyama printf("%s\n", *(hokuriku2 + 1)); // ishikawa printf("%s\n", hokuriku2[1]); // ishikawa }
- 講義中に質問をうけたときにちゃんと答えられなかったので回答します これも上の質問への回答と同じです。
-
AI日記の優秀?作品集は、説明の時間がなければ文面での紹介だけでもいいので、見てみたいです
-
AI日記の紹介はまた今度でしょうか?
- すいません、ちょっとまだ時間がかかります。。。
-
EOFのASCIIコードは0x1AなのにCだと-1ですよね。これってテキストファイルにEOFが実体としてあるのではなく、関数がファイルの終わりを判断して-1を返しているということですか?EOFが実際についているファイルもあるのですか?
- これは非常に良い質問です。最近のOSでは、ファイルの最後に実態としてのEOFは存在しないらしいです(あまり適切なリファレンスではなくて恐縮ですがStack over flow)
-
一つ初歩的な疑問なのですが、char型ポインタpに文字列を代入した後に
printf("%s\n", p)
とすると代入した文字列が出てくるのはなぜなのでしょうか。配列を代入するとき実際は先頭アドレスが代入されるはずなのにprintfをすると配列自体が出てくるのがいまいち納得できていません。(もちろん%pでプリントしたらアドレスが出てきますが)普通の配列ではできないと思うのですが、文字列特有の機能なのでしょうか。- 下記の場合に、s1は納得できるけどs2は納得できないということですか?それに対する答えとしては、「関数に配列が渡されるときは全てポインタになっている」ので、s1の場合もs2の場合もprintfに渡されるのは文字列の先頭のポインタだけです。
#include <stdio.h> int main() { char s1[] = "abc"; char *s2 = "abc"; printf("%s\n", s1); printf("%s\n", s2); }
- それとも、「printf関数にはポインタ1つしか与えていないのに、配列(文字列)の中身をスキャンできるのはおかしい。長さを与えていない」という質問ですか?それであれば、答えは「文字列は特殊で、最後にNULL文字があるかどうかで長さを判定できる。なので、先頭アドレスを与えるだけで文字列をスキャンできる」ということになります。実際、最後にヌル文字が入っていない不完全な文字列では、うまくいきません。
#include <stdio.h> int main() { char s_ok[] = {'a', 'b', 'c', '\0'}; // same as "abc" char s_no[] = {'x', 'y', 'z'}; // W/o NULL character. This is not a valid string printf("%s\n", s_ok); printf("%s\n", s_no); // Will produce strange result }
- 下記の場合に、s1は納得できるけどs2は納得できないということですか?それに対する答えとしては、「関数に配列が渡されるときは全てポインタになっている」ので、s1の場合もs2の場合もprintfに渡されるのは文字列の先頭のポインタだけです。
Week6¶
-
構造体へのポインタとは構造体の最初の要素のアドレスを変数にいれるという認識で良いのでしょうか。
- 講義中では曖昧だったので調べました はい、そうです
King, p405
。 もちろん、構造体そのものへのポインタと、直接構造体の中の変数のポインタでは、値(アドレス)は同じでも型は違うので注意してください。typedef struct pt { int x; int y; } Pt; int main () { Pt a; Pt *p1 = &a; // 構造体そのものを指すポインタ int *p2 = &(a.x); // 構造体の最初の要素を指すポインタ printf("%p %p\n", p1, p2); // 0x7fff05739490 0x7fff05739490 値は同じだがポインタの型は違う }
- 講義中では曖昧だったので調べました はい、そうです
-
松井先生に「言語を指定せずジェネラルによく使うエディタを1つ教えてください」と言ったらvscodeになりますか、markdownのようなプログラム以外の文字を書くエディタについても知りたいです
- 最近はmarkdownもただのテキストもjson/yaml編集もvscodeですね。。。 しいていえばcsvの手動編集はvscodeでも大変かもしれないです(拡張機能とか使えばできますが) といいつつ編集するときはやっぱりvscodeにしてるかもですね。。。 命の危機が迫ったときのためにemacsを懐に忍ばせてはいます(?)
- そういえば最近jetbrainsはfleetというvscode対抗軽量エディタを出しているので、これとかはvscodeの対抗にはなりえますね。
-
構造体の宣言やtypeofはmain関数の中で書いてもコンパイルできますが、サンプルで外に書いているのはふつう構造体をmainの中だけで使うことが少ないからですか?
- 普通は構造体の宣言などは、型を定義する別ファイルにまとめておいたりすることが多いと思います。
-
#define N 3; int a[N];
などとしたらこれも可変長扱いですか?- 良い質問です。これは可変長扱いに「ならない」です。なぜなら、#defineというのは、イメージとしては最初にプログラムがmain.cファイルの中を見て「N」が登場しているところをすべて「3」に書き換える、というようなものです。なので、ただ単に「3」と書いていることと同じになります。実行してみてください。なので、昔のCの教材とかだとdefineがたくさんでてきます
-
講義内容とは関係ないのですが、言語ごとに向いているエディターなどはあるのでしょうか?プログラミング演習ではpythonではコラボレトリを勧めれられました。確かc言語ではクラウドシェルを勧められて気になりました。
- 「エディタ」でいうと、ジェネラルに今どんな言語でも一番楽なのはvscodeだと思われます。vscodeが強すぎて設定も楽なので、それ一個で全部済ませてる人が多いかもしれません。
- pythonであれば、pycharmというのが強いです(python特化ということであればpycharmのほうがvscodeよりいいと個人的には思います) cでいうと難しいですが、上記のpycharmと同じjetbrain社のclionとかはいいかもしれません(松井は使ったことは無い)あとは本当はVisual Studioが最強ではあります(vscodeではない)。松井は昔はQtCreatorというのを使っていました。vimワールドの人はneovimとかを使う一派もいます。
- 上記は「ソースファイルに書き込んで実行する普通のプログラミング」の時の話です。そうではなく、インタラクティブに実行するような場合も考えられます。たとえばjupyter notebook (pythonをインタラクティブに実行)とかです。そのような場合は、エディタと実行環境を一緒にして考える必要があります。その意味で、pythonであればnotebokkシリーズ(jupyter, colaboratoryなど)は便利です。
- cではそういうインタラクティブ環境はふつうやらないので、colabは不向きです。なので、クラウドシェルやwslや大学のマックのように、普通のターミナル+エディタというほうがいいです。
-
講義内容とはまったく関係ありませんが、講義ページの「元」のテキストデータは先生のGitHubの非公開リポジトリにあるということですか?
- そうですね。プライベートリポジトリ中にあります。mkdocsというやつで、マークダウンファイル(テキストファイル)からhtmlを生成し、github pagesという機能で公開しています。(全く本筋とは関係ありませんが、github actions(CI/CD)上でレンダリングしたhtmlをartifactとしてgithub pagesにアップロードするという、ナウナウな方式でやってます・・・)
Week7¶
-
最終課題に関して質問です。新たに(0,0)にoを追加する時、すでに落下されたものに左右のコマンドは効かず、新たに追加されたオブジェクトのみにコマンドが適用されるという認識であってますか?
- そうです。すでに落下したものはそこに固定され、もう動きません。
-
最終課題に関して、音を出してもいいですか?
- 大丈夫ですが、音を出す場合は環境再現が難しいので注意してください。音が出るバージョンを手元で実行した動画を撮って共有してもらってもいいです。
-
cat hoge.txt | ./a.out と ./a.out < hoge.txt は同じですか?
- ぱっと見の処理内容は同じになりそうな気がしますが、catのほうは「cat」というプログラムを実行しているので、リダイレクトとは異なる処理をしています。参考
-
個人の感想ですがチーム開発をするときはdiscordとgithubを連携させると,commitの通知とかが来るので便利でした.(discord以外でもなんか連携できるやつはあると思います)
- 私の世代ではSlackと連携させたりするのは普通という感覚です。discordはちょっと若者のツールというイメージがあります(?)
-
git statusを実行したときの1行目がOn branch mainではなくOn branch masterなんですが、何が違うんでしょうか
- それはブランチがmasterになっちゃってます。こういうサイトを見ながらmainに変更してもらえるとよいです https://qiita.com/masakinihirota/items/1a657674e609be112fc6
- ただ、なぜmasterになっちゃったのか気になります。今日の講義の通りにやっていればmainになるはずです。