【问题标题】:Strange character replacement where it makes no sense (to me)奇怪的字符替换没有意义(对我来说)
【发布时间】:2013-09-24 01:11:44
【问题描述】:

对不起,代码太长了,但我很难过,需要帮助!

我的具体问题是,当我使用我的 parse 方法来调用“del”事件时,我会在一行中进行奇怪的字符替换,据我所知,它没有被触及。当我直接调用函数“del”时,不会发生这种情况。我花了太长时间研究这段代码无济于事,试图实现一种不同的字符串标记方式;你的名字。我包含了我的所有代码,因为我不知道问题出在哪里,因为我开始认为它不在函数“parse”中。

我会闲逛并提供所要求的尽可能多的信息,目前我不知道还要添加什么。

附:编译器链接到 gnu windows 库,这就是 strsep 的来源。

LibGW32C for Windows

P.P.S.只有编译器警告是抱怨我不使用 char* buf

db.h

#define MAX_ITEMS 80

typedef struct item {
    long id;
    char* name;
    char* desc;
    float price;
} item_t;

extern char *strsep (char **restrict stringp, const char *restrict delim);

int isLong (char* str);

int isFloat (char* str);

void add (item_t* item, long id, char* name, char* desc, float price);

void del (item_t* item, long id);

void modify (item_t* item, long id, char* name, char* desc, float price);

void disp (item_t* item, long id);

void itemCopy (item_t* from, item_t* to);

void parse (item_t* item, char* buf);

int findLastElement (item_t* item);

db.c

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "db.h"

int isLong (char* str) {
    if (str == NULL) {
        return 0;
    }
    char* pEnd;
    strtol (str, &pEnd, 10);
    if (isalpha (*pEnd) || *pEnd == ' ') {
        return 0;
    } else {
        return 1;
    }
}

int isFloat (char* str) {
    if (str == NULL) {
        return 0;
    }
    char* pEnd;
    strtod (str, &pEnd);
    if (isalpha (*pEnd) || *pEnd == ' ') {
        return 0;
    } else {
        return 1;
    }
}


void add (item_t *item, long id, char* name, char* desc, float price) {
    int i = 0;
    while (1) {
        if (item[i].id == id) {
            printf ("Item \"%s\" with ID %lu already exists.\n", item[i].name, id);
            break;
        } else if (item[i].id == 0) {
            item[i].id = id;
            item[i].name = name;
            item[i].desc = desc;
            item[i].price = price;
            break;
        } else {
            i++;
        }
    }
}

void del (item_t* item, long id) {
    int i = 0;
    int end = findLastElement (item);
    while (1) {
        if (item[i].id == id) {
            item[i].id = 0;
            item[i].name = "";
            item[i].desc = "";
            item[i].price = 0;
            while (i < end) {
                itemCopy (&item [i + 1], &item [i]);
                i++;
            }
            break;
        } else {
            if (i == MAX_ITEMS) {
                printf ("Item with ID %lu does not exist.\n", id);
                break;
            }
            i++;
        }
    }
}

void modify (item_t *item, long id, char* name, char* desc, float price) {
    int i = 0;
    while (1) {
        if (item[i].id == id) {
            item[i].name = name;
            item[i].desc = desc;
            item[i].price = price;
            break;
        } else {
            if (i == MAX_ITEMS) {
                printf ("Item with ID %lu does not exist.\n", id);
                break;
            }
            i++;
        }
    }
}

void disp (item_t* item, long id) {
    int end = findLastElement (item);
    printf ("\nID\tNAME\tDESCRIPTION\tPRICE\n--\t----\t-----------\t-----\n");
    if (id == -1) {
        for (int i = 0; i < end; i++) {
            printf ("%lu\t%s\t%s\t$%2.2f\n", item[i].id, item[i].name, item[i].desc, item[i].price);
        }
    } else {
        for (int i = 0; i < end; i++) {
            if (item[i].id == id) {
                printf ("%lu\t%s\t%s\t$%2.2f\n", item[i].id, item[i].name, item[i].desc, item[i].price);
                break;
            }
        }
    }
}

void itemCopy (item_t* from, item_t* to) {
    to -> id = from -> id;
    to -> name = from -> name;
    to -> desc = from -> desc;
    to -> price = from -> price;
}

