我在c中创建了一个函数作为链表,但是我不明白如何将其转换为链表。
我的问题是如何将链接列表转换为动态数组。此功能将元素添加到链接列表,我希望能够将元素添加到动态数组。我不知道struct blockhead_node是否正确,就像我说的我还在学习c。我不了解动态数组,所以我试图创建一个使用它们的程序,以便我可能更好地理解它们。我想创建一个添加功能,将元素添加到列表的开头或结尾。这就是我所拥有的:
//this struct i'm trying to use for dynamic array
struct blockhead_node
{
float x, y;
float dx, dy;
long color;
int size; // slots used so far
int capacity; // total available slots
int *data; // array of integers we're storing
};
//this struct is for the linked list
struct blockhead_node
{
float x,y;
float dx, dy;
long color;
int size;
struct blockhead_node * next;
};
void add(struct blockhead_node ** blockhead_list) // double pointer because we can't modify the list it self
{
while((*blockhead_list)!=NULL)
{
blockhead_list=&(*blockhead_list)->next;
}
(*blockhead_list) = (struct blockhead_node*) malloc(sizeof(struct blockhead_node));
(*blockhead_list)->x = rand()%screen_width + (*blockhead_list)->size;
//(*blockhead_list)->x = 400;
//
//look up how to create an random floating point number
//
(*blockhead_list)->dx = ((float)rand()/(float)(10000));
(*blockhead_list)->y = rand()%screen_height + (*blockhead_list)->size;
(*blockhead_list)->dy = ((float)rand()/(float)(10000));
(*blockhead_list)->size = rand()%100;
(*blockhead_list)->next = NULL;
if((*blockhead_list)->x + (*blockhead_list)->size > screen_width)
{
(*blockhead_list)->x = screen_width - (*blockhead_list)->size;
}
if((*blockhead_list)->y + (*blockhead_list)->size > screen_height)
{
(*blockhead_list)->y = screen_height - (*blockhead_list)->size;
}
}
答案 0 :(得分:0)
使用动态数组与使用链表没有太大不同。主要区别在于,您需要在size
时(或在realloc
使用新结构时)跟踪data
和size == capacity
的{{1}}数组。 / p>
除此之外,您要么为每个节点分配一个链表,另一方面使用动态数组,当{{1}时,可以通过分配当前capacity == 0
的几倍来以更有效的方式分配}。对于完全未知大小的数组,可以以capacity
或size == capacity
开头,然后以某个倍数增加(例如capacity = 2
或8
等)或固定每次需要重新分配的金额(3/2
)。我通常只是当前容量的两倍,例如开始2
,随着更多数字添加到8, 16, etc..
,在2
中为data
整数重新分配存储空间。只要您跟踪自己的 4, 8, 16, 32, ...
和 data
,就可以按照自己喜欢的任何方式进行操作。
一个简短的示例可能会有所帮助。让我们从一个简单的结构开始,其中size
是我们关注的唯一动态成员。例如:
capacity
data
是您的#define CAP 2 /* initial capacity for new struct */
typedef struct {
size_t size,
capacity;
int *data;
} blkhd_node;
,而size
是您的"slots used so far"
,而capacity
是您的"total available slots"
。
data
函数非常简单。您需要做的只是检查是否需要"array of integers we're storing"
(例如,这是尚未使用的结构,其中add
或使用了所有插槽并realloc
)。由于capacity == 0
可以用于新分配和调整分配大小,因此这就是您所需要的。该方案很简单,如果这是一个新结构,我们将分配size == capacity
个数字realloc
,否则,如果CAP
我们将分配int
个数字{{1} }。
无论何时我们size == capacity
都使用临时指针这样做!为什么?当2 * capacity
失败时,它将返回int
。如果您使用原始指针realloc
(例如返回realloc
,并且返回了NULL
,则您用realloc
覆盖了data = realloc (data, newsize);
的原始指针地址,并且可以访问(或NULL
)丢失了原来的内存块–造成了内存泄漏。通过使用临时指针,我们可以之前验证data
是否成功,然后分配新的地址到NULL
。重要的是,如果free
确实失败了–那么我们用realloc
指向的现有整数仍然可以使用,因此在{ {1}}失败。重要的是要记住。
我们还需要一种方法来指示or data
函数的成功/失败。在这里,您没有添加新节点,因此不能选择返回指向新节点的指针。在这种情况下,如果realloc
失败,则data
的简单realloc
返回就等于成功。
有了这个,add
函数可能很简单:
int
注意:由于您正在初始化结构,并且0
和1
均为add
,因此您可以省去{{1} }和int add (blkhd_node *b, int v)
{
/* realloc if (1) new struct or (2) size == capacity */
if (!b->capacity || b->size == b->capacity) {
size_t newsize;
if (!b->capacity) /* new stuct, set size = CAP */
newsize = CAP;
else if (b->size == b->capacity) /* otherwise double size */
newsize = b->capacity * 2;
/* alway realloc with a temporary pointer */
void *tmp = realloc (b->data, newsize * sizeof *b->data);
if (!tmp) { /* validate reallocation */
perror ("realloc_b->data");
return 0; /* return failure */
}
b->data = tmp; /* assign new block of mem to data */
b->capacity = newsize; /* set capacity to newsize */
}
b->data[b->size++] = v; /* set data value to v */
return 1; /* return success */
}
,并使用三元设置size
。可以说这是一种不太易读的方法,一个好的编译器将对它们进行相同的优化,但是为了完整起见,您可以将代码设置capacity
替换为:
0
鉴于此选项,您的选择应该始终是针对更具可读性和可维护性的代码。完成您的工作,然后让编译器担心其余的事情。
(您可以以完全相同的方式用 来制作capacity == 0
的动态数组-仅考虑{{1} },每个size == capacity
留给您)
因此,让我们看一下我们最初为newsize
分配的方案是否可以让我们将newsize
/* realloc if (1) new struct or (2) size == capacity */
if (b->size == b->capacity) {
/* set newsize */
size_t newsize = b->capacity ? b->capacity * 2 : CAP;
放入我们的struct blockhead_node
数组,并给出一个简短的示例:< / p>
size, capacity
使用/输出示例
data
内存使用/错误检查
在您编写的任何动态分配内存的代码中,对于任何分配的内存块,您都有2个职责:(1)始终保留指向起始地址的指针因此,(2)当不再需要它时可以释放。
当务之急是使用一个内存错误检查程序来确保您不会尝试访问内存或在已分配的块的边界之外/之外进行写入,不要试图以未初始化的值读取或基于条件跳转,最后,以确认您释放了已分配的所有内存。
对于Linux,2-int
是正常选择。每个平台都有类似的内存检查器。它们都很容易使用,只需通过它运行程序即可。
add
始终确认已释放已分配的所有内存,并且没有内存错误。
仔细检查一下,如果还有其他问题,请告诉我。