Ex10

From Prog0

Jump to: navigation, search

演習第10回

Contents

演習問題

主な内容

  • 標準入出力・エラー出力
  • リダイレクション(リダイレクト)
  • パイプ

以下の問題を解いて期限内に解答を提出してください。

出席確認

演習時間中に出席確認をLMS上の「演習出欠」で行ってください。出席確認用のパスワードは演習時間のどこかのタイミングで提示されます。


A問題

A-1 パイプ、リダイレクション(リダイレクト)

ファイル名: ex10a1.txt

du は "disk usage" の略で、ファイルやディレクトリのサイズを表示するコマンドである。例えば

% du -s ~/Prog0/*

とすることで、"Prog0"ディレクトリの配下にあるファイルやディレクトリのサイズのリストを得ることができる。

以下の処理:

  • 上の du コマンドの標準出力をパイプで sort コマンドに渡す
  • その sort コマンドでは、du が出力するサイズの降順でソートする
  • その sort コマンドの標準出力の上から5番目までをファイル ex10a1.txt に書き出す

を、パイプ( | )、出力リダイレクション( > ) を組み合わせた1行の命令で行ってください。

ファイルの提出:

  • そうして出来上がったファイル ex10a1.txt を開いて結果を確認し、
  • 最後に、どのような命令を使用したか、採点の人がわかるよう、 ex10a1.txt の末尾に自分の使用した命令(パイプやリダイレクションを含む全体)を追記して、 ex10a1.txt を提出してください。

A-2 二次元配列、標準エラー出力

ファイル名: ex10a2.c

以下は2行3列の行列matの指定された各要素に正の整数dataを順に入力して全要素数MAX回入力後に、[実行例1]のようにその行列を表示するプログラムである。

このプログラムでは、matの行数GYOと列数RETSUの値はマクロで定義しており、dataに負の数を入力した場合に、[実行例2]のようにエラーメッセージを出力して処理を終了するようになっている。この時、メッセージの出力先は標準エラー出力(stderr)である。また、ハンドアウトLec10-4の例と異なり、forの二重ループでなくwhile文のみで二次元配列の要素を入力できるようにしている。下記の空白部を埋めて実行例のような動作を示すプログラムを完成させ、提出すること。


#include <stdio.h>
#define GYO 2
#define _______

int main(){
  int i,j,k;
  int data,mat[GYO][RETSU];
  int MAX=GYO*RETSU;
 
  k=0;
  while(k<MAX){
    i=k/RETSU;
    j=____%____;
    printf("%d行%d列の要素の値を正の整数で入力してください\n",____,____);
    scanf("%d",&data);
        
    if (data <0){
      _______(_______,"Error!負の値が入力されました\n");
      _______;
    }
    mat[i][j]=data;
    k+=1;
  }
  if (data >=0){
    printf("行列の値は\n");
    for (i=0; i< GYO; i++){
      for (j=0; j < RETSU; j++){
        printf(_________);
      }
      __________
    }
  }
  return 0;
}

[実行例1]

% ./a.out 
1行1列の要素の値を正の整数で入力してください
1
1行2列の要素の値を正の整数で入力してください
2
1行3列の要素の値を正の整数で入力してください
0
2行1列の要素の値を正の整数で入力してください
4
2行2列の要素の値を正の整数で入力してください
5
2行3列の要素の値を正の整数で入力してください
8
行列の値は
1 2 0
4 5 8
%

[実行例2]

% ./a.out 
1行1列の要素の値を正の整数で入力してください
7
1行2列の要素の値を正の整数で入力してください
11
1行3列の要素の値を正の整数で入力してください
-4
Error!負の値が入力されました
%


B問題

B-1 成績処理プログラム

ファイル名: ex10b1.c

2次元配列を使った成績処理を考える。成績データはファイル(score.text)に保存されており、下記のよう1行目には科目数と学生数が、それ以降の行には学生毎の科目の成績が書き込まれているものとする。ここで、このデータをリダイレクションにより読み込み、各科目を列、各学生を行に対応させた成績を2次元配列に格納して実行例のように表示するプログラムを作成しなさい。この際、科目数は最大9、学生数は最大20としてマクロで定義して、2次元配列の定義中に使用すること。 また、学生毎と科目毎の平均点をそれぞれ求めて、実行例にそった形で配列と同時に表示させなさい(実行例の最終行が各科目に対する学生平均、右端が各学生に対する科目平均を表している)。なお、成績データとして、以下のデータを score.txt というファイル名で自分の ~/Prog0/Ex10 に保存して使用すること。

[score.txt]

4 6
52 64 78 72
82 58 84 74
95 78 83 92
44 98 50 66
68 35 48 52
89 75 92 84

[実行例]

% ./a.out < score.txt
科目数:4, 学生数:6
 52    64    78    72   : 66.5
 82    58    84    74   : 74.5
 95    78    83    92   : 87.0
 44    98    50    66   : 64.5
 68    35    48    52   : 50.8
 89    75    92    84   : 85.0
 71.7  68.0  72.5  73.3 
%

B-2 標準エラー出力

ファイル名: ex10b2.c

入力された整数値に対して各桁の数字を逆順にして出力する(「123」と入力したら「321」と出力する)処理を繰り返し行い、「0」が入力されたらそのまま終了、負数が入力されたらエラーメッセージを出力して終了するプログラムを作成して提出しなさい。

この時、[実行例(リダイレクションあり)]のように、実行結果をファイル名[reverse.txt]にリダイレクションした際でも入力を促すメッセージやエラーメッセージはターミナル上に表示されるようにしつつ、リダイレクション先のファイルには処理結果のみが書き込まれるようにすること (出力ファイルreverse.txtを作成した後、ファイルに出力結果のみが記載されている事も確認するようにすること)。


[実行例(リダイレクションなし)]

% ./a.out 
Enter a number: 1234
4321
Enter a number: 76
67
Enter a number: 543
345
Enter a number: -4
An error occurred!
%


[実行例(リダイレクションあり)]

% ./a.out > reverse.txt
Enter a number: 1234
Enter a number: 76
Enter a number: 543
Enter a number: -4
An error occurred!
% cat reverse.txt
4321
67
345
%

B-3 画像の上下反転

ファイル名: ex10b3.c

以下に、プログラムで画像を上下反転させるための手順とそのプログラムのソースがあります。 プログラム中の下線部を埋めて完成させなさい。

なお、実行ファイル名は gflpud とすること(以下の実行例とハンドアウトを参照)。

手順:

  1. 画像情報を保持するための2次元配列とその他の変数の宣言
  2. カウンタ変数の宣言
  3. 画像サイズ、濃淡情報の読み込み及びエラーチェック
  4. 画像データの読み込み及びエラーチェック
  5. データ形式の出力
  6. 画像サイズ、濃淡情報の出力
  7. 画像データの出力(2重ループを使い、上下を逆にする)

/*
* pgm形式の画像データを受け取って,上下反転する。
*
* 終了コード
* 0 : 正常終了
* 1 : 入力データの形式がおかしい
* 2 : 入力データの画素数または階調が範囲外
* 3 : 入力データがおかしいかデータが揃わないうちにEOFになった
* 4 : 入力データの画素の値が範囲外
*/
#include <stdio.h>
#include <stdlib.h>
#define MSIZE 800

