初回ということもあり、提出はどちらか1つだけでもよい、という条件で以下のような課題を提出してみました。
- "hello world" とコンソールに出力するプログラム
- 掛け算の表をコンソールに出力するプログラム
今回の目的は、ぶっちゃけて書くと
- 見て分かるプログラムスタイルを意識してもらう
- プログラミングスタイルの確認
- 何のプログラム言語で課題を提出するかの確認
- 課題を提出しないような輩が混じっていないかの確認
ということでした。
全員が両方の課題を普通に提出してくれて、正直ほっとしているところです。
ちなみに、私が考えた「こんな解答例を出す人がいたらどうしよう...」なサンプルは以下の通りです。
#include <stdio.h>
int main(int argc, char *argv[]) {
printf(" 1 2 3 4 5 6 7 8 9\n"
" 2 4 6 8 10 12 14 16 18\n"
" 3 6 9 12 15 18 21 24 27\n"
" 4 8 12 16 20 24 28 32 36\n"
" 5 10 15 20 25 30 35 40 45\n"
" 6 12 18 24 30 36 42 48 54\n"
" 7 14 21 28 35 42 49 56 63\n"
" 8 16 24 32 40 48 56 64 72\n"
" 9 18 27 36 45 54 63 72 81\n");
return 0;
}
ま、これらは冗談として話を先に進めましょう。
この勉強会の目標の1つが「見た瞬間、内容が分かるプログラムを書こう」です。そういう意味では、このプログラムは特にコメントがなくても分かります。
プログラム名が hello.c だとか、hello_world.c という風になっていたら完璧です。
プログラムの理解を助ける情報には、
- ファイル名
- ファイル冒頭のコメント
- 関数の名前
- 関数の冒頭のコメント
- 処理ブロックにつけられたコメント
- 変数名
- 変数名につけられたコメント
- 外部ドキュメント
などがあります。今後プログラムを作るときは、こういうことにも気を配るようにしてみましょう。具体例は、今回の課題2のときに少しだけ示します。
あと、もう1つ。
規格に準拠したプログラムを書く習慣を身につけるために、gcc を用いたコンパイル時には、-Wall -Werror をつけましょう。
例えば、
#include <stdio.h>
void main(void) {
printf("hello world.\n");
}
のようなプログラムを -Wall -Werror オプションをつけてコンパイルすると、以下のような警告がでます。
% gcc -Wall -Werror hello.c
hello.c:3: 警告: return type of 'main' is not `int'
%
つまり、void main(void) でなく、int main(void) で宣言しろ、ってことです。今後 gcc を使ってプログラムをコンパイルするときは、-Wall -Werror を付加して下さい。
#include<stdio.h>
main(){
printf("hello world\n");
}
#include<stdio.h>
main()
{
printf("hello world!\n");
}
#include <stdio.h>
int main(void) {
printf("\"hello world\"\n");
return 0;
}
↑ printf 内で "(ダブルクオーテーション) を取り込んでいるのが涙を誘います。よいです。
#include <iostream>
using namespace std;
int
main()
{
cout << "Hello, world!" << endl;
return 0;
}
↑関数名前での改行、インデント幅が 4, なつかしいスタイルです。
#include<stdio.h>
int main(){
printf("hello world\n");
}
↑メールに貼りつける前にはあったのかもしれませんが、インデントは入れましょう。(printf 前に空白を入れる)
ここでは、コメントの意義について少しだけ解説します。
課題提出時に私が想定したプログラムは以下のようなものです。
multiplication.cpp
#include <stdio.h>
int main(int argc, char *argv[]) {
for (int y = 1; y <= 9; ++y) {
for (int x = 1; x <= 9; ++x) {
printf("%3d ", x * y);
}
printf("\n");
}
return 0;
}
このプログラムがぱっと見で主張しているのは、
- main 冒頭でのコメント(「かけ算の表 -> 9x9 の表 -> 2重ループ」という連想を期待)
- 表を作るループ変数が x, y で、2次元の表の連想を期待
- 表のループの数値が 1, 9 であり、1から9の段の表を作ることを主張
というあたりです。
コメント付けでは「余分でなく、不足もしていない」というのが理想です。あとは、コメントと実装が食い違わないのようにするのも、重要なことです。
ま、いいや。解答へのコメントを示して今回は終わりにします。
#include<stdio.h>
#include<math.h>
int main(){
int x,y;
printf(" y 0 1 2 3 4 5 6 7 8 9\nx\n");
for(x=0;x<10;x++){
printf("%d ",x);
for(y=0;y<10;y++){
printf("%2d ",x*y);
}
printf("\n");
}
}
↑個人的に、0 の段はいらないんじゃ...、とか思った。まぁ、課題で指定してないので問題はないです。
#include <iostream>
using namespace std;
int
main()
{
cout << " ";
for(int i = 1; i < 10; i++){
cout << "|";
cout.width(2);
cout << i;
}
cout << endl;
cout << "-----------------------------" << endl;
for(int i = 1; i < 10; i++){
cout.width(2);
cout << i;
for(int j = 1; j < 10; j++){
cout << "|";
cout.width(2);
cout << i * j;
}
cout << endl;
cout << "-----------------------------" << endl;
}
return 0;
}
↑「"|2d" 的な表示の箇所」は、同じ実装が2回でてきているので、いっそのこと関数化しては、と思った。「"\n---...---\n"」も同様。処理ブロック毎にコメントがあるのは、大変よいです。
#include <stdio.h>
int main() {
int i, j;
for(i = 1; i < 10; i++) {
for(j = 1; j < 10; j++) {
printf("%d*%d=%d ", i, j, i*j);
}
printf("\n");
}
return 0;
}
#include<stdio.h>
main()
{
char i,m;
for(i=1;i<10;i++){
printf("%dの段",i);
for(m=1;m<10;m++){
printf("%3d|",i*m);
}
printf("\n");
}
}
↑char i, m; とありますが、数値は収まるのであれば int でよいです。というか、お願いですから int にして下さい。
#include<stdio.h>
main(){
int i,j;
int n=9;
for(i=1;i<=n;i++)
printf("\t%d",i);
printf("\n");
for(i=1;i<=n;i++)
printf("\t-----");
printf("\n");
for(j=1;j<=n;j++){
printf("%d :",j);
for(i=1;i<=n;i++)
printf("\t%d",j*i);
printf("\n");
}
}
↑正直、最初の for ループが何をしているのか想像できなかった。軽くコメントがあった方がよいかと。