没有链接列表的内存分配

时间:2015-10-04 02:06:10

标签: c pointers

说我有这个结构:

struct Book
{
   int book_id;
   struct Book *book_ptr;
};
/* navigation pointers */
struct Book *front;
struct Book *rear;

我想在我的记忆中添加一个新的Book,所以我有这个功能:

void add_book() {
    struct Book *temp;  
    temp = (struct Book*)malloc(sizeof(struct Book));    
    temp->book_id = t;
    t++;    
    temp->book_ptr = NULL;       
    if (rear  ==  NULL)
    {
        front = temp;
        rear = temp;
    }
    else
    {
        rear->book_ptr = temp;
        rear = temp;
    }        
}

如果我想要一个我的Books列表:

void see_all_the_books()
{
    struct Book *temp;     
    temp = front;    
    if (front  ==  NULL)
    {
        printf("> YOU HAVEN'T ADDED ANY BOOK YET\n");
    }
    while (temp)
    {
        printf("Book #%d\n", temp->book_id);
        temp = temp->book_ptr;
    }
}

相当简单,而且有效。 如果我不想使用链接列表该怎么办?我想做的是每次我正在制作新书时将rear指针移动一个块。

然后我的结构将是这样的:

struct Book
{
   int book_id;
};
/* navigation pointers */
struct Book *front;
struct Book *rear;

每次我想添加Book

时,我需要移动指针1块
 void add_book() {
    struct Book *temp;
    temp = (struct Book*)malloc(sizeof(struct Book));

    temp->book_id = t;
    t++;

    if (rear  ==  NULL)
    {
        printf("Your FIRST book has been added\n");        
        front = temp; 
        rear = temp;
    }
    else
    {
        rear++;         // MOVED TO NEXT BLOCK
        rear = temp;    // OBVIOUSLY WRONG      
        printf("ANOTHER book has been added\n"); 
    }        
}

我在上一段代码中需要更改哪些内容?

2 个答案:

答案 0 :(得分:1)

您在struct Book中分配新add_book的方法引发了一些微妙的问题。这样做是没有错的,事实上它很常见,但你必须注意如何将所需的参数传递给add_book。要在main()中成功创建指针数组并使用add_book为每个添加的新书分配,您必须将指针数组的地址传递给{{1}在需要更多指针的情况下处理重新分配。您还需要一种方法来传递和跟踪已分配的指针数当前可用的最大指针数。因此add_book的基本声明如下所示:

add_book

struct Book *add_book (struct Book ***book, int id, size_t *idx, size_t *nmax); ***book中声明的指针数组的地址,main()是要分配给id的新值,book_id是要添加的idx的当前索引和struct Book是可填写的指针数。

注意:您正在向nmax功能传递指向idxnmax的指针。这允许您在add_book中增加/更改其值,同时在add_book中提供更新的值。 main()的完整原型可能如下所示:

add_book

注意,因为您已将 struct Book *add_book (struct Book ***book, int id, size_t *idx, size_t *nmax) { if (!book || !*book) return NULL; size_t n = *idx; (*book)[*idx] = xcalloc (1, sizeof **book); (*book)[*idx]-> book_id = id; (*idx)++; if (*idx == *nmax) { /* realloc if nmax reached, update nmax */ void *tmp = realloc (*book, *nmax * 2 * sizeof tmp); if (!tmp) { fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__); return NULL; } *book = tmp; /* use memset to initialize all new pointers NULL */ memset (*book + *nmax, 0, *nmax * sizeof tmp); *nmax *= 2; } return (*book)[n]; } 地址传递给该函数,因此您必须取消引用Book(即Book)在*book中,以便正确使用指针数组。另请注意,add_book只是一个错误检查函数,它调用xcalloc以防止在测试每次分配calloc的返回时使逻辑混乱。

Windows注意事项: Visual Studio中的编译器不知道calloc只是返回函数名称的宏。因此,如果您使用visual studio编译代码,只需将__func__替换为__func__

一个完整的例子将有所帮助。下面将所有部分组合在一起,以使用一组指针来保存您的"function name"集合。注意:在下面的示例中,最大图书数定义为struct Book,但8被强制重新分配10 book_id Bookadd_book*idx == *nmax

*idx & *nmax = 8

Sampe输入(10 int)

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

#define NBOOKS 8

struct Book {
    int book_id;
};

void *xcalloc (size_t n, size_t s);
struct Book *add_book (struct Book ***book, int id, size_t *idx, size_t *nmax);

int main (void) {

    size_t idx = 0;
    size_t nbooks = 0;
    size_t nmax = NBOOKS;
    int id = 0;
    struct Book **Book = NULL;

    /* create NBOOKS pointers to struct Book */
    Book = xcalloc (NBOOKS, sizeof *Book);

    /* read integer input from stdin */
    while (scanf ("%d", &id) == 1)
        add_book (&Book, id, &idx, &nmax);

    nbooks = idx;   /* save the number of books added */

    /* print the book_id for each book */
    for (idx = 0; idx < nbooks; idx++)
        printf ("  Book[%2zu] : %d\n", idx, Book[idx]->book_id);

    /* free all allocated memory */
    for (idx = 0; idx < nbooks; idx++)
        free (Book[idx]);
    free (Book);

    return 0;
}

/* add one struct Book to array of pointers to Book with book_id = 'id'
 * NOTE: since you must protect against writing beyond the last pointer 
 * you must pass the ADDRESS OF Book (the reason for ***) in the event a
 * realloc occurs. Otherwise the address of Book in main() will never
 * reflect the reallocation. (pointers to idx and nmax are passed so their
 * updated values are available in main() ).
 */
struct Book *add_book (struct Book ***book, int id, size_t *idx, size_t *nmax)
{
    if (!book || !*book)   return NULL;

    size_t n = *idx;
    (*book)[*idx] = xcalloc (1, sizeof **book);

    (*book)[*idx]-> book_id = id;
    (*idx)++;

    if (*idx == *nmax) {    /* realloc if nmax reached, update nmax */
        void *tmp = realloc (*book, *nmax * 2 * sizeof tmp);
        if (!tmp) {
            fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
            return NULL;
        }
        *book = tmp;  /* use memset to initialize all new pointers NULL */
        memset (*book + *nmax, 0, *nmax * sizeof tmp);
        *nmax *= 2;
    }

    return (*book)[n];
}


/** xcalloc allocates memory using calloc and validates the return.
 *  xcalloc allocates memory and reports an error if the value is
 *  null, returning a memory address only if the value is nonzero
 *  freeing the caller of validating within the body of code.
 */
void *xcalloc (size_t n, size_t s)
{
    register void *memptr = calloc (n, s);
    if (memptr == 0) {
        fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
        exit (EXIT_FAILURE);
    }

    return memptr;
}

<强>输出

$ cat dat/10int_nl.txt
8572
-2213
6434
16330
3034
12346
4855
16985
11250
1495

内存错误检查

$ ./bin/struct_book_simple <dat/10int_nl.txt
  Book[ 0] : 8572
  Book[ 1] : -2213
  Book[ 2] : 6434
  Book[ 3] : 16330
  Book[ 4] : 3034
  Book[ 5] : 12346
  Book[ 6] : 4855
  Book[ 7] : 16985
  Book[ 8] : 11250
  Book[ 9] : 1495

答案 1 :(得分:0)

您需要创建一个指针数组,每个指针都指向一本书。这将需要您的代码稍微改变,因为将不再需要前后。

int maxbooks = somenumber;
Struct book *books= malloc(maxbooks*sizeof(struct book));
int numbooks = 0;


addbook()
{
(books+numbooks)->book_id = t;
numbooks++;
}