検討char *a[] = {"abc", "xyz", "def"};
char *a[]
へのディープコピーchar **b
。
誰かがディープコピーとは何かを言うことができますか? そして、どのくらいのメモリを割り当てる必要がありb
ますか?
a
配列を歩いて、ファミリ関数a[i]
の 1 つを使用してそれを割り当てるためのスペースを要求し、結果をそれぞれの に入れます。ポインター自体は、文字列の数をポインターとして保持するのに十分なスペースを持つポインターでなければなりません。次のように計算します。*alloc()
b[i]
b
a
int bsize = (sizeof(a)/sizeof(a[0])) * sizeof(char*);
char **b = malloc(bsize);
int i,len;
/* if(b == NULL) /* error: no memory */
for(i = 0,len = sizeof(a)/sizeof(a[0]); i < len; i++) {
char *tmp = malloc(strlen(a[i])+1);
if(tmp == NULL) /* error: no memory */
strcpy(tmp, a[i]);
b[i] = tmp;
}
b
配列のサイズをメモリに保持するかNULL
、配列の最後に配置する必要があることに注意してください。
char *a[n];
文字への n 個のポインターの配列です。配列の各要素はメモリ内で連続しています。必要なメモリのサイズは
sizeof(char *) * n
ここで sizeof() 演算子を使用しました... ポインターに 4 バイトを想定できますが、これは安全ではない可能性があります... これはハードウェアによって異なります。
char **b
若干異なります。これは、point-to-char へのポインターです。**b はポインターの配列を割り当てていません。最初に配列を割り当てます...
char **b = malloc( sizeof(char *) * n);
編集:私の間違いを指摘してくれたinterjayに感謝します...以下の例では、各b [i]にメモリを割り当てるためにstrdup()を使用しています
**b は、n ポインターの配列の先頭を指します。その配列内の各ポインターに対して、浅いコピーの場合は b[0] = a[0] を実行できます
b[0] は a[0] が指すのと同じメモリを指すため、これは浅いコピーです。したがって、b[0] の内容を変更すると、a[0] の内容が変更されます。
ディープ コピーは、2 つの完全に独立したエンティティがあることを意味します。したがって、b[0] の内容を変更しても、a[0] の内容は変更されません。これは、b[i] ごとに新しいメモリを割り当て、文字列を a[i] からその新しいブロックにコピーする必要があることを意味します。
ディープ コピーするには:
char *a[n];
// ...intialise array a....
char **b = malloc( sizeof(char *) * n); // allocate array of pointers
if( b )
{
int i = 0;
for(; i < n; ++i)
b[i] = (char *)strdup(a[i]); // allocate memory for new string and copy string
}
else
printf("You ran out of memory!\n");
余談ですが...定数文字列を使用したため、技術的に変更しないでください...
char *xxx = "String";
char yyy[] = "String";
yyy の内容は安全に変更できます。通常、xxx の内容は問題なく変更できますが、文字列メモリはコンパイル時に割り当てられるため、たとえば、コンパイラによって読み取り専用メモリに配置されていることがわかる場合があります。
編集: malloc から return をキャストするかどうかについて議論があったようです (私はこれを習慣にしていましたが、これは悪い習慣だったようです!) ...なぜ malloc が返すものをキャストする必要があるのか を参照してください?
あなたはただすることができます
b=a
これにより、ポインターの配列のベースアドレス *a[3] が b に割り当てられます。
b を使用して文字列にアクセスできるようになりました
for example string 1 can be accessed by *(b+0) gives address of string 1
string 2 " " *(b+1) " " string 2
string 3 " " *(b+2) " " string 3
ポインターの配列をポインターへのポインターに割り当てているため、既にメモリを b に割り当てているため、malloc を使用する必要はありません。
実行時にデータをポインターに割り当て、プログラムでメモリーをポインターに割り当てていない場合にのみ、malloc のみを使用します。