プログラマが知らなければならないメモリのこと---ポインタドメイン配列の対比


ポインタドメイン配列の比較:
C++/Cプログラムでは,ポインタと配列が互いに置き換えられていることが多く,両者が等価であると錯覚する.
配列は、グローバル配列などの静的ストレージ領域に作成されるか、スタックに作成されます.配列名は(指向ではなく)メモリに対応し、そのアドレスと容量はライフサイクル内で変わらず、配列の内容だけが変更できます.
ポインタは、「可変」を特徴とする任意のタイプのメモリブロックをいつでも指すことができるので、ダイナミックメモリを操作するためにポインタをよく使用します.ポインタは配列よりはるかに柔軟ですが、危険です.
        
変更内容:
char a[] = "hello";
a[0] = 'X';
cout << a << endl;
char* p = "world";//    p    --      
p[0] = 'X'; //          
cout << p << endl;

コンテンツのコピーと比較:
配列名を使用して直接レプリケーションと比較はできません.配列aの内容を配列bにコピーするには、文b=aは使用できません.そうしないとコンパイルエラーが発生します.標準ライブラリ関数strcpy()でコピーする必要があります.同様に,比較bとaの内容が同じかどうかはif(b==a)で判断できず,標準ライブラリ関数strcmp()で比較すべきである.
int len = strlen(a);
char* p = (char*)malloc(sizeof(char)*(len+1));
strcpy(p,a);
if(strcmp(p,a) == 0)

メモリ容量の計算:
演算子sizeof()で配列の容量(バイト数)がわかります.注意:配列が関数として渡されると、配列は自動的に同じタイプのポインタに劣化します.
char a[] = "hello world";
char* p = a;
cout << sizeof(a) << endl; //12  
cout << sizeof(p) << endl; //4  

void func(char a[100])
{
	cout << sizeof(a) << endl;//4     100  
}

ポインタパラメータはどのようにメモリを渡しますか?
関数のパラメータがポインタである場合、そのポインタでダイナミックメモリを申請することを期待しないでください.
void GetMemory(char* p,int num)
{
	p = (char*)malloc(sizeof(char)*num);
}

void Test(void)
{
	char* str = NULL;
	GetMemory(str,100);
	strcpy(str,"hello");
}
の欠点はGetMemoryに現れ、コンパイラは常に関数の各パラメータに対して一時的なコピーを作成し、ポインタパラメータpのコピーは_p,コンパイラ使_p = p .関数内のプログラムが変更されたら_pの内容は、パラメータpの内容を相応に修正することになり、これがポインタが出力パラメータとして使用できる理由である.実際、GetMemory()を一度も実行しないとメモリが漏れてしまいます.
メモリをポインタで申請しなければならない場合は、「ポインタを指すポインタ」に変更する必要があります.
void GetMemory2(char** p,int num)
{
	*p = (char*)malloc(sizeof(char)*num);
}

void Test2(void)
{
	char* str = NULL;
	GetMemory2(&str,100);
	strcpy(str,"hello");
	cout << str << endl;
	free(str);
}

「ポインタを指すポインタ」という概念は理解しにくいため、関数を使用して値を返して動的なメモリを常に渡すことができます.
void GetMemory3(int num)
{
	char *p = (char*)malloc(sizeof(char)*num);
	return p;
}

void Test3(void)
{
	char* str = NULL;
	GetMemory3(&100);
	strcpy(str,"hello");
	cout << str << endl;
	free(str);
}

関数で値を返してメモリを渡す方法は使いやすいが、return文を間違って使う人が多い.ここでは、関数の終了時に自動的にメモリが消滅するため、return文でスタックメモリを指すポインタは使用しないことを強調します.
void *GetString(void)
{
	char p[] = "hello world";
	return p;//       
}
void Test4(void)
{
	char *str = NULL;
	str = GetString();//str        
	cout << str << endl;
}
デバッガを使用してTest 4関数を逐次追跡し、str=GetString()に実行されることが分かった.文の場合、strはNULLポインタではありませんが、strの内容は「hello world」ではなく、ゴミの内容です.
次のプログラムを検出します.
char *GetString2(void)
{
	char* p = "hello world";
	return p;
}

void Test5(void)
{
	char* str = NULL;
	str = GetString2();
	cout << str << endl;
}

関数Test 5()の実行にはエラーはありませんが、関数GetString 2の設計概念は間違っています.GetString 2内の「hello world」は定数文字列であり、静的記憶領域にあり、プログラムのライフサイクル内では一定であり、いつGetString 2を呼び出しても、彼が返したクロックは同じ読み取り専用のメモリモジュールです.