void parse (item_t* item, char* str) {
    char **ap, *argv[10], *inputstr = malloc (sizeof(str)), *ptr;
    strcpy (inputstr, str);
    memset (argv, 0, sizeof (argv));
    for (ap = argv; (*ap = strsep (&inputstr, ",\n")) != NULL;) {
        if (**ap != '\0') {
            if (++ap >= &argv[10]) {
                break;
            }
        }
    }

    if (strcmp (argv[0], "add\0") == 0) {
        if (!isLong (argv[1]) || argv[1] == NULL) {
            printf ("\nInvalid/Missing ID\n");
            return;
        } else if (argv[2] == NULL) {
            printf ("\nInvalid/Missing Product Name.\n");
            return;
        } else if (argv[3] == NULL) {
            printf ("\nInvalid/Missing Product Description.\n");
            return;
        } else if (!isFloat (argv[4]) || argv[4] == NULL) {
            printf ("\nInvalid/Missing Price\n");
            return;
        } else {
            add (item, strtol (argv[1], &ptr, 10), argv[2], argv[3], strtod (argv[4], &ptr));
        }
    } else if (strcmp (argv[0], "del\0") == 0) {
        if (!isLong (argv[1]) || argv[1] == NULL) {
            printf ("\nInvalid/Missing ID\n");
            return;
        } else {
            del (item, strtol (argv[1], &ptr, 10));
        }
    }
} 

int findLastElement (item_t* item) {
    for (int i = 0; i < MAX_ITEMS; i++) {
        if (item[i].id == 0) return i;
    }
    return -1;
}

main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "db.h"


int main (int argc, char* argv[]) {
    item_t item [MAX_ITEMS];
    memset (item, 0, sizeof (item));
    char* buf = malloc (255);
    int exit = 0;

    while (!exit) {
        printf ("Adding 3 test items.\n");
        add (item, 1234, "Pizza", "Tasty Pizza", 9.99F);
        add (item, 5678, "Pasta", "Tasty Pasta", 19.99F);
        add (item, 9012, "Ribs", "Tasty Ribs", 29.99F);
        disp (item, -1);
        printf ("\nDeleting Item with ID 5678.\n");
        del (item, 5678);
        disp (item, -1);
        printf ("\nModifying item with ID 1234.\n");
        modify (item, 1234, "Soup", "Tasty Soup", 4.99F);
        disp (item, -1);
        printf ("\nAdding another item with id 5678.");
        add (item, 5678, "Pasta", "Tasty Pasta", 19.99F);
        printf ("\nAdding item \"Pizza\" with the same ID as \"Soup\".\n");
        add (item, 1234, "Pizza", "Tasty Pizza", 9.99F);
        disp (item, -1);
        printf ("\nDeleting item \"Soup\" and re-adding \"Pizza\".\n");
        del (item, 1234);
        add (item, 1234, "Pizza", "Tasty Pizza", 9.99F);
        disp (item, -1);
        printf ("\nDisplaying only the item with id 5678.\n");
        disp (item, 5678);
        printf ("\nAdding item \"Wings\" using the parsing function.\n");
        parse (item, "add,9898,Wings,Tasty Wings,14.99\n");
        disp (item, -1);
        printf ("\nAttempting to Delete non-existent item with ID 9999.\n");
        //del (item, 9999);
        parse (item, "del,9999\n"); <--- This is the problem line
        printf ("\nAttempting to Modify non-existent item with ID 9999.\n");
        modify (item, 9999, "Test", "Test", 0.0F);
        disp (item, -1);
        exit = 1;
    }
}

最后,我的输出:

Adding 3 test items.

ID      NAME    DESCRIPTION     PRICE
--      ----    -----------     -----
1234    Pizza   Tasty Pizza     $9.99
5678    Pasta   Tasty Pasta     $19.99
9012    Ribs    Tasty Ribs      $29.99

Deleting Item with ID 5678.

ID      NAME    DESCRIPTION     PRICE
--      ----    -----------     -----
1234    Pizza   Tasty Pizza     $9.99
9012    Ribs    Tasty Ribs      $29.99

Modifying item with ID 1234.

ID      NAME    DESCRIPTION     PRICE
--      ----    -----------     -----
1234    Soup    Tasty Soup      $4.99
9012    Ribs    Tasty Ribs      $29.99

Adding another item with id 5678.
Adding item "Pizza" with the same ID as "Soup".
Item "Soup" with ID 1234 already exists.

ID      NAME    DESCRIPTION     PRICE
--      ----    -----------     -----
1234    Soup    Tasty Soup      $4.99
9012    Ribs    Tasty Ribs      $29.99
5678    Pasta   Tasty Pasta     $19.99

Deleting item "Soup" and re-adding "Pizza".

