システムプログラミング序論 演習

演習3: 配列とポインタ

例題1: 引数に与えられたポインタが指すメモリ領域に値を書き込む関数

#include <stdio.h>
#include <stdlib.h>

void plus(int *a, int p, int q)
{
  *a = p + q;
}

int main(int argc, char *argv[])
{
  int x, y, answer;
  int *answerp;

  if (argc != 3) {
    fprintf(stderr, "Missing argument\n");
    return 1;
  }

  x = atoi(argv[1]);
  y = atoi(argv[2]);

  answerp = &answer;
  plus(answerp, x, y);

  printf("%d + %d = %d\n", x, y, answer);

  return 0;
}

例題2: 文字列の中間を指すポインタ

#include <stdio.h>

int my_strcmp(char *s1, char *s2)
{
  char c1, c2;
  while (1) {
    c1 = *s1;
    c2 = *s2;
    if (c1 < c2) {
      return -1;
    } else if (c1 > c2) {
      return 1;
    } else {
      if (c1 == '\0') {
        return 0;
      }
    }
    s1++;
    s2++;
  }
}

int main(int argc, char *argv[])
{
  printf("\"%s\" \"%s\": %d\n", "abc", "def",         my_strcmp("abc", "def"));
  printf("\"%s\" \"%s\": %d\n", "def", "abc",         my_strcmp("def", "abc"));
  printf("\"%s\" \"%s\": %d\n", "Ibaragi", "Ibaraki", my_strcmp("Ibaragi", "Ibaraki"));
  printf("\"%s\" \"%s\": %d\n", "Ibaraki", "Ibaragi", my_strcmp("Ibaraki", "Ibaragi"));
  printf("\"%s\" \"%s\": %d\n", "Tsukuba", "Tsukuba", my_strcmp("Tsukuba", "Tsukuba"));
  printf("\"%s\" \"%s\": %d\n", "$$$", "$$$",         my_strcmp("$$$", "$$$"));
  printf("\"%s\" \"%s\": %d\n", "pqr", "pqrstu",      my_strcmp("pqr", "pqrstu"));
  printf("\"%s\" \"%s\": %d\n", "vwxyz", "vw",        my_strcmp("vwxyz", "vw"));
  printf("\"%s\" \"%s\": %d\n", "", "",               my_strcmp("", ""));
  printf("\"%s\" \"%s\": %d\n", "abc", "",            my_strcmp("abc", ""));
  printf("\"%s\" \"%s\": %d\n", "", "def",            my_strcmp("", "def"));
  return 0;
}

課題1

例題1のプログラムを参考に,整数の配列へのポインタと配列の要素数を引数に受け取って,配列内の全整数の和,最大値,最小値を求める関数を書きなさい. その関数は和,最大値,最小値を書き込むべきメモリ領域へのポインタも引数として受け取るものとする. 具体的には,このプログラムの空いている場所を埋める形でプログラムを作りなさい. このプログラムは sum = の後に和,max = の後に最大値,min = の後に最小値を表示するものとする. できたプログラムを実行し,正しい結果が表示されることを確認しなさい.

課題2

例題2のプログラムを参考に,strncasecmpという文字列比較のためのライブラリ関数に似た処理を実現する関数my_strncasecmpを作成しなさい. my_strncasecmpの中ではライブラリ関数を呼び出してはいけないものとする. my_strncasecmpの処理はmy_strcmpの処理とほとんど同じだが以下の点で異なるものとする.
  • 文字列の先頭の最大n文字目までを比較する.すなわち,2つの文字列の先頭のn文字が同一ならば,それらの文字列は「同じ」とする.
  • アルファベットの大文字と小文字を区別しない.
なお,ライブラリ関数のstrncasecmpは,第一引数の文字列が第二引数の文字列よりも「小さい」場合に,-1ではなく他の負の数を返すことがあり, 「大きい」場合に,1ではなく他の正の数を返すことがあることに注意せよ. 今回作成するmy_strncasecmpは,「小さい」場合には必ず-1,「大きい」場合には必ず1を返すものとする. 具体的には,このプログラムの空いている場所を埋める形でプログラムを作りなさい. できたプログラムを実行し,正しい結果が表示されることを確認しなさい.

課題3

rand関数によって生成される乱数の列の最初の10万個において,RAND_MAXの半分(具体的にはRAND_MAX / 2で計算される値)より大きい数の出現回数と,RAND_MAXの半分以下の数の出現回数を表示するプログラムを作成しなさい. このプログラムはコマンドラインから整数の引数1つを受け取り,最初の乱数を生成する前に,srand 関数によりその整数を乱数の種として指定するものとする. 表示のフォーマットは以下の実行例と同じものにしなさい.すなわち行頭から順に,RAND_MAXの半分より大きい数の出現回数,空白1つ,RAND_MAXの半分より小さい数の出現回数,改行を表示しなさい. 計算機室の端末のMac環境でコンパイルと実行を行いなさい.乱数の種を100と指定したときの出力を実行結果に含めなさい.

備考: もしrand関数が返す乱数が真に乱雑であるならば,大数の法則によって,2つの出現回数はだいたい同じになるはずである.

実行例(Mac端末とは別の環境でコンパイル,実行しているので,Mac端末での結果とは異なる):
$ ./ex3_3 1
49962 50038
$ ./ex3_3 10
50160 49840
$ ./ex3_3 12345
49801 50199
$ ./ex3_3 100
50298 49702
$ 

課題4

発展課題: 単位取得のためには提出は必須ではないが,提出すれば加点する.

コマンドライン引数として第1引数に入力ファイルの名前,第2引数に文字列A,第3引数に文字列Bを受け取り,入力ファイルの中身を,文字列Aをすべて文字列Bに置換して標準出力に出力するプログラム(UNIX の sed コマンドに似たプログラム)を作成しなさい. できたプログラムを実行し,正しい出力が行われることを確認しなさい.

  • ファイルの各行の文字数は変換前も変換後も4095文字以下であることを仮定してよい.
  • 変換前文字列も変換後文字列も255文字以下であることを仮定してよい.
  • 変換前文字列も変換後文字列も制御文字を含まないと仮定してよい.
  • 入力ファイルでは変換前文字列が改行をまたいで出現することはないと仮定してよい.
AとBは同じ長さである場合もあれば,Aのほうが長い場合もあれば,Bのほうが長い場合もある.これら3つの場合すべての実行結果をレポートに含めなさい.

実行例を以下に示す.この例では,作成したプログラムをコンパイルしてできた実行型ファイルの名前を mysed としている. 実行例の入力ファイルと実行例の3通りの文字列A,Bの組を用いて,プログラムが正しく動くことを確認しなさい.

$ cat gnu.txt
  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
$ ./mysed gnu.txt software firmware
  When we speak of free firmware, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free firmware (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the firmware or use pieces of it in new
free programs, and that you know you can do these things.
$ ./mysed gnu.txt software apps
  When we speak of free apps, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free apps (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the apps or use pieces of it in new
free programs, and that you know you can do these things.
$ ./mysed gnu.txt software commercial-programs
  When we speak of free commercial-programs, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free commercial-programs (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the commercial-programs or use pieces of it in new
free programs, and that you know you can do these things.
$