1

動的配列のスコープに関して簡単な質問があります。これは、私が書いているプログラムでバグを引き起こしていると思います。このスニペットは、関数パラメーターをチェックし、ユーザーが渡す内容に応じて、最初または 2 番目のいずれかに分岐します。

ただし、プログラムを実行すると、スコープ関連のエラーが発生します。

エラー: 'Array' はこのスコープで宣言されていません

C++ に関する私の知識に失敗しない限り、分岐が終了すると、条件内で作成された変数が範囲外になることを知っています。ただし、これらの配列を動的に割り当てたので、ポインターはそのままにしておく必要があるため、プログラムの後半で配列を操作できない理由がわかりません。

        //Prepare to store integers
        if (flag == 1) {
                int *Array;
                Array = new int[input.length()]; 
            } 
        //Prepare to store chars
        else if (flag == 2) {
                char *Array;
                Array = new char[input.length()];
            }

誰でもこれに光を当てることができますか?

4

5 に答える 5

5

Arrayの前に宣言しifます。また、異なる型の配列を一つの変数として宣言することはできないので、to ポインターを使うべきだと思います。

int *char_array = nullptr;
int *int_array  = nullptr;

//Prepare to store integers
if (flag == 1) {
    int_array = new int[input.length()]; 
} 
//Prepare to store chars
else if (flag == 2) {
    char_array = new char[input.length()];
}

if (char_array)
{
    //do something with char_array
}
else if (int_array)
{
    //do something with int_array
}

また、j_random_hacker が指摘しているように、多くのことを避けるためにプログラムの設計を変更することをお勧めします。if

于 2012-07-19T06:35:31.960 に答える
3

ヒープに動的に割り当てたため、メモリは明示的に削除する (またはプログラムが終了する) までシステムに解放されないことは正しいですが、メモリへのポインタは、ブロックがあったときに範囲外になります。 exit で宣言されます。したがって、ポインターがブロックの後に使用される場合、ポインターはより広い範囲に存在する必要があります。

于 2012-07-19T06:39:44.953 に答える
3

メモリは割り当てられたままです(つまり、貴重なスペースを占有します)。終了後にアクセスする方法はありません}。その時点で、プログラムはメモリにアドレスする能力を失うためです。new[]これを回避するには、 によって返されるポインターを、外側のスコープで宣言されたポインター変数に割り当てる必要があります。

別の問題として、2 つの異なるタイプのいずれかのメモリを割り当てようとしているように見えます。これを移植可能にしたい場合は、 a を使用しvoid *てポインターを保持するか、(あまり一般的ではありませんが)union各型のポインターを含む型を使用する必要があります。いずれにせよ、どの種類の割り当てが行われたかをプログラムに知らせる状態情報を維持する必要があります。 通常、これを実行したいということは、すべてのアクセスでこの状態情報をオンにする必要があるため、設計が不十分であることを示しています。

于 2012-07-19T06:48:09.720 に答える
2

私があなたの意図を正しく理解している場合、あなたがやろうとしていることは次のとおりです。いくつかのロジックに応じて、メモリを割り当ててn 個の要素を格納するか、intまたはchar後で関数内で、単一のステートメントを必要とせずに、またはその配列にアクセスします。intcharif

上記の理解が正しければ、単純な答えは次のとおりです。

ただし... C++は非常に強力で柔軟な言語でもあるため、次のことができます。

鋳造。次のようなもの:

void * Array;
if(flag1) Array = new int[len]
else Array = new char[len];
// ... later in the function
if(flag) // access as int array
  int i = ((int*)Array)[0];

はい、これは醜いのでif、関数の周りにこれらの s を散りばめる必要があります。したがって、ここに代替案があります:テンプレート

template<class T> T foo(size_t _len)
{
  T* Array = new T[_len];
  T element = Array[0];
  return element;
}

さらに別の、さらにあいまいな方法として、unionsを使用することもできます。

union int_or_char {int i; char c;};
int_or_char *Array = new int_or_char[len];
if(flag) // access as int
  int element = Array[0].i;

しかし、いずれにせよ (または 3 番目の方法で) 、処理しようとしているデータを処理する方法をコンパイラーが認識しなければならないという事実を回避する方法はありません。

于 2012-07-19T06:58:11.033 に答える
1

Turixの答えは正しいです。ここでは、配列用のメモリと、配列の場所が格納されるときのメモリの 2 つが割り当てられていることに注意する必要があります。

そのため、配列のメモリがヒープから割り当てられ、必要に応じてコードで使用できるようになったとしても、配列の場所が格納されているメモリ (Array 変数) はスタックに割り当てられ、すぐに失われます。対象外なので。この場合は if ブロックが終了したときです。同じ if の else 部分でも使用できません。

私が与えるアンドリューからの別の異なるコードの提案は次のとおりです。

void *Array = nullptr;

if (flag == 1) {
    Array = new int[input.length()];
} else if (flag == 2) {
    Array = new char[input.length()];
}

その後、意図したとおりに if を直接使用できます。

この部分はよくわかりません: int か char かを知りたい場合は、typeidリテラルを使用できます。うまくいきません、少なくとも私はうまくいきません。

または、フラグ変数を使用して、それがどのタイプであるかを推測することもできます。

于 2012-07-19T06:49:08.000 に答える