[an error occurred while processing this directive] [an error occurred while processing this directive]

エラー処理 (C)

C 言語には、try ... catch みたいな便利な仕組みがありません。 だから、エラー処理を含むコードはちょっと工夫が必要です。

問題

関数 f() を呼ぶためには、A, B, C の三つの構造体を用意する必要があります。 それぞれ、初期化処理と終了処理が必要です。 エラー処理を含まないコードはこんな感じ。
void do_f(){
  struct A *a;
  struct B *b;
  struct C *c;

  a = create_a();
  b = create_b();
  c = create_c();

  f(a,b,c);

  free_c(c);
  free_b(b);
  free_a(a);
}
create_a() は中で malloc() を呼んで、初期化を行い、a のアドレスを返します。 ただし初期化でエラーが発生すると、NULL を返します。
a,b は無事確保できたのに、c の確保に失敗した場合は、 メモリリークしないように a, b を解放しなければいけません。

簡単に思いつく回答

void do_f(){
  struct A *a;
  struct B *b;
  struct C *c;

  a = create_a();
  if(a == NULL) return;
  b = create_b();
  if(b == NULL){
    free_a(a);
    return;
  }
  c = create_c();
  if(c == NULL){
    free_b(b);
    free_a(a);
    return;
  }

  f(a,b,c);

  free_c(c);
  free_b(b);
  free_a(a);
}
意味的には OK ですが、free_a() を色んなところに書かないといけなかったりして、あまりきれいではありません。

goto を使う

void do_f(){
  struct A *a;
  struct B *b;
  struct C *c;

  a = create_a();
  if(a == NULL) return;
  b = create_b();
  if(b == NULL) goto free_a;
  c = create_c();
  if(c == NULL) goto free_c;

  f(a,b,c);

  free_c(c);
free_b:
  free_b(b);
free_a:
  free_a(a);
}
goto を使うことで、かえってコピペの少ない、きれいなコードになっています。 資源の確保と解放が逆順になっているのがポイント。
(a,b,c の順で確保し、c,b,a の順で解放)

do .. while(0) を使う

ちょっと奥の手で、do {} while (0); を使うと、ブロックを途中で抜けることが出来ます。
void do_f(){
  struct A *a = NULL;
  struct B *b = NULL;
  struct C *c = NULL;

  do {
    a = create_a();
    if(a == NULL) break;
    b = create_b();
    if(b == NULL) break;
    c = create_c();
    if(c == NULL) break;

    f(a,b,c);
  } while(0);

  if(c) free_c(c);
  if(b) free_b(b);
  if(a) free_a(a);
}
ループのようですが、while の条件が 0 (偽)なので、実は一回しか実行されません。
最後のところでは a, b, c をフラグのように使っています。初期化で NULL を代入しているのもポイント。
[an error occurred while processing this directive]