int main()
{
  int dat[MSIZE][MSIZE];
  int i, j, width, height, maxval;
  /* 入力 */
  /* ファイル形式のチェック */
  /* この部分はプログラミング入門の範囲を越えているので、このまま使って下さい。*/
  if (getchar() != 'P' || getchar() != '2'){
    fprintf(stderr, "データの形式が違います\n");
    exit(1);
  }

  /* x,yそれぞれの画素数を得る */
  scanf("%d %d", &width, &height);
 
  /* Maxval(白の値)を得る */
  scanf("%d",&maxval);
 
  /* 画素数が範囲外の場合 */
  if (width < 1 || height < 1 || width > MSIZE || height > MSIZE){
    fprintf(stderr, "設定サイズが範囲外です\n");
    exit(2);
  }

  /* Maxvalが範囲外 */
  if (maxval < 1 || maxval >= 65536){
    fprintf(stderr, "階調が範囲外です\n");
    exit(2);
  }

  /* 実際のデータ入力 */
  for (i = 0; i < height; i++){
    for (j = 0; j < width; j++){
      /* scanf入力データがおかしいかEOFになった場合 */
      if(scanf("%d",&dat[i][j]) != 1){
        fprintf(stderr, "データ入力に異常があります\n");
        exit(3);
      }
      /* データが範囲外 */
      if (dat[i][j] < 0 || dat[i][j] > maxval){
        fprintf(stderr, "データが異常でした\n");
        exit(4);
      }
    }
  }
  /* これより上はどのプログラムもほぼ同じ */

  /* 出力 */
  /* 最初にP2とx,yの画素数、Maxvalを出力 */
  printf("P2\n");
  printf("%d %d\n", width, height);
  printf("%d\n", maxval);

  /* 実際のデータ出力 */
  for (i = 0; i < height; i++){
    for (j = 0; j < width; j++){
      printf("%2d ",dat[________][________]);
    }
    printf("\n");
  }
  return 0;
}

