質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

Webサーバー

Webサーバーとは、HTTPリクエストに応じて、クライアントに情報を提供するシステムです。

サーバ

サーバは、 クライアントサーバモデルにおいてクライアントからの要求に対し 何らかのサービスを提供するプログラムを指す言葉です。 また、サーバーソフトウェアを稼動させているコンピュータ機器そのもののことも、 サーバーと呼ぶ場合もあります。

Q&A

3回答

2341閲覧

C言語 ファイルから読み込んだデータを指示通り変数に代入できない

退会済みユーザー

退会済みユーザー

総合スコア0

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

Webサーバー

Webサーバーとは、HTTPリクエストに応じて、クライアントに情報を提供するシステムです。

サーバ

サーバは、 クライアントサーバモデルにおいてクライアントからの要求に対し 何らかのサービスを提供するプログラムを指す言葉です。 また、サーバーソフトウェアを稼動させているコンピュータ機器そのもののことも、 サーバーと呼ぶ場合もあります。

0グッド

1クリップ

投稿2020/11/19 13:04

プログラムの内容

c言語で、ファイルから読み取ったデータをもとにサーバーが動いているかどうかを確認するプログラムを作成しています。
読み込むファイル
20201019133124,10.20.30.1/16,-
20201019133125,10.20.30.2/16,1
20201019133134,192.168.1.1/24,10
20201019133135,192.168.1.2/24,5
20201019133224,10.20.30.1/16,522
20201019133225,10.20.30.2/16,1
20201019133234,192.168.1.1/24,8
20201019133235,192.168.1.2/24,15
20201019133324,10.20.30.1/16,-
20201019133325,10.20.30.2/16,3
20201019134510,192.168.1.1/24,1
20201019135050,192.168.1.2/24,15
20201019135051,10.20.30.1/16,-
20201019135052,10.20.30.2/16,3
20201019135055,10.20.30.1/16,2
20201019135100,10.20.30.2/16,2
20201019135510,192.168.1.1/24,-
20201019135550,192.168.1.2/24,15
20201019135600,192.168.1.1/24,-
20201019135601,192.168.1.2/24,15
20201019135610,192.168.1.1/24,1
20201019135611,192.168.1.2/24,15
左から<確認日時>,<サーバアドレス>,<応答結果>という並びになっています。
応答結果で-が返ってきた場合にサーバー故障とみなすようになっています。

このファイルを読み込み、故障状態のアドレスとそのアドレスの故障期間を出力するプログラムを作りたいと考えています。
(故障期間は、最初に-が出てから次にちゃんとしたping値がかえるまでの期間)

該当のソースコード

