分析されたコードは次で始まります。
fgets(input,sizeof(input),stdin);
if("\n"==input[strlen(input)-1]) // to remove '\n' from string
input[strlen(input)-1]=='\0';
からの戻り値を確認して、分析するfgets()
データがあるかどうかを確認する必要があります。input
は、文字列ではなく文字に対してテストするif
必要があります*。型の不一致に関するコンパイラの警告が表示されているはずです。このような警告が表示されない場合は、より優れたコンパイラを入手してください。警告が表示された場合は、コンパイラに注意してください。それはあなたよりも C のことをよく知っています (そして、そうする楽しみのためだけに警告を生成するわけではありません)。if (input[strlen(input)-1] == '\n')
'\n'
"\n"
の後の割り当てには、double ではなくif
single が必要です — おそらく、何もしないステートメントについて警告を受けているはずです。=
==
* この順序を推奨する人if ('\n' == input[strlen(input)-1])
もいますが、私にはあまりよく読まれません。==
このメカニズムは、条件のvs=
ミスから保護することを目的としています。これは不完全です — たとえば、LHS と RHS の両方が変数 ( ) の場合は保護できませんif (lhs = rhs)
— そして、まともなコンパイラは、条件付きになりすました割り当てがある場合に警告します (条件付きについて警告するのと同じように)。割り当てを装う)。
したがって、コードは次のように開始する必要があります。
if (fgets(input, sizeof(input), stdin) != 0)
{
if (input[strlen(input)-1] == '\n')
input[strlen(input)-1] = '\0';
への繰り返し呼び出しの「非効率性」を無視していstrlen()
ます。心配するより大きな問題があります。改訂されたコードは、入力操作の結果をチェックすることに注意してください。fgets()
EOF またはエラーを検出し、 の結果をテストしていない場合、問題が発生しますfgets()
。
コードの元のバージョンは、次のように続きます。
if(input == "point"){
scanf("%d %d",&x1,&y1);
point(x1,y1);
}
if(input == "rectangle"){
scanf("%d %d",&x1,&y1,&x2,&y2);
rectangle(x1,y1,x2,y2) // x1,y1 for top left coordinate x2,y2 for bottom right
}
ジャンボノが答えで正しく指摘したように、これは機能しません。そのような文字列を比較することはできません。
残念ながら、書き直したのは次のとおりです。
if(strcmp(input,point)==0){
scanf("%d %d",&x1,&y1);
point(x1,y1);
}
if(strcmp(input,rectangle)==0){
scanf("%d %d",&x1,&y1,&x2,&y2);
rectangle(x1,y1,x2,y2) // x1,y1 for top left coordinate x2,y2 for bottom right
}
文字列が関数ポインターに変更されたため、これもコンパイラーから警告を生成する必要がありましたconst char *
。
正しい比較は次のようになります。
if (strcmp(input, "point") == 0)
if (strcmp(input, "rectangle") == 0)
これらは、単語が単独の行に表示され、データが別の行に続く限り機能します。
point
1 2
rectangle
2 3 4 5
質問が読みやすいようにフォーマットされる前の回答
もちろん、2 番目scanf()
には書式文字列の修正が必要であり、scanf()
意図したとおりに機能することを常にテストする必要があります。
if (scanf("%d %d %d %d", &x1, &y1, &x2, &y2) != 4)
...deal with error...
このscanf()
呼び出しは改行を置き去りにし、別の呼び出しfgets()
でその行に (残っている) 唯一の文字として読み取る準備ができていることに注意してください。fgets()
データを含む行を読み取り、その行sscanf()
を解析するために を2 回呼び出したほうがよいと思います。
すべての変更の組み立て (を使用scanf()
):
if (fgets(input, sizeof(input), stdin) != 0)
{
if (input[strlen(input)-1] == '\n')
input[strlen(input)-1] = '\0';
if (strcmp(input, "point") == 0)
{
if (scanf("%d %d",&x1,&y1) != 2)
...report format error and return/exit...
point(x1, y1);
}
else if (strcmp(input, "rectangle") == 0)
{
if (scanf("%d %d %d %d", &x1, &y1, &x2, &y2) != 4)
...report format error and return/exit...
rectangle(x1, y1, x2, y2);
}
else
...unexpected input (format error)...
}
fgets()
と の使用sscanf()
:
if (fgets(input, sizeof(input), stdin) != 0)
{
if (input[strlen(input)-1] == '\n')
input[strlen(input)-1] = '\0';
if (strcmp(input, "point") == 0)
{
if (fgets(input, sizeof(input), stdin) == 0)
...report unexpected EOF and return/exit...
if (sscanf(input, "%d %d",&x1,&y1) != 2)
...report format error and return/exit...
point(x1, y1);
}
else if (strcmp(input, "rectangle") == 0)
{
if (fgets(input, sizeof(input), stdin) == 0)
...report unexpected EOF and return/exit...
if (sscanf(input, "%d %d %d %d", &x1, &y1, &x2, &y2) != 4)
...report format error and return/exit...
rectangle(x1, y1, x2, y2);
}
}
を使用した例では、ユーザーに報告できる入力行全体があることに注意してください。これは、一部の行を読み取って残りの変換を拒否したfgets()
後に残っているものを見つけるよりも、おそらく見つけやすいでしょう。scanf()
たとえば、入力が次の場合:
rectangle
10 10 2O 22
変換はO
( である必要があります0
) で失敗しますが、ユーザーに報告するために入力から収集できる唯一の情報は ですO 22
。これは、行全体を表示できるほど役に立たない可能性があります。
読みやすいようにフォーマットされた質問の後の回答
入力は 1 行です。
point 1 1
rectangle 1 0 0 1
その場合、 を使用scanf()
して数字を取得することはできません (既にfgets()
行全体を読み取っているため) 。ただし、比較コードと への呼び出しを変更する必要があります。特定の文字列が他の文字列のプレフィックスであるかどうかを確認するための非常に小さな関数を作成します。sscanf()
fgets()
sscanf()
int str_prefix(const char *haystack, const char *needle)
{
return strncmp(haystack, needle, strlen(needle)) == 0;
}
needle
が の先頭にある場合、これは true を返しますhaystack
。C99 以降のコンパイラを使用している場合は、それを修飾することができます(また、戻り値の型をorstatic inline
に賢明に変更できます)。bool
_Bool
if (fgets(input, sizeof(input), stdin) != 0)
{
if (input[strlen(input)-1] == '\n')
input[strlen(input)-1] = '\0';
if (str_prefix(input, "point "))
{
if (sscanf(input, "point %d %d",&x1,&y1) != 2)
...report format error and return/exit...
point(x1, y1);
}
else if (str_prefix(input, "rectangle "))
{
if (sscanf(input, "rectangle %d %d %d %d", &x1, &y1, &x2, &y2) != 4)
...report format error and return/exit...
rectangle(x1, y1, x2, y2);
}
}
「針」文字列の末尾の空白に注意してください。これにより、「指摘されたコメント」を「ポイント」行の開始と誤解するのを防ぐことができます。
フォーマット文字列をキーワードで開始する代わりsscanf()
に、キーワードの後に検索を開始できます。
if (sscanf(&input[sizeof("rectangle")], "%d %d %d %d", &x1, &y1, &x2, &y2) != 4)