我被指派在ANSI C中编写通用堆栈。它适用于原始数据类型。直到这里,没有任何大问题。
之后我被要求重新编程我的应用程序,以便即使是复杂的数据类型也可以在我的堆栈上使用。我在上周进行了搜索和研究,但没有发现任何有用的东西。
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stddef.h>
#include "genstacklib.h"
void (*freefn) (void*);
/*
* ToDo
*/
void GenStackNew(genStack *s, int elemSize, void (*freefunk) (void*))
{
s->elems = malloc (elemSize * GenStackInitialAllocationSize);
freefn = freefunk;
assert (s->elems != NULL);
s->elemSize = elemSize;
s->logLength = 0;
s->allocLength = GenStackInitialAllocationSize;
}
/*
* ULStackPush adds an element to the stack and allocates new memory if
* needed. If there is not enough memory, ULStackPush does nothing.
*/
void GenStackPush (genStack *s, const void *elemAddr)
{
/*assert (sizeof(*elemAddr) == s->elemSize);*/
assert (s->elems != NULL);
if (s->logLength == s->allocLength)
{
void *temp = NULL;
temp = realloc (s->elems, 2 * s->allocLength * s->elemSize);
assert (temp != NULL);
s->allocLength = 2 * s->allocLength;
s->elems = temp;
}
memcpy(currentval(s), elemAddr, s->elemSize);
s->logLength = s->logLength + 1;
}
void GenStackPop (genStack *s, const void *elemAddr)
{
assert (s->elems != NULL);
assert (s->logLength != 0);
(s->logLength)--;
memcpy((void *)elemAddr, currentval(s), s->elemSize);
}
void *currentval(genStack *s)
{
assert (s->elems != NULL);
return ((size_t*)s->elems + s->logLength * s->elemSize);
}
bool GenStackEmpty (const genStack *s)
{
assert (s->elems != NULL);
return s->logLength == 0;
}
void GenStackDispose (genStack *s)
{
assert (s->elems != NULL);
s->logLength = 0;
free (s->elems);
freefn();
}
/*
* ToDO
*/
void *freefn (void *) {
free
我的标题数据是:
#ifndef GENSTACKLIB_H
#define GENSTACKLIB_H
#include <stdbool.h>
#define GenStackInitialAllocationSize 4
typedef struct
{
void *elems;
int elemSize;
int logLength;
int allocLength;
} genStack;
void GenStackNew (genStack * s, int elemSize);
bool GenStackEmpty (const genStack * s);
void GenStackPush (genStack * s, const void *elemAddr);
void GenStackPop (genStack * s, const void *elemAddr);
void GenStackDispose (genStack * s);
void *currentval(genStack *s);
#endif
在第一段代码中,我认为必须要做的是在ToDo标记中。 如何使用我的堆栈来处理复杂的数据类型?
提前致谢
答案 0 :(得分:0)
我没有看到像字符串这样的“复杂”类型有任何问题...指向字符串和指向int的指针之间没有真正的区别。所以只需存储指针(或指针指针),这应该有用。
因此,元素不是“int”..元素是指向指针的指针。
非常“伪”C代码形式的基本思想
typedef struct Wrapper
{
void * primitiveData;
} Wrapper;
void PrimitivePush(void * data)
{
Wrapper * w = malloc();
w->primitiveData = malloc();
memcpy(w->primitiveData, data);
ClassicComplexTypePush(&w)
}
ClassicComplexTypePush(void ** data)
{
push data to stack
}
答案 1 :(得分:0)
Consider using a singularly linked list for implementation, since when
使用堆栈,我们不知道可能需要多少项目。
使用字节*或(char *)来存储内存的内容,而不是void *(这也可以,但我们可能需要填充分配,以包含结构)
将内存复制到新的分配中,该分配被压入堆栈, 然后删除pop上使用的内容。
每个节点必须属于同一类型,或者至少大小相同, 使用错误类型的错误可能是不受欢迎的
pop可用于通过传递检查堆栈是否为空(NULL) 或者通过引用你想要设置的内存来实际弹出堆栈。
typedef unsigned char byte;
创建将用于跟踪堆栈的结构
struct gStackNode {
byte *data;
struct gStackNode *next;
};
struct gStack {
unsigned size;
struct gStackNode *head;
};
初始化堆栈,包括我们将使用的类型的大小
void stack_initalize(struct gStack *stk, unsigned size) {
if (!stk)
return;
stk->size = size;
stk->head = (void*)0;
}
总是,我们需要手动释放堆栈,以防万一没有弹出
void stack_free(struct gStack *stk) {
if (!stk)
return;
struct gStackNode *temp;
/* step through the remaining stack, deleting each item */
while(stk->head) {
temp = stk->head->next;
free((byte*)stk->head->data);
free((struct gStackNode *)stk->head);
stk->head = temp;
}
}
将项目推入堆栈
void stack_push(struct gStack *stk, void *data) {
struct gStackNode *node = (struct gStackNode*)malloc(sizeof(struct gStackNode));
struct gStackNode *temp = stk->head;
node->next = temp;
node->data = (byte*)malloc(sizeof(byte)*(stk->size));
byte * src = (char*)(data);
byte * dest = (char*)(node->data);
unsigned n = stk->size;
/* fill the new allocation with source data */
for(;n;n--)
*(dest++) = *(src++);
/* the node becomes the new head */
stk->head = node;
}
有时我们不想使用局部变量,即:stack_pop_(stack,&amp; type)我们可以使用stack_push_arg_no_ref(stack,10)。
void stack_push_arg_no_ref(struct gStack *stk, void *data) {
stack_push(stk, &data);
}
现在我们可以弹出,并使用相同的方式来查看,传递(NULL)数据将导致窥视, 如果堆栈中有项目则返回(1),如果空白则返回(0)
int stack_pop(struct gStack *stk, void * data) {
if (!stk)
return 0;
if (!stk->head)
return 0;
if (data == (void*)0) {
/*
simply check to see if the stack is empty or not
don't actually pop the stack
*/
return ((!stk->head == (void*)0));
} else {
struct gStackNode *next = stk->head->next;
struct gStackNode *node = stk->head;
unsigned i;
byte *c_temp = (byte*)data;
for(i=0;i<stk->size;i++)
*c_temp++ = node->data[i];
free((byte*)node->data);
free((struct gStackNode*)node);
stk->head = next;
}
}
最后我们可以实现堆栈
使用任何ANSI C数据类型
需要修复字符串的大小
结构也可以使用
使用字符串
注意,对于此示例,字符串需要以NULL结尾 可以使用非NULL终止字符串
char ta[32] = "ta: text 1";
char tb[32] = "tb: text 2";
char tc[32];
struct gStack stack_char; stack_initalize(&stack_char, sizeof(ta));
stack_push(&stack_char, ta);
stack_push(&stack_char, tb);
while (stack_pop(&stack_char, &tc))
printf("%s\n", tc);
一定要释放堆栈
stack_free(&stack_char);
使用整数
int a = 120, b = -32, c;
struct gStack stack_int; stack_initalize(&stack_int, sizeof(int));
stack_push(&stack_int, &a);
stack_push(&stack_int, &b);
/* or we can use */
stack_push_arg_no_ref(&stack_int, 1776);
/* we can now see the contents of the stack */
while (stack_pop(&stack_int, &c))
printf("%d\n", c);
stack_free(&stack_int);