十分な大きさのトークン バッファーを宣言する必要があります。安全のために、それらすべてを入力バッファー自体と同じ大きさにすることをお勧めします。このスレッドを参照してくださいCでscanfがバッファオーバーフローを引き起こすのを防ぐ方法? 詳細については。
GNU コンパイラを使用している場合は、代わりにバッファを動的に割り当てることができる拡張機能を使用できます。scanf() による動的割り当てを確認してください
例:
スキャンされたトークンに定義済みのバッファを使用する:
すべてのトークンが入力バッファーと同じサイズであることに注意してください。
/* sscanf-test.c */
#include <stdio.h>
int main(int argc, char** argv)
{
FILE *file = fopen("sample.txt", "r");
const int BufferSize=256;
char buffer[BufferSize];
char tokenOne[BufferSize];
char tokenTwo[BufferSize];
char tokenThree[BufferSize];
char tokenFour[BufferSize];
while (fgets(buffer, sizeof(buffer), file) != NULL)
{
tokenOne[0]='\0';
tokenTwo[0]='\0';
tokenThree[0]='\0';
tokenFour[0]='\0';
int tokenCount = sscanf(buffer, "%s %s %s %s", tokenOne, tokenTwo, tokenThree, tokenFour);
printf("scanned %d tokens 1:%s 2:%s 3:%s 4:%s\n", tokenCount, tokenOne, tokenTwo, tokenThree, tokenFour);
}
fclose(file);
return 0;
}
プログラムは次の出力を生成します (読みやすくするために書式設定を少しクリーンアップしました)。
gcc sscanf-test.c -o sscanf-test
./sscanf-テスト
スキャンされた 2 つのトークン 1:READ 2:N 3: 4:
スキャンされた 3 つのトークン 1:N: 2:DS 3:1 4:
スキャンされた 3 つのトークン 1:SUM: 2:DS 3:1 4:
スキャンされた 4 つのトークン 1:LOOP: 2:MOVER 3:AREG 4:N
スキャンされた 3 つのトークン 1:ADD 2:AREG 3:N 4:
スキャンされた 3 つのトークン 1:COMP 2:AREG 3:='5' 4:
スキャンされた 3 つのトークン 1:BC 2:LE 3:LOOP 4:
スキャンされた 3 つのトークン 1:MOVEM 2:AREG 3:SUM 4:
スキャンされた 2 つのトークン 1:PRINT 2:SUM 3: 4:
スキャン 1 トークン 1:STOP 2: 3: 4:
後で処理するためにスキャンしたトークンを保存する場合は、while ループ内の別の場所にコピーする必要があります。この関数strlen
を使用して、トークンのサイズを取得できます (末尾の文字列ターミネータ '\0' を除く)。
トークンの動的メモリ割り当ての使用:
私が言ったように、scanf にバッファを動的に割り当てることもできます。scanf(3)のマニュアル ページには、GNU 拡張機能 'a' または 'm' を使用してそれを行うことができると記載されています。具体的には次のように述べています。
オプションの「a」文字。これは文字列変換で使用され、呼び出し元が入力を保持するために対応するバッファーを割り当てる必要がなくなります。代わりに、scanf() は十分なサイズのバッファーを割り当て、このバッファーのアドレスを対応するポインター引数に割り当てます。 char * 変数へのポインターである必要があります (この変数は呼び出し前に初期化する必要はありません)。呼び出し元は、このバッファが不要になったときに、後で free(3) する必要があります。これは GNU 拡張です。C99 は変換指定子として「a」文字を使用します (GNU 実装でもそのまま使用できます)。
「a」修飾子を使用して scanf を機能させることができませんでした。ただし、同じこと (およびそれ以上) を行う 'm' 修飾子もあります。
バージョン 2.7 以降、glibc は a 修飾子と同じ目的で m 修飾子も提供しています。m 修飾子には次の利点があります。
%c 変換指定子 (例: %3mc) にも適用できます。
%a 浮動小数点変換指定子に関するあいまいさを回避します (また、gcc -std=c99 などの影響を受けません)。
これは、POSIX.1 標準の今後の改訂で指定されます。
/* sscanf-alloc.c */
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
FILE *file = fopen("sample.txt", "r");
const int BufferSize=64;
char buffer[BufferSize];
char *tokenOne = NULL;
char *tokenTwo = NULL;
char *tokenThree = NULL;
char *tokenFour = NULL;
while (fgets(buffer, sizeof(buffer), file) != NULL)
{
// note: the '&', scanf requires pointers to pointer to allocate the buffers.
int tokenCount = sscanf(buffer, "%ms %ms %ms %ms", &tokenOne, &tokenTwo, &tokenThree, &tokenFour);
printf("scanned %d tokens 1:%s 2:%s 3:%s 4:%s\n", tokenCount, tokenOne, tokenTwo, tokenThree, tokenFour);
// note: the memory has to be free'd to avoid leaks
free(tokenOne);
free(tokenTwo);
free(tokenThree);
free(tokenFour);
tokenOne = NULL;
tokenTwo = NULL;
tokenThree = NULL;
tokenFour = NULL;
}
fclose(file);
return 0;
}
gcc sscanf-alloc.c -o sscanf-alloc
./sscanf-alloc
スキャンされた 2 つのトークン 1:READ 2:N 3:(null) 4:(null)
スキャンされた 3 つのトークン 1:N: 2:DS 3:1 4:(null)
スキャンされた 3 つのトークン 1:SUM: 2:DS 3:1 4:(null)
スキャンされた 4 つのトークン 1:LOOP: 2:MOVER 3:AREG 4:N
スキャンされた 3 つのトークン 1:ADD 2:AREG 3:N 4:(null)
スキャンされた 3 つのトークン 1:COMP 2:AREG 3:='5' 4:(null)
スキャンされた 3 つのトークン 1:BC 2:LE 3:LOOP 4:(null)
スキャンされた 3 つのトークン 1:MOVEM 2:AREG 3:SUM 4:(null)
スキャンされた 2 つのトークン 1:PRINT 2:SUM 3:(null) 4:(null)
スキャンされた 1 トークン 1:STOP 2:(null) 3:(null) 4:(null)