読者です 読者をやめる 読者になる 読者になる

ゆとりーなの日記

日記的な事を書いて行くと思はれる

リストとかの話

yappy氏のカンニング幇助疑惑の話はどうやら露骨に解答らしきものを載せなければいいとの話だったみたいなので、これなら耐えそうだということでリストの話でも。
さてさてお題はCtrl+Dを押すまでの数値を取って、それら全てを表示するというもの。授業資料を軽く見たところ、こんな感じだと受信しました。

struct numbers {
  int num_;
  struct numbers *next_;
};

まずはこんな感じの構造体を作るわけです。ここまではまあいいです。で、こいつをどう使うのか、資料を読み進めると、

struct numbers *begin = NULL;

グローバル変数でした。私のかわいいグローバル変数がこんなところにさらされていいわけありません。
続いて挿入のコードを見てみると、

int push_back(int num) {
  struct numbers *cur, *temp, *end;
  for (cur = begin, end = NULL; cur; end = cur, cur = cur->next_) {
  }
  temp = alloc(sizeof(*temp));
  if (!temp) {
    return 0;
  }
  temp->num_ = num;
  if (begin && cur == begin) {
    temp->next_ = begin;
    begin = temp;
  } else if (!begin) {
    begin = temp;
  } else {
    temp->next_ = cur;
    end->next_ = temp;
  }
  return 1;
}

最初見たとき何やってるのかよく分からなかったのですが、どうやら先頭から順次まわしていって、最後の要素に追加的なことをやっているみたいです。
何度も言いますが、最初見た時はこのコードが意味不明且つ授業を全く聞いていなかったので、私が書いたコードはこんなになってしまいました。

// numbersは適当にtypedefしとく
typedef struct list_ {
  numbers *begin_;
  numbers *cur_;
  numbers *end_;
} list;

なんとなくリスト型を作ってみました。グローバル変数は使わずに、メイン関数内に作ります。

int main(void) {
  list l;
}

初期化関数をさりげなく用意しておきます。

void init_list(list * const l) {
  l->begin_ = l->cur_ = l->end_ = NULL;
}

挿入です。

int push_back(list * const l, const int num) {
  numbers *temp = alloc(sizeof(*temp));
  if (!temp) {
    return 0;
  }
  temp->num_ = num;
  temp->next_ = l->end_;
  if (!l->cur_) {
    l->begin_ = temp;
  } else {
    l->cur_->next_ = temp;
  }
  l->cur_ = temp;
  return 1;
}

多分こんなのでいいと思います。挿入のたびにリストをまわさない分幸せな気がします。
ついでに出力もなんとなくやってみました。

void for_each(list * const l, void (*func)(numbers *)) {
  numbers it;
  for (it = l->begin_; it != l->end_; it = it->next_) {
    (*func)(it);
  }
}

void print_list(const numbers * const it) {
  printf("%d", it->num_);
}

int main(void) {
  list l;
  init_list(&l);
  // 要素挿入とか
  for_each(&l, &print_list);
  return 0;
}

まあconst付いてると型が違うとか警告出ますがほっといて。
まぁ授業聞いてないとロクなものができないという典型例ですね。