c

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4#include <stdbool.h> 5 6#define N 50 7struct HANDAN{ 8 char handan_name[N]; 9 int kaisuu; 10 long time; 11 bool count; 12}; 13 14struct LOG{ 15 long time; 16 char server_name[N]; 17 char result[N]; 18}; 19 20void printTime(long kikan){ 21 char kikan2[14]; 22 sprintf(kikan2,"%ld",kikan); 23 int len = strlen(kikan2); 24 long sec,min,hour,day,month,year; 25 year = kikan/10000000000; 26 month = (kikan/1000000)%100; 27 day = (kikan/10000)%100; 28 hour = (kikan/100)%100; 29 min = kikan/100; 30 sec = kikan%100; 31 32 if(sec>=60){ 33 sec = sec-60; 34 min = min+1; 35 } 36 if(min>=60){ 37 sec = min-60; 38 hour = hour+1; 39 } 40 //printf("%ld年%ld月%ld日%ld時%ld分です\n",year,month,day,hour,min); 41 //printf("kikan is %ld\n",kikan); 42 43 if(len<=2){ 44 printf("故障期間は%ld秒です\n",sec); 45 }else if(len<=4){ 46 printf("故障期間は%ld分%ld秒です\n",min,sec); 47 }else if(len<=6){ 48 printf("故障期間は%ld時%ld分%ld秒です\n",hour,min,sec); 49 }else if(len<=8){ 50 printf("故障期間は%ld日%ld時%ld分%ld秒です\n",day,hour,min,sec); 51 }else if(len<=10){ 52 printf("故障期間は%ld月%ld日%ld時%ld分%ld秒です\n",month,day,hour,min,sec); 53 }else if(len<=14){ 54 printf("故障期間は%ld年%ld月%ld日%ld時%ld分%ld秒です\n",year,month,day,hour,min,sec); 55 } 56} 57 58 59 60int main(){ 61 FILE *fp; 62 struct HANDAN han[N]; 63 struct LOG log[N]; 64 char s[N][N],*cp; 65 char name[4][15]={"10.20.30.1/16","10.20.30.2/16","192.168.1.1/24","192.168.1.2/24"}; 66 const char *sikiri=","; 67 long handan_time=0,kikan; 68 int i = 0,j = 0,h=0; 69 int kaisuu[4] = {}; 70 bool count[N]={};//countによって故障したかどうか判断 71 72 fp = fopen("server.txt","r"); 73 74 while(fgets(s[i],N,fp)!=NULL){ 75 cp = strtok(s[i],sikiri); 76 log[i].time=atol(cp);//ここで時間を挿入、文字列から数に変換 77 int c=0; 78 while(cp!=NULL){ 79 cp = strtok(NULL,sikiri); 80 if(cp!=NULL&&c==0){ 81 strcpy(log[i].server_name,cp); //ここでサーバーの名前を挿入 82 c++; 83 84 for(h=0;h<=j;h++){ 85 if(han[h].count==true){ //if(故障していたら)故障状況をプリント 86 if(strcmp(han[h].handan_name,log[i].server_name)==0){ 87 kikan=log[i].time-han[h].time; 88 printf("サーバー%sが故障状態です\n",han[h].handan_name); 89 printf("log.time is %ld\nhandan is %ld\n",log[i].time,han[h].time); 90 printTime(kikan); 91 han[h].count = false; 92 93 } 94 } 95 96 } 97 98 } 99 100 if(cp!=NULL&&c==1){ 101 strcpy(log[i].result,cp);//ここで結果を挿入 102 if(strncmp(log[i].result,"-",1)==0){ //1."-"かどうか 103 for(h=0;h<4;h++){//回数計算 104 if(strcmp(log[i].server_name,name[h])==0){ //入力された値がどれかと一緒ならkaisuuを+1する 105 if(kaisuu[h]==0){ //2.一回目か 106 strcpy(han[j].handan_name,log[i].server_name); 107 han[j].time = log[i].time; 108 } 109 kaisuu[h]++; 110 } 111 } 112 //printf("%d %d %d %d\n",kaisuu[0],kaisuu[1],kaisuu[2],kaisuu[3]); 113 }else{ 114 for(h=0;h<=j;h++){ 115 if(strcmp(han[h].handan_name,log[i].server_name)==0){//名前が以前に出てきていないか確認 116 han[h].count=true; 117 } 118 } 119 } 120 } 121 j++; 122 } 123 124 i++; 125 } 126 127 fclose(fp); 128 return 0; 129}

発生している問題

実行してみると、以下のように出力されます。

サーバー10.20.30.1/16が故障状態です log.time is 20201019133324 handan is 20201019133124 故障期間は2分0秒です サーバー10.20.30.1/16が故障状態です log.time is 20201019135051 handan is 20201019133124 故障期間は19分27秒です サーバー10.20.30.1/16が故障状態です log.time is 20201019135055 handan is 20201019133124 故障期間は19分31秒です サーバー192.168.1.1/24が故障状態です log.time is 20201019135610 handan is 20201019135510 故障期間は1分0秒です

出力された結果を見ると、応答結果で-が出た後、応答結果が正常かどうかは関係なく同じアドレスのログを一つ飛ばしで参照されてしまいます。

例)

サーバー10.20.30.1/16が故障状態です

と出力された後、本当ならば
20201019133224,10.20.30.1/16,522
のログを参照して変数に代入したいのですが、
20201019133324,10.20.30.1/16,-
のログを参照してしまいます。

どう変更すればうまく参照できるようになるのでしょうか。
言葉足らずな説明で申し訳ありません。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tatsu99

2020/11/20 01:48

これは、何かの課題なのでしょうか。 それとも、実際の業務で使うものなのでしょうか。
tatsu99

2020/11/20 05:18

課題なら現行の方法になるかも知れませんが、 実際の業務ならもっと改善の余地があります。 言語はC言語でなく、perlとかrubyでやった方が簡単です。 現行ではserver.txtの行数が最大50行、監視対象のサーバーが4つの前提になりますが、 実際の業務ならserver.txtの行数及び監視対象のサーバー数に特に制約を設けたくないかと思います。 perlとかrubyなら制約を設けなくても簡単に実現できます。 C言語でやる場合なら、server.txtの行数は制限なしにできますが、サーバー数については、制限が必要に した方が簡単に実現できます。(工数を増やせば制限なしにすることも可能ですが・・・)
guest

回答3

0

とりあえず、修正しました。
Nがいろいろな用途で使用されていたので1つの用途に限定しました。

