2023 年度「数学特論」 2024-02-09

§16.1 ワイルドカードを用いた複数ファイルの指定

コマンドプロンプトで、cd 23tok のあと dir を実行するとファイルの一覧が出る。

dir *.c」を実行してみよ。 すると、ファイルの名前が .c で終わるファイルだけの一覧が出る。 この「*」は、0 文字以上の任意の文字列を表す。 ほかに、「?」は任意の一文字を表す。 たとえば、renshu...c という名前のファイルがあるとして、 「dir renshu?.c」とすると、renshu1.c, renshu2.c などは出るが、 renshu12.c は出ない。 この「*」「?」を「ワイルドカード」と呼ぶ。

§16.2 Windows のアプリケーション find

Windows についている find は、指定された文字列を複数ファイルから探しだすものである。 「find "文字列" ファイル名」として実行する。 「find "printf" *.c」「find "strcmp" *.c」など、実行してみよ。

注意:unix の find はまったく違うプログラムである。

§16.3 find のように動く自作プログラム

§11.1 のプログラムでは、 コマンドライン引数が「?」「*」を含んでいると、 それらは“展開”されるのだった。 これを利用すると、find のように動くプログラムが書ける。

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

#define MAXLINE 1024

int main(int argc, char *argv[]) {
  int i, first;
  FILE *in;
  char line[MAXLINE];

  if (argc == 1) {
    fprintf(stderr, "使い方が違います.\n");
    exit(1);
  }
  for (i = 2; argv[i] != NULL; i++) {
    if ((in = fopen(argv[i], "rt")) == NULL) {
      fprintf(stderr, "%s が開けません.\n", argv[i]);
      exit(1);
    }
    first = 0;          /* そのファイルでまだ見つかっていなければ 0 */
    while (fgets(line, MAXLINE, in) != NULL) {
      if (strstr(line, argv[1]) != NULL) {  /* argv[1] を line が含んでいれば */
        if (first == 0) {
          printf("== %s ==\n", argv[i]);    /* ファイル名は一度だけ表示 */
          first = 1;
        }
        fputs(line, stdout);                /* その行を表示 */
      }
    }
    fclose(in);     /* たくさんのファイルを開くので、済んだら閉じる必要あり */
  }
}

関数 strstr(char *string, char *key) は、 keystring に含まれていれば、 最初に含まれている位置を返す。含まれていなければ NULL を返す。

§16.4 文字列の一部分を移動するプログラム

0123456789」の「2345」を文字 8 の前に移動するプログラムを書いてみよう。 「0167234589」となれば成功である。 もう一つ同じ長さの配列をとれるなら簡単だが、それはできないものとする。

これには、昔から知られているアルゴリズムがある。 まず、2345 を反転して 5432 とする。 67 を反転して 76 とする。 これで「0154327689」となった。 最後にこれらを合わせた 543276 を反転させると「0167234589」となる。 反転は、ソートプログラムで作った関数 swap() の要領でできる。

#include <stdio.h>

char str1[] = "0123456789";
char str2[] = "0123456789";

void move(char *str, int from, int to, int here);

int main() {
  puts(str1);
  move(str1, 2, 5, 8);
  puts(str1);
  putchar('\n');
  puts(str2);
  move(str2, 5, 8, 2);
  puts(str2);
}


void move(char *str, int from, int to, int here) {
  int i, j;
  char tmp;

  i = from; j = to;
  while (i < j) {
    tmp = str[i]; str[i] = str[j]; str[j] = tmp; i++; j--;
  }
  if (to < here) {
    i = to + 1; j = here - 1;
    while (i < j) {
      tmp = str[i]; str[i] = str[j]; str[j] = tmp; i++; j--;
    }
    i = from; j = here - 1;
    while (i < j) {
      tmp = str[i]; str[i] = str[j]; str[j] = tmp; i++; j--;
    }
  } else if (here < from) {
    i = here; j = from - 1;
    while (i < j) {
      tmp = str[i]; str[i] = str[j]; str[j] = tmp; i++; j--;
    }
    i = here; j = to;
    while (i < j) {
      tmp = str[i]; str[i] = str[j]; str[j] = tmp; i++; j--;
    }
  }
}

move(2, 8, 5) などを実行した場合の動作は保証されない。

終わりに

これが、私が金沢大学の授業で作る最後のプリントです。 長い間ありがとうございました。 SDG (= Soli Deo gloria)。


岩瀬順一