2013-03-19 66 views
0

我试图创建下面的数组:创建嵌套结构的动态自定义数组用C

"Fruits", 25, { 
    {"Apple", 2}, 
    {"Grapes", 13}, 
    {"Melon", 10} 
} 
"Meats", 40, { 
    {"Beef", 9}, 
    {"Chicken", 27}, 
    {"Pork", 4} 
} 

... 

感觉像有做什么我走到这一步,更优雅的方式。值得赞赏的是,在给定输入结构的情况下,如何创建此结构的任何反馈/示例都会更有效。

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

typedef struct Product { 
    char *name; 
    int qty; 
} Prods; 

typedef struct Category { 
    char *name; 
    int qty; 
    int prods_count; 
    Prods *prod; 
} Cats; 

typedef struct Inventory { 
    Cats *cat; 
    int cats_count; 
} Inv; 

struct tmp_input { 
    char name[12]; 
    int qty; 
    char cat[12]; 
}; 

// return index if found 
int in_array(Inv *inv, char *k) { 
    int i; 
    if (inv->cats_count == 0) 
     return -1; 
    for (i = 0; i < inv->cats_count; i++) { 
     if (strcmp (k, inv->cat[i].name) == 0) return i; 
    } 
    return -1; 
} 

int main() { 
    int i, j, exists = 0; 
    // temp struct. 
    struct tmp_input items[] = { 
     {"Apple", 2, "Fruit"}, {"Coke", 10, "Drink"}, {"Pork", 4, "Meat"}, 
     {"Beef", 9, "Meat"}, {"Chicken", 27, "Meat"}, {"Melon", 10, "Fruit"}, 
     {"Tea", 3, "Drink"}, {"Coffee", 20, "Drink"}, {"Grapes", 13, "Fruit"} 
    }; 

    size_t len = sizeof (items)/sizeof (struct tmp_input); 

    Inv *inven = malloc(sizeof(Inv)); 
    inven->cats_count = 0; 
    inven->cat = calloc(1, sizeof(Cats)); 

    for (i = 0; i < len; i++) { 
     exists = in_array(inven, items[i].cat); 
     // category does not exist 
     if (exists == -1) { 
      inven->cat = realloc(inven->cat, sizeof(Cats) * (inven->cats_count + 1)); 
      inven->cat[inven->cats_count].name = strdup(items[i].cat); 
      inven->cat[inven->cats_count].qty += items[i].qty; 

      inven->cat[inven->cats_count].prods_count = 1; 
      inven->cat[inven->cats_count].prod = calloc (1, sizeof (Prods)); 
      inven->cat[inven->cats_count].prod->name = strdup (items[i].name); 
      inven->cat[inven->cats_count].prod->qty = items[i].qty; 
      inven->cats_count++; 
     } 
     // category found 
     else { 
      inven->cat[exists].qty += items[i].qty; 

      int size = inven->cat[exists].prods_count + 1; 
      inven->cat[exists].prod = realloc(inven->cat[exists].prod, sizeof(Prods) * (size)); 
      inven->cat[exists].prod[size - 1].name = strdup (items[i].name); 
      inven->cat[exists].prod[size - 1].qty= items[i].qty; 
      inven->cat[exists].prods_count++; 
     } 
    } 

    for (i = 0; i < inven->cats_count; i++) { 
     printf("%3d %s\n", inven->cat[i].qty, inven->cat[i].name); 
     for (j = 0; j < inven->cat[i].prods_count; j++) { 
      printf("%3d %s\n", inven->cat[i].prod[j].qty, inven->cat[i].prod[j].name); 
     } 
    } 

    return 0; 
} 
+0

每个类别中总是有三种产品? – teppic 2013-03-19 00:59:49

+0

@teppic:不,每个类别可以有x个产品数量。 – 2013-03-19 01:05:24

+0

x是否为最大值?还是需要完全灵活? – teppic 2013-03-19 01:05:58

回答

0

您还没有分配的PROD数组的内存。

喜欢的东西

... 

