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

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

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

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

Q&A

解決済

2回答

3228閲覧

住所録のプログラムのあちこち分からないところがあります。教えてください。

退会済みユーザー

退会済みユーザー

総合スコア0

C

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

0グッド

0クリップ

投稿2017/11/12 09:51

下記の住所録プログラムについて分からないところを質問させてください。
質問1:if (1 <= i && i <= 5) cnt = func[i - 1](ad, cnt);
質問2:while (j++ < cnt){}条件がよくわかりません
質問3:for (j = i - 1; j < cnt - 1; j++)
ap[j]= ap[j + 1];がいまいちわかりません。
よろしくお願いします。

コード // アドレス帳 住所録プログラム #include <stdio.h> #include <stdlib.h> #include <string.h> // プログラム中で多用する配列の大きさ #define BUFSIZE 128 #define DATASIZE 100 // 構造体の宣言 -- typedefを使用して以後srtuctを省略できるようにした typedef struct address { char szAdd[51]; // 住所 char szName[21]; // 氏名 char szTel[21]; // 電話番号 } Address; // 関数のプロトタイプ宣言 -- ジャンプテーブルに入れるため引数及び返却値型は // すべて同じとした int search(Address *ap, int cnt); int add(Address *ap, int cnt); int amend(Address *ap, int cnt); int del(Address *ap, int cnt); int printall(Address *ap, int cnt); // 関数のジャンプテーブル int (*func[])(Address *, int) = {search, add, amend, del, printall}; // 処理を番号で選ばせ、所定の関数に飛ばす // 処理によっては配列の要素数が変化する事があるので常に要素数 cnt を返させる // 構造体の配列 -- 大きくてスタックを消費する可能性があるので静的に定義した Address ad[DATASIZE]; int main(void) { char dummy[BUFSIZE]; int i, cnt = 0; while (1) { puts("●メニューを入力して下さい"); puts("1.検索\n2.追加\n3.修正\n4.削除\n5.全体表\示\n6.終了"); scanf("%d", &i); gets(dummy); if (1 <= i && i <= 5) cnt = func[i - 1](ad, cnt); //cntは要素番号 else if (i == 6) break; } return 0; } // 検索するデータをswitch文によって処理を選択 int search(Address *ap, int cnt) { char buf[BUFSIZE], dummy[BUFSIZE]; char *target[] = {"住所", "氏名", "電話番号"}; int i, j = 0, count = 0; Address *t = ap; while (1) { puts("何で探しますか?\n1.住所 2.氏名 3.電話番号"); scanf("%d", &i); gets(dummy); //scanfは変換が終わったら入力の残りをそのままにします。 //つまり、改行が内部バッファーに残り、これがgetsに渡ってしまいます。 //getsはこれを受け取り、新たなキー入力を待たずに終了してしまいます。 //一番簡単な修正はscanf後にfgetsでダミーで一行を読み込むことでしょう。 if (1 <= i && i <= 3) break; } printf("%sを入力して下さい:", target[--i]); gets(buf); while (j++ < cnt) { switch (i) { case 0: // 住所 if (!strcmp(t->szAdd, buf)) goto print; break; case 1: // 氏名 if (!strcmp(t->szName, buf)) goto print; break; case 2: // 電話番号 if (!strcmp(t->szTel, buf)) goto print; break; default: // no condition、ここには来ない break; } t++; continue; print:; printf("%d: 住所:%s 氏名:%s 電話番号:%s\n", j, t->szAdd, t->szName, t->szTel); t++; count++; } printf("%d件見つかりました\n", count); return cnt; } // 構造体の*最後*の次に新しいデータを付け加える // もし既に構造体の配列が一杯になっていたら警告を発して戻る // 追加に成功したら構造体の要素数が 1 増えるので cnt + 1 を返す int add(Address *ap, int cnt) { Address *t = ap + cnt; // 配列の最後の次のアドレスの計算 、配列の最後の要素の // 次のアドレスを指してもよい if (cnt == DATASIZE) { puts("これ以上追加できません"); return cnt; } printf("住所:"); // 住所 gets(t->szAdd); printf("氏名:"); // 氏名 gets(t->szName); printf("電話番号:"); // 電話番号 gets(t->szTel); // 表示 // printf("%s %s %s\n", t->szAdd, t->szName, t->szTel); return cnt + 1; } // 任意の構造体の内容を修正する // 修正しない要素はreturnで飛ばせるようにした int amend(Address *ap, int cnt) { Address *t; char buf[BUFSIZE]; int i; puts("何番を修正しますか?"); scanf("%d", &i); gets(buf); if (i > 0 && i <= cnt) { t = ap + i - 1; // 配列のアドレスの計算 puts("変更しない場合は単に[return]を押して下さい"); printf("住所: %s -> ", t->szAdd); gets(buf); if (strlen(buf)) strcpy(t->szAdd, buf); printf("氏名: %s -> ", t->szName); gets(buf); if (strlen(buf)) strcpy(t->szName, buf); printf("電話番号: %s -> ", t->szTel); gets(buf); if (strlen(buf)) strcpy(t->szTel, buf); } else puts("番号が不適切です"); return cnt; } // 任意の構造体を削除する // 削除方法はそれより後ろの構造体を一つ前にずらし cnt - 1 を返す // i == cnt の時は実際には cnt - 1 を返すだけである int del(Address *ap, int cnt) { char buf[BUFSIZE]; int i, j; puts("何番を削除しますか?"); scanf("%d", &i); gets(buf); if (i > 0 && i <= cnt) { for (j = i - 1; j < cnt - 1; j++) ap[j]= ap[j + 1]; return cnt - 1; } else { puts("番号が不適切です"); return cnt; } } // 格納された構造体を全部表示する // 構造体には番号が付いてないので、カウンタ i で内部的に処理する(構造体の添え字i + 1) int printall(Address *ap, int cnt) { int i = 0; while (i < cnt) { printf("%d: 住所:%s 氏名:%s 電話番号:%s\n", ++i, ap->szAdd, ap->szName, ap->szTel); ap++; // 配列へのポインタが次の配列要素を指すようにする } return cnt; }

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

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

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

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

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

