【问题标题】:Doubling Dynamic Stack Array加倍动态堆栈数组
【发布时间】:2014-08-15 04:58:34
【问题描述】:

我有一个用来表示通用堆栈的数组。

struct Stack {
    int size;
    int type;
    int capacity;
    void **data; // An array of generic data.
};

Stack *new_stack(int type) {
    Stack *tmp = malloc(sizeof(Stack));
    assert(tmp != NULL);
    tmp->size = 0;
    tmp->type = type;
    tmp->capacity = DEFAULT_CAPACITY;
    tmp->data = calloc(tmp->capacity, type);
    assert(tmp->data != NULL);
    return tmp;
}

这是在保留数据的同时将数组加倍的正确方法吗?

void realloc_stack(Stack *s) {
    int old_capacity = s->capacity;
    s->capacity *= 2;
    s->data = realloc(s->data, s->capacity);
    memset(s->data + old_capacity, 0, old_capacity);
    assert(s->data != NULL);
}

但是,当我尝试像这样从 push_stack() 调用它时:

void push_stack (Stack *s, void *data) {
    if (full_stack(s)) realloc_stack(s);
    s->data[s->size++] = data;
}

我遇到了这个问题:基本上是一堆零,实际数字应该是。

int main() {

    Stack *intStack = new_stack(sizeof(int));

    for (int i = 0; i < 15; ++i) {
        push_stack(intStack, (void*)i);
    }
}

结果:

Printing stack: 
14
13
12
11
10
0
0
0
0
9
8
7
6
1
0

【问题讨论】:

  • Stack.data的类型是什么?请记住,s-&gt;data + old_capacity 将基于该大小,而不是 sizeof(char)。您在这里冒着缓冲区溢出的风险。
  • tmp-&gt;data = calloc(tmp-&gt;capacity, type); s-&gt;data = realloc(s-&gt;data, s-&gt;capacity); : 这在容量的意义上是不一致的。
  • @Raymond 你有一个结构类型Stack,你没有显示。它有一个data 成员,我们看不到它的类型和大小。
  • s-&gt;data[s-&gt;size++] = data;type 和大小没有一致性。
  • 所以应该是:s->data = realloc(s->data, s->type * s->capacity);对吗?

标签: c arrays dynamic stack realloc


【解决方案1】:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#define DEFAULT_CAPACITY 8

typedef struct Stack {
    int size;    //number of element
    size_t type; //size of type, there are no problems with int
    int capacity;//max number of element
    void *data;  //memory of type * capacity
} Stack;

Stack *new_stack(size_t type) {
    Stack *tmp = malloc(sizeof(Stack));
    assert(tmp != NULL);
    tmp->size = 0;
    tmp->type = type;
    tmp->capacity = DEFAULT_CAPACITY;
    tmp->data = calloc(tmp->capacity, type);
    assert(tmp->data != NULL);
    return tmp;
}

void realloc_stack(Stack *s) {
    int old_capacity = s->capacity * s->type;
    s->capacity *= 2;
    s->data = realloc(s->data, s->capacity * s->type);
    assert(s->data != NULL);
    memset((char*)s->data + old_capacity, 0, old_capacity);
}

static inline int full_stack(Stack *s){//Deleting a "static inline" if you are open to the public as an interface
    return s->capacity == s->size;
}

void push_stack (Stack *s, void *data) {
    if (full_stack(s)) realloc_stack(s);
    memcpy((char*)s->data + s->type * s->size++, data, s->type);
}

void printIntObjectDump(Stack *s){
    int i, *p = s->data;
    for(i=0;i<s->capacity;++i){
        printf("%d\n", p[i]);
    }
}

int main() {
    Stack *intStack = new_stack(sizeof(int));

    for (int i = 0; i < 15; ++i) {
        push_stack(intStack, &i);
    }
    printIntObjectDump(intStack);
    return 0;
}

【讨论】:

  • 嗨,BLUEPIXY,这行得通。你能解释一下为什么我们需要 char* 演员表吗?感谢您的帮助!
  • @Raymond ; 1) 指向void * 的指针算术是UB(未定义行为)。 2) 基于void * 大小的内存位置不代表所需内存的位置。它应该基于s-&gt;type 的大小。 (例如 int *p = 0;p + 1 表示 0 + sizeof(int))
  • 可以正确计算转换为char*,因为sizeof(char)1是有保证的。所以等于指定位置。
  • 注意:在 GCC 中计算到 void * 是允许作为扩展规范的。
【解决方案2】:

扩展 Paul Roub 在上述 cmets 中所说的话:

您正在调用memset(s-&gt;data + old_capacity, 0, old_capacity); 您的意图是用0 写入数组的后半部分;然而,这不是正在发生的事情。根据the C++ reference,memset “将 ptr 指向的内存块的第一个 bytes 设置为指定值。”您正在尝试用 32 位的整数填充数组,而不是 8。因此,您可能应该将调用调整为:

memset(s->data + (old_capacity * s->type), 0, old_capacity * s->type);

应该可以解决您的问题。祝你好运!

【讨论】:

  • 这不起作用,但它确实改变了一点输出。打印堆栈:14 13 12 11 10 0 0 0 0 9 8 7 6 1 0
  • 哦,哇,我的脑子放了个屁。对于那个很抱歉。我认为在这两种情况下都应该是s-&gt;type 而不是s-&gt;type / 4。如果这不起作用,请尝试将其保留为 s-&gt;data + old_capacity 作为起始位置。我会自己尝试一下,但我在这台计算机上没有 c++ 编译器。
  • 出于同样的原因,您也可能希望将 realloc 调用更改为 realloc(s-&gt;data, s-&gt;capacity * s-&gt;type);
猜你喜欢
  • 1970-01-01
  • 2021-12-10
  • 1970-01-01
  • 2016-03-15
  • 2019-02-02
  • 2012-12-20
  • 2013-02-11
  • 2019-06-19
  • 2014-12-14
相关资源
最近更新 更多