首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >基于C指针的可增长堆栈rev2

基于C指针的可增长堆栈rev2
EN

Code Review用户
提问于 2020-03-04 18:35:17
回答 1查看 69关注 0票数 4

以下是我上一个问题的内容:基于C指针的可增长堆栈

我已经做了一些改进(希望如此!)基于非常有帮助的意见和建议。我已经检查了堆栈现在可以推送和弹出双倍,所以希望它也能用结构。

对于我所作的改变,我有很多疑问:

  1. 我注意到memcpy()没有使用void *,所以我转而使用uin8_t;这是推荐的/必要的,还是可以转换为uint8_t for memcpy()?不确定哪种方法是最好的..。
  2. 如何处理失败的malloc()/realloc()?返回错误代码?出口?返回NULL?

再次,我非常感谢任何建议/批评:

代码语言:javascript
复制
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>

#define MAX_ITEMS 16

typedef struct {
    uint8_t *data;
    size_t itemSize;
    unsigned count;
    unsigned capacity;
} Stack;

void stack_init(Stack *stack, size_t itemSize, unsigned capacity);
bool stack_is_empty(const Stack *stack);
void stack_push(Stack *stack, void *item);
void* stack_pop(Stack *stack);
void stack_destroy(Stack *stack);

void stack_init(Stack *stack, size_t itemSize, unsigned capacity)
{
    unsigned initialCapacity = capacity == 0 ? 1 : capacity;
    size_t size = initialCapacity * itemSize;

    stack->count = 0;
    stack->capacity = initialCapacity;
    stack->itemSize = itemSize;
    stack->data = (uint8_t *)malloc(size);

    if (stack->data == NULL)
    {
        // TODO
    }

    memset(stack->data, 0, size);
}

bool stack_is_empty(const Stack *stack)
{
    return stack->count == 0;
}

void stack_push(Stack *stack, void *item)
{
    if (stack->count >= stack->capacity)
    {
        stack->capacity *= 2;
        stack->data = (uint8_t *)realloc(stack->data, stack->capacity * stack->itemSize);

        if (stack->data == NULL)
        {
            // TODO
        }
    }

    unsigned offset = stack->count * stack->itemSize;
    memcpy(stack->data + offset, item, stack->itemSize);
    stack->count++;
}

void* stack_pop(Stack *stack)
{
    if (stack_is_empty(stack) == true)
    {
        // TODO
    }

    uint8_t *item = (uint8_t *)malloc(stack->itemSize);

    if (item == NULL)
    {
        // TODO
    }

    stack->count--;
    unsigned offset = stack->count * stack->itemSize;
    memcpy(item, stack->data + offset, stack->itemSize);

    return (void *)item;
}

void stack_destroy(Stack *stack)
{
    free(stack->data);
    stack->count = 0;
}

int main(void)
{
    Stack stack;
    stack_init(&stack, sizeof(int), 0);

    for (int i = 0; i < MAX_ITEMS; i++)
    {
        stack_push(&stack, (void *)&i);
    }

    while (!stack_is_empty(&stack))
    {
        int value;
        value = *((int *)stack_pop(&stack));
        printf("%d\n", value);
    }

    stack_destroy(&stack);
}
EN

回答 1

Code Review用户

回答已采纳

发布于 2020-03-04 18:49:28

stack->data = (uint8\_t \*)realloc(stack->data, stack->capacity \* stack->itemSize);

这是错误的,因为如果realloc()失败了,那么现在就没有办法访问stack->data以前指出的内存了。realloc()的正确模式是:

代码语言:javascript
复制
void *newData = realloc(stack->data, stack->capacity * stack->itemSize);
if (!newData) {
    // Insert error handling - you'll want to restore the old stack->capacity here
    // or (better) wait until we're okay before updating.
    return FAILURE:
}
stack->data = newData;

我建议在分配时不要转换malloc()家族的结果--这些函数返回void*,它可以分配给没有强制转换的任何指针类型。不必要的强制转换只会分散读者的注意力(因为强制转换通常表示代码中的危险区域)。从指针类型到void*的转换也是如此,如下所示:

退回(无效*)项目;

那很简单

代码语言:javascript
复制
return item;

stack_pop接口很难使用-调用者必须处理可能的空指针返回,并且必须记住free()结果。相反,考虑让调用方提供要写入的内存:

代码语言:javascript
复制
void stack_pop(Stack *stack, void *target);

调用方应该已经知道了target所需的大小,现在可以在本地(auto)存储中获得结果:

代码语言:javascript
复制
int foo;
stack_pop(&stack, &foo);
// no need to check for null, or to call free()
票数 5
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/238380

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档