guest

回答2

0

ベストアンサー

質問1:if (1 <= i && i <= 5) cnt = func[i - 1](ad, cnt);

関数へのポインターは5要素あり、iはそのどの要素の関数かを示すインデックス(ただしCで普通にもちいるような0始まりのインデックスではなくなぜか1始まりとしているようです)で、
func[i-1]はi番目の要素の関数ポインターfunc[i-1](ad, cnt)はその関数ポインターが指す関数を、adとcntを引数にして呼び出すコードです。

質問2:while (j++ < cnt){}条件がよくわかりません

このプログラムは誰が書いたか知りませんが・・・これは本来

C

1for (int j = 0; j < cnt; j++) { 2 ... 3}

と書くべきように思えます。個人的な意見としてはひどいコードです。jが0で初期化されてるのは関数の先頭の変数宣言ですね。そもそもjはこのループ内部でしか参照されていないように見えますので「なぜ関数の先頭で宣言しなけりゃいけないの?」と思ってしまいます。もし勉強のためのこのコードを見ているならあえて言わせていただければ「やめた方がよい」です。

質問3:for (j = i - 1; j < cnt - 1; j++)

ap[j]= ap[j + 1];がいまいちわかりません。

これは配列の各要素を順番に先頭方向へひとつずつずらしているコードです。これがわからないとするとループについてご自分でプログラムを書いて経験を積むべきと思います。また質問の際に「いまいちわからない」という表現は禁句と思ってください。閲覧者にも「あなたに何がわからないのかイマイチわかりません」わからないことを具体的に書いてください。

投稿2017/11/12 10:13

KSwordOfHaste

総合スコア18394

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

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

退会済みユーザー

退会済みユーザー

2017/11/12 10:24

そうですね。少し疲れていました。休憩して1つ1つ分からないところをつぶしていきたいとおもいます。 ありがとうございました。
KSwordOfHaste

2017/11/12 10:48

根をつめすぎると・・・ということもあるかもです。地道にすすめてみてくださいね。
退会済みユーザー

退会済みユーザー

2017/11/12 11:01

悪いコードの指摘のプログラムは削除して、明日からよみなおします。 回答していただいた、ものはプログラムに貼り付けて参考にしていきたいとおもいます。ありがとうございます。ボケ防止にやっています。 なかなか読み込みが悪くて、ごめんなさい。あまり長くやっていると余計おかしくなりますね。またよろしくおねがいいたします。
KSwordOfHaste

2017/11/12 11:12

プログラミングは非常に広範囲の知識や経験がきいてくるものなので何もかも一挙にわかることはまずないと思います。地道にと申し上げたのはあわててもしかたないという考えがあるからです。自分は、ん十年続けてますがまだまだ初心者的な感じで永遠にベテランにはなれそうにないですが、アマチュアなので小さなことでもいいので何かしら面白さをみつけて楽しめるのが一番と思っています。
guest

0

質問1:if (1 <= i && i <= 5) cnt = func[i - 1](ad, cnt);

入力値が不正でないかチェックして、ジャンプテーブルの要素を参照・実行しています。


質問2:while (j++ < cnt){}条件がよくわかりません

後置インクリメントです。条件式の評価後、jの値をインクリメントします。
個人的には、ただのfor文を使えばいいような気もします。

C

1#include <stdio.h> 2 3int main(void) { 4 int j = 0; 5 for(int i = 0; i < 10; i++) { 6 printf("%d", j++); 7 } 8 printf("\n"); 9 return 0; 10}

実行すると、『0123456789』が出力される。


質問3:for (j = i - 1; j < cnt - 1; j++)

i-1番目以降の要素を参照しています。
前後のコードを見る限り、要素の削除に伴って値を詰めているようです。


動作がわからないのか、構文がわからないのかがちょっとはっきりしない印象です。

  • 前者ならば、何らかの方法で動作を追ってみてください。

デバッガを使えるならそれがよいでしょうし、標準出力を使ってもよいでしょう。

  • 後者ならば、参考書を確認してください。

そして自身の理解が正しいのか、簡単にコードで試せるとよいでしょう。

参考にしているコードも、ちょっと怪しいかなぁって気がしますね。
何食わぬ顔でgoto文使ってますし...

投稿2017/11/12 10:03

編集2017/11/12 10:07
LouiS0616

総合スコア35660

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

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

退会済みユーザー

退会済みユーザー

2017/11/12 10:17

ありがとうございます。もう少し自分で見てみます。色々分からないところがあって、1日質問していて疲れました。明日少しやってみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問