C

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4#include <stdbool.h> 5 6#define N (50) //読み込むファイルの1行の長さ 7#define H (100) //判断テーブルhan[]の最大要素数 8struct HANDAN { 9 char handan_name[N]; 10 int kaisuu; 11 long time; 12 bool count; 13}; 14 15struct LOG { 16 long time; 17 char server_name[N]; 18 char result[N]; 19}; 20 21void printTime(long kikan) 22{ 23 char kikan2[14]; 24 sprintf(kikan2, "%ld", kikan); 25 int len = strlen(kikan2); 26 long sec, min, hour, day, month, year; 27 year = kikan / 10000000000; 28 month = (kikan / 1000000) % 100; 29 day = (kikan / 10000) % 100; 30 hour = (kikan / 100) % 100; 31 min = kikan / 100; 32 sec = kikan % 100; 33 34 if (sec >= 60) { 35 sec = sec - 60; 36 min = min + 1; 37 } 38 if (min >= 60) { 39 sec = min - 60; 40 hour = hour + 1; 41 } 42 //printf("%ld年%ld月%ld日%ld時%ld分です\n",year,month,day,hour,min); 43 //printf("kikan is %ld\n",kikan); 44 45 if (len <= 2) { 46 printf("故障期間は%ld秒です\n", sec); 47 } else if (len <= 4) { 48 printf("故障期間は%ld分%ld秒です\n", min, sec); 49 } else if (len <= 6) { 50 printf("故障期間は%ld時%ld分%ld秒です\n", hour, min, sec); 51 } else if (len <= 8) { 52 printf("故障期間は%ld日%ld時%ld分%ld秒です\n", day, hour, min, 53 sec); 54 } else if (len <= 10) { 55 printf("故障期間は%ld月%ld日%ld時%ld分%ld秒です\n", month, day, 56 hour, min, sec); 57 } else if (len <= 14) { 58 printf("故障期間は%ld年%ld月%ld日%ld時%ld分%ld秒です\n", year, 59 month, day, hour, min, sec); 60 } 61} 62 63 64 65int main() 66{ 67 FILE *fp; 68 struct HANDAN han[H]; 69 struct LOG log; 70 char s[N], *cp; 71 const char *sikiri = ","; 72 long kikan; 73 bool find; 74 int i = 0, h = 0; 75 int han_ctr = 0; //han[N]に登録した件数 76 fp = fopen("server.txt", "r"); 77 78 while (fgets(s, N, fp) != NULL) { 79 cp = strtok(s, sikiri); 80 if (cp == NULL) continue; 81 log.time = atol(cp); //ここで時間を挿入、文字列から数に変換 82 cp = strtok(NULL, sikiri); 83 if (cp == NULL) continue; 84 strcpy(log.server_name, cp); //ここでサーバーの名前を挿入 85 cp = strtok(NULL, sikiri); 86 if (cp == NULL) continue; 87 strcpy(log.result, cp); //ここで結果を挿入 88 if (strncmp(log.result, "-",1) == 0) { //1."-"かどうか 89 find = false; 90 for (h = 0; h < han_ctr; h++){ //判断テーブル検索 91 if (strcmp(log.server_name, han[h].handan_name) == 0){ 92 find = true; 93 break; 94 } 95 } 96 //判断テーブル上にサーバーが存在しない場合 97 if (find == false){ 98 if (han_ctr >= H){ //上限オーバーなら、次のログの読み込みへ 99 printf("判断テーブル上限:%d オーバー |%ld|%s|の故障監視をスキップ\n",H,log.time,log.server_name); 100 continue; 101 } 102 //判断テーブルに新規登録(値は初期値) 103 h = han_ctr; 104 strcpy(han[h].handan_name,log.server_name); 105 han[h].count = false; 106 han[h].time = 0; 107 han[h].kaisuu = 0; 108 han_ctr++; 109 } 110 han[h].kaisuu++; //回数カウントアップ 111 if (han[h].count == false){ //故障中でなければ、故障中にし、時刻を登録する。 112 //故障中ならなにもしない。(回数カウントアップのみ) 113 han[h].count = true; 114 han[h].time = log.time; 115 } 116 }else{ 117 //"-"以外のケース 118 for (h = 0; h < han_ctr; h++) { 119 if (strcmp(log.server_name, han[h].handan_name) == 0) { //入力された値がどれかと一緒なら検索終了 120 if (han[h].count == true){ //故障中なら故障状況をプリント 121 kikan = log.time - han[h].time; 122 printf("サーバー%sが故障状態です\n", 123 han[h].handan_name); 124 printf("log.time is %ld\nhandan is %ld\n", 125 log.time, han[h].time); 126 printTime(kikan); 127 han[h].count = false; 128 } 129 continue; //次のログの読み込みへ 130 } 131 } 132 } 133 } 134 135 fclose(fp); 136 return 0; 137} 138

