CでのLinux関連のgetline()関数の予期しない動作

CでのLinux関連のgetline()関数の予期しない動作
#include <stdio.h>
#include <stdlib.h>
#define MAXLEN 1024

void reverse(FILE *, FILE *);

int main(int argc, char ** argv)
{
  ...
  reverse(fptr, stdout);
  ...

  return 0;
}

void reverse(FILE * instream, FILE * outstream)
{
  char ** buf;
  char * lbuf;
  int counter, i;
  size_t slen;

  counter = 0;

  buf = malloc(MAXLEN * sizeof(char));
  if (buf == NULL)
  {
    fputs("malloc failed\n", stderr);
    exit(EXIT_FAILURE);
  }

  lbuf = NULL;
  while ((counter < MAXLEN) && (getline(&lbuf, &slen, instream) != -1))
  {
    buf[counter] = lbuf;
    counter++;
    lbuf = NULL;
  }


  for (i = counter - 1; i >= 0; i--)
  {
    fputs(buf[i], outstream);
    free(buf[i]);
  }

  free(buf);
}

私はファイルを逆順に印刷するためにこの関数を書いています。

Hello World
How are you ?
what are you doing ?

出力は次のようにする必要があります

what are you doing ?
How are you ?
Hello World

ところで、予期しない動作が発生しました。私はランダムに長い行をスキャンするためにLinux固有のstdio機能を使用しています。getline()問題は、値が4、5、6、...の場合、MAXLEN出力を印刷するときにプログラムがdouble free or corrupt address error abort()特定の機能を提供することです。free()

関数が返したアドレスを調べたところ、geline()4回の繰り返し後に関数が返した最初のバッファのアドレスがgetline()破損しているようです。 2または十分に大きい場合MAXLEN(例:1024)、問題はありません。

入力サンプル私が取った

When to the sessions of sweet silent thought
I summon up remembrance  of things past,
I sigh the lack of many a thing I sought,
And with old woes new wail my dear time's waste:
Then can I drown an eye, unused to flow,
For precious friends hid in death's dateless night
And weep afresh love's long since cancell's woe,

答え1

の型はchar ** buf;スペースを割り当てる配列bufです。pointer to char*char*

buf = malloc(MAXLEN * sizeof(char));

これは、MAXLENポインタ(64ビットCPUではそれぞれ8バイト)ではなく、MAXLEN文字にのみスペースを割り当てます。したがって、後で割り当てられたスペースを超えてアイテムが破損します(重複buf[counter])。

正しい割り当ては次のとおりです。buf = malloc (MAXLEN * sizeof(char *));

通常、私は返されるポインタの種類に応じて割り当てることを好みます。

buf = malloc (MAXLEN * sizeof(*buf));

つまり、「bufモノが指すMAXLEN項目にスペースを割り当てます」これにより、bufタイプを変更したときに発生するエラーを回避できます。

getline()問題の一部ではありません。返されるポインタを小さすぎる配列に保存するだけです。コードが小さなデータセットに対して機能する理由は、malloc()オブジェクトのソートを維持するために割り当てが16バイトまたは32バイトに丸められるためです。どちらも自己使用可能リストに反対するため、コンパイラはユーザー構造の仮定の並べ替えについて合理的な決定を下すことができます。

したがって、(通常)データの最初の2行は大丈夫で、次の2行には次の行の隠しヘッダーが破損し(broken free())、次の行にはテキストデータが破損しています。

関連情報