2013-02-19 60 views
2

我已經寫了下面的代碼段,並且無法理解爲什麼它不會到達最後一行printf行。我在第4行之後立即得到一段segfault。kill_char只是用來殺死在前一個scanf中添加的'enter'字符。任何幫助將不勝感激,謝謝!C編程segf on scanf

int remove = 0; 
char kill_char = 'a'; 
printf("Enter the product number to be removed: "); 
scanf("%d", &remove); 
scanf("%c", &kill_char); 
printf("Does not get here"); 

編輯: 全部代碼如下,與錯誤的removeProduct功能

#include <stdio.h> 
#include <stdlib.h> 

struct product_node { 
char *supply_type; 
long number; 
char *description; 
float price; 
int quantity_bought; 
float retail_price; 
int quantity_sold; 
struct product_node *next; 
}; 

struct product_node *head;//declaring head out here 
//allows the list to be in scope for the functions 

/*Function Prototypes*/ 
void addProduct(); 
void removeProduct(); 
void listProduct(); 
void listSupplierTypes(); 
void supplierTypeProfit(); 
void totalProfit(); 

void addProduct(){ 
    char kill_char = 'a';//used to kill the enter characters 
    struct product_node *new_node; 
    new_node = malloc(sizeof(struct product_node)); 

    printf("\nEnter a string for type: "); 
    scanf("%s", &(*new_node).supply_type); 
    scanf("%c", &kill_char); 
    printf("Enter the product number: "); 
    scanf("%ld", &(*new_node).number); 
    scanf("%c", &kill_char); 
    printf("Enter the description: "); 
    scanf("%s", &(*new_node).description); 
    scanf("%c", &kill_char); 
    printf("Enter the wholesale price: "); 
    scanf("%f", &(*new_node).price); 
    scanf("%c", &kill_char); 
    printf("Enter the quantity bought: "); 
    scanf("%d", &(*new_node).quantity_bought); 
    scanf("%c", &kill_char); 
    printf("Enter the retail price: "); 
    scanf("%f", &(*new_node).retail_price); 
    scanf("%c", &kill_char); 
    printf("Enter the quantity sold: "); 
    scanf("%d", &(*new_node).quantity_sold); 
    scanf("%c", &kill_char); 

    struct product_node *walker; 
    walker = head; 
    int can_insert = 1; 
    while (!(walker == NULL)) 
    { 
     if (((*walker).number == (*new_node).number) && ((*walker).supply_type == (*new_node).supply_type)) 
     { 
      can_insert = 0; 
     } 
     walker = (*walker).next; 
    } 

    if (can_insert==1) 
    { 
     (*new_node).next = head; 
     head = new_node; 
     printf("Insertion Successful"); 
    } 
    else 
    { 
     printf("\nERROR INSERTING:This product name and number is already in the list\n"); 
    } 
    free(new_node); 
} 
void removeProduct(){ 
    int remove = 0; 
    char kill_char = 'a'; 
    printf("Enter the product number to be removed: "); 
    scanf("%d", &remove); 
    scanf("%c", &kill_char); 
    printf("Does not get here"); 
    struct product_node *walker; 
    struct product_node *prev; 
    prev = head; 
    walker = (*head).next; 

    if ((*prev).number == remove) 
    { 
    head = walker; 
    }//points head to second node to remove first 

    while (!(walker = NULL)) 
    { 
     if ((*walker).number == remove) 
     { 
      (*prev).next = (*walker).next; 
     } 
    } 
} 
void listProduct(){ 
    printf("Still unsure what defines a supplier..."); 
} 
void listSupplierTypes(){ 
    printf("Same as above"); 
} 
void supplierTypeProfit(){ 
    printf("Again"); 
} 
void totalProfit(){ 
    float total = 0.0; 
    struct product_node *walker; 
    walker = head; 
    while(!(walker == NULL)) 
    { 
     total += ((float)(*walker).quantity_sold * (*walker).retail_price) - ((float)(*walker).quantity_bought * (*walker).price); 
     walker = (*walker).next; 
    } 
    printf("Total Profit is: $%.2f\n", total); 
} 

int main() 
{ 
    head = NULL; 

    char *temp_type; 
    char *temp_description; 
    int temp_number, temp_quantity_bought, temp_quantity_sold; 
    float temp_price, temp_retail_price; 

    while(!feof(stdin)) 
    { 
     scanf("%s %ld %s %f %d %f %d\n", &temp_type, &temp_number, &temp_description, &temp_price, &temp_quantity_bought, &temp_retail_price, &temp_quantity_sold); 

     struct product_node *new_node; 
     new_node = malloc(sizeof(struct product_node)); 
     (*new_node).next = head; 
     head = new_node; 

     (*head).supply_type = temp_type; 
     (*head).number = temp_number; 
     (*head).description = temp_description; 
     (*head).price = temp_price; 
     (*head).quantity_bought = temp_quantity_bought; 
     (*head).retail_price = temp_retail_price; 
     (*head).quantity_sold = temp_quantity_sold; 
    } 

    freopen("/dev/tty", "rw", stdin); 

    int done=0; 
    int selection=0; 

    while (!done) 
    { 
     printf("\nMENU OPTIONS:\n"); 
     printf("1. Add a product number\n");//Okay 
     printf("2. Remove a product number\n"); 
     printf("3. List the products for a supplier\n"); 
     printf("4. List all unique supplier types\n"); 
     printf("5. Show profit margin for a specific supplier type\n"); 
     printf("6. Show total profit\n");//Okay 
     printf("7. Quit\n");//Okay 
     printf("Enter a selection (1-7): "); 

     scanf("%d", &selection); 
     char garbage = 'a'; 
     scanf("%c", &garbage); 

     switch(selection){ 
     case 1: 
      addProduct(); 
      break; 
     case 2: 
      removeProduct(); 
      break; 
     case 3: 
      listProduct(); 
      break; 
     case 4: 
      listSupplierTypes(); 
      break; 
     case 5: 
      supplierTypeProfit(); 
      break; 
     case 6: 
      totalProfit(); 
      break; 
     case 7: 
      done = 1; 
      break; 
     default: 
      printf("Invalid selection.\n"); 
      break; 
     } 
    } 
} 
+1

