c中的结构列表

时间:2016-02-27 22:08:21

标签: c pointers memory-management

我希望实现一个简单的数据结构,比如链接列表,但我不需要任何复杂的东西,或者我呢?

假设我有书籍数据结构。

typedef struct {
    char* name;
    size_t number;
} book;

我想将这些内容附加到越来越多的书中,这些书在记忆中看起来应该是这样的。

------------------------
| 0 | 1 | 2 | 3 | ......
------------------------

因为我没有做任何花哨的事情,除了添加一堆书并且从不更改订单并且只在程序结束时释放书籍我不需要链接列表的所有功能。

我试图用这样的双指针来做它,以创建书籍的原始结构。

public book** add_bookd(book** books, book* b) {
    static int index = -1;
    int count;
    index++;
    count = index + 1;
    book** books = realloc(books, sizeof(book*)*count);
    books[index] = calloc(1, sizeof(book));
    copy_bookd(books[index], b); //this is just a series of memcopy
                                 //since i have POD data types
   return books;
}

我尝试过一个非常简单的char,但我遇到了seg错误。

char** double_pointer(char** a, char* b) {
    static int index = -1; int count;
    index++;
    count = index + 1;
    a = realloc(a, sizeof(char*)*count);
    for(int i = 0; i < index; i++) {
        a[i] = calloc(1, sizeof(char));
        a[i] = b;
        printf("%s\n",a[i]);
    }
    return a;
}


char** tmp = calloc(1, sizeof(char*));
for(int i = 0; i < 3; i++) {
    double_pointer(tmp, "a");
    //printf("%s\n",tmp)); //seg faults here
}

这是用链表更好地实现的东西吗?为什么我会遇到seg故障?我的意思是gdb显示我崩溃了。

当我打印tmp gdb报告的值

p tmp $1 = (char **) 0x0

尝试访问tmp [0] gdb表示无法访问0x0处的内存。

3 个答案:

答案 0 :(得分:0)

这些界限:

book** books = realloc(books, sizeof(book*)*count);
books[index] = calloc(1, sizeof(book));
copy_bookd(books[index], b);

显示出一些问题,尤其是缺少错误检查。

推荐:

book* temp = realloc(*books, sizeof(book*)*count);

if( temp != NULL )
{ // then, realloc successful

    *books = temp;
     (*books)[index] = calloc(1, sizeof(book));
     if( (*books)[index] != NULL )
     { // then, calloc successful
         copy_bookd((*books)[index], b);
     }

     else
     {
         // handle calloc failure
     }
}

else
{
    // handle realloc failure
}

答案 1 :(得分:0)

所以,您正在寻找存储大量书籍的可能性,您可能只会添加这些书籍?这确实可以通过与您已有的方法非常相似的方法来完成。但是,让我们从下往上:

基本上,在内存中的某个地方存储了一个“数组”的书籍,在连续的内存位置中有几个struct book。您可以使用指向第一本书的指针指向该数组:

struct book * books;

不知何故,您还需要知道该数组的结束位置。因此,我看到的两种可能性是使用sentinel值(类似于C字符串对'\0'所做的)或者只是跟踪数组的大小。我选择后者:

size_t count;

由于您不想迷路,我们使用结构化编程技术并将这两个信息绑定在一起:

struct bookstore {
  struct book * books;
  size_t count;
};

为了与这样的商店合作,常见的操作应该放在花哨的名字后面。这称为抽象,可能 编程时最重要的事情。在C中执行此操作的设备是该功能。从一个开始,初始化一个空商店:

char init_store(struct bookstore * store) {
  assert(store != NULL);
  store->count = 0;
  store->books = malloc(0);
  return (store->books == NULL) ? 0 : 1;
}

并添加其双重功能,以“完成”商店:

void finish_store(struct bookstore * store) {
  assert(store != NULL);
  assert(store->books != NULL);
  store->count = 0;
  free(store->books);
  store->books = NULL;
}

这些函数仅对已存在的struct bookstore实例进行操作。您可以在堆栈或堆上分配它们(通过malloc,也不要忘记free)。

现在到关键部分:添加一本书。为此,您需要放大“数组”以便能够在其中存储新项目。这是使用realloc完成的。然后你只需将它复制到免费的地方即可添加:

char add_book(struct bookstore * store, struct book book) {
  assert(store != NULL);
  assert(store->books != NULL);
  struct book * books =
    realloc(store->books, (store->count + 1) * sizeof(struct book));
  if (books == NULL) {
    return 0;
  }
  books[store->count] = book;
  store->books = books;
  store->count += 1;
  return 1;
}

这就是我如何处理这个问题,尽管有足够的优化空间。请注意,上面的代码是未经测试的。

