みずまずぷろぐらみんぐ日記

日々学んだことや頭に浮かんだことを、そこはかとなく書き連ねます

AGC013 A Sorted Arraysとgoto 文とエラー

こんにちはー、みずまずです^^

AGCの過去問を解いていたら、goto 文使用時の注意点に気づいたので書いていきますね。


今回扱う問題はこちら↓
atcoder.jp


N=1,2(配列の要素が2個まで)ならどうしたって配列Aは単調非減少か単調非増加になるので、その場合はあれこれ処理するより先にgotoで最後の出力の文までワープできるようにしたくて、こんな感じのコードを書きました↓

#include <bits/stdc++.h>
using namespace std;

int main() {
  int n;
  cin >> n;
  int answer = 1;
  vector<int> a(n);
  if (n == 1 || n == 2) goto OWA;
  for (int i = 0; i < n; i++) cin >> a[i];
  int zogen = 0;//増加1→、減少-1→、初期値→0
  for (int i = 1; i < n; i++) {
    if(zogen == 1 && a[i-1] <= a[i]) continue;
    else if(zogen == 1 && a[i-1] > a[i]) {
      answer++;
      zogen = 0;
    }else if(zogen == -1 && a[i-1] < a[i]) {
      answer++;
      zogen = 0;
    }else if(zogen == -1 && a[i-1] >= a[i]) continue;
    else if(zogen == 0 && a[i-1] < a[i]) zogen = 1;
    else if(zogen == 0 && a[i-1] > a[i]) zogen = -1;
  }
  OWA:
  cout << answer;
}


が、これを実行するとエラーが……。

./Main.cpp: In function ‘int main()’:
./Main.cpp:24:3: error: jump to label ‘OWA’
   24 |   OWA:
      |   ^~~
./Main.cpp:9:30: note:   from here
    9 |   if (n == 1 || n == 2) goto OWA;
      |                              ^~~
./Main.cpp:11:7: note:   crosses initialization of ‘int zogen’
   11 |   int zogen = 0;//増加1→、減少-1→、初期値→0
      |       ^~~~~


goto 文関連のエラーっぽいですが、なぜかint型の変数zogen(変数のネーミングセンスは大目に見てください)も指摘されています。
"変数の初期化を横断している"みたいな感じですかね。

うーん、こんな時は
goto 文 - cppreference.com


説明欄とその1つ目の例がそれっぽい?

変数の宣言はできる(変数のスコープに入ることはできる)けど、初期化はできないよ
……ってことかな。

試しに以下のようにzogenの宣言の行をgotoより上に持ってきてあげたら無事通りました。

#include <bits/stdc++.h>
using namespace std;

int main() {
  int n;
  cin >> n;
  int answer = 1;
  vector<int> a(n);
  int zogen = 0;//増加1→、減少-1→、初期値→0
  if (n == 1 || n == 2) goto OWA;
  for (int i = 0; i < n; i++) cin >> a[i];
  for (int i = 1; i < n; i++) {
    if(zogen == 1 && a[i-1] <= a[i]) continue;
    else if(zogen == 1 && a[i-1] > a[i]) {
      answer++;
      zogen = 0;
    }else if(zogen == -1 && a[i-1] < a[i]) {
      answer++;
      zogen = 0;
    }else if(zogen == -1 && a[i-1] >= a[i]) continue;
    else if(zogen == 0 && a[i-1] < a[i]) zogen = 1;
    else if(zogen == 0 && a[i-1] > a[i]) zogen = -1;
  }
  OWA:
  cout << answer;
}


ちなみに初期化が駄目以外にもVLA*1VM*2のスコープにはそもそも入ることもできないってことで、試しに配列の宣言" vector a(n); " を " goto OWA; " の次の行に移動させるのもやってみたんですが、やっぱり同じようなエラーが出てきました。
a(n, 0)みたいに初期値決めなくても「要素数nね!」って言うだけで駄目なんですね……。


goto 文、便利なんですけど、私みたいな初心者が使うには結構落とし穴が多いのかも?と思いました。

ちなみに前回goto 文使って落とし穴にはまった時の記事もあります。
良かったら読んでくださいな↓

mizumazu.hatenablog.com

*1:可変長配列(Variable Length Array, 長さを変えれる配列)のこと

*2:可変修飾 (variably modified; VM)のこと