電子書籍の厳選無料作品が豊富!

よろしくお願いします。前回の質問で、テキストファイルにあらかじめ記述してある、「名前と電話番号を検索して表示するプログラム」は、皆さんのおかげで実行できるようになったのですが、
10人分の名前のうち、4人は表示されるのですが残りの6人は表示されません。
テキストファイルは、windowsxpに付属のものを使っています。
書き方は、10人とも同じ書き方です。
山野桜見
000000000 (半角で記入後エンターで改行してます)

春野花咲
1111111
この様にして10人分が書いてあります。同じ書き方なのに表示されるものとされないものとは、どこが違うのでしょうか、アドバイスをお願いします。
         

A 回答 (5件)

★編集ミスしていますね。


・編集ミスが2箇所あります。

1箇所目:電話番号を読み込む fgets の場所
if ( fgets(phone[loop],sizeof(phone[0]),fp) != NULL ){
 if ( (find = strchr(name[loop],'\n')) != NULL ){ ←間違い
  *find = '\0';
 }
}

if ( fgets(phone[loop],sizeof(phone[0]),fp) != NULL ){
 if ( (find = strchr(phone[loop],'\n')) != NULL ){ ←正しい
  *find = '\0';
 }
}
※strchr の文字列は name ではなくて phone が正しいです。

2箇所目:不必要な処理がある
fgets( name[loop], 22, fp );
name[ loop ][ strlen(name[loop]) - 1 ] = '\0';
fgets( phone[loop], 13, fp );
phone[ loop ][ strlen(phone[loop]) - 1 ] = '\0';
※この4行は必要ありません。改行を削除する処理ですが、strchr で見つかった位置に
 '\0'していますので不必要です。また、次の『名前+電話番号』を読み込んでいます。
 これでは1回のループで二人分のデータを読み込んでいることになりますよ。ここが間違い!

3箇所目:『検索と表示』の部分
if ( strcmp(name[loop],input) == '\0' ){ ←間違いではないが '\0' ではなく 0 です
 /*電話番号を表示*/
 printf( "%sさんの電話番号は : %s\n", input, phone[loop] );
}
※strcmp 関数は文字列を比較して 0、0以下、0以上を返します。
 一致した場合はゼロですが、'\0' を使うのはお勧めしません。'\0'は文字列の終端を表しますので
 数値のゼロは 0 と表記した方が良いと思います。→両方ともゼロという数値ですので動作には全く
 悪影響はありません。単純に可読性に疑問を感じてしまいます。なお、文字列で一致し場合の判定は
 『if ( !strcmp(name[loop],input) ){ … }』と『!』演算子で論理反転する方が一般的です。
 もちろん、0 とイコール演算子を使って判定しても構いませんけど。私は『!』演算子を使います。

最後に:
・編集ミスしている1箇所目の name を phone に変更して、2箇所目の不必要な処理4行を削除すると
 正しく動作しました。
・それから『検索と表示』の部分で見つからなかった場合は、何も表示されませんね。
 見つからない時はそのようなメッセージを出すようにしてみるのも良いでしょう。
・以上。おわり。
    • good
    • 0
この回答へのお礼

いつも適切なアドバイスありがとうございます。ご指摘の箇所を修正した所、データファイルの行間に関係なくすべての表示ができるようになりました。テキスト本にない記述をずいぶんと知ることが出来てとても参考になりました。後は、「検索と表示の部分で見つからない時のメッセージ」を表示するように改良してみます。
本当にありがとうございました。

お礼日時:2007/04/15 23:00

★最初に前回質問の URL の表示の仕方。


・マイページの『質問履歴』から過去に質問した履歴が見れますよね。
 そしたら、貼り付けたいリンクの上で右メニューより『ショートカットのコピー(T)』を
 選択するとクリップボードにリンク文字列がコピーされます。その後、質問内容を書く欄に
 右メニューより『貼り付け(P)』を選択すれば URL を簡単に貼り付けられます。

●本題
・原因はデータとプログラムでの『行数』があっていないからです。
 プログラムでは2行単位で1つの『名前+電話番号』を取得しています。
 でも、データは3行単位で1つの『名前+電話番号+空行』が記述されています。
・このことから、交互に表示と非表示が繰り返されたのです。

●改善方法
・データか、プログラムのどちらかを編集します。
 お勧めはプログラムです。→理由はどんなデータでも正しく動作(エラー表示も含み)できるように
 すべきですので。
