普通C中的泛型堆栈无法正确复制结构
因此,我用纯C实现了一个通用堆栈。它应该复制不同类型的数据,包括结构。从结构上看,我有问题 下面是堆栈的结构:普通C中的泛型堆栈无法正确复制结构,c,generics,stack,memcpy,structure,C,Generics,Stack,Memcpy,Structure,因此,我用纯C实现了一个通用堆栈。它应该复制不同类型的数据,包括结构。从结构上看,我有问题 下面是堆栈的结构: /* * Definite genStack as a structure. * Pointer elems points to the objects lying on the stack * The variable elemSize spiecifies the size of an element * The variable logLength specifies t
/*
* Definite genStack as a structure.
* Pointer elems points to the objects lying on the stack
* The variable elemSize spiecifies the size of an element
* The variable logLength specifies the number of actually
* lying on the stack objects
* The variable allocLenght specifies the allocated size
*/
typedef struct{
void* elems;
int elemSize;
int logLength;
int allocLength;
}genStack;
推送和弹出功能:
void GenStackPush(genStack *s, const void *elemAddr)
{
/* if stack is full - allocates more memory */
if (GenStackFull(s))
{
GenStackAlloc(s, s->elemSize);
}
memcpy((char*) (s->elems)+(s->logLength), elemAddr, sizeof(*elemAddr));
s->logLength++;
}
void GenStackPop(genStack *s, void *elemAddr)
{
if(GenStackEmpty(s))
{
fprintf(stderr, "Can't pop element from stack: stack is empty.\n");
} else
{
s->logLength--;
memcpy((void*) elemAddr, (s->elems)+(s->logLength), sizeof(s->elems[s->logLength]));
}
}
简单结构测试:
最温柔的h:
#ifndef GENTEST1_H
#define GENTEST1_H
typedef struct {
char* name;
int age;
char gender;
}person;
#endif
gentest.c:
#include <stdio.h>
#include <stdlib.h>
#include "gentest1.h"
#include "genstacklib.h"
int main(int argc, char* argv[])
{
genStack StructStack;
person testPerson[5];
person* newPerson;
person* test;
int i;
newPerson = (void*) malloc (sizeof(person));
testPerson[0].name = "Alex";
testPerson[0].age = 21;
testPerson[0].gender = 'm';
testPerson[1].name = "Vanja";
testPerson[1].age = 20;
testPerson[1].gender = 'm';
testPerson[2].name = "sjrgsde";
testPerson[2].age = 11;
testPerson[2].gender = 'w';
testPerson[3].name = "wergsggsd";
testPerson[3].age = 99;
testPerson[3].gender = 'y';
testPerson[4].name = "adaasxx";
testPerson[4].age = 13;
testPerson[4].gender = 'g';
GenStackNew(&StructStack, sizeof(person));
printf("sizeof(person) = %lu\n", sizeof(person));
for (i = 0; i < 5; i++) {
newPerson = &testPerson[i];
GenStackPush(&StructStack, newPerson);
printf("Pushed: %s, %d, %c\n", newPerson->name, newPerson->age, newPerson->gender);
}
test = (void*) malloc (sizeof(person));
test->name = "test";
test->age = 0;
test->gender = 't';
while(!GenStackEmpty(&StructStack))
{
GenStackPop(&StructStack, test);
printf("Popped: %s, %d, %c\n", test->name, test->age, test->gender);
}
GenStackDispose(&StructStack);
return 0;
}
GenStackNew(&StructStack, sizeof(person));
printf("sizeof(person) = %lu\n", sizeof(person));
如你所见,我可以收到姓名,但没有年龄或性别。我尝试了很多选择,但仍然得到分割错误或上面的输出。目前,上面的输出是我得到的最好的输出,但仍然不是我想要的
问题是-我怎样才能得到我需要的输出?
提前谢谢
为了避免一些问题:
sizeof(person)=s->elemSize
它是通过创建堆栈来定义的:
/*
* Definite genStack as a structure.
* Pointer elems points to the objects lying on the stack
* The variable elemSize spiecifies the size of an element
* The variable logLength specifies the number of actually
* lying on the stack objects
* The variable allocLenght specifies the allocated size
*/
typedef struct{
void* elems;
int elemSize;
int logLength;
int allocLength;
}genStack;
genstacklib.c:
void GenStackNew(genStack *s, int elemSize)
{
void* newElems;
/* Allocate a new array to hold the contents. */
newElems = (void*) malloc(elemSize * GenStackInitialAlocationSize);
printf("elemSize = %d\tGenStackInitialAlocationSize = %d\n",
elemSize, GenStackInitialAlocationSize);
if (newElems == NULL)
{
fprintf(stderr, "Error with allocating the stack.\n");
exit(1); /* Exit, returning error code. */
}
s->elems = newElems;
s->elemSize = elemSize;
s->allocLength = GenStackInitialAlocationSize;
s->logLength = 0; /*is empty*/
}
gentest.c:
#include <stdio.h>
#include <stdlib.h>
#include "gentest1.h"
#include "genstacklib.h"
int main(int argc, char* argv[])
{
genStack StructStack;
person testPerson[5];
person* newPerson;
person* test;
int i;
newPerson = (void*) malloc (sizeof(person));
testPerson[0].name = "Alex";
testPerson[0].age = 21;
testPerson[0].gender = 'm';
testPerson[1].name = "Vanja";
testPerson[1].age = 20;
testPerson[1].gender = 'm';
testPerson[2].name = "sjrgsde";
testPerson[2].age = 11;
testPerson[2].gender = 'w';
testPerson[3].name = "wergsggsd";
testPerson[3].age = 99;
testPerson[3].gender = 'y';
testPerson[4].name = "adaasxx";
testPerson[4].age = 13;
testPerson[4].gender = 'g';
GenStackNew(&StructStack, sizeof(person));
printf("sizeof(person) = %lu\n", sizeof(person));
for (i = 0; i < 5; i++) {
newPerson = &testPerson[i];
GenStackPush(&StructStack, newPerson);
printf("Pushed: %s, %d, %c\n", newPerson->name, newPerson->age, newPerson->gender);
}
test = (void*) malloc (sizeof(person));
test->name = "test";
test->age = 0;
test->gender = 't';
while(!GenStackEmpty(&StructStack))
{
GenStackPop(&StructStack, test);
printf("Popped: %s, %d, %c\n", test->name, test->age, test->gender);
}
GenStackDispose(&StructStack);
return 0;
}
GenStackNew(&StructStack, sizeof(person));
printf("sizeof(person) = %lu\n", sizeof(person));
您没有在所有相关位置使用
elemSize
。您没有在所有相关位置使用elemSize
。您的推送功能是复制sizeof(*elemAddr)
,这是一个void*
,因此它的大小是指针,而不是person
结构的插入大小。因此,您可能只复制了前4个字节,而push函数复制的是sizeof(*elemAddr)
,这是一个void*
,因此它的大小是指针的大小,而不是person
结构的插入大小。因此,您可能只复制了前4个字节,如上所述,推送复制了错误大小的数据。它应该是elemSize
。
memcpy
也在覆盖自己的数据。这样的办法应该行得通
memcpy((char*)(s->elems)+(s->logLength)*elemSize、elemAddr、elemSize);
s->logLength++;
如上所述,推送复制了错误大小的数据。它应该是elemSize
。
memcpy
也在覆盖自己的数据。这样的办法应该行得通
memcpy((char*)(s->elems)+(s->logLength)*elemSize、elemAddr、elemSize);
s->logLength++;
这是非常错误的;表达式*elemAddr
的类型为void
,这是一种约束冲突(sizeof
不能在类型不完整的表达式上调用,而void
是一种不完整的类型)。您将希望在编译器上提高警告级别。我编写了一个测试程序来计算void*
和void
类型表达式的sizeof
,我得到了一个关于gcc-pedantic
的警告。如果我扔掉-pedantic
我不会得到警告,但是sizeof(void)
的结果是1,我很确定这不是人的大小。为什么不在这里使用s->elemSize
其次,你为什么要把s->elems
转换成char*
编辑
如果我可以提供一些建议的话,我在过去设计了一些通用容器,下面是我从中得到的经验教训:
首先,将所有类型感知操作(分配、解除分配、复制、比较、显示等)委托给单独的函数,这些函数通过作为参数传递给泛型容器函数的函数指针调用;i、 例如,推送的定义如下
GenStackPush(genStack *stack, const void *data, void *(*copy)(const void *))
{
stack->elems[++stack->logLength] = copy(data);
}
...
void *myIntCopyFunc(const void *data)
{
const int *inputData = (const int *) data;
int *copy = malloc(sizeof *copy);
if (copy)
*copy = *inputData;
return copy;
}
...
GenStackPush(&myIntStack, &intVal, myIntCopyFunc);
您的人员
类型存在的一个问题是,您没有对姓名
成员进行深度复制;您只是将指针值复制到堆栈。在本例中,这不是什么大问题,因为您使用的是字符串文本,但如果您使用的是本地char[]
,则会出现问题。通过为每种类型编写一个单独的复制函数,您可以处理这些问题,而不是试图在容器函数本身中进行一刀切的分配
其次,不要直接调用泛型容器函数;在您和容器之间放置一个类型感知接口(基本上是穷人版本的函数重载):
这给了你两个好处;首先,它允许您将文本值作为参数传递(对于类型为void*
的参数,您无法这样做)。其次,它提供了一种在容器上强制执行类型安全的方法。您不能以这种方式意外推送错误类型的值
这是很多额外的工作吗?哦,天哪,是的。为了让泛型容器类型正常工作,必须在引擎盖下进行大量的魔术。如果你试图复制与C++代码> STD::堆栈容器类型相同的功能,你将编写大量代码。p>
这是非常错误的;表达式*elemAddr
的类型为void
,这是一种约束冲突(sizeof
不能在类型不完整的表达式上调用,而void
是一种不完整的类型)。您将希望在编译器上提高警告级别。我编写了一个测试程序来计算void*
和void
类型表达式的sizeof
,我得到了一个关于gcc-pedantic
的警告。如果我扔掉-pedantic
我不会得到警告,但是sizeof(void)
的结果是1,我很确定这不是人的大小。为什么不在这里使用s->elemSize
其次,你为什么要把s->elems
转换成char*
编辑
如果我可以提供一些建议的话,我在过去设计了一些通用容器,下面是我从中得到的经验教训:
首先,将所有类型感知操作(分配、解除分配、复制、比较、显示等)委托给单独的函数,这些函数通过作为参数传递给泛型容器函数的函数指针调用;i、 例如,推送的定义如下
GenStackPush(genStack *stack, const void *data, void *(*copy)(const void *))
{
stack->elems[++stack->logLength] = copy(data);
}
...
void *myIntCopyFunc(const void *data)
{
const int *inputData = (const int *) data;
int *copy = malloc(sizeof *copy);
if (copy)
*copy = *inputData;
return copy;
}
...
GenStackPush(&myIntStack, &intVal, myIntCopyFunc);
您的人员
类型存在的一个问题是,您没有对姓名
成员进行深度复制;