2

私はいくつかの本を読んでいますが、ポインタ/動的メモリを使用するクラス/関数(またはヒープまたはそれらがそれを呼び出すw / e)に関しては、混乱し始めます。

私が使用している本は非常に複雑な例(大規模なクラスまたは複数の関数)を使用しており、理解するのが難しいため、誰もが簡単な例のように簡単な例を示していますか?とにかくポインタは常に私の弱点でしたが、私はBASICポインタを理解しています。それらを使用するクラス/関数だけでは、少し混乱します。

また.....いつそれらを使用するかは別の質問です。

4

6 に答える 6

5

スタック割り当て:

char buffer[1000];

ここで、1000は定数でなければなりません。bufferスコープ外になると、メモリは自動的に解放されます。

ヒープ割り当て:

int bufsz = 1000;
char* buffer = new char[bufsz];
//...
delete [] buffer;

ここで、bufszは変数にすることができます。メモリは明示的に解放する必要があります。

ヒープを使用する場合:

  • コンパイル時に必要なスペースがわかりません。
  • メモリ/オブジェクトを現在のスコープを超えて永続化する必要があります。
  • 大量のメモリが必要です(スタックスペースはヒープスペースよりも制限されています)
于 2011-01-21T17:27:17.867 に答える
4

コンピュータのRAMは、次々に並べられたバイトの大きな山であり、それらのバイトのそれぞれは、そのアドレス(ゼロから上に向かって始まる整数)によって独立してアクセスできます。ポインタは、メモリ内の1つの場所のアドレスを保持するための単なる変数です。

RAMはバイトの大きなチャンクであるため、CPUは通常、その大きなバイトの山をいくつかのチャンクに分割します。最も重要なものは次のとおりです。

  1. コード
  2. ヒープ
  3. スタック

コードチャンクは、アセンブリコードが存在する場所です。ヒープは、以下を割り当てるために使用されるバイトの大きなプールです。

  • グローバル変数
  • newC++またはCでの操作による動的データmalloc()

スタックは、以下を格納するために使用されるメモリのチャンクです。

  • ローカル変数
  • 関数パラメーター
  • 戻り値(C / C ++のreturnステートメント)。

スタックとヒープの主な違いは、その使用方法です。ヒープはバイトの大きなプールですが、スタックは皿のスタックのように「成長」します。上部に皿がない場合を除いて、下部の皿を削除することはできません。

これが再帰の実装方法です。関数を再帰的に呼び出すたびに、メモリがスタック上で増大し、パラメータ、ローカル変数を割り当て、戻り関数の戻り値を、皿のスタックと同じように他の関数の上に格納します。

スタックに存在するデータは、ヒープに存在するデータとは異なる「寿命」を持っています。関数が終了すると、ローカル変数のデータは失われます。

deleteただし、ヒープにデータを割り当てる場合、またはfree()操作を使用してそのデータを明示的に解放すると、そのデータが失われることはありません。

于 2011-01-21T17:45:27.647 に答える
3

ポインタは基本的に、別の変数のメモリアドレスを含む変数です(または、他の場合は関数へのアドレスですが、最初の変数に焦点を当てることができます)。

つまりint[] x = {5,32,82,45,-7,0,123,8};、変数が特定のアドレスのメモリに割り当てられることを宣言した場合、それがアドレスに割り当てられたとしましょう。ただし、特定のメモリアドレス0x000001000x0000011F示す変数を作成し、それを使用してアクセスできます。

したがって、配列は次のようになります

Address           Contents
0x00000100        1
0x00000104        32
0x00000108        82
0x0000010B        45
0x00000110        -7
0x00000114        0
0x00000118        123
0x0000011B        8

たとえば、配列の先頭へのポインタを作成する場合、これを行うことができます。int* p = &x;このポインタ変数がメモリアドレス0x00000120を作成し、そのアドレスのメモリに配列の先頭のメモリ位置が含まれると想像してくださいx

Address           Contents
0x00000120        0x00000100

次に、ポインタを逆参照することにより、ポインタを介してそのアドレスのコンテンツにアクセスできます。これint y = *pにより、結果がになりy = 1ます。ポインタを移動することもできますp += 3;。ポインタを3アドレス前方に移動します(ただし、ポインタが指しているオブジェクトのタイプの3倍のサイズで移動することに注意してください。ここでは、32で例を作成しています。 intが32ビットまたは4バイトの長さであるビットシステム。したがって、アドレスは増分ごとに4バイト、または合計で12バイト移動するため、ポインタは)を指すようになり0x0000010Bます。を持っていることになります。これはほんの始まりに過ぎません。ポインタを使用して多くのことを実行できます。py = *p;y = 45

他の主な用途の1つは、ポインターをパラメーターとして関数に渡すことです。これにより、メモリー内の特定の値をすべてコピーしたり、関数のスコープ外で保持される変更を加えたりすることなく、操作を実行できます。

于 2011-01-21T17:34:50.167 に答える
1

警告:これを行わないでください。これが、ベクトルがある理由です。

データの配列を作成し、関数から返す場合は、どのように行いますか?

明らかに、これは機能しません。

