Q&A¶
ここでは講義中に出た質問に対する回答を載せていきます。随時更新です。
Week1¶
-
出席点はあるか?
- ありません。もしC言語を既に全部理解しているなら、講義に出なくても大丈夫です。宿題だけは全部やってください。宿題・最終レポートのみで成績をつけます。
-
他学部・他学科だが履修可能か?
- 履修出来ます。便覧やUTAS/UTOLをよく読んで取得単位等について確認してください。
-
どうして以下だとダメなのでしょうか?
#include <stdio.h> main() { float x = 1; printf("x^2+2x+3 = %f*%f + 2*%f + 3\n, x,x,x"); }
- 後ろのダブルくオーテーションの位置が変になっていますね。
\n
の直後であるべきです
- 後ろのダブルくオーテーションの位置が変になっていますね。
-
Githubのアカウント名をどこで見れば良いか教えていただけますか
- 個人ページのURLが
https://github.com/matsui528
だとしたら、アカウント名はmatsui528
です
- 個人ページのURLが
-
メモリアドレスについて質問です。実態は64bitにもかかわらず、printfで表示されるアドレスが16進数で12桁しかないのはなぜですか?
- week1の最後の部分に追記しました。
-
floatやdoubleの変数に0を代入したら、内部では完全な0ではなく非常に小さい小数として表現されるのですか?
- 0は特殊な扱いになります。こちらなどを参考にしてください。浮動小数点数の他の特殊な扱いの数として,±無限大なども表現可能です。
-
int型ではなくchar型が選ばれる場面というのは、具体的にどのようなものなのでしょうか?
- char型は文字を表すときによく使います。詳しくはweek2以降で述べます。
- また、値が小さい数しかとらないことが分かっている場合は当然char型のほうがメモリ効率として優れています。例えば、現実的ではない例ですが、世界の国の数を200程度とすると、ある人の国籍を表現するためにはchar一つで表現できます。100万人の国籍を管理したいとき、charを使うと100万バイトで十分ですが、intを使うと400万バイト必要になります。
-
hello, world の部分をこんにちはなどに変えて出力しても、hello,world から全く変わらないのですがどのような理由が考えられるでしょうか。
- コンパイルが失敗していると思います。なので古いa.outを実行してしまっていると思います。まず古いa.outを削除してみてください
-
cat /user/include/stdio.hと打ってもNo such file or directoryとなってしまうのですが、何が原因だと考えられますか
- /usr/ ですね
-
google cloud shell editorにはいろいろな言語のコンパイラが最初から備わっているのですか?
- c, python, javac, go, rubyなどは入っていそうですが,rustcなどないものはないですね
-
stdio.h以外のファイルを読み込むのはどのような時ですか?
- 数学関数を使う際にmath.hを読み込むなど、これからいろいろ出てきます。
-
.以下のc py txtの違いってなんですか?
- それらの部分は「拡張子」と呼ばれています。なので拡張子が違うということになります。例えば「.py」であるなら一般にpythonのファイルを指すため、それをダブルクリックで開くと、vscodeといったpythonを開くためのアプリケーションでそのファイルが開かれます。拡張子は単なる識別子なので、拡張子が何であるかと、ファイルそのものが何かは、直接関係はありません。たとえば
a.txt
というファイルを作ってそれをmv a.txt a.py
とリネームしても、中身は変わりません。
- それらの部分は「拡張子」と呼ばれています。なので拡張子が違うということになります。例えば「.py」であるなら一般にpythonのファイルを指すため、それをダブルクリックで開くと、vscodeといったpythonを開くためのアプリケーションでそのファイルが開かれます。拡張子は単なる識別子なので、拡張子が何であるかと、ファイルそのものが何かは、直接関係はありません。たとえば
-
先ほどのやってみようとしてあった"カレントディレクトリ以下に、以下のような構造のディレクトリおよびファイルを作ってみましょう:./aaa/bbb.py, ./aaa/ccc.py, ./aaa/ddd/fff.py."の詳しい操作がよくわからなかったので教えてほしいです。
- 例えば以下の手順で実行できます。
$ mkdir aaa # aaaというディレクトリを作成 $ cd aaa # aaaディレクトリに移動 $ touch bbb.py # aaaディレクトリの中にbbb.pyというファイルを作成
- 例えば以下の手順で実行できます。
-
printf
を書く際にformat:
という記述が自動的に出現する- 「左下の設定ボタン > Settings > 検索ボックスにinlayと入力 > Inlay Hints: Enabled を Off にすると "format:" 等は消せるみたいです」とのことです。教えてくださった方、ありがとうございます!week1にも追記しておきます。
-
キーボードの操作だけでソースコードの入力からターミナルの入力に移ることはできますか?
- 多分方法はないと思います。知っている人がいたら教えてください。
-
行末のセミコロンにはどのような役割がありますか?pythonにはないものなので、、、
- c言語ではセミコロンや{}などで文やブロックの区切りとしています。
-
$ man ls
とすると、unminimizeしろという指示が出て、説明が表示されないのですが、どうすれば良いでしょうか?- 最新のCloud Shell Editorではmanを直接使うことが出来ないようですね・・・
-
ふたつのファイルを同時に動かすことはできますか?
- できます。まず以下を説明します。
aaa
というディレクトリ、およびfile.txt
というファイルがある状況を考えます。mv file.txt aaa/file.txt
とすると、file.txt
をaaa
ディレクトリに移動できることは勉強しましたね。実はmv file.txt aaa
とするだけでも、file.txt
をaaa
ディレクトリに移動できます。 - これを拡張し、
mv file1.txt file2.txt aaa
とすると、file1.txt
とfile2.txt
をaaa
フォルダに同時に移動できます。
- できます。まず以下を説明します。
-
フォルダとディレクトリと位置が同じと言う認識でよろしいでしょうか?
- フォルダとディレクトリは同じです。「位置」は同じ単語とは言えないです。「フォルダを作る」とは言えますが「位置を作る」とは言えないです。
-
utolから講義のサイトに行けるようにしてくださると助かります。
- 対応しました。
-
プログラミング初心者なのですが、A2のソフトウェアⅡを取ることは望ましいですか?
- 電子情報は必修です。そうでない場合も、頑張ってとってみることをオススメします。他の講義で手一杯と言う場合は、取らないこともありだと思います。
-
A2で先生のプログラミングの授業はありますでしょうか?
- 無いです。
-
C実践プログラミングは推奨できますか?
- ちょっとコメントできないのですが、出版年は古めかもしれませんね・・
Week2¶
-
Success: Ok!が出たら宿題を提出したということでしょうか?
- はい、そうです(正確には、「宿題を提出して自動採点をパスした」ということです。Something is wrongであっても、「宿題を提出した」ことにはなっています)
-
mallocでメモリを明示的に確保した場合、感覚的にほぼ確実にセグフォが起きるのですが、これは使用可能なメモリ領域を指定したことでより厳密に保護を行うようになっているような気がしました。この感覚は正しいのでしょうか。
- この文脈からだけだと、何も言えないです。
-
func(i++)とfunc(++i)では前者では値のコピーが行われた後にiをインクリメントしていて、後者では先にiをインクリメントした後に値のコピーを行うという認識なのですが、これは正しいですか。
- その認識で正しいです。
func(++i)
ではインクリメントした後に値のコピーが起こりますが、func(i++)
ではコピーの後にインクリメントが起こります。for文におけるループ条件のところでfor (int i = 0; i < N; ++i)
のように書く際は++i
でもi++
でも結果は変わりませんが,定義した関数に引数として渡す場合は挙動が変わります.
- その認識で正しいです。
-
for文について、for (int i = 0; i < n; i++)とfor (int i = 0; i < n; ++i)では全く同じ結果が得られるとのことでしたが、インクリメントを前置した場合ではループに入る前にインクリメントが行われるかのような錯覚に陥ってしまいます。 for文では、まず1文目で使用変数を初期化して、2文目でループに入るかを判定し、この判定後にループの中身を実行して、中身の実行後に3文目を実行し、また2文目の判定に戻る、という流れなのでしょうか。
- その理解であってます.「式1で初期化->式2で条件を判定->真ならば中身を実行->式3を実行->式2の判定へ戻る.」なので++iでもi++でも実行はforの中身の実行後となり結果は同じになります.
-
a[3]について、a[0] ~ a[2]までしか定義されていない場合セグフォを起こすと思ったのですが、これはaの型によって異なるのですか?
- 「型によって異なる」というわけではなく、様々な要因が考えられます。「必ずセグフォになる」とは限りません(なのでやっかいなのです)
-
a[3]のアドレスはa[2]と連続になるように定義されていますか?定義されていない場合、どの段階でa[3]のアドレスが確定するのでしょうか。(コンパイル時なのか、実行時なのか)
- a[3]のアドレスはa[2]と連続になります。コンパイル時という言い方でもいいですが、例えば
int a[2]
と書いたときに「a[3]
と書いた場合、a[3]
のアドレスはa[2]
のもの+4である」ということは既に決まっています。また、「a[100]
と書いた場合、そのアドレスはa[2]
のアドレス+(98*4)である」ということも既に決まっています(当然a[100]
にアクセスすると範囲外アクセスになりおかしなことになりますが、アドレスという数字そのものは決定されます)
- a[3]のアドレスはa[2]と連続になります。コンパイル時という言い方でもいいですが、例えば
-
変数がメモリに格納されているとき、プログラムを書き換えてその変数を変更すると、同じメモリの場所で値が書き換わるのですか?
- 「ソースコード中で
int a
と書いて色々したあと、後にa = 3
のようにa
を書き換える場合、それは同じメモリの場所の値を書き換えているのか?」という質問であれば。その通りです。 - 「プログラムAを実行した際に
int a
という変数は0xff123
というアドレスだったとして、そのAを書き換えてプログラムBにした際、int a
のアドレスは同じ0xff123
なのか?」という質問であれば、それはそうとは限りません。
- 「ソースコード中で
-
変数をプログラム上で削除するとメモリ上でも削除されるのでしょうか?
- C言語には「変数を削除する」という概念はありません。変数を使わなくなった場合(例えばスコープ内側で宣言した変数が、スコープを抜けてアクセスできなくなった場合)、そのメモリ番地は「使われなくなったメモリ」となり、あとはC言語側がよしなに判断します。
-
クイズにあるように、a[3]を%fで出力するとコンパイル毎に出力結果が変わりましたが、%dで出力すると何回コンパイルしても出力結果が同じでした。何か理由はありますか。
- 私の環境だと毎回違う結果になったので、「未定義動作なので結果はわからない」というのがショートアンサーになります。一方で、手元では%dの結果が常に同じになるという現象がありその理由が知りたい場合、printfの挙動(可変長変数の挙動)が関係しているかもしれません 一度a[3]を別の変数に保存してみて(この時点で変なことをしていますが)printfする、などとすると挙動の見通しがつくかもしれません
Week3¶
-
複写プログラムの最後のc=getchar()の意義がいまいちよく分からないです。
- 是非その部分を抜いてコンパイルしてみてください。そこにgetcharが無いと、一回しかgetcharが発動しないので、一文字しか出力されません。また、プログラム的には単純に無限ループになります(
c
に何か単語が入り、それをずっと出力する) - 以下のように
c = getchar()
のみのファイルを作って挙動を見てみると理解が深まるかもしれません。int main() { int c = getchar(); // 一文字読み込む printf("You entered %c\n", c); }
- 是非その部分を抜いてコンパイルしてみてください。そこにgetcharが無いと、一回しかgetcharが発動しないので、一文字しか出力されません。また、プログラム的には単純に無限ループになります(
-
「int n = c - '0'とすると、数字そのものが得られます。」の理由がわかりません、、
- 例えば
c = '3'
のときに、n
には単なる整数の3
が入ってほしいという状況です。しかしこれは単純には出来ません。なぜなら'3'
という文字は単なる整数の51
にすぎず、3
という情報を抜き出せないからです。 - 一方で、ASCIIコード上で整数は連続して並んでいるという特性があります。つまり、
'0'
を考えると、これが実際なんの整数かは不明だとしても、'3' - '0'
は必ず整数の3になります(連続して並んでいるので) - なので、
int n = '3' - '0'
により、n = 3
を得ることができます。
- 例えば
-
quotient = (float) dividend / divisor; quotient = dividend / (float) divisor;の違いはありますか?
- 上記の例では、どちらでも大丈夫です。より複雑な例では、演算子を挟む左右どちらにキャストをつけるかで結果が変わることがあるかもしれません。
-
失礼します。リテラルとは何ですか?
a = 1
,s = "hello"
における1
や"hello"
のようにプログラムに直接書かれた定数のことです.
-
以下のコードではそもそも"error: initializer-string for ‘char [3]’ is too long [-fpermissive]"のエラーが出てコンパイルできませんでした。
char s1[3] = "abcdefg"; char s2[3] = "hijklm";
- はい、コンパイラが警告したりエラーにしてくれることもあると思います
-
細かいですが、oの文字コードは111ではないですか?
- 本当ですね。ありがとうございます!
Week4¶
- for文で*s = 0;とせず、単に;とするのは何か違いはあるのでしょうか?今は単に簡略化されただけという認識でいいですか?
-
なぜ「*s != 0」と「*s」の返す値が同じなのでしょうか。前者は論理式で0か1を返し、後者は任意の文字を返しそうですが
- 講義で返答したよりも丁寧に返答します 文字列
s
について考えたときに、for (XX; YY; ZZ)
のYY
の位置に、*s != '\0'
がある場合と*s
がある場合で、なぜどちらも同じ挙動になるのか、という質問ですね。 - 結論から言うと、
*s != '\0'
という式が返す値と、*s
と単に書いた場合に返す値が、真偽値の意味で同じ(偽=0であるか、真=0以外であるか)なので、どちらを書いても同じということになります。なので処理としては違いますが、得られる結果は同じということになります。 - より詳しくみていきましょう。例えば
*s == 'a'
の場合を考えましょう。このとき、*s != '\0'
: これは、a
は'\0' (=0)
でないので、真を返します。*s
: これは、a
を返します。a
は'\0' (=0)
でないので、真を返すということです。
- 上記の通り、
*s
が普通の文字の場合は、上記の2つの表記の結果は同じく真を返します。 - 次に、
*s == '\0'
、すなわち*s == 0
の場合を考えましょう。このとき、*s != '\0'
: これは、定義より、偽を返します。*s
: これは、定義より、'\0' (=0)
そのものです。なので、偽を返すということです。
- よって、
*s
がどのような値の場合でも、*s != '\0'
と*s
は真偽値の意味で同じものを返します。 - (ちなみに、今回はsが単なるintやcharなのでいいのですが、もしsが別の者だった場合はこの2つの記載は違う意味になることがあるので注意してください。一致を許さない自作のクラスなど。)
- (また、今回の範囲では、コンパイルすると実際上記の2つの記載は全く同じ機械語(a.out)を生成すると思います)
- 講義で返答したよりも丁寧に返答します 文字列
-
こちらにコードについての質問をするときに、コピペすると一文として表示されてしまうのですが、見やすくする方法は何かありますでしょうか?
- 残念ながらslidoにその機能はないようです。
-
#include <stdio.h> int a[10], *p, *q; int main() { p = &a[0]; q = &a[3]; p++; int i = p - q; int j = q - p; printf("i: %d, j: %d\n", i, j); }
についてなのですが、iとjはそれぞれ配列の中身ではなく、そのアドレスの引き算をしているということでいいのでしょうか?- はい、アドレスの引き算です。ただし具体的なアドレスの差が出力されるわけではなく,アドレスの際を
sizeof(型)
で割ったものが返ります。
- はい、アドレスの引き算です。ただし具体的なアドレスの差が出力されるわけではなく,アドレスの際を
-
関数引数の例にあるコードで、関数部分で*int_partに値を代入するときにlongを()で囲っているのはなぜですか?
- これは先週の授業でやったキャストという明示的な型変換です
-
そると、というラーメン屋が美味しいです
-
下北沢でおいしいラーメンは、なおちゃんラーメン、貝麺みかわ、一蘭あたりだと思います。
- ありがとうございます!
-
前回の宿題の入力例は、ビルドしたファイルを実行したときの待ち状態に入力したり、./a.out <文字列>のようにしたりするのではなく、echo <文字列> | ./a.out のようにする設定になっていたと思います。これらの違い、および前回の宿題で「echo <文字列> | ./a.out」を使った意図は何でしょうか?
- 待ち状態入力にしなかったのは、自動採点を実行するためです。./a.out 文字列 タイプの入力はargvを習うときにやります。
- 今回の範囲で取り組んでほしかったのは、標準入力から受け取ったものを処理すること(=待ち状態入力を処理するもの)であり、それを採点するために自動採点にしてechoパイプ形式にした、と言う形です。これにより、パイプの使い方も学んでもらいたい、という意図があります。
-
宿題の解答例はどこかで見ることができるんでしょうか?
- 次の授業のタイミングで前の回のページに上がっています
Week5¶
- 変数の宣言と初期化を分けているのには、何か意図があるんですか?(前回の課題の解答例の話です)
- 深い意味はないです
- 自分の課題の達成度は公表されますか?
- これはされないです(最終課題の何か物を作るというやつは、講義が終わったあとに優秀作品を紹介することをします)
Week6¶
-
atoiがLLONG_MAXを超えてオーバーフローすると-1が出力されるのは、LLONG_MAXを超えた場合は全てのbitが立つから、という認識で良いのですか?また、LLONG_MINを下回ってオーバーフローすると0が出力されるのは、一番左の桁からさらに左の桁を1にしようとした結果なのでしょうか、ここがよくわかりませんでした。
- C言語的にはatoiにおいて範囲を超える数字が来たときの挙動は未定義というだけのようです。
-
課題難しかったです.プログラムめっちゃ汚くなっちゃいました.
- 是非汚いコードを書いて「もっと綺麗にならないかなあ」と思ったりする経験をたくさん積んでみてください!それが力になります
Week7¶
-
git statusでは、まだpullしていない情報があることは教えてくれないんですか?
- 教えてくれないです。git statusは手元の情報に関するstatusを報告してくれるコマンドです。
-
では、pullすべき情報があることはどのように把握していますか?初めにとりあえずpullしておく、というような感じなのでしょうか
- GitHubのウェブの画面を見るとわかります。実際に個人プロジェクトとしてやるときははじめにpullすればいいです。
-
main関数のreturn の数には何か意味があるんですか?(エラーの種類によって分ける、など)
- 特に意味はないです
-
代表者が作るリポジトリはパブリックじゃないといけないですか?
- プライベートでお願いします。