C99に対応した標準Cライブラリの実装レポートを行っていきます。

プロフィール 

Author:高木信尚

ホームページ
ブログ

最近の記事 

最近のコメント 

最近のトラックバック 

月別アーカイブ 

カテゴリー 

友達申請フォーム 

この人と友達になる

ホーム 全記事一覧 次ページ >>

 

2008/07/06 21:08|

 

strncmp関数も、strncat関数と同様、素直な仕様かと思います。strcmp関数に文字数制限の判定だけを追加すれば実現できそうです。それでは、実装です。

#include <stddef.h>

int strncmp(const char *s1,
            const char *s2, size_t n)
{
  register const unsigned char *ss1, *ss2, *t;
  for (ss1 = (const unsigned char*)s1,
      ss2 = (const unsigned char*)s2,
      t = ss1 + n;
      ss1 != t && *ss1 == *ss2 && *ss1 != '\0';
      ss1++, ss2++)
    ;
  return *ss1 - *ss2;
}

これも、strcmp関数と見比べていただければ、動作の違いがよくわかるかと思います。

2月から長々と取り組んできた<string.h>ヘッダの内容ですが、これで一通り終わり(のはず)です。次回からは、シグナル処理を扱う予定です。
2006/05/05 11:14|文字列操作TB:0CM:0

 

今回はstrncat関数です。この関数は、strcat関数の文字数制限版といった位置付けですが、strcpy関数の文字数制限版であるstrcpy関数とは動作がかなり異なります。

strncpy関数では、コピー元の文字列が文字数に満たない場合は、残りの領域をナル文字で埋めていました。また、コピー元の文字列が指定した文字数より長い場合には、末尾のナル文字は付加されませんでした。

しかし、strncat関数は、残りの領域をナル文字で埋めることもなければ、末尾にナル文字が付加されないこともありません。どちらかといえば、より直感的でわかりやすい仕様だといえます。それでは実装です。

#include <stddef.h>

char *strncat(char * __restrict__ s1,
              const char * __restrict__ s2, size_t n)
{
  register char *ss, *t;
  for (ss = s1; *ss != '\0'; ss++)
    ;
  for (t = ss + n;
      ss != t && (*ss = *s2) != '\0';
      ss++, s2++)
    ;
  if (ss == t)
    *ss = '\0';
  return s1;
}

strcat関数およびstrncpy関数と比べていただければ、動作の違いを把握していただけるかと思います。
2006/05/05 11:00|文字列操作TB:0CM:0

 

あまりにものらくらやってきたので、どの関数がまだだったのか、把握し切れているかどうか不安なのですが、<string.h>ヘッダに関しては、strncpy、strncat、strncmp関数で終わりだったかと思います。過不足に気づかれた方はご指摘ください。

というわけで、今回はstrncpy関数です。strncpy関数の仕様は、何となく変なのですが、末尾のナル文字が格納されることが保障されません。また、s2文字列がより短い場合、残りの部分にナル文字が書き込まれます。それでは、実装を見てみましょう。

#include <stddef.h>

char *strncpy(char * __restrict__ s1,
              const char * __restrict__ s2, size_t n)
{
  register char *ss, *t;
  for (ss = s1, t = ss + n;
      ss != t && (*ss = *s2) != '\0';
      ss++, s2++)
    ;
  for (; ss != t; ss++)
    *ss = '\0';
  return s1;
}

ご覧の通り、見たままの内容ですが、他の関数同様、nをデクリメントするのではなく、終端を指すポインタtを宣言して、文字数を管理するようにしています。

2006/05/04 00:20|文字列操作TB:0CM:2

 

strspn関数は、strcspn関数とよく似ていますが、条件が逆になります。すなわち、指定した文字群の文字だけで構成される先頭部分の長さを求めます。言い換えれば、指定した文字群に含まれない文字が最初に現れた位置の添え字を返します。

機能は似ているのですが、実現方法はstrcspn関数とは結構違います。実装を見てみましょう。

#include <stddef.h>

size_t strspn(const char *s1, const char *s2)
{
  register const char *ss1 = s1, *ss2;
  if (*s2 != '\0') {
    for (register int c; (c = *ss1) != '\0'; ss1++) {
      for (ss2 = s2; *ss2 != '\0'; ss2++)
        if (c == *ss2)
          break;
      if (*ss2 == '\0')
        break;
    }
  }
  return ss1 - s1;
}

strcspn関数では、s1文字列の各文字が、s2文字列のどれかと一致した時点で即ループを抜ければよかったのですが、strspn関数では、s2文字列のどの文字とも一致しないことを確認しなければなりません。そのため、やや条件判定が複雑になっています。
2006/05/03 12:06|文字列操作TB:0CM:0

 

<string.h>ヘッダの関数が続いていますが、この辺で少しピッチを上げて、次のヘッダに早く移りたいと思います。

今回は、strcspn関数ですが、前回のstrpbrk関数とやっていることは大差ありません。strpbrk関数は、文字列の中から指定した文字群に含まれる文字を探し、最初に見つかった位置を返しますが、strcspn関数は、指定した文字群以外から構成される先頭部分の長さを求めます。つまり、指定した文字郡に含まれる文字が最初に現れた位置の添え字を返すことになります。

それでは実装です。

#include <stddef.h>

size_t strcspn(const char *s1, const char *s2)
{
  register const char *ss1 = s1;
  for (register int c; (c = *ss1) != '\0'; ss1++)
    for (register const char *ss2 = s2; *ss2 != '\0'; ss2++)
      if (c == *ss2)
        goto quit;
quit:
  return ss1 - s1;
}

s1の値を文字する必要があるため、いったんss1で受けてはいますが、それ以外はstrpbrk関数とほぼ同じです。後は、返却値が異なるので、return文の式が変わっています。ループからの脱出は、直接returnで抜けてもよいのですが、それは結局、コンパイル時の最適化でreturn ss1 - s1;のところに分岐することを期待しているので、だったら、最初からgotoで記述することにしました。
2006/05/03 11:35|文字列操作TB:0CM:0

ホーム 全記事一覧 次ページ >>

ブログ内検索 

お勧め書籍 

RSSフィード 

リンク 

このブログをリンクに追加する

Powered By FC2ブログ 

Powered By FC2ブログ
ブログやるならFC2ブログ

Copyright(C) 2006 TAKAGI Nobuhisa All rights reserved.
Powered by FC2ブログ. 無料ホームページ アフィリエイト レンタルサーバー FC2ブログ 一戸建て template designed by 遥かなるわらしべ長者への挑戦.