int [10] makeArray(int val)
{
    int arr[10];
    for(int i=0; i<10; ++i)
        arr[i] = val;
    return arr;
}

関数から配列を返すことはできません。次のように、ポインタを使用して配列の最初の要素を参照できます。

int * makeArray(int val)
{
    int arr[10];
    for(int i=0; i<10; ++i)
        arr[i] = val;
    return &(arr[0]);  // Return the address of the first element.
                       // Not strictly necessary, but I don't want to confuse.
}

ただし、これも失敗します。arrはローカル変数であり、スタックに配置されます。関数が戻ると、データは無効になり、無効なデータを指すポインターが作成されます。

私たちがする必要があるのは、関数が終了した後も存続する配列を宣言することです。そのために、その配列を作成し、ポインタに格納する必要があるアドレスを返すキーワードnewを使用します。

int * makeArray(int val)
{
    int * arr = new int[10];
    for(int i=0; i<10; ++i)
        arr[i] = val;
    return arr;
}

次に、その関数を呼び出して、次のようにその配列を使用できます。

int * a = makeArray(7);

for(int i=0; i<10; ++i)
    std::cout << a[i] << std::endl;

delete [] a; // never forget this.  Obviously you wouldn't do it right
             // away like this, but you need to do it sometime.

newでポインターを使用すると、実行時に配列のサイズを決定できるという利点もあります。これは、ローカルの静的配列では実行できません(Cでは実行できます)。

int * makeArray(int size, int val)
{
    int * arr = new int[size];
    for(int i=0; i<size; ++i)
        arr[i] = val;
    return arr;
}

これ、ポインタの主な目的の1つでした。しかし、冒頭で述べたように、私たちはもうそれをしません。を使用しますvector

ポインターの最後の痕跡の1つは、動的配列用ではありません。私がこれまでに使用したのは、あるオブジェクトが別のオブジェクトにアクセスできるようにし、そのオブジェクトの所有権を与えないクラスでのみです。したがって、オブジェクトAはオブジェクトBについて知る必要がありますが、オブジェクトAがなくなっても、オブジェクトBには影響しません。これに参照を使用することもできますが、オブジェクトAにどのオブジェクトを変更するオプションを与える必要がある場合は使用できません。にアクセスできます。

于 2011-01-21T18:05:11.573 に答える
0

(テストされておらず、書き留めるだけです。要求に応じて、意図的に原始的なものを維持します。)

int* oneInt  = new int;  // allocate
*oneInt = 10;            // use: assign a value
cout << *oneInt << endl; // use: retrieve (and print) the value
delete oneInt;           // free the memory

今度はintの配列:

int* tenInts = new int[10];  // allocate (consecutive) memory for 10 ints
tenInts[0] = 4353;           // use: assign a value to the first entry in the array.
tenInts[1] = 5756;           // ditto for second entry
//... do more stuff with the ints
delete [] tenInts;           // free the memory

今クラス/オブジェクトで:

MyClass* object = new MyClass();  // allocate memory and call class constructor
object->memberFunction("test");   // call a member function of the object
delete object;                    // free the object, calling the destructor

それはあなたが望んでいたことですか?お役に立てば幸いです。

于 2011-01-21T17:24:10.453 に答える
0

私はこれがあなたが求めていることだと思います:

基本的に、C++は可変サイズの配列を許可しません。C ++の配列には、非常に特定のサイズを指定する必要があります。ただし、ポインタを使用してそれを回避できます。次のコードを検討してください。

int *arry = new int[10];

これは、10個の要素を持つintの配列を作成したばかりであり、これとほとんど同じです。

int arry[] = int[10];

唯一の違いは、それぞれが異なる構文のセットを使用することです。ただし、これを実行しようとしていると想像してください。

Class class:
{
public:
    void initArry(int size);

private:
    int arry[];
};

void class::initArry(int size)
{
    arry = int[size]; // bad code
}

何らかの理由で、C ++は、実行時に決定されるサイズを通常の配列に割り当てられないように設計されています。代わりに、コーディング時にサイズを割り当てる必要があります。ただし、C ++で配列を作成する他の方法(ポインターを使用)には、この問題はありません。

Class class:
{
public:
    ~class();
    void initArry(int size);

private:
    int *arry;
};

class::~class()
{
    delete []arry;
}

void class::initArry(int size)
{
    arry = new int[size]; // good code
}

2番目の例ではメモリのクリーンアップを行う必要があるため、デストラクタを含めましたが、そのようにポインタを使用することで、実行時に配列のサイズを変更できます(可変サイズ)。これは動的配列と呼ばれ、ここでのメモリは動的に割り当てられると言われています。もう1つの種類は静的配列です。

2次元配列に関する限り、次のように処理できます。

Class class:
{
public:
    ~class();
    void initArrays(int size1, int size2);

private:
    int **arry;
};

class::~class()
{
    delete [] arry[0];
    delete [] arry[1];
    delete [] arry;
}

void class::initArrays(int size1, int size2)
{
    arry = new int*[2];
    arry[0] = new int[size1];
    arry[1] = new int[size2];
}

ただし、免責事項:私はこの言語をしばらく使っていないので、構文の一部が少し間違っている可能性があります。

于 2011-01-21T22:41:37.910 に答える