fscanf
「ファイルスキャンフォーマット済み」の略で、ユーザーデータは可能な限りフォーマットされていません。
"%s"
何を読み取ることができるかを完全に制御できないデータでは、裸のフォーマット文字列を使用しないでください。
fgets
バッファオーバーフローを防ぐことができるため、最善の解決策は、を使用して行を読み取ることです。
次に、行のサイズがわかれば、それが必要な各文字列の最大サイズになります。sscanf
実際のフィールドを取得するために心ゆくまで使用してください。
最後にもう1つ。int*
整数の型はすでに特定の最大サイズを持っていることがわかっているので、整数の型を使用するのはおそらく少し無駄です。私は、次のような非ポインタバリアントを使用します。
struct Data {
char *sname; char *country;
int a; int b; int c; int d;
char *hsisno;
};
例として、安全なコードを次に示します。
#include <stdio.h>
#include <string.h>
// Here's all the stuff for a linked list of your nodes.
typedef struct sData {
char *sname; char *country; char *hsisno;
int a; int b; int c; int d;
struct sData *next;
} Data;
Data *first = NULL; Data *last = NULL;
#define MAXSZ 100
int main (void) {
char line[MAXSZ], sname[MAXSZ], country[MAXSZ], hsisno[MAXSZ];
int a, b, c, d;
FILE *fIn;
Data *node;
// Open the input file.
fIn = fopen ("file.in", "r");
if (fIn == NULL) {
printf ("Cannot open file\n");
return 1;
}
// Process every line.
while (fgets (line, sizeof(line), fIn) != NULL) {
// Check line for various problems (too short, too long).
if (line[0] == '\0') {
printf ("Line too short\n");
return 1;
}
if (line[strlen (line)-1] != '\n') {
printf ("Line starting with '%s' is too long\n", line);
return 1;
}
line[strlen (line)-1] = '\0';
// Scan the individual fields.
if (sscanf (line, "%s %s %d %d %d %d %s",
sname, country, &a, &b, &c, &d, hsisno) != 7)
{
printf ("Line '%s' didn't scan properly\n", line);
return 1;
}
// Allocate a new node to hold data.
node = malloc (sizeof (Data));
if (node == NULL) {
printf ("Ran out of memory\n");
return 1;
}
node->sname = strdup (sname);
node->country = strdup (country);
node->a = a;
node->b = b;
node->c = c;
node->d = d;
node->hsisno = strdup (hsisno);
node->next = NULL;
if (first != NULL) {
last->next = node;
last = node;
} else {
first = node;
last = node;
}
}
fclose (fIn);
// Output the list for debugging.
node = first;
while (node != NULL) {
printf ("'%s' '%s' %d %d %d %d '%s'\n",
node->sname, node->country, node->a, node->b,
node->c, node->d, node->hsisno);
node = node->next;
}
return 0;
}
ファイルを読み込み、リンクリストに保存します。以下を出力します。
'Lee' 'AUS' 2 103 2 62 'TRUE'
'Check' 'AUS' 4 48 0 23 'FALSE'
'Mills' 'AUS' 8 236 0 69 'FALSE'
予想通り、最後に。
私は、*scanf
制御されていないデータで関数を使用する際の落とし穴について一連の回答を行いました(user:14860 fgets
上の検索ボックスに入力してください)。そのうちのいくつか(たとえば、ここ、ここ、ここ)には、私の長年のお気に入りの関数が含まれています。getLine
、より安全なユーザー入力のために。