以下のようにして、テスト用画像ファイル(.pgm)を自分の ~/Prog0/Ex10 にコピーして使用すること:

% cd ~/Prog0/Ex10 
% cp /home/course/prog0/public_html/2024/ex/source/ex10/feep64.pgm .
% cp /home/course/prog0/public_html/2024/ex/source/ex10/neko64.pgm .
% cp /home/course/prog0/public_html/2024/ex/source/ex10/ajisai64.pgm .
% cp /home/course/prog0/public_html/2024/ex/source/ex10/Nakaniwa64.pgm .

テスト用画像ファイルの情報:

feep64.pgm:   Netpbm image data, size = 24 x 7, greymap, ASCII text
neko64.pgm:   Netpbm image data, size = 265 x 202, greymap, ASCII text
ajisai64.pgm: Netpbm image data, size = 437 x 305, greymap, ASCII text

"size"の部分が画像の横縦のピクセル数である。

コピーしたテスト用画像ファイルは以下のコマンドで表示することができる。

% display feep64.pgm

Image:Ex12B_P01_0.gif

"feep64.pgm"は非常に小さい画像のため、ディスプレイ上では注意すること。

この実行例は拡大した画像を表示している。"neko64.pgm"、"ajisai64.pgm" 、"Nakaniwa64.pgm"についても、表示して確認するとよい。

[プログラムの実行例1]

% gcc ex10b3.c -o gflpud  
% ./gflpud < feep64.pgm
P2
24 7
63
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
0 12  0  0  0  0  0 29 29 29 29  0  0 46 46 46 46  0  0 63  0  0  0  0
0 12  0  0  0  0  0 29  0  0  0  0  0 46  0  0  0  0  0 63  0  0  0  0
0 12 12 12  0  0  0 29 29 29  0  0  0 46 46 46  0  0  0 63 63 63 63  0
0 12  0  0  0  0  0 29  0  0  0  0  0 46  0  0  0  0  0 63  0  0 63  0
0 12 12 12 12  0  0 29 29 29 29  0  0 46 46 46 46  0  0 63 63 63 63  0
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
%

[プログラムの実行例2]

% ./gflpud < feep64.pgm | display -

Image:Ex12B_P01_1.gif

[プログラムの実行例3]

% ./gflpud < neko64.pgm | display -

Image:neko64_upsidedown.gif

Extra問題

E-1 コントラストを上げる

ファイル名: ex10e1.c

コントラストを上げるプログラムを作成しなさい。

「コントラストを上げる」とは下の実行例の画像を見ても分かるように、各点の明るさ(輝度)を、明るい物はより明るく、暗い物はより暗くする事で、 全体として元画像よりコントラストが高い画像(白黒がはっきりした画像)を得ることです。

プログラムの実行ファイル名は gcont として作成すること。

「考え方」

  • 倍率をマクロCOEFにて定義(#define COEF 1.5 のように)
  • 濃淡の幅Maxvalの半分Maxval/2を基準に、ある点の明るさが
    • Maxval/2以上(明るい)の場合、点の明るさをCOEF倍する
    • Maxval/2未満(暗い)の場合は、点の明るさを1/COEF倍する
  • また、補正後の値がMaxvalを超えた場合は値をMaxvalとする
  • 最終的な値は整数(切り捨て)とする

[例](例はCOEFを1.5とした時の実行例)

% display Nakaniwa64.pgm
 元画像                                                              
 Image:Nakaniwa64.gif

[プログラムの実行例]

% ./gcont < Nakaniwa64.pgm | display -
 コントラストを上げた画像
 Image:Nakaniwa64co.gif

課題提出上の注意事項

解答ファイルはmenuコマンドを使って提出してください。以下のようにmenuコマンドを実行し、表示されるメッセージに沿って操作すること。

% ~prog0/bin/menu

menuコマンドは、解答ファイルが ~/Prog0/Ex## のディレクトリに指定されたファイル名で置かれているものとして処理します。正常に提出された場合は ○ が、何らかのエラーが生じた場合は × が表示されます。

解答の提出期間は以下のとおりです。

問題提出受付開始提出〆切
A問題 演習日の6日前の午後9時演習終了時刻
B, Extra問題 演習日の6日前の午後9時演習日の6日後の午後9時

提出は〆切前であれば何度でもやり直すことができます。再提出すると、前に提出したファイルは新しい内容で上書きされます。

Personal tools