第26回
データ構造(5)~ポインタを使った文字列処理関数を作る

関数の動作確認

ポインタを使った文字列処理関数を紹介しました。これらの動作を確認するために、リスト7のようなプログラムを作ってみました。非常に単純なものですが、自分で作った関数をテストする場合の参考にもなるでしょう。

なお、サンプルでは標準関数と区別するため、関数名の前に"ex_"を付けています。

実行形式ファイルはMS-DOSの.exe形式で、LSI-Cでコンパイルしたものです。実行すると、以下のように表示されます。
C:\;Clang\;exe>ex26.exe
Test of function [strlen] : 8
Test of function [strcpy] : abcdefgh -> abcdefgh
Test of function [strcat1] : abcdefghHello!
Test of function [strcat2] : abcdefghHello!
C:\;Clang\;exe>

リスト7:関数の動作をテストするためのプログラム(ex26.cEX26.EXE
#include <stdio.h>
#include <stdlib.h>    /* malloc関数の定義 */

/* 関数のプロトタイプ宣言 */
unsigned long int ex_strlen(const char *);
char * ex_strcpy(const char *, char *);
char * ex_strcat1(char *, const char *);
char * ex_strcat2(const char *, const char *);

/* --------------------------------------
   main -- 各関数の動作テスト
   -------------------------------------- */
int main(void)
{
  char str1[] = "abcdefgh";    /* 8文字 */
  char str2[20];
  char str3[] = "Hello!";
  char str4[] = " This is a test string of functions.";

  printf("Test of function [strlen] : %d\n", ex_strlen(str1));

  ex_strcpy(str1, str2);
  printf("Test of function [strcpy] : %s -> %s\n", str1, str2);

  ex_strcat1(str2, str3);
  printf("Test of function [strcat] : %s\n", str2);

  ex_strcat2(str2, str4);
  printf("Test of function [strcat] : %s\n", str2);

  return (0);
}

/* --------------------------------------
   strlen -- 文字列の文字数を返す
   -------------------------------------- */
unsigned long int ex_strlen(const char * s)
{
  unsigned long int i;  /* カウンタ */

  i = 0;                /* カウンタを初期化 */
  while (*s != '\0') {  /* 文字列の終端まで繰り返す */
    s++;                /* ポインタを進める */
    i++;                /* カウンタを加算 */
  }
  return (i);           /* カウンタを返す */
}

/* --------------------------------------
   strcpy -- 文字列のコピー
   -------------------------------------- */
char * ex_strcpy(const char *s, char *d)
{
  char *r;
  r = d;
  while (*s != '\0') {
    *d++ = *s++;          /* 1文字コピーしてポインタを進める */
  }
  *d = '\0';
  return (r);
}

/* --------------------------------------
   strcat -- 文字列の連結
   -------------------------------------- */
char * ex_strcat1(char *s1, const char *s2)
{
  char *p;   /* 作業用のポインタ */
  p = s1;    /* s1の値を受け取る */

  /* p(s1)の末尾までポインタを進める */
  while (*p != '\0') {
    p++;
  }
  /* p(s1)の末尾にs2をコピー */
  while (*s2 != '\0') {
    *p++ = *s2++;
  }
  *p = '\0';
  return (s1);
}

/* --------------------------------------
   strcat -- 文字列の連結(メモリ確保版)
   -------------------------------------- */
char * ex_strcat2(const char *s1, const char *s2)
{
  static char *ret;    /* 戻り値のポインタを静的に宣言 */
  char *p;             /* 作業用のポインタ */
  /* 必要なバイト数を確保する */
  p = malloc(ex_strlen(s1) + ex_strlen(s2) + 1);
  ret = p;    /* 戻り値に値を代入 */

  while (*s1 != '\0') {
    *p++ = *s1++;
  }
  while (*s2 != '\0') {
    *p++ = *s2++;
  }
  *p = '\0';
  return (ret);
}

あとがき

今回は、staticキーワードやmalloc関数によるメモリの確保など、このコラムでまだ紹介していない機能を使いました。これらについては、回を追って取り上げます。今の段階では、詳しく理解しなくても構いません。

大切なのは、「細部にこだわらず、まず大まかなイメージを把握する」ことです。そして大枠を理解したら、試して失敗しながら、細部の理解へと進みましょう。次回は、ちょっと難しくなります。