実行結果は以下の通り
サーバー10.20.30.1/16が故障状態です
log.time is 20201019133224
handan is 20201019133124
故障期間は1分0秒です
サーバー10.20.30.1/16が故障状態です
log.time is 20201019135055
handan is 20201019133324
故障期間は17分31秒です
サーバー192.168.1.1/24が故障状態です
log.time is 20201019135610
handan is 20201019135510
故障期間は1分0秒です

ところで、年末に故障が発生し、翌年復旧するケースで例えば、以下のようなデータ
20201231235959,10.20.30.1/16,-
20210101000009,10.20.30.1/16,1
を処理すると
サーバー10.20.30.1/16が故障状態です
log.time is 20210101000009
handan is 20201231235959
故障期間は69月76日41時88697640分88697580秒です
のような結果になりますが、これはよろしいのでしょうか。
(故障期間は10秒です。・・・・これが期待する結果のような気がします)

投稿2020/11/22 02:38

tatsu99

総合スコア5438

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

回答としては不十分かと思いますが、、、

まず、中で何をしているか把握しているでしょうか? インデントが途中で合っていないところを見ると、どこからか、コピーし、張り合わせたのでしょうか。

さて、最初にある

if(cp!=NULL&&c==0){

のカッコの中(インデントが合ってないので範囲が分かりにくい)で、サーバーの名前をコピーし、for(h=0;h<=j;h++){では何をしたいのでしょう? 次の if()のコメントは、"(故障していたら)"とありますが、ここでは、故障かどうかの判定はできません。

次の

if(cp!=NULL&&c==1){

で、応答結果を見ているので、ここで故障かどうかの判定となると思います。
if(strncmp(log[i].result,"-",1)==0){ が故障だと思いますが、kaisuu[h]に入れた値は何に使うのでしょう? ここで、han[h].count=true;にすべきでは?
で、ここの }else{が故障じゃない時と思わるので、前回が故障なら、、という処理にすべきではないかと考えます。

直接、コードを書くのも良いですが、どこで何をすべきかの検討が足りてないように思われます。

また、jの変数は何を意味しているでしょうか? han[N]のインデックスにも参照されているようですが、多分、オーバーフローしてます。

具体的にどう書き換えるかは、全体の流れを見直す事が必要です。
(このコードの流れで書き換えるのはちょっと大変か?)

中のwhile() 内について、ちょっと参考コード。こんな感じかという事で。

C

1 while(cp!=NULL){ 2 cp = strtok(NULL,sikiri); 3 if(cp!=NULL&&c==0){ 4 strcpy(log[i].server_name,cp); //ここでサーバーの名前を挿入 5 //// ここから 対応するサーバー番号を探す hに設定 (無い場合は? ...) 6 // for(h=0;h<4;h++){ 7 // if(strcmp(log[i].server_name, name[h])==0) break; 8 // } 9 } 10 11 if(cp!=NULL&&c==1){ 12 strcpy(log[i].result,cp);//ここで結果を挿入 13 if(strncmp(log[i].result,"-",1)==0){ //1."-"かどうか 14 //// 障害が発生した場合には、それを記録 サーバー番号 h 15 // if (!han[h].count) { // ただし、最初に初期化で false としておく 16 // han[h].count = true; 17 // han[h].time = log[i].time 18 // } 19 }else{ 20 //// 前回が障害の場合の処理 21 // if (han[h].count) { 22 // kikan=log[i].time - han[h].time; 23 // printf("サーバー%sが故障状態です\n",han[h].handan_name); 24 // printf("log.time is %ld\nhandan is %ld\n",log[i].time,han[h].time); 25 // printTime(kikan); 26 // han[h].count = false; 27 // } 28 } 29 } 30 }

投稿2020/11/20 09:42

編集2020/11/20 11:32
pepperleaf

総合スコア6383

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pepperleaf

2020/11/21 00:51

書き換えてみようかと思ったのですが、以下の理由で保留。 - VCでコンパイルすると、intのサイズが違うとかで動作が変わる - 細々した箇所が気になり、大幅に手を入れたくなる
guest

0

C言語のコードを書くなら、デバッグできる環境を整えましょう。
Eclipseや、WindowsならVisualStudioなど。
コードの任意の場所で実行を止め、変数のナカミを見ることができます。そこから1行づつ実行して、コードの流れを見れるようになります
そうすれば、アテズッポでコードを書かなくて済むようになります。

投稿2020/11/19 13:41

y_waiwai

総合スコア87774

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問