最近、あるc言語入門サイトを一通り終わったばかりのレベルの者です。
考えながら電話帳のプログラムを書いてみたのですが、gets_s,strncmp,fscanfが思った通りの動作をしません。
文法的なエラーも警告もないので何が間違っているのかわかりません。
touroku関数は最初の氏名電話番号は登録できるのですが、2回目の登録の際、fscanfで配列plarryにファイルを読み込んで配列内容が0だった場合、その配列要素に入力内容を代入するというイメージです。しかしデバッグモードのローカル変数を見ると氏名は読み込めますが電話番号は読み込めてないです。なぜかわかりません。
そして、strncmpで読み込んだ内容(0の場合)と入力内容が違う場合その配列要素に入力内容を代入するという書き方も、代入処理にならずスルーになってしまいます。
あと名前の入力のところで1回目のgets_s関数がスルーされてしまいます。swichのエンターが働いているのだと思いますが、どう対処すればよいでしょうか?
code
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
typedef struct {
char name[60];
unsigned int number;
}phoneLIst;
void touroku(void);
void search(void);
void dele(void);
int main(void) {
int a = 0;
printf("\n-----電話帳-----\n");
printf("新規登録 -- 1\n");
printf("検索 -- 2\n");
printf("削除 -- 3\n");
printf("終了 -- 他\n");
scanf_s("%d", &a);
switch (a) {
case 1:touroku();
break;
case 2:search();
break;
case 3:dele();
break;
default:
break;
}
printf("\n終了");
return 0;
}
void touroku(void) {
printf("10件まで登録可\n");
phoneLIst pl = { 0,0 };
phoneLIst plarry[10] = { 0,0 };
int i = 0;
printf("名前の入力 -- ");
gets_s( pl.name,60);
gets_s( pl.name, 60);
printf("\n番号入力(-)なし -- ");
scanf_s("%d",&pl.number);
FILE* fp = NULL;
fopen_s(&fp, "PhoneList.txt", "r+");
if (fp == NULL) { //ファイルがなければ書き込みモード
fopen_s(&fp, "PhoneList.txt", "w");
plarry[0] = pl;
if (fp != NULL) {
fprintf(fp, "氏名:%s,電話番号:%d\n", plarry.name, plarry.number);
printf("保存完了");
return;
}
else {
printf("ERROR");
return;
}
}
else if (fp != NULL) { //ファイルがあれば読み込み
while(fscanf(fp, "氏名:%s,電話番号:%d\n", plarry.name, &plarry.number)!=EOF){
//if(strncmp(plarry.name,pl.name,60) != 0) //読み込んだ内容と違う場合
if (plarry.name == 0) //読み込んだ内容が0の場合
{
plarry = pl;
break;
}
}
fseek(fp, 0, SEEK_SET);
for (int i = 0; i < 10; i++) {
fprintf(fp, "氏名: % s, 電話番号 : % d\n", plarry.name, plarry.number);
}
printf("登録完了");
fclose(fp);
}
else{
printf("登録不可");
}
return;
}
void search(void) {
phoneLIst pl = { 0 };
phoneLIst plarry[10] = { 0 };
int i = 0, j = 0;
printf("検索 名前の入力\n");
gets_s(pl.name, 60);
gets_s(pl.name, 60);
FILE* fp = NULL;
fopen_s(&fp, "PhoneList.txt", "r");
if (fp != NULL) {
while (fscanf(fp, "氏名:%s,電話番号:%d\n", plarry.name, &plarry[i].number) != EOF) {
if (strncmp(pl.name,plarry[i].name,60)==0) { //同じ名前があれば表示
printf("氏名:%s,電話番号:%d", plarry[i].name, plarry[i].number);
j++;
break;
}
}
}
else {
printf("電話帳なし\n");
return;
}
if (j>0) {
printf("該当なし");
}
return;
}
void dele(void) {
phoneLIst pl = { 0 };
phoneLIst plarry[10] = { 0 };
int a;
printf("電話帳リスト\n");
FILE* fp = NULL;
fopen_s(&fp, "PhoneList.txt", "r+");
int i = 0;
if (fp != NULL) {
while (fscanf(fp, "%s,%d", plarry[i].name, &plarry[i].number) != EOF) {
printf("番号[%d]氏名:%s,電話番号:%d", i, plarry[i].name, plarry[i].number);
}
printf("削除する番号の選択---");
scanf_s("%d", &a);
plarry[a] = pl;
fseek(fp, 0, SEEK_SET);
for (int i = 0; i < 10; i++) {
fprintf(fp, "氏名:%s,電話番号:%d", plarry[i].name, plarry[i].number);
if (plarry[i].name == 0) {
plarry[i] = pl;
break;
}
}
printf("登録完了");
fclose(fp);
}
return;
}
/code
gets_s,fscanf,strncmpが思ったように動きません.
Re: gets_s,fscanf,strncmpが思ったように動きません.
東上☆海美☆「
Windows 10 Pro 64bit
VS2019
にぶっこんだら、74 行を初めとして、エラー出まくりでみみ。
いったいどのような環境で、「文法的なエラーも警告もない」のでしょうかみみ ?
ファイルのアップミスでしょうかみみ ?
」
Windows 10 Pro 64bit
VS2019
にぶっこんだら、74 行を初めとして、エラー出まくりでみみ。
いったいどのような環境で、「文法的なエラーも警告もない」のでしょうかみみ ?
ファイルのアップミスでしょうかみみ ?
」
VTuber:
東上☆海美☆(とうじょう・うみみ)
http://atassyu.php.xdomain.jp/vtuber/index.html
レスがついていないものを優先して、レスするみみ。時々、見当外れなレスしみみ。
中の人:
手提鞄あたッしュ、[MrAtassyu] 手提鞄屋魚有店
http://ameblo.jp/mratassyu/
Pixiv: 666303
Windows, Mac, Linux, Haiku, Raspbery Pi, Jetson Nano, 電子ブロック 持ち。
東上☆海美☆(とうじょう・うみみ)
http://atassyu.php.xdomain.jp/vtuber/index.html
レスがついていないものを優先して、レスするみみ。時々、見当外れなレスしみみ。
中の人:
手提鞄あたッしュ、[MrAtassyu] 手提鞄屋魚有店
http://ameblo.jp/mratassyu/
Pixiv: 666303
Windows, Mac, Linux, Haiku, Raspbery Pi, Jetson Nano, 電子ブロック 持ち。
Re: gets_s,fscanf,strncmpが思ったように動きません.
ん?エラー出まくりですか?そうなんですね!ん?
環境は
Windows 10 Home64bit
Microsoft Visual Studio Community 2019
Version 16.8.6
です。
ファイルはソースをそのまんまコピペしましたのでアップミスはないはずです。
見直してみましたがそのままだと思います。
これでソリューションのビルドをしても問題は見つかりませんでしたってなります。
========== ビルド: 0 正常終了、0 失敗、1 更新不要、0 スキップ ==========
失敗1はやはり失敗なんですよね?といいますか、そもそもvisualstudioをインストールしなおした方がいい気がしてきました。
環境は
Windows 10 Home64bit
Microsoft Visual Studio Community 2019
Version 16.8.6
です。
ファイルはソースをそのまんまコピペしましたのでアップミスはないはずです。
見直してみましたがそのままだと思います。
これでソリューションのビルドをしても問題は見つかりませんでしたってなります。
========== ビルド: 0 正常終了、0 失敗、1 更新不要、0 スキップ ==========
失敗1はやはり失敗なんですよね?といいますか、そもそもvisualstudioをインストールしなおした方がいい気がしてきました。
Re: gets_s,fscanf,strncmpが思ったように動きません.
codeタグに必要な[]が抜けているというミスがあります。
この掲示板は[/i]が無くても[i]が斜体タグとして解釈されてしまう不親切設計なので、
codeタグで囲まれていないコードは引用画面からコピーするべきです。
※ここの[i]はU+200Bを挟むことで、タグとしての解釈を回避しています
失敗1ではなく、「0 失敗、1 更新不要」ですね。
熊ーさんの解釈が失敗です。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)
Re: gets_s,fscanf,strncmpが思ったように動きません.
こういうことですね!
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
typedef struct {
char name[60];
unsigned int number;
}phoneLIst;
void touroku(void);
void search(void);
void dele(void);
int main(void) {
int a = 0;
printf("\n-----電話帳-----\n");
printf("新規登録 -- 1\n");
printf("検索 -- 2\n");
printf("削除 -- 3\n");
printf("終了 -- 他\n");
scanf_s("%d", &a);
switch (a) {
case 1:touroku();
break;
case 2:search();
break;
case 3:dele();
break;
default:
break;
}
printf("\n終了");
return 0;
}
void touroku(void) {
printf("10件まで登録可\n");
phoneLIst pl = { 0,0 };
phoneLIst plarry[10] = { 0,0 };
int i = 0;
printf("名前の入力 -- ");
gets_s( pl.name,60);
gets_s( pl.name, 60);
printf("\n番号入力(-)なし -- ");
scanf_s("%d",&pl.number);
FILE* fp = NULL;
fopen_s(&fp, "PhoneList.txt", "r+");
if (fp == NULL) { //ファイルがなければ書き込みモード
fopen_s(&fp, "PhoneList.txt", "w");
plarry[0] = pl;
if (fp != NULL) {
fprintf(fp, "氏名:%s,電話番号:%d\n", plarry[i].name, plarry[i].number);
printf("保存完了");
return;
}
else {
printf("ERROR");
return;
}
}
else if (fp != NULL) { //ファイルがあれば読み込み
while(fscanf(fp, "氏名:%s,電話番号:%d\n", plarry[i].name, &plarry[i].number)!=EOF){
//if(strncmp(plarry[i].name,pl.name,60) != 0) //読み込んだ内容と違う場合
if (plarry[i].name == 0) //読み込んだ内容が0の場合
{
plarry[i] = pl;
break;
}
}
fseek(fp, 0, SEEK_SET);
for (int i = 0; i < 10; i++) {
fprintf(fp, "氏名: % s, 電話番号 : % d\n", plarry[i].name, plarry[i].number);
}
printf("登録完了");
fclose(fp);
}
else{
printf("登録不可");
}
return;
}
void search(void) {
phoneLIst pl = { 0 };
phoneLIst plarry[10] = { 0 };
int i = 0, j = 0;
printf("検索 名前の入力\n");
gets_s(pl.name, 60);
gets_s(pl.name, 60);
FILE* fp = NULL;
fopen_s(&fp, "PhoneList.txt", "r");
if (fp != NULL) {
while (fscanf(fp, "氏名:%s,電話番号:%d\n", plarry[i].name, &plarry[i].number) != EOF) {
if (strncmp(pl.name,plarry[i].name,60)==0) { //同じ名前があれば表示
printf("氏名:%s,電話番号:%d", plarry[i].name, plarry[i].number);
j++;
break;
}
}
}
else {
printf("電話帳なし\n");
return;
}
if (j>0) {
printf("該当なし");
}
return;
}
void dele(void) {
phoneLIst pl = { 0 };
phoneLIst plarry[10] = { 0 };
int a;
printf("電話帳リスト\n");
FILE* fp = NULL;
fopen_s(&fp, "PhoneList.txt", "r+");
int i = 0;
if (fp != NULL) {
while (fscanf(fp, "%s,%d", plarry[i].name, &plarry[i].number) != EOF) {
printf("番号[%d]氏名:%s,電話番号:%d", i, plarry[i].name, plarry[i].number);
}
printf("削除する番号の選択---");
scanf_s("%d", &a);
plarry[a] = pl;
fseek(fp, 0, SEEK_SET);
for (int i = 0; i < 10; i++) {
fprintf(fp, "氏名:%s,電話番号:%d", plarry[i].name, plarry[i].number);
if (plarry[i].name == 0) {
plarry[i] = pl;
break;
}
}
printf("登録完了");
fclose(fp);
}
return;
}
Re: gets_s,fscanf,strncmpが思ったように動きません.
strncmpは解決しました。
//if(strncmp(plarry.name,pl.name,60) != 0) //読み込んだ内容と違う場合
if (plarry.name == 0) //読み込んだ内容が0の場合
{
plarry = pl;
break;
}
このif文をif(strncmp(plarry.name,"",60) == 0)にしました。
これで空の配列要素に代入できました。
touroku関数のfscanfは、なぜplarry.nameに氏名と電話番号が読み込まれるのでしょうか?
//if(strncmp(plarry.name,pl.name,60) != 0) //読み込んだ内容と違う場合
if (plarry.name == 0) //読み込んだ内容が0の場合
{
plarry = pl;
break;
}
このif文をif(strncmp(plarry.name,"",60) == 0)にしました。
これで空の配列要素に代入できました。
touroku関数のfscanfは、なぜplarry.nameに氏名と電話番号が読み込まれるのでしょうか?
Re: gets_s,fscanf,strncmpが思ったように動きません.
とりあえず思った通りの動作はするようになりました。
やはりgets_s関数を二重にしないと動かないのと、初めのfscanfでファイルに名前が保存されてないときplist[ret].nameに電話番号:が代入されるのもなぜなんでしょうか?半角の空白で区切ってるのですが。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct {
char name[60];
char number[12];
}phoneLIst;
void touroku(int);
void search(void);
void dele(int);
int main(void) {
int a = 0;
FILE* fp = NULL;
int ret = 0;
phoneLIst plist[10] = { 0 };
fopen_s(&fp, "PhoneList.txt", "r");
if (fp != NULL) { //登録の空きがあるかチェック
while (fscanf(fp,"氏名:%s 電話番号:%s\n", plist[ret].name,plist[ret].number) != EOF) {
if (strncmp(plist[ret].number, "", 12) == 0) {
break;
}
ret++;
}
fclose(fp);
}
printf("\n-----電話帳-----\n");
printf("新規登録 -- 1\n");
printf("検索 -- 2\n");
printf("削除 -- 3\n");
printf("終了 -- 他\n");
scanf_s("%d", &a);
switch (a) {
case 1: if (ret == 10) {
printf("これ以上登録できません");
break;
}
touroku(ret);
break;
case 2:search();
break;
case 3:dele(ret);
break;
default:
break;
}
printf("\n終了\n");
return 0;
}
void touroku(int ret) {
printf("10件まで登録可\n");
phoneLIst pl = { 0,0 };
phoneLIst plarry[10] = { 0,0 };
int i = 0;
printf("名前の入力 -- ");
gets_s(pl.name, 60);
gets_s(pl.name, 60);
printf("\n番号入力(-)なし -- ");
gets_s(pl.number, 12);
FILE* fp = NULL;
fopen_s(&fp, "PhoneList.txt", "r+");
if (fp == NULL) { //ファイルがなければ書き込みモード
fopen_s(&fp, "PhoneList.txt", "w");
plarry[0] = pl;
if (fp != NULL) {
for (int i = 0; i < 10; i++) {
fprintf(fp, "氏名:%s 電話番号:%s\n", plarry[i].name, plarry[i].number);
}
printf("保存完了");
return;
}
else {
printf("ERROR");
return;
}
}
else if (fp != NULL) { //ファイルがあれば読み込み
while (fscanf(fp, "氏名:%s 電話番号:%s\n", plarry[i].name, &plarry[i].number) != EOF) {
if (ret == i) { //読み込んだ内容が0の場合入力内容の代入
plarry[i] = pl;
}
i++;
}
fseek(fp, 0, SEEK_SET);
for (int i = 0; i < 10; i++) {
fprintf(fp, "氏名:%s 電話番号:%s\n", plarry[i].name, plarry[i].number);
}
printf("登録完了");
fclose(fp);
}
else {
printf("登録不可");
}
return;
}
void search(void) {
phoneLIst pl = { 0 };
phoneLIst plsearch = { 0 };
int i = 0, j = 0;
printf("検索 名前の入力\n");
gets_s(pl.name, 60);
gets_s(pl.name, 60);
FILE* fp = NULL;
fopen_s(&fp, "PhoneList.txt", "r");
if (fp != NULL) {
while (fscanf(fp, "氏名:%s 電話番号:%s\n", plsearch.name, &plsearch.number) != EOF) {
if (strncmp(pl.name, plsearch.name, 60) == 0) { //同じ名前があれば表示
printf("\n氏名:%s 電話番号:%s\n", plsearch.name, plsearch.number);
j++;
//break;
}
}
}
else {
printf("電話帳なし\n");
return;
}
if (j == 0) {
printf("該当なし");
}
return;
}
void dele(int ret) {
phoneLIst pl = { 0 };
phoneLIst plarry[10] = { 0 };
int a;
printf("電話帳リスト\n");
FILE* fp = NULL;
fopen_s(&fp, "PhoneList.txt", "r+");
int i = 0;
if (fp != NULL) {
while (fscanf(fp, "氏名:%s 電話番号:%s\n", plarry[i].name, &plarry[i].number) != EOF) {
printf("番号[%d]氏名:%s 電話番号:%s\n", i, plarry[i].name, plarry[i].number);
i++;
}
printf("削除する番号の選択--- 0-9,キャンセルは10\n");
while (1) {
scanf_s("%d", &a);
if (a<10&&a>=0) {
break;
}
else if (a==10) {
printf("キャンセルします\n");
return;
}
printf("不正な番号です。再入力待ち\n");
}
plarry[a] = pl;
fclose(fp);
}
fopen_s(&fp, "PhoneList.txt", "w");
if (fp != NULL) {
for (int i = 0; i < 10; i++) {
fprintf(fp, "氏名:%s 電話番号:%s\n", plarry[i].name, plarry[i].number);
printf("番号[%d]氏名:%s 電話番号:%s\n", i, plarry[i].name, plarry[i].number);
}
printf("削除完了");
fclose(fp);
}
return;
}
やはりgets_s関数を二重にしないと動かないのと、初めのfscanfでファイルに名前が保存されてないときplist[ret].nameに電話番号:が代入されるのもなぜなんでしょうか?半角の空白で区切ってるのですが。
Re: gets_s,fscanf,strncmpが思ったように動きません.
gets_s関数ってたぶん処理系独自のものだから
何とも言えないところですが、末尾の'\n'を取り除く処理が
いるのではないでしょうか。
標準のgets関数では、例えば か何かで強制的に改行を取っ払うことが必要だったように思います。
何とも言えないところですが、末尾の'\n'を取り除く処理が
いるのではないでしょうか。
標準のgets関数では、例えば か何かで強制的に改行を取っ払うことが必要だったように思います。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。
プログラムは思ったとおりには動かない。書いたとおりに動く。
Re: gets_s,fscanf,strncmpが思ったように動きません.
'\n'の除去はgets_s関数側でやってくれるようなので、明示的に書く必要は無いでしょう。
gets_s, _getws_s | Microsoft Docs
gets_s then replaces the newline character with a null character ('\0') before returning the line.
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)
Re: gets_s,fscanf,strncmpが思ったように動きません.
は改行文字をストリームから除去しないので、次のgets_s関数はこの改行文字を読み込んで止まってしまいます。
ここもgets_s関数で読み込んで、sscanf_s関数で数値に変換するようにするといいでしょう。
行が のようになっているとすると、%sは空白文字を読み飛ばすので、
「氏名:」の次に来る空白文字でない文字で始まる文字列、すなわち「電話番号:」が
%sによってplist[ret].nameに読み込まれることになります。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)
Re: gets_s,fscanf,strncmpが思ったように動きません.
東上☆海美☆「
とりあえず、
main 関数を書き換えてみたみみ
」
とりあえず、
int
main(void)
{
//int a = 0;
FILE* fp = NULL;
int ret = 0;
phoneLIst plist[10] = { 0 };
fopen_s(&fp, "PhoneList.txt", "r");
if (fp != NULL) { //登録の空きがあるかチェック
while (fscanf(fp, "氏名:%s 電話番号:%s\n", plist[ret].name, plist[ret].number) != EOF) {
if (strncmp(plist[ret].number, "", 12) == 0) {
break;
}
ret++;
}
fclose(fp);
}
try {
while (1) {
printf("\n-----電話帳-----\n");
printf("新規登録 -- 1\n");
printf("検索 -- 2\n");
printf("削除 -- 3\n");
printf("終了 -- 他\n");
//scanf_s("%d", &a);
{
const int BUFMAX = 60;
char buf[BUFMAX];
gets_s(buf, BUFMAX);
switch (buf[0]) {
case '1':
if (ret == 10) {
printf("これ以上登録できません");
break;
}
touroku(ret);
break;
case '2':
search();
break;
case '3':
dele(ret);
break;
default:
throw "LoopBreak";
break;
}
}
}
} catch(...) {
printf("\n終了\n");
}
return 0;
}
」
VTuber:
東上☆海美☆(とうじょう・うみみ)
http://atassyu.php.xdomain.jp/vtuber/index.html
レスがついていないものを優先して、レスするみみ。時々、見当外れなレスしみみ。
中の人:
手提鞄あたッしュ、[MrAtassyu] 手提鞄屋魚有店
http://ameblo.jp/mratassyu/
Pixiv: 666303
Windows, Mac, Linux, Haiku, Raspbery Pi, Jetson Nano, 電子ブロック 持ち。
東上☆海美☆(とうじょう・うみみ)
http://atassyu.php.xdomain.jp/vtuber/index.html
レスがついていないものを優先して、レスするみみ。時々、見当外れなレスしみみ。
中の人:
手提鞄あたッしュ、[MrAtassyu] 手提鞄屋魚有店
http://ameblo.jp/mratassyu/
Pixiv: 666303
Windows, Mac, Linux, Haiku, Raspbery Pi, Jetson Nano, 電子ブロック 持ち。