讓我們先看看你創建的結構;接下來我們將嘗試查看它是否可以修復。 我離開了細節,所以我們可以看到大輪廓:
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
- 但編譯器會抱怨。原因是在優秀Q & A在 Why can't variables be declared in a switch statement?
另一方面 - 如果你可以聲明一個這樣的變量 - 你在做什麼?您的代碼當前讀入值並返回。但只要你離開變量的「範圍」(在你的情況下,因爲你在switch
內聲明s
,這將是它的範圍)變量消失(用於它的內存被標記爲「空閒」被重新使用。)
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
函數之外,這樣我們就可以使用便攜式代碼。其次 - 如果我們想要創建多個客戶記錄,我們需要將它們存儲在一個數組中。真的,你會想要一個列表,所以你可以無限延長,但讓我們保持簡單,並允許最多10條記錄。然後,我們需要提高菜單功能的邏輯(如果選擇不爲1,2或3,你發出的信息,然後再試一次;在當前的代碼行
printf("You have entered an incorrect value");
沒有得到執行,直到你有退出測試不正確值的循環...所以當你終於到達那裏時,這個值是有效的,而不是無效的
在我們真正開始寫「正確的」代碼之前,還有另外一件值得注意的事情。使用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
你與幹嘛'無效菜單()'有不正確 - 移動出來的' main'函數,沒有它返回一個值,並將其稱爲只是'menu();' - 沒有'void'。 –
@ChristianTernus,它應該返回'選擇' – Leeor
我試過了,但是在 –