作成した構造を見てみましょう。次に、修正できるかどうかを確認します。大まかな概要を確認できるように、詳細は省略しています。
main {
struct{}
void menu(){
do {
stuff
} while (selection > 3)
printf("you have entered an incorrect value"); // if selection is > 3
}
switch(selection) {
// do something if selection is 1 or 2, exit if 3
}
コードに最後の閉じ中かっこがありません。コピペミスだと思いますので追記しました。-Wall
(警告とエラーの報告を得るために)でコンパイルすると、いくつかのエラーが発生します。
sel.c:18: error: nested functions are disabled, use -fnested-functions to re-enable
sel.c: In function ‘menu’:
sel.c:31: warning: ‘return’ with a value, in function returning void
sel.c: In function ‘main’:
sel.c:38: error: expected expression before ‘struct’
sel.c:41: error: ‘s’ undeclared (first use in this function)
sel.c:41: error: (Each undeclared identifier is reported only once
sel.c:41: error: for each function it appears in.)
sel.c:61: warning: control reaches end of non-void function
それらを順番に見てみましょう:
sel.c:18: error: nested functions are disabled, use -fnested-functions to re-enable
ある関数を別の関数の中に入れることは「入れ子」です。あなたがそれをしたいと思うことはめったにありません-それは、あなたが他の関数の中にいるときだけ関数が「見える」ことを意味します(ローカル変数に少し似ていますが、関数用です)。これは標準の C ではありません - の拡張ですgcc
。非標準の (したがって移植性のない) 拡張機能を使用することは、ほとんどの場合、悪い考えです。http://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.htmlを参照してください。
sel.c: In function ‘menu’:
sel.c:31: warning: ‘return’ with a value, in function returning void
関数を宣言するときvoid
、値を返さないと言います。return 0;
値を返すようなステートメントがある場合。コンパイラはそれを無視しますが、あることを言って別のことをしたことを警告します。パラメータなしで使用するだけreturn;
で、警告は消えます。
sel.c:38: error: expected expression before ‘struct’
sel.c:41: error: ‘s’ undeclared (first use in this function)
sel.c:41: error: (Each undeclared identifier is reported only once
sel.c:41: error: for each function it appears in.)
これは最もトリッキーなものです。38 行目で変数を適切に宣言していると思いますs
が、コンパイラは文句を言います。この理由は、
なぜ switch ステートメントで変数を宣言できないのですか?の優れた Q&A で説明されています。
余談ですが、このような変数を宣言できるとしたら、それで何をしていますか? あなたのコードは現在、値を読み込んで戻ります。しかし、変数の「スコープ」を離れるとすぐに(あなたの場合、s
内で宣言したのでswitch
、それがそのスコープになります)、変数は消えます(変数に使用されたメモリは「フリー」とマークされ、再-使用済み。)
sel.c:61: warning: control reaches end of non-void function
return someValue;
これは、値を返すことを期待する関数の最後に到達したことを示していますが、ステートメントの型がありません。繰り返しますが、デフォルトの動作は値が指定されていない場合に戻るため、これは警告のみを引き起こしますが、これ0
は、あることを言って別のことをしたという兆候です。
ここまでは、コンパイラが出力したエラーについて説明しました。コード構造を詳しく見てみましょう。あなたがやりたいと思うことは、次のようなものです:
define customerInfo structure
define menu function
main()
repeat:
call menu, get selection
switch(selection):
case 1: create new record
case 2: display records
case 3: quit program
これを機能させるには、プログラムにいくつかの変更を加える必要があります。まず、menu
関数定義を関数の外に移動して、main
コードを移植できるようにします。2 つ目 - 複数の顧客レコードを作成できるようにする場合は、それらを配列に格納する必要があります。無制限に拡張できるリストが本当に必要ですが、単純にして、最大 10 レコードまで許可するようにしましょう。次に、メニュー機能のロジックを改善する必要があります (選択が 1、2、または 3 でない場合は、メッセージを表示して再試行します。現在のコードでは次の行
printf("You have entered an incorrect value");
間違った値をテストしたループを終了するまで実行されません…したがって、最終的にそこに到達したとき、値は無効ではなく有効です。
実際に「正しい」コードを書く前に、注意すべきことがもう 1 つあります。を使用して値を読み取るときはscanf
、次のようなことを行います。
scanf("%s", s.FirstName);
s.FirstName
は文字列の先頭へのポインタであるため、これは正しいです。ただし、文字列には有限のスペース (つまり、末尾の を含めて 15 文字'\0'
) を割り当てているため、誰かが長い名前を入力すると、プログラムがクラッシュします。「適切な防御コーディング」では、これをキャッチする必要があります-例を使用してください
scanf("%14s", s.FirstName);
これは「14文字以内で読む」と言っています。より良いトリックがありますが、少なくともこれが始まりです。ただし、実際に行うと間違いを犯します
scanf("%s", s.ID);
ID
は として定義されているため、文字列をそのアドレスだけでなく、 の値が指す場所にint
読み込んでいます。これにより、セグメンテーション エラー (「自分のものではない」メモリへのアクセス) が発生する可能性が非常に高くなります。あなたがしているはずです:s.ID
scanf("%d", &s.ID);
"整数を次の場所に読み込みますs.ID
"
また、使用する場所もあればFirstName
、使用する場所もありますFirstname
。同上LastName
。大文字化の問題 - 他のコンパイラ エラーを修正すると、これらが表示され始めます。
複数の顧客レコードを読み込めるようにしたいので、レコードの配列が必要です。上で述べたように、配列が switch ステートメントのスコープ内で使用可能であること、およびそのステートメントが "存続" していることを確認する必要があります (そのため、配列を使用して何かを行うことができます)。これらすべてをまとめると、次のようになります。
#include <stdio.h>
// define function prototype:
int menu();
struct CustomerInfo
{
char FirstName[15]; /* These are the variables for the customer infomation */
char LastName[20];
int ID;
};
int menu()
{ /* Menu loop function */
int flag = 0;
int selection;
do
{ /* menu start */
if(flag > 0) printf("You have entered an incorrect value"); /* If selection is greater than 3 then end program */
printf("\n\n - What would you like to do?");
printf("\n1 - Store a customer record");
printf("\n2 - View customer Records");
printf("\n3 - Quit program\n>> ");
scanf("%i", &selection);
flag++;
} while (flag < 10 && (selection < 0 ||selection > 3));
return selection;
}
int main(void)
{ /* program starts */
struct CustomerInfo s[10];
int selection;
int customerCount = 0;
while(1) {
int ii; // loop counter we will need later
selection = menu();
switch(selection)
{
case 1:
printf("Please enter the customers details including First name, Lastname and ID.\n\n");
printf("Enter First name: ");
scanf("%s", s[customerCount].FirstName); /* Option 1: Asks to enter the customers details to store then loops back to program */
printf("Enter Last name: ");
scanf("%s", s[customerCount].LastName);
printf("Enter Customer ID: ");
scanf("%d", &s[customerCount].ID);
customerCount++;
break;
case 2:
printf("\nDisplaying Infomation\n");
for(ii = 0; ii < customerCount; ii++) {
printf("First name: %s\n",s[ii].FirstName); /* Option 2: Prints the customer details as listed in option 1 */
printf("Last name: %s\n",s[ii].LastName);
printf("Customer ID: %d\n---\n",s[ii].ID);
}
break;
case 3: /* Option 3: Program ends if option 3 is chosen. */
return 0; // program returns
break;
}
}
}
テスト出力:
- What would you like to do?
1 - Store a customer record
2 - View customer Records
3 - Quit program
>> 1
Please enter the customers details including First name, Lastname and ID.
Enter First name: John
Enter Last name: Smith
Enter Customer ID: 123
- What would you like to do?
1 - Store a customer record
2 - View customer Records
3 - Quit program
>> 5
You have entered an incorrect value
- What would you like to do?
1 - Store a customer record
2 - View customer Records
3 - Quit program
>> -1
You have entered an incorrect value
- What would you like to do?
1 - Store a customer record
2 - View customer Records
3 - Quit program
>> 1
Please enter the customers details including First name, Lastname and ID.
Enter First name: Harry
Enter Last name: Jones
Enter Customer ID: 654
- What would you like to do?
1 - Store a customer record
2 - View customer Records
3 - Quit program
>> 2
Displaying Infomation
First name: John
Last name: Smith
Customer ID: 123
---
First name: Harry
Last name: Jones
Customer ID: 654
---
- What would you like to do?
1 - Store a customer record
2 - View customer Records
3 - Quit program
>> 3