ID      NAME    DESCRIPTION     PRICE
--      ----    -----------     -----
9012    Ribs    Tasty Ribs      $29.99
5678    Pasta   Tasty Pasta     $19.99
1234    Pizza   Tasty Pizza     $9.99

Displaying only the item with id 5678.

ID      NAME    DESCRIPTION     PRICE
--      ----    -----------     -----
5678    Pasta   Tasty Pasta     $19.99

Adding item "Wings" using the parsing function.

ID      NAME    DESCRIPTION     PRICE
--      ----    -----------     -----
9012    Ribs    Tasty Ribs      $29.99
5678    Pasta   Tasty Pasta     $19.99
1234    Pizza   Tasty Pizza     $9.99
9898    Wings   Tasty Wings     $14.99

Attempting to Delete non-existent item with ID 9999.
Item with ID 9999 does not exist.

Attempting to Modify non-existent item with ID 9999.
Item with ID 9999 does not exist.

ID      NAME    DESCRIPTION     PRICE
--      ----    -----------     -----
9012    Ribs    Tasty Ribs      $29.99
5678    Pasta   Tasty Pasta     $19.99
1234    Pizza   Tasty Pizza     $9.99
9898    Win♦    Çdel    $14.99 <--- THIS IS WHAT'S DOING MY HEAD IN

提前感谢您的帮助!

我真的希望这不会成为一些愚蠢的新手错误。

【问题讨论】:

  • 查找数组索引越界问题 --> 未定义行为
  • 我也做到了,只是不知道去哪里找。
  • 你的解析函数可能有问题。
  • 顺便说一句:strcmp (argv[0], "add\0")strcmp (argv[0], "add") 相同

标签: c string parsing strsep


【解决方案1】:

我原以为编译器会抱怨 parse 将 char* 作为其第二个参数,因为您实际上提供了 const char*(即字符串常量)。但是,您实际上尝试复制字符串,因此您可以(并且应该)制作原型const char*

让我们专注于“尝试复制”。抛开你的混淆初始化,你要做的是:

 inputstr = malloc (sizeof(str));
 strcpy(inputstr, str);

在我继续之前,我建议你看看strdup,它完全符合你的要求,只是正确:

 inputstr = strdup(str);

没有大惊小怪,没有错误。但无论如何,

strchar*;即指向字符的指针。 (它应该是const char*,但它仍然是一个指向字符的指针。)所以sizeof(str) 是一个指针的大小,在您的平台上可能是四个字节,尽管它可能是八个。无论哪种方式,它都不足以容纳字符串"add,9898,Wings,Tasty Wings,14.99\n",因此当您将其复制到inputstr 时,您最终会覆盖随机内存。 (可能又是del 字符串)。

sizeof(*str) 将是一个字符的大小,即一个字节。我认为您的意思可能是 strlen(str),它是字符串 str 的字节长度,但这也不对,因为它忽略了终止 NUL 字节。

简而言之,你想要的是上面的strdup调用,相当于:

char* inputstr = malloc(strlen(str) + 1);
strcpy(inputstr, str);

【讨论】:

  • 绝对精彩的解释!正如我之前所说,stackoverflow 的乐于助人的人帮助我比大多数人了解了更多关于编程的知识!毕竟这是一个菜鸟错误;我一直在努力避免这些。但我觉得我在进步。感谢您的详细解释!
  • @capncoolio:不用担心。顺便说一句,parse 泄漏了它为inputstr 分配的内存。在您的设计中,您无法释放该内存,因为您将指向 inputstr 片段的指针放入数据库中。因此,一旦您超越“玩具”阶段,您就必须重新考虑您的内存管理策略。祝你好运。
  • 不是inputstr 本地到parse 吗?或者这是我认为我正在复制inputstr 的一部分,而实际上我指向inputstr 的每个实例中的位置?
  • @capncoolio:这就是 strsep 的工作原理,正如man strsep 中明确解释的那样(linux.die.net/man/3/strsep,如果你在 Windows 上没有 man)。而 mallocd storage isn't local. inputstr` 是本地的,但它只是一个指针;指向的存储是堆存储,而不是堆栈存储,它一直存在,直到你释放它,即使没有指向它。
  • 嗯...没错。对我来说,这引出了一个问题:它在记忆方面有什么不同?从某种意义上说,即使它被复制,它也会占用相同的空间,对吧?显然我使用的实际方法是极差的练习;但对记忆有何影响?
猜你喜欢
  • 1970-01-01
  • 2016-02-14
  • 2015-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-20
相关资源
最近更新 更多