该方法与您的方法基本相同:您将使用指向(包含)指向书籍的指针的指针。重要的区别在于尺寸也存储了。您的代码使用静态局部变量,这实际上限制您只有一个书籍的“列表”。作为建议:避免全球或静态状态,如地狱。

答案 2 :(得分:0)

有许多方法可以跟踪多个结构。关于最简单的动态结构是动态结构数组。内存管理的相同方法也适用,但您可以添加另一个外部结构来帮助保存与该一组书籍相关的信息。例如。如果你有多个你感兴趣的集合,你可以做类似的事情:

typedef {
    size_t nbooks;
    size_t allocsz;
    char colname[16];
    struct {
        char* name;
        size_t number;
    } book;
} collection;

这样的方法允许一个结构,它包含它包含的书籍数量,当前的分配大小,以及集合的唯一名称(例如小说非小说< / em>,等......

您可以考虑这样的内容是否会添加足够的额外数据以满足您的需求。至于结构数组的基本处理,动态声明的数组就是它所需要的。然后由您来跟踪当前分配的号码,填写的号码,然后在填写的号码达到您的限制时转到realloc

要在您的收藏中添加图书,您可以做一些简单的事情,例如:

void addbook (book **books, char *name, size_t num, size_t *n, size_t *max)
{
    (*books)[*n].name = strdup (name);
    (*books)[*n].number = num;

    if ( ++(*n) >= *max) {  /* realloc */
        void *tmp = realloc (*books, sizeof **books * 2 * *max);
        if (!tmp) {
            fprintf (stderr, "error: realloc, virtual memory exhausted.\n");
            exit (EXIT_FAILURE);
        }
        *books = tmp;
        memset (*books + *max, 0, sizeof **books * *max);
        *max *= 2;
    }
}

传递结构数组的地址以及要添加的书名数字,当前的书数,和当前最大。 strdup用于为名称分配空间,分配书号,然后检查重新分配。这就是它的全部内容。

数组方法的一个简短示例是:

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

enum { MAXB = 64 };

typedef struct {
    char* name;
    size_t number;
} book;

void addbook (book **books, char *name, size_t num, size_t *n, size_t *max);

int main (void) {

    book *books = calloc (MAXB, sizeof *books); /* check for error cond */
    char name[MAXB] = "";
    size_t maxb = MAXB, i, idx = 0, len = 0, n = 0, nadd = 0;

    printf ("\n number of books to enter: ");
    while (scanf ("%zu%*c", &nadd) != 1) {
        printf ("  invalid number, try again: ");
    }

    for (i = 0; i < nadd; i++) {  /* take input and add to books */
        size_t nlen;
        printf (" enter book title : ");
        while (scanf ("%[^\n]%*c", name) != 1) {
            printf ("  invalid name, try again: ");
        }
        printf (" enter book number: ");
        while (scanf ("%zu%*c", &n) != 1) {
            printf ("  invalid number, try again: ");
        }
        addbook (&books, name, n, &idx, &maxb);

        nlen = strlen (name);  /* max length for output formatting */
        if (nlen > len) len = nlen;
    }
    putchar ('\n');

    for (i = 0; i < idx; i++) {  /* print the books added */
        printf (" book[%2zu]  %-*s   %zu\n", i, (int)len,
                books[i].name, books[i].number);
    }

    for (i = 0; i < idx; i++)   /* free allocated memory */
        free (books[i].name);
    free (books);

    return 0;
}

void addbook (book **books, char *name, size_t num, size_t *n, size_t *max)
{
    (*books)[*n].name = strdup (name);
    (*books)[*n].number = num;

    if ( ++(*n) >= *max) {  /* realloc */
        void *tmp = realloc (*books, sizeof **books * 2 * *max);
        if (!tmp) {
            fprintf (stderr, "error: realloc, virtual memory exhausted.\n");
            exit (EXIT_FAILURE);
        }
        *books = tmp;
        memset (*books + *max, 0, sizeof **books * *max);
        *max *= 2;
    }
}

示例使用/输出

$ ./bin/struct_books_single

 number of books to enter: 4
 enter book title : Moby Dick
 enter book number: 23478
 enter book title : Tom Sawyer
 enter book number: 23479
 enter book title : Of mice and men
 enter book number: 23480
 enter book title : Of other flesh & tongue
 enter book number: 23510

 book[ 0]  Moby Dick                 23478
 book[ 1]  Tom Sawyer                23479
 book[ 2]  Of mice and men           23480
 book[ 3]  Of other flesh & tongue   23510

查看示例,如果您有任何疑问,请告诉我。您可以添加尽可能多的书籍,因为您的记忆可以容纳。所有书籍在退出时都会被释放。