一つの方法は、一度に入力行を読み込むことfgets()
代わりのscanf()
を使用して伴うだろう下回っ
はラフなコード例を追加しました。その後、strtok()
を使用して、入力行をトークンに分割し、strtol()
を使用してトークンを数値に解析することができます。 scanf()
と比較すると、構造化されていないユーザー入力を処理するのに、fgets
を使用するほうがずっと簡単です。
以下のコードはこれを行います。入力行に要素が多すぎる場合、要素が少なすぎる場合、または要素の1つが有効な数でない場合は、メッセージが出力され、行を再度入力する必要があります。
各行がユーザーによって入力されると、strtok()
は、行をトークンに分割するために使用されます。トークン区切り文字のリストはdelims[]
に格納されています。トークンはスペースやタブで区切ることができます。区切り文字自体はトークンの一部ではないため、\r
と\n
を含めて、これらの文字が1行の最後のトークンに含まれないようにします。
トークンが見つかった場合は、できるだけstrtol()
を使用して整数に変換します。 strtol()
への呼び出しの後、ポインタtail
は、トークン内の数字の一部ではない最初の文字を指します。 tail
がNUL
ターミネータを指している場合は、文字列全体が数値として解析されます。そうでない場合、入力は不良とみなされ、再度入力されなければなりません。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUF_SIZE 1000
int main(void)
{
size_t r = 3;
size_t c = 5;
size_t i, j;
char buffer[BUF_SIZE];
char *token;
char *tail;
const char delims[] = " \t\r\n";
int arr[r][c];
int temp_val;
printf("Enter rows of %zu data elements:\n", c);
for(i = 0; i < r; i++){
j = 0;
if (fgets(buffer, BUF_SIZE, stdin) == NULL) {
perror("Error in fgets()");
exit(EXIT_FAILURE);
}
token = strtok(buffer, delims);
while (token != NULL) {
temp_val = strtol(token, &tail, 10);
if (*tail == '\0') {
arr[i][j] = temp_val;
++j;
} else { // token not a valid number
j = 0;
break;
}
if (j > c) { // too many input values
break;
}
token = strtok(NULL, delims);
}
if (j != c) {
printf("insufficient datapoints\n");
--i; // enter row again
}
}
for (i = 0; i < r; i++) {
for (j = 0; j < c; j++) {
printf("%5d", arr[i][j]);
}
putchar('\n');
}
return 0;
}
サンプルの相互作用:
Enter rows of 5 data elements:
1 2 3 4
insufficient datapoints
1 2 3 4 5 6
insufficient datapoints
1 x 2 3 4
insufficient datapoints
1 2 3 4 x
insufficient datapoints
1 2 3 4 5 x
insufficient datapoints
1 2x 3 4 5
insufficient datapoints
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
(scanfの '場合)'パイプが近くないEOF' '戻りません。 – Stargateur
@ccpghどうすればいいですか? –
'fgets'と' strtok'を使用しますか? – BLUEPIXY