このコードには、C/C++ を理解するのに苦労している、または他のプログラマーや言語から悪い習慣を学んでいることが示唆されることがたくさんあります。
FILE *file;
file = fopen("fonts.dat", "rb");
可能な限り、宣言と代入を分離しないようにしてください。これはテキスト ファイルなので、「バイナリ」モードで開く必要はありません。バイナリで読み取るということは、さまざまな行末タイプについて心配する必要があることを意味します。テキスト モードで開くと、オペレーティング システム/libc が変換を行い、魔法のように行末が「\n」になるようにします。
char readLineBuffer[200];
if(readLineBuffer == NULL) { return 1; }
if(readLineBuffer == 0) { return 1; }
まず、先ほど行った方法で固定サイズのストレージを使用する利点の 1 つは、決して NULL に評価されないことです。ポインターを操作する場合は、null チェックのみが必要です。内部的には、「readLineBuffer」をポインターとして使用できるのは事実ですが、これは配列でもあります。次の簡単なプログラムを試してください。
#include <stdio.h>
int main(int argc, const char* argv[])
{
char buffer[1234];
char* bufPointer = buffer; // yes, it looks like a pointer.
printf("the size of buffer is %u but the size of bufPointer is %u\n",
sizeof(buffer),
sizeof(bufPointer));
return 0;
}
次に、「NULL」は単なる #define です。
#define NULL 0
(これが、C++11 で特別な「nullptr」定数が追加された理由です)。
while (fgets(readLineBuffer, 200, file) != NULL)
手動でサイズを繰り返すのは危険です。「sizeof()」コマンドを使用する
while (fgets(readLineBuffer, sizeof(readLineBuffer), file)
ファイル内のどの行も長さが 200 バイトを超えていないことを確信していますか? 次のことを想像してください。
fgets(buffer, 20, file);
次の行を想像してください。
123456789012345678#コメントです
fgets は「123456789012345678#」を読み取り、コードは末尾の「#」を削除して「puts」を実行し、「123456789012345678\n」をファイルに書き込みます。次に、コメント文字を見つけるのではなく、「これはコメントです」と読み、「これはコメントです\n」という新しい行をファイルに書き込みます。
第二に、とにかく行を反復するため、次のいずれかを検討することをお勧めします。
を。for(int i = 0; i < sizeof(readLineBuffer) && i[0] != '\0') { if(readLineBuffer[i] == '\n' || readLineBuffer[i] == '#') { readLineBuffer[i] = 0; 壊す; } }
b. strpbrk char* eol = strpbrk("#\n", readLineBuffer); を使用します。if ( eol != NULL ) // コメントまたは行末が見つかりました *eol = '\0';
これにより、コードは次のようになります。このコードは「C++」コンパイラでコンパイルされますが、ほとんど純粋な「C」です。
FILE *file = fopen("fonts.dat", "r");
if (file == NULL)
return 1;
char readLineBuffer[200];
while (fgets(readLineBuffer, sizeof(readLineBuffer), file) != NULL)
{
// find comment or end of line so we can truncate the line.
char* eol = strpbrk(readLineBuffer, "#\n");
if ( eol != NULL )
*eol = '\0';
puts(readLineBuffer);
}
fclose(file);
system("PAUSE");
return 0;
通過する実際の情報を処理して保存する場合は、それを保存する変数を作成し、readLineBuffer の各行を検査/「解析する」コードを作成する必要があります。 「sscanf」、「atoi」、「strtoul」などのコマンドの使用方法を学習するには、最終的にミニチュアの種類のステート マシンを作成する必要があります。
または、このようなタスク用に設計された「Perl」や「Python」などのスクリプト言語を調べることもできます。
# perl version
local $/ = /\n{2,}/; # Read the file as paragraphs.
open(file, "font.dat") || die "Can't open font.dat";
my %data = ();
while ($line = <>) {
$line =~ s/\s+#.*$//mg; # Get rid of all the comments.
$line =~ s/\n\n/\n/sg; # Fix any blank lines we introduced.
# Each data block starts with an ini-style label, that is a
# line starting with a "[", followed by some word-characters (a-z, A-Z, 0-9)
# and a closing "]", maybe with some whitespace after that.
# Try to remove a label line, capturing the label, or skip this block.
next unless $line =~ s/^ \[ (\w+) \] \s* \n+ //sx;
# Store the remaining text into data indexed on the label.
my ($label) = ($1); # the capture
$data{$label} = $line;
}
print("FONT_ID = $data{'FONT_ID'}\n");
またはperlier-perlで書かれた
local $/ = /\n{2,}/; # Read blocks separated by 2-or-more newlines (paragraphs)
die "Can't open file" unless open(file, "font.dat");
while (<>) {
s/\s+#.*$//mg;
s/\n{2,}/\n/sg;
$data{$1} = $_ if (s/^\[(\w+)\][^\n]+\n+//s);
}
$fontId = ;
print("font_id = ", int($data{'FONT_ID'}), "\n");