if (exists == -1) { 
    inven->cat = realloc(inven->cat, sizeof(Cats) * (inven->cats_count + 1)); 
    inven->cat[inven->cats_count].name = items[i].cat; 
    inven->cat[inven->cats_count].qty += items[i].qty; 

    // Allocate memory for 1 product 
    inven->cat[inven->cats_count].prods_count = 1; 
    inven->cat[inven->cats_count].prod = malloc (sizeof (Prods)); 

    // Now allocate space and copy the name 
    inven->cat[inven->cats_count].prod->name = strdup (items[i].name + 1); 

    inven->cats_count++; 
} 
... 

我将它留给你来处理,其中有一个类别,在那里你会需要再次重新分配内存超过1种产品的情况。

另一个错误是,你需要分配并复制类别名称

inven->cat[inven->cats_count].name = items[i].cat; 

inven->cat[inven->cats_count].name = strdup (items[i].cat); 

这是因为items数组不此功能之外存在被替换,因此如果你只是做

inven->cat[inven->cats_count].name = items[i].cat; 

然后你离开这个功能invent->cat[inven->cats_count].name将指向垃圾内存。

最后的建议是将每个结构拆分为一个函数来处理它的创建,只是为了清理代码。

---编辑添加的抽象数据类型,如果你有,你知道你将通过索引来访问数据

数组是有用的意见。如果你不知道你想要的项目的索引(就像在这种情况下一样),那么一个数组就没那么有用。

与其他评论不同,我不认为使用链接列表真的会给你任何有用的东西。当你需要顺序遍历所有项目时,链接列表非常有用,而不必真正关心他们在列表中的位置。在我看来,像你这样的系统最常见的用例是搜索:我们有库存有水果吗?将10箱可乐添加到库存......这些东西。

另外,您只需要为每个类别/产品输入单个条目。数据中不需要3个水果类别。数组和链表对于多次添加相同结构没有任何限制。这意味着每次您需要检查整个列表以查看是否需要添加新结构。

因此,我一定会将类别和产品数组放入哈希表(或称为某些语言的字典)中,这些哈希表映射名称 - >结构。这将加快您的搜索速度,因为您不必每次都搜索整个数据集,并且会阻止您多次添加相同的结构。

在哈希表维基百科的文章:http://en.wikipedia.org/wiki/Hashtable

+0

谢谢。我得到它的工作。现在你还会推荐使用链表,而不是我已有的(问题更新)? – 2013-03-19 02:12:11

+0

我将更新我的回答,并附上我对使用什么抽象数据类型的评论。 – iain 2013-03-19 11:41:59

0

下面是如何设置的结构动态(比链表简单,但不灵活)的例子。

typedef struct Product { 
    char *name; 
    int qty; 
} Prods; 

typedef struct Category { 
    char *name; 
    int qty; 
    int prods_count; 
    Prods *prod;  // dynamic array of Products 
} Cats; 

它们是这样的结构。

struct Category categ[10]; 

类别任意数量的,目前采取categ[0]关于“水果”。

下动态地创建10个产品的结构数组:

Prods *prod_array = malloc(sizeof(Prods) * 10); // i.e. prod_array[0] to [9] 

现在只是存储在品类结构数组:

categ[0].prod = prod_array; 
    categ[0].prods_count = 10; 

如果您需要访问的产品名称,它只是: categ[i].prod[j].name

现在,如果您需要其他10个产品,您可以使用realloc来增加数组的大小,并且upd吃了它的数量。

把所有这些东西放在函数中,代码不是太复杂。

+0

谢谢。我得到它的工作(问题更新)。您能否详细介绍一下如何使用链表?我觉得它不是太干净/优雅。 – 2013-03-19 02:14:39

+0

@PeteDarrow - 如果你只是想要一个开放式的列表,这会更容易。链接列表非常灵活,但有点工作。基本上''malloc''每次你想要一个新的产品结构,并将其插入到列表中。每个结构都有一个指向另一个结构的指针(通常它写成'struct Product * next;')。当'next'为NULL时,你在列表的最后。如果您搜索该网站,您会发现我期望的大量示例。 – teppic 2013-03-19 02:17:13

+0

我会查看链接列表。谢谢! – 2013-03-19 02:23:27