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;
}
}
}
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)
:和固定在此之后,该代码将如下更加清晰。
尝试自己使用调试器,一次修复一个问题,并注意任何编译器警告。
我试过了,但我认为错误也不在这里。我将所有删除实例更改为外卖,效果也一样,只要我输入第一个scanf调用的值,就会发生段错误。 – WhatsInAName 2013-02-19 20:22:07
@WhatsInAName:你输入了什么值? – 2013-02-19 20:26:15
只有一个数字的整数,如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);
你的代码看起来很好。您未向我们展示的代码中可能存在问题。 – 2013-02-19 19:58:25
你的代码很好 - 请告诉我们实际的问题,请! – 2013-02-19 19:58:45
“第4行”是第一个“scanf”调用吗? – 2013-02-19 20:12:48