私はcでのプログラミングに慣れていないので、配列を作成してから、ファイル内の可変量の変数と、配列内のこれらのファイルを読み取る方法を考えています。
//how do I declare an array whose sizes varies
do {
char buffer[1000];
fscanf(file, %[^\n]\n", buffer);
//how do i add buffer to array
}while(!feof(file));
私はcでのプログラミングに慣れていないので、配列を作成してから、ファイル内の可変量の変数と、配列内のこれらのファイルを読み取る方法を考えています。
//how do I declare an array whose sizes varies
do {
char buffer[1000];
fscanf(file, %[^\n]\n", buffer);
//how do i add buffer to array
}while(!feof(file));
int nlines = 0
char **lines = NULL; /* Array of resulting lines */
int curline = 0;
char buffer[BUFSIZ]; /* Just alloocate this once, not each time through the loop */
do {
if (fgets(buffer, sizeof buffer, file)) { /* fgets() is the easy way to read a line */
if (curline >= nlines) { /* Have we filled up the result array? */
nlines += 1000; /* Increase size by 1,000 */
lines = realloc(lines, nlines*sizeof(*lines); /* And grow the array */
}
lines[curline] = strdup(buffer); /* Make a copy of the input line and add it to the array */
curline++;
}
}while(!feof(file));
Cでは、配列は常に固定サイズです。サイズを変更することはできません。できることは、事前に必要なスペースの量を見積もり、そのスペースを動的に(を使用してmalloc()
)割り当てることです。スペースが足りなくなった場合は、再割り当てします。そのためのドキュメントを参照してくださいrealloc()
。基本的に、あなたはします:
buffer = realloc(size);
新しいサイズは、以前のサイズよりも大きくしたり小さくしたりできます(つまり、配列を「拡大」または「縮小」できます)。したがって、最初に5000文字のスペースが必要な場合は、次のようにします。
char* buffer = malloc(5000);
後でスペースが不足し、さらに2000文字が必要な場合(新しいサイズは7000になります)、次のようにします。
buffer = realloc(7000);
の既存のコンテンツbuffer
は保持されます。realloc()
メモリブロックを実際に拡張できない可能性があるため、最初に完全に新しいブロックを割り当て、次に古いメモリの内容を新しいブロックにコピーしてから、古いメモリを解放する可能性があることに注意してください。つまり、buffer
ポインタのコピーを別の場所に保存すると、もう存在しない古いメモリブロックを指すことになります。例えば:
char* ptr = buffer;
buffer = realloc(7000);
その時点で、ptr
が有効である場合にのみ有効ですがptr == buffer
、これが当てはまるとは限りません。
文字列データが配列エントリにある配列は、通常、最適ではありません。データの完全なセットがメモリに快適に収まり、エントリ数に妥当な上限がある場合は、ポインタ配列が1つの選択肢です。
ただし、最初に、明示的な長さのないscanf%sおよび%[]形式は避けてください。例のバッファサイズ1000を使用すると、読み取ることができる最大文字列長は999なので、次のようになります。
/* Some needed data */
int n;
struct ptrarray_t
{
char **strings;
int nalloc; /* number of string pointers allocated */
int nused; /* number of string pointers used */
} pa_hdr; /* presume this was initialized previously */
...
n = fscanf(file, "%999[\n]", buffer);
if (n!=1 || getc(file)!='\n')
{
there's a problem
}
/* Now add a string to the array */
if (pa_hdr.nused < pa_hdr.nalloc)
{
int len = strlen(buffer);
char *cp = malloc(len+1);
strcpy(cp, buffer);
pa_hdr.strings[pa_hdr.nused++] = cp;
}
以降の任意の文字列への参照はpa_hdr.strings[i]であり、適切な設計では、関数呼び出しまたはマクロを使用してヘッダーを管理します。ヘッダーは、インラインではなくヘッダーファイルに含まれます。配列を使い終わったら、malloc()されたすべてのポインターを解放するdelete関数が必要になります。
小さな文字列が多数ある場合、malloc()は時間とスペースの両方のオーバーヘッドでコストがかかる可能性があります。ホストOSのメモリ割り当てとページングとうまく連携する大きなブロックで文字列のプールを管理する場合があります。関数のセットを使用して、この文字列配列からオブジェクトを効果的に作成すると、開発に役立ちます。上記のように単純な戦略を選択し、後で実装を最適化することができます。
改行を読むまで読み込もうとしているようです。
これを行う最も簡単な方法は、getlineを使用することです。
char *buffer = NULL;
int buffer_len;
int ret = getline(&buffer, &buffer_len, file);
...これにより、ファイルから1行のテキストが読み取られますfile
(エラーret
が-1
ある場合、またはファイルの最後にいる場合を除く)。