Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
普通C中的泛型堆栈无法正确复制结构_C_Generics_Stack_Memcpy_Structure - Fatal编程技术网

普通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

因此,我用纯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 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);
您的
人员
类型存在的一个问题是,您没有对
姓名
成员进行深度复制;