C言語の質問です
-
きょろ
C言語の質問です
テキストファイルに英単語を登録したり、それを検索(読み出)したりするプログラムを作りました。
しかし、登録までは上手くいくのですが検索になるとうまく行きません。何処が悪いのでしょうか?
下のプログラムをご覧下さい。(登録は大丈夫でしたが、全文を載せておきます)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#
#
#define FILENAME "tango.txt"
#//夫々の配列の要素数
#define SPELL 20
#define MEAN 100
#define PAGE 10
#define LINE 10
#define SNT 100
#
#define GOKEI SPELL + MEAN + PAGE + LINE + SNT
char Spelling[SPELL], //単語の綴り
Meaning[MEAN], //単語の意味
Page[PAGE], //単語の登録されているページ
Line[LINE], //単語の登録されている行数
Sonota[SNT]; //その他の情報
// 綴り 意味 ページ 行数 その他の情報
char *format = "%-20s%-100s%-5d%-5d%-100s";
char *format2 = "%-100s%-5d%-5d%-100s";
int menu(); //メニュー関数
int toroku(); //単語を登録する関数
int kensaku(); //単語を検索する関数
int shusei(); //単語を修正する関数 ※まだ此れは未制作です
int main()
{
int no;
no = menu();
while(1) {
switch(no) {
case 1: no = toroku();
continue;
case 2: no = kensaku();
continue;
case 3: no = shusei();
continue;
case 0: break;
case 4: no = menu();
continue;
}
break;
}
return 0;
}
//メニュー画面
int menu()
{
char no[4];
int so;
while(1) {
system("cls");
puts("-----------------------");
puts("1:単語の登録");
puts("2:単語の検索");
puts("3:単語の修正");
puts("0:終了");
puts("-----------------------");
printf("->>");
gets(no);
if(no[0] < '0' || no[0] > '3') {
printf("入力が不正です\n\n");
continue;
}else{
no[1] = '\0';
}
so = atoi(no);
break;
}
system("cls"); //画面を消去
return so;
}
//データの登録
int toroku()
{
FILE *fp;
int Pa, Li, no;
char yesno[5];
fp = fopen(FILENAME,"a");
if(fp == NULL) {
perror("ファイルをオープンできません\n");
return -1;
}
while(1) {
printf("単語を入力して下さい\n");
printf("-> ");
gets(Spelling);
printf("単語の意味を入力して下さい\n");
printf("-> ");
gets(Meaning);
printf("単語の登録されているページを入力して下さい\n");
printf("-> ");
gets(Page);
Page[PAGE - 1] = '\0';
Pa = atoi(Page);
printf("単語の登録されているページの行数を入力して下さい\n");
printf("-> ");
gets(Line);
Line[LINE - 1] = '\0';
Li = atoi(Line);
printf("その他の情報がありましたら入力して下さい\n");
printf("-> ");
gets(Sonota);
printf("\nこれらを登録しますか?\n");
printf("はい -- Y\n");
printf("もう一度打ち直す-- N\n");
printf("タイトルに戻る -- E\n");
printf("-> ");
gets(yesno);
if(yesno[0] == 'Y' || yesno[0] == 'y') {
fprintf(fp, format, Spelling, Meaning, Pa, Li, Sonota); //入力したデータを書き込む
printf("入力を続けますか?(Y/N):");
gets(yesno);
if(yesno[0] == 'Y' || yesno[0] == 'y')
continue;
else
break;
}else if(yesno[0] == 'N' || yesno[0] == 'n') {
continue;
}else if(yesno[0] == 'E' || yesno[0] == 'e'){
break;
}else{
break;
}
}
system("cls"); //画面を消去
fclose(fp);
return 4;
}
int kensaku()
{
saisho_K:
FILE *fp;
char search[SPELL], str2[SPELL], yesno[5] = {0};
int Pa1 = 0, Li1, i = -1, find = 0;
fp = fopen(FILENAME, "r");
if(fp == NULL){
perror("ファイルをオープンできません\n");
return -1;
}
printf("検索したい単語名を入力して下さい\n");
printf("-> ");
gets(search);
while(1) {
i++;
fseek(fp, GOKEI*i, SEEK_SET);
if(fscanf(fp, "%s", str2) == EOF) {
printf("見つかりませんでした\n");
Pa1 = 100;
break;
}
if(strcmp(str2, search) == 0) {
fscanf(fp, format2, Meaning, Page, Line, Sonota);
find++;
printf("見つかりました\n");
printf("-------------------");
printf("単語名:%-20s\n", str2);
printf("意味 :%-100s\n", Meaning);
printf("ページ:%dページ\n", Page);
printf("行 :%d行\n",Line);
printf("その他の情報\n"
"%s",Sonota);
printf("-------------------");
printf("更に検索を続けますか?(Y/N):");
gets(yesno);
if(yesno[0] == 'Y' || yesno[0] == 'y')
continue;
else
break;
}
}
printf("%d件が検索されました",find);
if(Pa1 == 100) {
printf("もう一度検索しますか?(Y/N):");
gets(yesno);
if(yesno[0] == 'Y' || yesno[0] == 'y')
goto saisho_K;
}
fclose(fp);
return 4;
}
ご解答宜しくお願いします
また、ご不明な点がございましたら仰って下さい。
しかし、登録までは上手くいくのですが検索になるとうまく行きません。何処が悪いのでしょうか?
下のプログラムをご覧下さい。(登録は大丈夫でしたが、全文を載せておきます)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#
#
#define FILENAME "tango.txt"
#//夫々の配列の要素数
#define SPELL 20
#define MEAN 100
#define PAGE 10
#define LINE 10
#define SNT 100
#
#define GOKEI SPELL + MEAN + PAGE + LINE + SNT
char Spelling[SPELL], //単語の綴り
Meaning[MEAN], //単語の意味
Page[PAGE], //単語の登録されているページ
Line[LINE], //単語の登録されている行数
Sonota[SNT]; //その他の情報
// 綴り 意味 ページ 行数 その他の情報
char *format = "%-20s%-100s%-5d%-5d%-100s";
char *format2 = "%-100s%-5d%-5d%-100s";
int menu(); //メニュー関数
int toroku(); //単語を登録する関数
int kensaku(); //単語を検索する関数
int shusei(); //単語を修正する関数 ※まだ此れは未制作です
int main()
{
int no;
no = menu();
while(1) {
switch(no) {
case 1: no = toroku();
continue;
case 2: no = kensaku();
continue;
case 3: no = shusei();
continue;
case 0: break;
case 4: no = menu();
continue;
}
break;
}
return 0;
}
//メニュー画面
int menu()
{
char no[4];
int so;
while(1) {
system("cls");
puts("-----------------------");
puts("1:単語の登録");
puts("2:単語の検索");
puts("3:単語の修正");
puts("0:終了");
puts("-----------------------");
printf("->>");
gets(no);
if(no[0] < '0' || no[0] > '3') {
printf("入力が不正です\n\n");
continue;
}else{
no[1] = '\0';
}
so = atoi(no);
break;
}
system("cls"); //画面を消去
return so;
}
//データの登録
int toroku()
{
FILE *fp;
int Pa, Li, no;
char yesno[5];
fp = fopen(FILENAME,"a");
if(fp == NULL) {
perror("ファイルをオープンできません\n");
return -1;
}
while(1) {
printf("単語を入力して下さい\n");
printf("-> ");
gets(Spelling);
printf("単語の意味を入力して下さい\n");
printf("-> ");
gets(Meaning);
printf("単語の登録されているページを入力して下さい\n");
printf("-> ");
gets(Page);
Page[PAGE - 1] = '\0';
Pa = atoi(Page);
printf("単語の登録されているページの行数を入力して下さい\n");
printf("-> ");
gets(Line);
Line[LINE - 1] = '\0';
Li = atoi(Line);
printf("その他の情報がありましたら入力して下さい\n");
printf("-> ");
gets(Sonota);
printf("\nこれらを登録しますか?\n");
printf("はい -- Y\n");
printf("もう一度打ち直す-- N\n");
printf("タイトルに戻る -- E\n");
printf("-> ");
gets(yesno);
if(yesno[0] == 'Y' || yesno[0] == 'y') {
fprintf(fp, format, Spelling, Meaning, Pa, Li, Sonota); //入力したデータを書き込む
printf("入力を続けますか?(Y/N):");
gets(yesno);
if(yesno[0] == 'Y' || yesno[0] == 'y')
continue;
else
break;
}else if(yesno[0] == 'N' || yesno[0] == 'n') {
continue;
}else if(yesno[0] == 'E' || yesno[0] == 'e'){
break;
}else{
break;
}
}
system("cls"); //画面を消去
fclose(fp);
return 4;
}
int kensaku()
{
saisho_K:
FILE *fp;
char search[SPELL], str2[SPELL], yesno[5] = {0};
int Pa1 = 0, Li1, i = -1, find = 0;
fp = fopen(FILENAME, "r");
if(fp == NULL){
perror("ファイルをオープンできません\n");
return -1;
}
printf("検索したい単語名を入力して下さい\n");
printf("-> ");
gets(search);
while(1) {
i++;
fseek(fp, GOKEI*i, SEEK_SET);
if(fscanf(fp, "%s", str2) == EOF) {
printf("見つかりませんでした\n");
Pa1 = 100;
break;
}
if(strcmp(str2, search) == 0) {
fscanf(fp, format2, Meaning, Page, Line, Sonota);
find++;
printf("見つかりました\n");
printf("-------------------");
printf("単語名:%-20s\n", str2);
printf("意味 :%-100s\n", Meaning);
printf("ページ:%dページ\n", Page);
printf("行 :%d行\n",Line);
printf("その他の情報\n"
"%s",Sonota);
printf("-------------------");
printf("更に検索を続けますか?(Y/N):");
gets(yesno);
if(yesno[0] == 'Y' || yesno[0] == 'y')
continue;
else
break;
}
}
printf("%d件が検索されました",find);
if(Pa1 == 100) {
printf("もう一度検索しますか?(Y/N):");
gets(yesno);
if(yesno[0] == 'Y' || yesno[0] == 'y')
goto saisho_K;
}
fclose(fp);
return 4;
}
ご解答宜しくお願いします
また、ご不明な点がございましたら仰って下さい。
Re: C言語の質問です
とりあえず、コードを提示するときはBBcodeを有効にした状態でcodeタグで囲み、
かつ適切なインデントをしていただけると、見やすくて助かります。
かつ適切なインデントをしていただけると、見やすくて助かります。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)
Re: C言語の質問です
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)
Re: C言語の質問です
さらに、PAGEおよびLINEマクロの情報とformatに代入されている情報が矛盾しており、
上記の問題を修正しても不都合が生じる原因になります。
上記の問題を修正しても不都合が生じる原因になります。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)
-
きょろ
Re: C言語の質問です
ああ
GOKEI * i
だと
SPELL + MEAN + PAGE + LINE + SNT * i
つまり
SPELL + MEAN + PAGE + LINE +( SNT * i)
こうなるという事ですか!?
GOKEI * i
だと
SPELL + MEAN + PAGE + LINE + SNT * i
つまり
SPELL + MEAN + PAGE + LINE +( SNT * i)
こうなるという事ですか!?
Re: C言語の質問です
書き込まれる1単語あたりのデータサイズと、読み込むときの1単語あたりのシーク距離が違うので、きょろ さんが書きました:format
が矛盾してるってどういう事ですか?
読み込むが上手くいかない可能性が高いと思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)
Re: C言語の質問です
そうですね。 とするのがいいと思います。きょろ さんが書きました:ああ
GOKEI * i
だと
SPELL + MEAN + PAGE + LINE + SNT * i
つまり
SPELL + MEAN + PAGE + LINE +( SNT * i)
こうなるという事ですか!?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)
-
きょろ
Re: C言語の質問です
済みません、BBcodeとかのやり方が解らないのでそのまま載せます。
ひとまず所々直し、検索して無事に見つかったのですが、やはりご指摘通りformatが悪いのかページが「3666733ページ」
とか表示されます。しかし、どうすれば直るか解りません。
アドバイスだけでもいいので頂けませんか?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#
#
#define FILENAME "tango.txt"
#define SPELL 20
#define MEAN 100
#define PAGE 10
#define LINE 10
#define SNT 100
#define GOKEI (SPELL + MEAN + PAGE + LINE + SNT)
char Spelling[SPELL], //単語の綴り
Meaning[MEAN], //単語の意味
Page[PAGE], //単語の登録されているページ
Line[LINE], //単語の登録されている行数
Sonota[SNT]; //その他の情報
// 綴り 意味 ページ 行数 その他の情報
char *format = "%-20s%-100s%-5d%-5d%-100s";
char *format2 = "%-100s%-5d%-5d%-100s";
int menu(); //メニュー関数
int toroku(); //単語を登録する関数
int kensaku(); //単語を検索する関数
int shusei(); //単語を修正する関数
int main()
{
int no;
no = menu();
while(1) {
switch(no) {
case 1: no = toroku();
continue;
case 2: no = kensaku();
continue;
case 3: no = shusei();
continue;
case 0: break;
case 4: no = menu();
continue;
}
break;
}
return 0;
}
//メニュー画面
int menu()
{
char no[4];
int so;
while(1) {
system("cls");
puts("-----------------------");
puts("1:単語の登録");
puts("2:単語の検索");
puts("3:単語の修正");
puts("0:終了");
puts("-----------------------");
printf("->>");
gets(no);
if(no[0] < '0' || no[0] > '3') {
printf("入力が不正です\n\n");
continue;
}else{
no[1] = '\0';
}
so = atoi(no);
break;
}
system("cls"); //画面を消去
return so;
}
//データの登録
int toroku()
{
FILE *fp;
int Pa, Li;
char yesno[5];
fp = fopen(FILENAME,"a");
if(fp == NULL) {
perror("ファイルをオープンできません\n");
return -1;
}
while(1) {
printf("単語を入力して下さい\n");
printf("-> ");
gets(Spelling);
printf("単語の意味を入力して下さい\n");
printf("-> ");
gets(Meaning);
printf("単語の登録されているページを入力して下さい\n");
printf("-> ");
gets(Page);
Page[PAGE - 1] = '\0';
Pa = atoi(Page);
printf("単語の登録されているページの行数を入力して下さい\n");
printf("-> ");
gets(Line);
Line[LINE - 1] = '\0';
Li = atoi(Line);
printf("その他の情報がありましたら入力して下さい\n");
printf("-> ");
gets(Sonota);
printf("\nこれらを登録しますか?\n");
printf("はい -- Y\n");
printf("もう一度打ち直す-- N\n");
printf("タイトルに戻る -- E\n");
printf("-> ");
gets(yesno);
if(yesno[0] == 'Y' || yesno[0] == 'y') {
fprintf(fp, format, Spelling, Meaning, Pa, Li, Sonota); //入力したデータを書き込む
printf("入力を続けますか?(Y/N):");
gets(yesno);
if(yesno[0] == 'Y' || yesno[0] == 'y')
continue;
else
break;
}else if(yesno[0] == 'N' || yesno[0] == 'n') {
continue;
}else if(yesno[0] == 'E' || yesno[0] == 'e'){
break;
}else{
break;
}
}
system("cls"); //画面を消去
fclose(fp);
return 4;
}
int kensaku()
{
FILE *fp;
char search[SPELL], str2[SPELL], yesno[5] = {0};
int Pa1 = 0, Li1, i = -1, find = 0;
fp = fopen(FILENAME, "r");
if(fp == NULL){
perror("ファイルをオープンできません\n");
return -1;
}
printf("検索したい単語名を入力して下さい\n");
printf("-> ");
gets(search);
while(1) {
i++;
fseek(fp, GOKEI*i, SEEK_SET);
if(fscanf(fp, "%s", str2) == EOF) {
printf("見つかりませんでした\n");
Pa1 = 100;
break;
}
if(strcmp(str2, search) == 0) {
fscanf(fp, format2, Meaning, Page, Line, Sonota);
find++;
printf("見つかりました\n");
printf("-------------------\n");
printf("単語名:%-20s\n", str2);
printf("意味 :%-100s\n", Meaning);
printf("ページ:%dページ\n", Page);
printf("行 :%d行\n",Line);
printf("その他の情報\n"
"%s",Sonota);
printf("-------------------\n");
printf("更に検索を続けますか?(Y/N):");
gets(yesno);
if(yesno[0] == 'Y' || yesno[0] == 'y')
continue;
else
break;
}
}
printf("%d件が検索されました",find);
if(Pa1 == 100) {
printf("もう一度検索しますか?(Y/N):");
gets(yesno);
if(yesno[0] == 'Y' || yesno[0] == 'y')
return 2;
}
gets(yesno);
while(1)
if(yesno[0] == '\0')
break;
fclose(fp);
return 4;
}
int shusei()
{
return 4;
}
ひとまず所々直し、検索して無事に見つかったのですが、やはりご指摘通りformatが悪いのかページが「3666733ページ」
とか表示されます。しかし、どうすれば直るか解りません。
アドバイスだけでもいいので頂けませんか?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#
#
#define FILENAME "tango.txt"
#define SPELL 20
#define MEAN 100
#define PAGE 10
#define LINE 10
#define SNT 100
#define GOKEI (SPELL + MEAN + PAGE + LINE + SNT)
char Spelling[SPELL], //単語の綴り
Meaning[MEAN], //単語の意味
Page[PAGE], //単語の登録されているページ
Line[LINE], //単語の登録されている行数
Sonota[SNT]; //その他の情報
// 綴り 意味 ページ 行数 その他の情報
char *format = "%-20s%-100s%-5d%-5d%-100s";
char *format2 = "%-100s%-5d%-5d%-100s";
int menu(); //メニュー関数
int toroku(); //単語を登録する関数
int kensaku(); //単語を検索する関数
int shusei(); //単語を修正する関数
int main()
{
int no;
no = menu();
while(1) {
switch(no) {
case 1: no = toroku();
continue;
case 2: no = kensaku();
continue;
case 3: no = shusei();
continue;
case 0: break;
case 4: no = menu();
continue;
}
break;
}
return 0;
}
//メニュー画面
int menu()
{
char no[4];
int so;
while(1) {
system("cls");
puts("-----------------------");
puts("1:単語の登録");
puts("2:単語の検索");
puts("3:単語の修正");
puts("0:終了");
puts("-----------------------");
printf("->>");
gets(no);
if(no[0] < '0' || no[0] > '3') {
printf("入力が不正です\n\n");
continue;
}else{
no[1] = '\0';
}
so = atoi(no);
break;
}
system("cls"); //画面を消去
return so;
}
//データの登録
int toroku()
{
FILE *fp;
int Pa, Li;
char yesno[5];
fp = fopen(FILENAME,"a");
if(fp == NULL) {
perror("ファイルをオープンできません\n");
return -1;
}
while(1) {
printf("単語を入力して下さい\n");
printf("-> ");
gets(Spelling);
printf("単語の意味を入力して下さい\n");
printf("-> ");
gets(Meaning);
printf("単語の登録されているページを入力して下さい\n");
printf("-> ");
gets(Page);
Page[PAGE - 1] = '\0';
Pa = atoi(Page);
printf("単語の登録されているページの行数を入力して下さい\n");
printf("-> ");
gets(Line);
Line[LINE - 1] = '\0';
Li = atoi(Line);
printf("その他の情報がありましたら入力して下さい\n");
printf("-> ");
gets(Sonota);
printf("\nこれらを登録しますか?\n");
printf("はい -- Y\n");
printf("もう一度打ち直す-- N\n");
printf("タイトルに戻る -- E\n");
printf("-> ");
gets(yesno);
if(yesno[0] == 'Y' || yesno[0] == 'y') {
fprintf(fp, format, Spelling, Meaning, Pa, Li, Sonota); //入力したデータを書き込む
printf("入力を続けますか?(Y/N):");
gets(yesno);
if(yesno[0] == 'Y' || yesno[0] == 'y')
continue;
else
break;
}else if(yesno[0] == 'N' || yesno[0] == 'n') {
continue;
}else if(yesno[0] == 'E' || yesno[0] == 'e'){
break;
}else{
break;
}
}
system("cls"); //画面を消去
fclose(fp);
return 4;
}
int kensaku()
{
FILE *fp;
char search[SPELL], str2[SPELL], yesno[5] = {0};
int Pa1 = 0, Li1, i = -1, find = 0;
fp = fopen(FILENAME, "r");
if(fp == NULL){
perror("ファイルをオープンできません\n");
return -1;
}
printf("検索したい単語名を入力して下さい\n");
printf("-> ");
gets(search);
while(1) {
i++;
fseek(fp, GOKEI*i, SEEK_SET);
if(fscanf(fp, "%s", str2) == EOF) {
printf("見つかりませんでした\n");
Pa1 = 100;
break;
}
if(strcmp(str2, search) == 0) {
fscanf(fp, format2, Meaning, Page, Line, Sonota);
find++;
printf("見つかりました\n");
printf("-------------------\n");
printf("単語名:%-20s\n", str2);
printf("意味 :%-100s\n", Meaning);
printf("ページ:%dページ\n", Page);
printf("行 :%d行\n",Line);
printf("その他の情報\n"
"%s",Sonota);
printf("-------------------\n");
printf("更に検索を続けますか?(Y/N):");
gets(yesno);
if(yesno[0] == 'Y' || yesno[0] == 'y')
continue;
else
break;
}
}
printf("%d件が検索されました",find);
if(Pa1 == 100) {
printf("もう一度検索しますか?(Y/N):");
gets(yesno);
if(yesno[0] == 'Y' || yesno[0] == 'y')
return 2;
}
gets(yesno);
while(1)
if(yesno[0] == '\0')
break;
fclose(fp);
return 4;
}
int shusei()
{
return 4;
}
Re: C言語の質問です
単語や単語の意味に空白やタブを含めると正しく表示されないはずですが、きょろ さんが書きました:済みません
*((int*)Page)
と変えても表示結果が正しく表示されません。
こちらでのテストではそれらのコーナーケースを与えなければ正しく表示されているように思えます。
ソースコードとデータファイル、実行形式バイナリを添付します。
kensaku関数の という行において、Page配列の先頭に%10dという指定で読み込まれたint型のデータが格納されます。きょろ さんが書きました:あと、何故*((int*)Page)とすれば良かったのでしょうか?
この時、Page配列は10バイト確保されているので、int型のサイズが4バイト/8バイトの環境ではバッファオーバーランは起きません。
しかし、Page配列はchar[10]型なので、int型のデータをそのまま取り出すことはできません。
そこで、(int*)Pageという記述により、コンパイラにPage配列の先頭をint型へのポインタとして解釈させ、
さらに*((int*)Page)という記述によりそのint型へのポインタが差す場所(Page配列の先頭)に格納されているint型のデータを読み取り、
printf関数に渡すので、きちんと読み取ったページが表示されるはずです。
- 添付ファイル
-
- tango_kensaku.zip
- テストに使用したファイル一式
- (6.66 KiB) ダウンロード数: 124 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)