メモリを自動的に割り付けるgets

こんなくだらないコードでも欲しがる人はそれなりにいるようですので、一応掲載しておきます。

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

#define AGETS_DEFAULT_BUFSIZE 64  /* バッファサイズの既定値 */

char *agets(char **ps)
{
  size_t n = AGETS_DEFAULT_BUFSIZE;
  size_t i;
  int c;
  char *s;

  s = malloc(n);
  if (s == NULL)
    return NULL;

  for (i = 0; (c = getchar()) != EOF; i++)
  {
    if (n - 1 <= i) /* バッファに収まりきらない場合は拡張する */
    {
      char *temp;

      n *= 2;
      temp = realloc(s, n);
      if (temp == NULL)
        goto failure;
      s = temp;
    }
    if (c == '\n') break;
    s[i] = (char)c;
  }
  if (c == EOF && ferror(stdin))
    goto failure;

  s[i] = '\0';
  if (ps != NULL)
    *ps = s;
  return s;

failure:
  free(s);
  return NULL;
}

簡単に解説すると、agets は標準入力から1行分の文字列を読み込みます。読み込んだ文字列は内部で割り付けたメモリブロックに格納されます。その際、改行文字は取り除かれ、終端にはナル文字が付加されます。agets は文字列を指すポインタを返します。また、ps が空ポインタでない場合、*ps に文字列を指すポインタを格納します。エラーが発生した場合は空ポインタを返し、*ps には値を格納しません。なお、agets が返した文字列は、呼び出し側の責任で free を用いて解放してください。

このコードはマルチスレッドに配慮していません。マルチスレッドに対応するには、POSIXの場合には、getchar の代わりに getc_unlocked を使い、flockfile を使って排他制御を行ってください。Windows の場合は _getc_nolock を使うことになります。

この記事のトラックバックURL:

http://www.kijineko.co.jp/trackback/701