C编程segf on scanf

问题描述:

我已经写了下面的代码段,并且无法理解为什么它不会到达最后一行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

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

您的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);