c获取分段错误

时间:2016-10-26 15:54:56

标签: c segmentation-fault

我是C的新手,我一直在写一个简单的脚本,如下所示:

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

typedef enum {FALSE, TRUE} bool;

// item_t: information for a single item to be purchased
typedef struct _item_t {
    char name[50];
    int price;
    int quantity;
} item_t;

// cart_t: information for the shopping cart
typedef struct _cart_t {
    item_t *items[10];
    int size;
} cart_t;

// Returns index of item with name `item_name` in the `items` array inside of `cart`. Returns -1 if not found.
int find_item(cart_t *cart, const char* item_name) {
    int i;
    for(i=0;i<sizeof(*cart);++i){
        if(strcmp(cart->items[i]->name,item_name) == 0){
            return i;
        }
    }

    if(i == sizeof(*cart) -1)
        return -1;
    return 0;
}

// Adds item to cart's items array, if the cart is not full. Returns `FALSE` if the cart is full, and returns `TRUE` otherwise.
bool add_new_item(cart_t *cart, item_t *item) {
    if(10 == cart->size)
        return FALSE;
    else{
        int i = cart->size;
        cart->items[i] = item;
        cart->size +=1;
        return TRUE;
    }
}

// Increases quantity by one of item with name `item_name` inside of `cart`, if such an item exists.
void add_existing_item(cart_t *cart, const char* item_name) {
    int i = find_item(cart,item_name);
    if(i == -1)
        return;
    else{
        cart->items[i]->quantity += 1;
    }
}

// Removes item with name from cart's items array. Returns a pointer to the removed item, and shifts the items to the right of the deleted item in the `items` array 
// left to fill in the gap.
// If the item is not found, return NULL.
item_t* remove_item(cart_t *cart, char *remove_me) {
        item_t *p;
        int j = 0;
        int i = find_item(cart,remove_me);
        if(i == -1)
            return NULL;
        else{

            if(i == cart->size-1){
                p = cart->items[i];
                cart->items[i] = NULL;
            }else{
                p = cart->items[i];
                for(j=i;j<cart->size-1;++j){
                    cart->items[j] = cart->items[j+1];
                }
                cart->items[cart->size-1] = NULL;
                cart->size -= 1;
            }
            return p;
        }
    }

// Determines and returns the total cost of items in cart.
int total_cost(cart_t *cart) {
    int total;
    int i;
    for(i=0;i<sizeof(*cart);++i){
        total += cart->items[i]->quantity * cart->items[i]->price;
    }
    return total;
}

//print  item's info and cost.
void print_item_cost(item_t *item) {
    printf("%s %d @ $%d = $%d\n", item->name, item->quantity,
           item->price, (item->price * item->quantity));
}

//print the shopping cart info
void print_total(cart_t *cart) {
    int i = 0;
    int cost = 0;

    printf("Number of Items: %d\n\n", num_items(cart));

    if (cart->size > 0) {
        for (i = 0; i < cart->size; ++i) {
            print_item_cost(cart->items[i]);
        }
    }

    else {
        printf("SHOPPING CART IS EMPTY\n");
    }

    cost = total_cost(cart);

    printf("\nTotal: $%d\n", cost);
}

//this function clears items in the cart
void clear_cart(cart_t *cart) {
    int i = 0;
    for (i = 0; i < cart->size; i++) {
        free(cart->items[i]);
    }
    cart->size = 0;
}

