私はそれらの違いが何であるかはっきりわかりません。私の教授は** arrayは* array []と同じであると書いており、私たちは彼が** arrayを使用する例を提示されました(したがって、クラスの後で* array [と交換した]そしてそれはうまくいきませんでした)、それらが実際に彼が書いたものと同じであるかどうか誰かに教えてもらえますか?とにかく、クラスは動的メモリ割り当てについてでした
@ダブルポインタを変更するとすぐに、この行はエラーをスローし始めました
lines = malloc(sizeof(char*));
そして、メモリが再割り当てされている他のいくつかの
@ 2地獄そう、ここにコード全体があります
そして、以下のコメントについては、彼の発言が
**array = *array[]
大きな更新
ご不便をおかけして申し訳ありません。この投稿を書いている時点で私はあまりにも疲れていました。ここに、編集なしのコード全体を示します
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **lines; // global text buffer, organized as an array of lines
// --------------------------------------------------------------------------------
// initialize global buffer
void initialize()
{
lines = malloc(sizeof(char*));
lines[0] = NULL;
}
// --------------------------------------------------------------------------------
// return number of lines in buffer
int countLines()
{
int count = 0;
while(lines[count++]) ;
return count-1;
}
// --------------------------------------------------------------------------------
// print one line
void printLine(int line)
{
printf("Line %d: %p %p %s\n",line, &lines[line], lines[line], lines[line]);
}
// --------------------------------------------------------------------------------
// print all lines
void printAll()
{
int num_lines = countLines();
int line = 0;
printf("----- %d line(s) ----\n",num_lines);
while (line < num_lines)
printLine(line++);
printf("---------------------\n");
}
// --------------------------------------------------------------------------------
// free whole buffer
void freeAll()
{
int line = countLines();
while (line >= 0)
free(lines[line--]);
free(lines);
}
// --------------------------------------------------------------------------------
// insert a line before the line specified
void insertLine(int line, char *str)
{
int num_lines = countLines();
// increase lines size by one line pointer:
lines = realloc(lines, (num_lines+2) * sizeof(char*));
// move line pointers backwards:
memmove(&lines[line+1], &lines[line], (num_lines-line+1)*sizeof(char*));
// insert the new line:
lines[line] = malloc(strlen(str)+1);
strcpy(lines[line],str);
}
// --------------------------------------------------------------------------------
// remove the specified line
void removeLine(int line)
{
int num_lines = countLines();
// free the memory used by this line:
free(lines[line]);
// move line pointers forward:
memmove(&lines[line], &lines[line+1], (num_lines-line+1)*sizeof(char*));
// decrease lines size by one line pointer:
lines = realloc(lines, num_lines * sizeof(char*));
}
// --------------------------------------------------------------------------------
// insert a string into specified line at specified column
void insertString(int line, int col, char *str)
{
// make room for the new string:
lines[line] = realloc(lines[line], strlen(lines[line])+strlen(str)+1);
// move characters after col to the end:
memmove(lines[line]+col+strlen(str), lines[line]+col, strlen(lines[line])-col);
// insert string (without terminating 0-byte):
memmove(lines[line]+col, str, strlen(str));
}
// --------------------------------------------------------------------------------
// MAIN program
int main()
{
initialize();
printAll();
insertLine(0,"Das ist");
printAll();
insertLine(1,"Text");
printAll();
insertLine(1,"ein");
printAll();
insertLine(2,"kurzer");
printAll();
printf("lines[2][4] = %c\n",lines[2][4]);
insertString(2,0,"ziemlich ");
printAll();
removeLine(2);
printAll();
freeAll();
return 0;
}
質問で参照するコードが、ポインターへのポインターのポインター配列の使用例として教授から与えられた場合、そのクラスが実際にどれほど優れているかはわかりません。私はそれがデバッグ演習として提供されたか、それが解決策であなたの試みだったのではないかと思います。いずれにしても、単に警告を有効にしてコンパイルすると、コードのデバッグに進む前に注意が必要な多くの問題が見つかります。
参照するコードについては、グローバルテキストバッファを自由に使用できますが、グローバルバッファを使用せず、必要に応じてデータへのポインタを渡すことで、はるかに効果的になります。グローバルデータを必要とするいくつかのインスタンスやさまざまなコールバック関数などがありますが、経験則として、これらは例外であり、規則ではありません。
あなたの質問は基本的に「ポインタとダブルポインタ(ポインタからポインタへの型)変数の配列を適切に使用するにはどうすればよいでしょうか。1つの答えでトピックを完全にカバーする方法はありません。どちらか一方を使用できる(または使用する必要がある)状況とコンテキスト、およびその理由が多すぎますが、いくつかの例が基本的な違いを理解するのに役立ちます。
typeへのポインタの配列で始まります(例:_char *array[]
_)。それは一般的にその形で関数の引数として見られます。変数として宣言すると、初期化が続きます。例えば。:
_char *array[] = { "The quick",
"brown fox",
"jumps over",
"the lazy dog." };
_
_char *array[];
_の間に配列サイズがないため、変数宣言としての_[..]
_自体は無効です。例のようにグローバルに使用すると、コンパイラは宣言を受け入れますが、宣言は警告1つの要素であると想定されます。
上記で宣言されたarray
の要素は、char型へのポインタです。具体的には、要素は宣言によって作成されたstring-literalsへのポインタです。各文字列には、array
内の関連するポインタから_array[0], ... array[3]
_としてアクセスできます。
タイプへのポインターへのポインター(ダブルポインター)は、その名前が示すとおりです。 ポインタを値として持つポインタです。基本的には、別のポインターを指すポインターです。次のようにarray
のアドレスを割り当てることにより、上記の配列のメンバーにアクセスするために使用できます。
_char **p = array;
_
ここで、_p[1]
_または*(p + 1)
は_"brown fox"
_などを指します。
あるいは、タイプへのポインターへのポインターの数を動的に割り当てて、タイプへのポインターの配列を作成するために使用することができ、それを割り当てて再割り当てして、不明な数の要素のアクセスまたはストレージを処理することができます。たとえば、stdin
から不明な数の行を読み取る簡単な例では、次のようになります。
_#define MAXL 128
#define MAXC 512
...
char **lines = NULL;
char buf[MAXC] = {0};
lines = malloc (MAXL * sizeof *lines);
size_t index = 0;
...
while (fgets (buf, MAXC, stdin)) {
lines[index++] = strdup (buf);
if (index == MAXL)
/* reallocate lines */
}
_
上記のlines
は、char-to-pointer-to-char(最初はNULL
)で、MAXL
(128)のpointers-to-charを割り当てるために使用されます。次に、行がstdin
からbuf
に読み取られ、読み取りが成功するたびに、buf
の内容を保持するためにメモリが割り当てられ、メモリの各ブロックの結果の開始アドレスが割り当てられます各ポインタへの_line[index]
_ここで、index
は_0-127
_であり、index
から128に増加すると、index
が再割り当てされて追加のポインタと読み取りが提供されます続けます。
トピックが1つの回答で処理できるよりも大きくなるのは、ポインターの配列またはタイプへのポインターへのポインターが任意のtype
に対応できることです。 (int
、struct
、または異なるタイプの構造体のメンバーとして、またはfunction
など...)これらを使用できますlinked-lists、ディレクトリ一覧の戻り(例:opendir
)、またはその他の方法で。静的に初期化したり、動的に割り当てたり、関数のパラメーターとして渡したりすることができます...異なるコンテキストが多すぎてすべてをカバーできません。しかし、すべての場合において、それらはここと他の回答でここに見られる一般的なルールに従い、1,000のより多くの回答でここStackStackflowに従います。
最後に、配列とダブルポインターのさまざまな基本的な使用方法を確認するために使用できる短い例を示します。ソースにコメントを追加しました。これは、いくつかの異なる基本的な使用法、静的宣言と動的割り当てを提供するだけです。
_#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (void) {
/* array is a static array of 4 pointers to char, initialized to the
4 string-literals that a part of the declaration */
char *array[] = { "The quick",
"brown fox",
"jumps over",
"the lazy dog." };
/* p is a pointer-to-pointer-to-char assigned the address of array */
char **p = array;
/* lines is a pointer-to-pointer-to-char initialized to NULL, used
below to allocate 8 pointers and storage to hold 2 copes of array */
char **lines = NULL;
size_t narray = sizeof array/sizeof *array;
size_t i;
printf ("\nprinting each string-literal at the address stored by\n"
"each pointer in the array of ponters named 'array':\n\n");
for (i = 0; i < narray; i++)
printf (" %s\n", array[i]);
printf ("\nprinting each string using a pointer to pointer to char 'p':\n\n");
for (i = 0; i < narray; i++, p++)
printf (" %s\n", *p);
p = array;
printf ("\nprinting each line using a pointer to pointer"
" to char 'p' with array notation:\n\n");
for (i = 0; i < narray; i++)
printf (" %s\n", p[i]);
/* allocate 8 pointers to char */
lines = malloc (2 * narray * sizeof *lines);
/* allocate memory and copy 1st 4-strings to lines (long way) */
for (i = 0; i < narray; i++) {
size_t len = strlen (array[i]);
lines[i] = malloc (len * sizeof **lines + 1);
strncpy (lines[i], array[i], len);
lines[i][len] = 0;
}
/* allocate memory and copy 1st 4-strings to lines
(using strdup - short way) */
// for (i = 0; i < narray; i++)
// lines[i] = strdup (array[i]);
/* allocate memory and copy again as last 4-strings in lines */
p = array;
for (i = 0; i < narray; i++, p++)
lines[i+4] = strdup (*p);
p = lines; /* p now points to lines instead of array */
printf ("\nprinting each allocated line in 'lines' using pointer 'p':\n\n");
for (i = 0; i < 2 * narray; i++)
printf (" %s\n", p[i]);
/* free allocated memory */
for (i = 0; i < 2 * narray; i++)
free (lines[i]);
free (lines);
return 0;
}
_
ご不明な点がありましたらお知らせください。これは、非常に多くのさまざまな方法やさまざまなコンテキストで適用できる、比較的小さなルールセットを持つ大きなトピックです。
私の教授は
**array
は*array[]
と同じだと書いています
これは、一部のコンテキストでは当てはまり、他のコンテキストでは当てはまりません。
引数として関数で使用される場合、
void foo(int **array) {}
と同じです
void foo(int *array[]) {}
変数として宣言すると、
int **array;
と同じではありません
int *array[];
免責事項:これは、同じ場所と異なる場所の完全なリストではありません。