・ではどこを修正すればよいか。
 それは、1つのデータを取得する部分を
 (1)名前の取得
 (2)電話番号の取得
 (3)連続する空行は読み飛ばす
 上記の3ステップを行えばよいのです。特に(3)の処理を追加しないと交互に表示、非表示が
 繰り返されるのです。下に繰り返し部分のサンプルを載せます。

改良サンプル:
int ch; ←また、宣言部に追加

for ( loop = 0 ; loop < 10 ; loop++ ){
 if ( fgets(name[loop],sizeof(name[0]),FP) != NULL ){
  if ( (find = strchr(name[loop],'\n')) != NULL ){
   *find = '\0';
  }
 }
 if ( fgets(phone[loop],sizeof(phone[0]),FP) != NULL ){
  if ( (find = strchr(name[loop],'\n')) != NULL ){
   *find = '\0';
  }
 }
 while ( (ch = fgetc(FP)) != EOF ){ ←ここが改良ポイント
  if ( ch != '\n' ){
   ungetc( ch, FP );
   break;
  }
 }
}

解説:
・while 文のブロックが連続する空行を読み飛ばす処理です。
・fgetc 関数で1文字ずつ読み込み、改行コード(\n)以外ならば繰り返しを抜けるようにしています。
 また、繰り返しを抜けるときに1文字多く読み込んでしまった文字を入力ストリームへ戻すために
 ungetc 関数を利用しています。これを忘れると次のデータの名前部分が半角で1文字分だけ削られて
 しまいます。その結果、名前部分が文字化けを起こします。→実際に試せば分かりますよ。
・あとファイルポインタの『FP』は小文字の『fp』の方が習慣的に分かりやすく感じます。なぜ大文字?
・以上。参考に!

参考URL:http://www.bohyoh.com/CandCPP/C/Library/ungetc.h …

この回答への補足

いつも的確なアドバイスありがとうございます。ご指摘のとおり、データファイルの行間を2行にした結果、全員が表示されました。
また、改良サンプルを新たに追加し、データファイルの行間を前回の3行でテストしてみたのですが、最初の一人だけしか表示されませんでした。よろしかったらアドバイスをお願いします。
それから「FP」 なのですが、参考にしているテキストの書き方なのでそのように書くものと思っていました。アドバイスありがとうございます。
改良したソースです。
#include <stdio.h>
#include <string.h>
int main()
{
char name[10][22] = {0};
char phone[10][13] = {0};
char input[21];
int loop;
FILE *fp;
char *find;
int ch;

if((fp = fopen("address.txt", "r")) == NULL)
{
printf("ファイルが開けません\n");
return(1);
}

for(loop = 0; loop < 10; loop++){
if(fgets(name[loop],sizeof(name[0]),fp) != NULL){
if((find = strchr(name[loop],'\n')) != NULL){
*find = '\0';
}
}
if(fgets(phone[loop],sizeof(phone[0]),fp) != NULL){
if((find = strchr(name[loop],'\n')) != NULL){
*find = '\0';
}
}
while((ch = fgetc(fp))!= EOF){
if(ch != '\n'){
ungetc(ch,fp);
break;
}
}

fgets(name[loop], 22, fp);
name[loop][strlen(name[loop]) -1] = '\0';
fgets(phone[loop], 13, fp);
phone[loop][strlen(phone[loop]) -1] = '\0';
}
printf("電話番号を検索したい名前を入力してください\n");
gets(input);

/*検索と表示*/
for(loop = 0; loop < 10; loop++){
if(strcmp(name[loop], input) == '\0'){

/*電話番号を表示*/

printf("%sさんの電話番号は : %s\n", input, phone[loop]);
}
}
return (0);
}

補足日時:2007/04/15 15:23
    • good
    • 0

>1、'0'から'\0'に変更


fgets(name[loop], 22, FP);
name[loop][strlen(name[loop]) -1] = '0';
fgets(phone[loop], 13, FP);
phone[loop][strlen(phone[loop]) -1] = '0';

直ってないですよね。

この回答への補足

