C言語練習問題
C言語練習問題
環境について
C言語の練習問題です。※追記、修正あり(2016/09/23 14:30)
開発環境は以下の通り。
PC:MacBook Pro 2011early 15inch
OS:Windows 8.1(デュアルブート) 64bit版(追記)
メモリ:16GB(8GB x 2)
CPU:Core i7-2635QM 2.00GHz
コンパイラ:MinGW-w64 5.3.0 (posix, sjlj) 64bit版(追記)
※問題文に書いてあるプログラムを実行する際は自己責任で実行してください。
※※各問題へのリンク一覧を作成しました。
問題
次のプログラムを作り実行したところ、以下のように表示された。
なお、この環境はコンパイラ、OSともに64bit環境である(追記)
プログラム(test38_0.c)
1 2 3 4 5 6 7 8 | #include <stdio.h> #include <stdint.h> int main( void ){ printf ( "sizeof(void*) = %d\n" , sizeof ( void *)); printf ( "sizeof(int32_t*) = %d\n" , sizeof ( int32_t *)); return 0; } |
実行結果
1 2 3 4 | > gcc test38_0.c -o test38_0.exe >test38_0 sizeof(void*) = 8 sizeof(int32_t*) = 8 |
その後、次のプログラムを作った。コンパイル、実行に関して以下の問いに答えよ。
プログラム(test38.c)
1 2 3 4 5 6 7 8 9 | #include <stdio.h> #include <stdint.h> int main( void ){ int32_t num[3]; int32_t (*pnum)[3] = # printf ( "sizeof(*pnum) = %d\n" , sizeof (*pnum)); return 0; } |
問1.次のコマンドをコマンドプロンプトから打ち込んだ。どのような結果になるか。
A,B,Cの選択肢から適切なものを選べ。また、選んだ選択肢の中の空欄を埋めよ。
なお、コマンドを入力する前はディレクトリ内のファイルはtest38.cのみであった。
1 | gcc test38.c -o test38.exe |
選択肢A,B,C
A.コンパイルに成功して( 空欄1 )が生成される。
B.( 空欄1 )ためコンパイルエラーが起こる。
C.コマンドの( 空欄1 )の部分が間違っているためコンパイルが実行されない。
問2.その後、次のコマンドをコマンドプロンプトから打ち込んだ。どのような結果になるか。 A,B,Cの選択肢から適切なものを選べ。また、選んだ選択肢の空欄を埋めよ。
1 | test38 |
選択肢A,B,C
A.ファイルが実行され( 空欄1 )と画面に表示される。
B.( 空欄1 )というファイルがないため実行できない。
C.コンパイルはされているが、( 空欄1 )という問題があるため実行は危険である。
解答
問1
A.コンパイルに成功して( test38.exe )が生成される。
問2
A.ファイルが実行され( sizeof(*pnum) = 12 )と画面に表示される。
解説
問1,問2
今回は「int32_t (*pnum)[3]」のメモリ上のサイズをsizeof演算子で調べている。
int32_t (*pnum)[3]と宣言した場合、pnumは「要素数3のint32_t型の配列」を示すポインタとなる。したがって、sizeof(*pnum)は「要素数3のint32_t型の配列」のサイズを示す。
int32_t型のメモリ上のサイズは4byteなので、4×3=12となる。
int32_t型およびそのポインタ、配列周りのサイズを調べるプログラムは以下の通り。
プログラム(test38_1.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #include <stdio.h> #include <stdint.h> int main( void ){ int32_t a = 0; int32_t b = 1; int32_t c = 2; int32_t num[3] = {a, b, c}; int32_t (*pnum)[3] = # int32_t *parr[3] = {&a, &b, &c}; printf ( "-------+----------------+-------------------\n" ); printf ( " var. : value : sizeof() \n" ); printf ( "-------+----------------+-------------------\n" ); printf ( " a : a = %6d : sizeof(a) = %d\n" , a, sizeof (a)); printf ( " &a : &a = %X : sizeof(&a) = %d\n" , &a, sizeof (&a)); printf ( "-------+----------------+-------------------\n" ); printf ( " num : num = %X : sizeof(num) = %d\n" , num, sizeof (num)); printf ( " *num : *num = %6d : sizeof(*num) = %d\n" , *num, sizeof (*num)); printf ( " &num : &num = %X : sizeof(&num) = %d\n" , &num, sizeof (&num)); printf ( "-------+----------------+-------------------\n" ); printf ( " pnum : pnum = %X : sizeof(pnum) = %d\n" , pnum, sizeof (pnum)); printf ( " *pnum : *pnum = %X : sizeof(*pnum) = %d\n" , *pnum, sizeof (*pnum)); printf ( " &pnum : &pnum = %X : sizeof(&pnum) = %d\n" , &pnum, sizeof (&pnum)); printf ( "-------+----------------+-------------------\n" ); printf ( " parr : parr = %X : sizeof(parr) = %d\n" , parr, sizeof (parr)); printf ( " *parr : *parr = %X : sizeof(*parr) = %d\n" , *parr, sizeof (*parr)); printf ( " &parr : &parr = %X : sizeof(&parr) = %d\n" , &parr, sizeof (&parr)); printf ( "-------+----------------+-------------------\n" ); return 0; } |
実行結果
※ブログ内部で正しく表示されていなかったため修正(2016/09/23)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | > gcc test38_1.c -o test38_1.exe >test38_1.exe -------+----------------+------------------- var. : value : sizeof() -------+----------------+------------------- a : a = 0 : sizeof(a) = 4 &a : &a = 23FE4C : sizeof(&a) = 8 -------+----------------+------------------- num : num = 23FE30 : sizeof(num) = 12 *num : *num = 0 : sizeof(*num) = 4 &num : &num = 23FE30 : sizeof(&num) = 8 -------+----------------+------------------- pnum : pnum = 23FE30 : sizeof(pnum) = 8 *pnum : *pnum = 23FE30 : sizeof(*pnum) = 12 &pnum : &pnum = 23FE28 : sizeof(&pnum) = 8 -------+----------------+------------------- parr : parr = 23FE10 : sizeof(parr) = 24 *parr : *parr = 23FE4C : sizeof(*parr) = 8 &parr : &parr = 23FE10 : sizeof(&parr) = 8 -------+----------------+------------------- |
配列とポインタ回りについてはプログラムの動作を予想できなかったり、プログラマの予想と異なる動作をすることも多い。 バッファオーバーフローにつながることもあり、システムに脆弱性が入り込む危険性がある。C言語の仕様書をよく読むとともに、正しいコーディングを行うこと。 JPCERTのページなどにセキュアコーディングに関する情報があるので、そちらを参照するのも良い。
実践力が身につくC言語講座 連載リンク
競技プログラミングをイメージしたライブラリ活用講座
競技プログラミング風-標準Cライブラリ入門 連載
アルゴリズムをマスターして技術力アップ!
実践アルゴリズム講座 連載
パズルゲームの解析をテーマにしたC++講座
ゲーム解析プログラミング 連載