//a menu of options to manipulate the shopping cart
void print_menu(cart_t *cart) {
    char choice = ' ';
    char name[50] = "";
    int price = 0;
    int quantity = 0;
    int i = 0;
    char c = ' ';
    item_t *item;

    while(choice != 'q') {

        printf("MENU\n");
        printf("a - Add item to cart\n");
        printf("r - Remove item from cart\n");
        printf("c - Change item quantity\n");
        printf("o - Output shopping cart\n");
        printf("q - Quit\n\n");

        while (choice != 'a' &&
               choice != 'r' &&
               choice != 'c' &&
               choice != 'o' &&
               choice != 'q') {
            printf("Choose an option: ");
            scanf(" %c", &choice);
            printf("\n");
        }

        switch (choice) {
            case 'a':
                while ((c = getchar()) != EOF && c != '\n');

                printf("ADD ITEM TO CART\n");
                printf("Enter the item name: ");
                fgets(name, 50, stdin);
                printf("\n");

                i = find_item(cart, name);
                if (i != -1) {
                    printf("Item found. Updating quantity of item. \n");
                    add_existing_item(cart, name);

                    choice = ' ';
                    printf("\n");
                    break;
                }

                if (cart->size >= 10) {
                    printf("Cart full. Cannot add new item. \n");

                    choice = ' ';
                    printf("\n");
                    break;
                }

                printf("Enter the item price: ");
                scanf("%d", &price);
                printf("\n");

                printf("Enter the item quantity: ");
                scanf("%d", &quantity);
                printf("\n");


                item = (item_t*)malloc(sizeof(item_t));
                strcpy(item->name, name);
                item->price = price;
                item->quantity = quantity;
                add_new_item(cart, item);

                choice = ' ';
                printf("\n");

                break;

            case 'r':
                while ((c = getchar()) != EOF && c != '\n');

                printf("REMOVE ITEM FROM CART\n");
                printf("Enter name of item to remove: ");
                fgets(name, 50, stdin);
                printf("\n");

                item = remove_item(cart, name);
                if (item == NULL) {
                    printf("Item not found. \n");
                }
                else {
                    printf("Item removed. \n");
                    free(item);
                }

                choice = '\0';
                printf("\n");
                break;

            case 'c':

                while ((c = getchar()) != EOF && c != '\n');

                printf("CHANGE ITEM QUANTITY\n");
                printf("Enter the item name: ");
                fgets(name, 50, stdin);
                printf("\n");

                i = find_item(cart, name);

                if (i == -1) {
                    printf("Item not found. \n");
                    choice = ' ';
                    printf("\n");
                    break;
                }

                printf("Enter the item price: ");
                scanf("%d", &price);
                printf("\n");


                printf("Enter the new quantity: ");
                scanf("%d", &quantity);
                printf("\n");

                update_item_in_cart(cart, name, price, quantity);

                choice = '\0';
                printf("\n");

                break;

            case 'o':
                while ((c = getchar()) != EOF && c != '\n');
                printf("OUTPUT SHOPPING CART\n");
                print_total(cart);
                choice = ' ';
                printf("\n");
                break;

        }
    }
    clear_cart(cart);
}

int main(){
    // malloc
    cart_t *cart;
    cart = (cart_t*)malloc(sizeof(cart_t));
    cart->size = 0;

    print_menu(cart);

    //free
    free(cart);
    return 0;
}

它可能看起来很长,但想法很简单,它模拟购物车中的项目,它接受命令添加项目/删除项目/更改数量/显示当前购物车信息。但是,在调试的最开始,当我在命令窗口中执行以下操作时:

$ ./try
MENU
a - Add item to cart
r - Remove item from cart
c - Change item quantity
o - Output shopping cart
q - Quit

Choose an option: a

ADD ITEM TO CART
Enter the item name: tira

Segmentation fault (core dumped)

我遇到了分段错误。我想知道这里的错误是什么?我是C的新手,并且不确定我的代码中指针内容的正确性。

PS: 感谢您的回复,是的,这有助于我解决add_new_item函数中的错误。但是,当我调试remove_item时,它会再次终止并出现分段错误,命令行如下所示:

$ ./try
MENU
a - Add item to cart
r - Remove item from cart
c - Change item quantity
o - Output shopping cart
q - Quit

Choose an option: a

ADD ITEM TO CART
Enter the item name: shoes

Enter the item price: 1

Enter the item quantity: 2


MENU
a - Add item to cart
r - Remove item from cart
c - Change item quantity
o - Output shopping cart
q - Quit

Choose an option: r

REMOVE ITEM FROM CART
Enter name of item to remove: shoes

Item removed.

MENU
a - Add item to cart
r - Remove item from cart
c - Change item quantity
o - Output shopping cart
q - Quit

Choose an option: o

OUTPUT SHOPPING CART
Segmentation fault (core dumped)

2 个答案:

答案 0 :(得分:3)

至少有一个问题是find_item功能。 sizeof(*cart)与购物车中的实际项目数无关,sizeof返回数据结构中的字节数。在这种情况下,这至少是44个字节(假设4个字节int和4个字节的指针)。您应该将此功能更改为以下内容:

// Returns index of item with name `item_name` in the `items` array inside of `cart`. Returns -1 if not found.
int find_item(cart_t *cart, const char* item_name) {
    int i;
    for(i=0;i<cart->size;++i){
        if(strcmp(cart->items[i]->name,item_name) == 0){
            return i;
        }
    }

    return -1;  // if we get here, then no items were found, so return -1.
                // I don't understand your logic in returning 0, since 0 is a valid item index
}

正如@Fang所述,将您的购物车中的商品数量(cart->size)与sizeof(*cart)混淆是整个代码中的常见错误。这需要在您尝试迭代项目的任何地方进行更改。

答案 1 :(得分:2)

代码中导致细分错误的问题出在find_item函数中,您使用的是sizeof关键字,您应该使用购物车的size属性。< / p>

sizeof为您提供购物车结构的大小(以字节为单位)(永远不会更改),而您将购物车中的商品数量存储在size属性中。

这意味着您的功能应该是:

// Returns index of item with name `item_name` in the `items` array inside of `cart`. Returns -1 if not found.
int find_item(cart_t *cart, const char* item_name) {
    int i;
    for(i=0;i<cart->size;++i){
        if(strcmp(cart->items[i]->name,item_name) == 0){
            return i;
        }
    }

    if(i == cart->size)
        return -1;
    return 0;
}