你的代碼看起來很好。您未向我們展示的代碼中可能存在問題。 – 2013-02-19 19:58:25

+1

你的代碼很好 - 請告訴我們實際的問題,請! – 2013-02-19 19:58:45

+0

「第4行」是第一個「scanf」調用嗎? – 2013-02-19 20:12:48

回答

3

remove是一個標準的功能,在 <stdio.h>聲明的名稱。定義自己的對象或其他具有相同名稱的實體具有未定義的行爲。該呼叫可能試圖在 remove()函數的地址處存儲 int值。

嘗試挑選不同的名稱。

更新:我想我錯了。標準頭文件中定義的函數名稱保留用作標識符,帶外部鏈接;如果相關標題爲#include d,則它們也被保留用作宏名稱和文件範圍的標識符。你的情況也不適用。儘管如此,避免自己定義這樣的標識符仍然是一個好主意。

而且,這可能是不相關的,你看到的症狀,但

scanf("%d", &obj); 

是未定義行爲,如果輸入的是語法上有效的整數,其值是int範圍之外。

執行確實達到您的「不在此處」行。您沒有看到它,因爲緩衝輸出在程序死亡之前未打印。更改此:

printf("Does not get here"); 

這樣:

printf("Does not get here\n"); 
fflush(stdout); 

當我gdb下運行您的程序,我看到了賽格故障在:

if ((*walker).number == remove) 

編譯過程中我也得到一些警告:

c.c: In function ‘addProduct’: 
c.c:32:5: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char **’ [-Wformat] 
c.c:38:5: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char **’ [-Wformat] 
c.c: In function ‘main’: 
c.c:134:9: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char **’ [-Wformat] 
c.c:134:9: warning: format ‘%ld’ expects argument of type ‘long int *’, but argument 3 has type ‘int *’ [-Wformat] 
c.c:134:9: warning: format ‘%s’ expects argument of type ‘char *’, but argument 4 has type ‘char **’ [-Wformat] 

這很容易導致內存損壞。修復這些,看看會發生什麼。

更新2:

我不知道還有什麼其他程序代碼仍可能有,但這樣的:

while (!(walker = NULL)) 
{ 
    if ((*walker).number == remove) 
    { 
     (*prev).next = (*walker).next; 
    } 
} 

幾乎肯定是錯誤的。您正在使用運算符=,您可能需要進行相等比較==

while (walker != NULL) 
{ 
    if (walker->number == remove) 
    { 
     prev->next = walker->next; 
    } 
} 

這只是我什麼跳了出來,當我把一個非常快看GDB告訴我後段錯誤就行了if ((*walker).number == remove):和固定在此之後,該代碼將如下更加清晰。

嘗試自己使用調試器,一次修復一個問題,並注意任何編譯器警告。

+0

我試過了,但我認爲錯誤也不在這裏。我將所有刪除實例更改爲外賣,效果也一樣,只要我輸入第一個scanf調用的值,就會發生段錯誤。 – WhatsInAName 2013-02-19 20:22:07

+0

@WhatsInAName:你輸入了什麼值? – 2013-02-19 20:26:15

+0

只有一個數字的整數,如3 – WhatsInAName 2013-02-19 20:30:45

0

您的printf不會出現,因爲它沒有從緩衝區刷新,只用一個「\ n」的字符串的結尾,你會看到它:

printf("Does not get here\n"); 

因此,錯誤,是不是在scanf,但在這行:

walker = (*head).next; 

正如我可以看到,該程序可能會到達那裏,而head不分配,這樣你就可以在函數的開始檢查:

void removeProduct(){ 
    int remove = 0; 
    char kill_char = 'a'; 
    if (head == NULL) { 
     printf("No product to remove!\n"); 
     return; 
    } 

我不確定是否有其他錯誤,但這是我注意到的。

順便說一句,你能避免通過scanf將在開始和格式字符串末尾的空格使用kill_char

scanf(" %d ", &remove); 

它會跳過所有白色字符(如製表符,空格和線路斷路器)。而且,如果你真的只想跳過一個字符,你可以使用*來忽略匹配:

scanf("%d%*c", &remove);