すみません、最初の質問の時のソースです。こちらが修正したものです。
#include <stdio.h>
#include <string.h>
int main()
{
char name[10][22];
char phone[10][13];
char input[21];
int loop;
FILE *FP;

if((FP = fopen("address.txt", "r")) == NULL){
printf("ファイルが開けません\n");
return(1);
}
for(loop = 0; loop < 10; loop++){
fgets(name[loop], 22, FP);
name[loop][strlen(name[loop]) -1] = '\0';
fgets(phone[loop], 13, FP);
phone[loop][strlen(phone[loop]) -1] = '\0';
}
printf("電話番号を検索したい名前を入力してください\n");
gets(input);
for(loop = 0; loop < 10; loop++){
if(strcmp(name[loop], input) == 0){
printf("%sさんの電話番号は : %s\n", input, phone[loop]);
}
}
return (0);
}
よろしくお願いします。

補足日時:2007/04/15 10:23
    • good
    • 0

5人目の具体的なデータをお願いいたします。

この回答への補足

回答ありがとうございます。実際に使用しているテキストファイルのコピーです。

鈴木一郎
001236540 (表示可)

鈴木二郎  (非表示)
00125458

鈴木三郎
03245872  (表示可)

鈴木四郎
879423124  (非表示)

鈴木五郎
998875120  (表示可)

山田一郎
101022    (非表示)

山田二郎
77845122   (表示可)

山田三郎
02121215   (非表示)

山田四郎
0021365    (非表示)

山田五郎
9987545    (非表示)
(非表示) とした所が名前だけが表示されて、電話番号が表示されません。電話番号は、テンキーから入力しました。
よろしくお願いします。

補足日時:2007/04/14 22:44
    • good
    • 0
この回答へのお礼

回答ありがとうございました。無事に解決することが出来ました。

お礼日時:2007/04/15 23:04

 申し訳ありませんが、参考までに前回の質問のURLをお願いします。


 またもし前回の質問にソースが無いようでしたらソースコードも書き込んでください。

 一応デバッグライトをお勧めしておきます。
 デバッグライトとは、適当なところで変数の値などを出力させる事です。
 そしてその場での値の整合性やプログラムがどこまで動いているか確認する方法です。

 確認するタイミングはこの辺りですね。
1.データの取得時(の全データ)
2.データの検索時(比較されるデータ)
3.出力時(何回目の出力か)
 他にもあると思うのでその辺りを加えて調べてみると良いでしょう。

 何よりも前質問のURLとソースコードをお願いします。

この回答への補足

回答ありがとうございます。前回質問のURLの表示の仕方が分かりませんので、質問番号をお知らせします。Q NO2897482です。
前回のアドバイスにより
1、'0'から'\0'に変更
2、質問時のソースでは少なくしたのですが、実際のソースには解説のためのコメントが多かったので、すべてのコメントを削除。
3、この2点を改良した結果実行できました。また、前回の回答のANO.3さんのアドバイスを基にしたプログラムでも実行できたのですが、全員の実行は無理でした。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main()
{
char name[10][22];
char phone[10][13];
char input[21];
int loop;
FILE *FP;
if((FP = fopen("address.txt", "r")) == NULL)
{
printf("ファイルが開けません\n");
return(1);
}
    /*ファイルからデータを読み込む*/
for(loop = 0; loop < 10; loop++)
{
fgets(name[loop], 22, FP);
name[loop][strlen(name[loop]) -1] = '0';
fgets(phone[loop], 13, FP);
phone[loop][strlen(phone[loop]) -1] = '0';
}
printf("電話番号を検索したい名前を入力してください\n");
gets(input);
/*検索と表示*/
for(loop = 0; loop < 10; loop++)
{
if(strcmp(name[loop], input) == 0)
{
 printf("%sさんの電話番号は : %s\n", input, phone[loop]);
}
}
return (0);
}
ここからはテキストファイルの中身です。
鈴木一郎
001236540 (表示可)

鈴木二郎
00125458 (非表示)

鈴木三郎
03245872 (表示可)

鈴木四郎
879423124 (非表示)

鈴木五郎
998875120 (表示可)

山田一郎
101022   (非表示)

山田二郎
77845122  (表示可)

山田三郎  (非表示)
02121215

山田四郎  (非表示)
0021365

山田五郎
9987545  (非表示)
以上です、よろしくお願いします。

補足日時:2007/04/14 22:13
    • good
    • 0
この回答へのお礼

アドバイスありがとうございました。無事解決することが出来ました。
デバッグライトと言う言葉を知り、いろいろ検索した結果、参考になる所を見つけることが出来ました。

お礼日時:2007/04/15 23:03

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!