C言語について質問があります。
以下のようにアドレスの個数とアドレスを入力として与えると、
入力
2
255.22.1.0
40.3.5.0
それぞれのアドレスが「.」か、0以上255以下の数値で構成されているなら、Yes、
そうでないなら、Noを出力させようと思い、プログラムを作成しました。
そして、以下のような入力に対して、以下の様な出力結果になると予想し、実行したところ、
入力
2
256.71.99.0
31.55.6.0
出力
No
Yes
下のような出力結果になりました。
出力
No
Abort trap: 6
また、入力値を変えて実行してみたところ、Yesと出力されるはずが、Noが出力されたり、Noと出るはずが、Yesと出力されました。
どなたか、原因が分かる方いましたら、回答お願いします。
補足ですが、配列suchiの生成時に、配列の大きさを変えてみると、出力結果が変わることがありますが、それでも同じような結果になりました。
「作成したプログラム」
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
int main(void){
int M = 0;//アドレスの数
scanf("%d",&M);
char IP[M][101];//M個のアドレス
int i = 0;
for(i = 0;i < M;i++){
scanf("%s",IP[i]);
}
for(i = 0;i < M;i++){
int j =0;
int hantei = -1;//文字列が書式に会ったものかを判定した結果を格納
while(IP[i][j]!='\n'){
char suchi[5];//数字を保管するためのもの
//現在の文字が数値の時
if(isdigit((unsigned char)IP[i][j])){
//文字が数値の間、連結する
while(isdigit((unsigned char)IP[i][j])){
sprintf(suchi,"%s%c",suchi,IP[i][j]);
j++;
}
//数値が条件を満たしている時
if(atoi(suchi)<=255&&atoi(suchi)>=0)hantei=1;
else {
hantei=-1;
break;
}
//配列suchiの中身を空にする
suchi[0] ='\0';
}
//現在の文字が'.'のとき
else if(IP[i][j]=='.'){
j++;
hantei = 1;
}
else if(IP[i][j]=='\0'){
break;
}
//いずれの条件にも一致しない時
else{
j++;
hantei = -1;
}
if(IP[i][j]=='\n'){
break;
}
if(hantei<0){
break;
}
}
if(hantei==1)printf("Yes\n");
else if(hantei==-1) printf("No\n");
}
return 0;
}
No.5
- 回答日時:
うまくいかない原因はほかの方が回答されていますが、
それ以前の問題として、IPアドレスのチェックの要件が不足しています。
ソースから読み取れる、チェック内容は以下の内容です。
1.数字は0~255の数値であること
2.数字(0~9)、ドット(.)以外の文字は使用しないこと
しかしながら、更に以下のチェックも必要なはずです。
3.ドットの数は3個であること
4.ドットの両端に数字があること
従って、
1)ドットで始まるアドレスはエラー
2)ドットで終わるアドレスはエラー
3)ドットが連続するアドレスはエラー
となります。
5.数字の先頭が0の場合は、次に数字が来ないこと
例えば、00、012、のような数字はエラーとすること
(これについては異論があるかも知れないが、ここではこのケースはエラーということにする)
尚、IP[i,j]のように2次元の配列を操作していますが、今回のようなケースでは
1次元の処理(1つの文字列の処理)を複数回繰り返すようにしたほうが、簡単ですっきりします。
又、atoi関数に渡す文字列をchar suchi[5]で定義し、そこに数字を格納していますが、
数字の開始位置を記憶し、その位置のアドレスをatoiに渡すようにしています。
(12.34 の場合、1のアドレス、3のアドレスをatoiに渡します。)
上記を踏まえて、作り直したものが、以下のプログラムです。
関数、check_addrに1つの文字列(IPアドレス)を渡し、チェックOKなら1を返します。
チェックNGの場合は、-1でなく、エラーの理由も判別できるように-1から-9の値を返します。
--------------------------------------------------------------------------------------
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#define ORIGINAL (1)
//アドレスチェック
//戻り値=1:正常終了
//戻り値<0:異常終了
int check_addr(char ip[]){
int i = 0;
int dot_ctr = 0; //ドット(.)のカウンター
int bx = -1; //数字列の開始位置の添え字
while(ip[i] != '\0'){ //文字列の最後の\nはscanfは取り込まないので\0で判定する
if (isdigit((unsigned char)(ip[i]))){
if (bx == -1){
bx = i; //数字列の先頭の位置を記憶する
}else{
if (ip[bx] == '0') return -1; //先頭の数字が0なら以降に数字があるのはエラー
}
if (i-bx > 2) return -2; //数字列が3桁を超過ならエラー
}else if (ip[i] == '.'){
dot_ctr++;
if (dot_ctr > 3) return -3; //.の数が3個を超過ならエラー
if (bx == -1) return -4; //.がいきなり出現場合はエラー
if (atoi(&ip[bx]) > 255) return -5; //数字列の値が255を超過(マイナスにはならないので上限のみのチェックで良い)
bx = -1; //開始位置の添え字を初期化
}else{
return -6; //数字、ドット(.)以外はエラー
}
i++; //次の文字を処理
}
if (dot_ctr != 3) return -7; //.の数が3個でないのはエラー
if (bx == -1) return -8; //.で終了しているのはエラー
if (atoi(&ip[bx]) > 255) return -9; //数字列の値が255を超過ならエラー
return 1; //正常終了
}
#if ORIGINAL
int main(void){
int M = 0;//アドレスの数
scanf("%d",&M);
char IP[M][101];//M個のアドレス
int i = 0;
for(i = 0;i < M;i++){
scanf("%s",IP[i]);
}
for(i = 0;i < M;i++){
int hantei;//文字列が書式に会ったものかを判定した結果を格納
hantei = check_addr(IP[i]);
if(hantei==1)printf("Yes\n");
else printf("No:%d\n",hantei); //hanteiが1以外ならエラー
}
return 0;
}
#else
int main(void){
int M = 0;//アドレスの数
char *IP[] = {
"1.2.3.4",
"255.255.255.255",
"0.0.0.0",
"01.2.3.4",
"1.00.3.4",
"1111.2.3.4",
"1.2.3.4.5",
".2.3.4",
"1.2..4",
"256.2.3.4",
"a.2.3.4",
"1.2.3",
"1.2.3.",
"1.2.3.256",
};
M = sizeof(IP)/sizeof(char*);
int i = 0;
for(i = 0;i < M;i++){
int hantei = -1;//文字列が書式に会ったものかを判定した結果を格納
printf("<%s>",IP[i]);
hantei = check_addr(IP[i]);
if(hantei==1)printf("Yes\n");
else printf("No:%d\n",hantei); //hanteiが1以外ならエラー(エラーコードも印字)
}
return 0;
}
#endif
--------------------------------------------------------------------------------------
尚、プログラムは、IPアドレスを画面から入力する方法(従来の方法)とIP用の文字列を予め作成しておき
それを渡す方法(第二の方法)のどちらかを選択できるようにしてあります。
#define ORIGINAL (1) とすると従来の方法 になります。
#define ORIGINAL (0) とすると第二の方法 になります。
第二の方法の実行結果は、以下の通りです。
<1.2.3.4>Yes
<255.255.255.255>Yes
<0.0.0.0>Yes
<01.2.3.4>No:-1
<1.00.3.4>No:-1
<1111.2.3.4>No:-2
<1.2.3.4.5>No:-3
<.2.3.4>No:-4
<1.2..4>No:-4
<256.2.3.4>No:-5
<a.2.3.4>No:-6
<1.2.3>No:-7
<1.2.3.>No:-8
<1.2.3.256>No:-9
No.4
- 回答日時:
「配列suchiの生成時に、配列の大きさを変えてみると、出力結果が変わることがありますが、それでも同じような結果になりました」の原因は #3 だなぁ.
ちなみに sprintf で入出力の範囲が重なるときは #1 に書いたように未定義動作>#2. この辺の規定は C89 では文章でしか書きようがなかったんだけど, C99 で restrict が導入されたことによりコードを見るだけで分かるようになりました.
細かいところまで、ご指摘ありがとうございます。指摘していただいたところを修正したところ、予想通りの出力がされました。ありがとうございます。
No.3ベストアンサー
- 回答日時:
>//配列suchiの中身を空にする
>suchi[0] ='\0';
最初のループの時、配列suchiには何が入ってるんでしょうかね?
宣言したローカル変数は全ビットが0になっているんですか??
No.2
- 回答日時:
sprintf(suchi,"%s%c",suchi,IP[i][j]);
入出力で範囲が重なるときって、ちゃんと動くんでしたっけ?
https://linuxjm.osdn.jp/html/LDP_man-pages/man3/ …
No.1
- 回答日時:
あんまりまじめにチェックしてないけどとりあえず
・while(IP[i][j]!='\n'){ の判定条件がおかしい
・sprintf(suchi,"%s%c",suchi,IP[i][j]); は未定義動作
と 2点指摘しておく.
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# c言語 プログラムのエラー 1 2023/02/11 20:31
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
- C言語・C++・C# プログラミング c言語 4 2023/03/07 01:05
- C言語・C++・C# カードシャッフルのブログラムを使ってc言語でブラックジャックをしたい 2 2022/04/12 15:13
- C言語・C++・C# C言語 3 2022/11/09 13:27
- C言語・C++・C# C言語 プログラミング 4 2022/05/22 11:53
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
c言語プログラミングで初項を1....
-
Expression: nptr != NULL
-
加減剰余のオーバーフローについて
-
C言語初心者です。計算がうまく...
-
情報の問題です。 サンプリング...
-
R-C直列回路にLを接続した時の...
-
減衰係数の求め方がわかりません
-
RCフィルタと三角波、方形波
-
火力発電 蒸気タービンのMSV、C...
-
一次遅れ系の制御における時定...
-
「跨川橋」は、「運河に架かる...
-
「寿司(すし)」は名詞とくっ...
-
クレーンでのCFブレーキとな...
-
定常応答 と 強制応答 は同...
-
雑音指数の疑問(その3)・過...
-
半波整流回路と平滑回路の波形...
-
入力容量(Input Capacitance)...
-
古典制御のゲイン交差周波数と...
-
小5算数 変わり方の問題
-
下の画像の問題を解説してくだ...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
c言語プログラミングで初項を1....
-
プログラミングが分かりません。
-
'printf':識別子が見つかりませ...
-
C言語のエラーについて
-
Expression: nptr != NULL
-
TCP/IP: 非ソケットに対するソ...
-
3×3のラテン方陣をつくるプログ...
-
加減剰余のオーバーフローについて
-
プログラムがエラーが出る原因
-
getch / putch用のヘッダ
-
コマンドライン引数について。
-
C言語で自作ヘッダーを作ったの...
-
コンソールAPIのSetConsoleScre...
-
分割コンパイルの手順と方法に...
-
C言語 コンパイルエラー(文字...
-
リターンキー又は、スペースキ...
-
C言語初心者です。計算がうまく...
-
最も文字数が多い行番号と文字...
-
モンテカルロ法で三角錐の体積...
-
C言語のソースコードについて教...
おすすめ情報