1

そのため、Plain 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]));
      }
}

単純構造テスト:

gentest.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;
}

そして、ここに私が得る出力があります:

./gentest1
elemSize = 16   GenStackInitialAlocationSize = 4
sizeof(person) = 16
Pushed: Alex, 21, m
Pushed: Vanja, 20, m
Pushed: sjrgsde, 11, w
Pushed: wergsggsd, 99, y
    New size of alloc = 8
Pushed: adaasxx, 13, g
Popped: adaasxx, 0, t
Popped: wergsggsd, 0, t
Popped: sjrgsde, 0, t
Popped: Vanja, 0, t
Popped: Alex, 0, t

ご覧のとおり、名前を受け取ることはできますが、年齢や性別はわかりません。多くのオプションを試しましたが、それでもセグメンテーション違反または上記の出力が得られます。現時点では、上記の出力は私が得た最高の出力ですが、それでも私が望むものではありません.

問題は、必要な出力を取得するにはどうすればよいかということです。前もって感謝します。

いくつかの質問を避けるために: sizeof(person) = s->elemSize

これは、スタックを作成することによって定義されます。

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:

GenStackNew(&StructStack, sizeof(person));
printf("sizeof(person) = %lu\n", sizeof(person));
4

4 に答える 4

1

あなたのプッシュ関数はコピーsizeof(*elemAddr)していvoid *て、それは であるため、構造体の意図したサイズではなく、ポインターのサイズを持っていますperson。したがって、おそらく最初の4バイトのみをコピーしています

于 2012-04-09T13:16:15.163 に答える
0

関連するすべての場所で使用しているわけではありませんelemSize...

于 2012-04-09T13:15:12.027 に答える
0

上記のように、プッシュは間違ったサイズのデータ​​をコピーしています。である必要がありますelemSizememcpyも自身のデータを上書きしています。このようなものがうまくいくはずです。

memcpy((char*) (s->elems)+(s->logLength)*elemSize, elemAddr, elemSize); s->logLength++;

于 2012-04-09T15:51:12.667 に答える
0
void GenStackPush(genStack *s, const void *elemAddr) 
{
  ...     
  memcpy((char*) (s->elems)+(s->logLength), elemAddr, sizeof(*elemAddr));
                                                      ^^^^^^^^^^^^^^^^^

これは非常に間違っています。式の型は*elemAddrですvoid。これは制約違反です (sizeofは不完全な型の式では呼び出されない可能性がありvoid、不完全な型です)。コンパイラの警告レベルを上げる必要があります。タイプandsizeofの式を計算するテスト プログラムを作成しましたが、 で警告が表示されます。をドロップしても警告は表示されませんが、得られる結果は 1 です。これは、 のサイズではないことは確かです。なんでここ使わないの? void *voidgcc -pedantic-pedanticsizeof (void)persons->elemSize

第二に、なぜあなたはにキャストs->elemsしていchar *ますか?

編集

アドバイスをするとしたら、私は過去にいくつかの一般的なコンテナーを作成しました。

まず、すべての型認識操作 (割り当て、割り当て解除、コピー、比較、表示など) を別の関数に委任します。これらの関数は、パラメーターとして汎用コンテナーの関数に渡された関数ポインターを介して呼び出されます。つまり、プッシュは次のように定義されます

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);

型に関する問題の 1 つは、メンバーpersonのディープ コピーを行っていないことです。nameポインタ値をスタックにコピーしているだけです。この場合、文字列リテラルを使用しているので大したことではありませんが、たとえば local を使用している場合char []は問題が発生します。型ごとに個別のコピー関数を作成することで、コンテナー関数自体で画一的な割り当てを試みる代わりに、この種の問題に対処できます。

次に、汎用コンテナ関数を直接呼び出さないでください。あなたとコンテナーの間に型認識インターフェースを配置します (基本的には、関数のオーバーロードの貧弱なバージョンです):

void pushInt(GenStack *stack, int intVal)
{
  GenStackPush(stack, &intVal, myIntCopyFunc);
}
...
genStack myIntStack;
...
pushInt(&myIntStack, 5);

This gives you two benefits; first, it allows you to pass literal values as parameters (which you can't do with parameters of type void *). Secondly, it gives you a way to enforce type safety on your container. You can't accidentally push a value of the wrong type this way.

Is this a lot of extra work? Oh my yes. There's a lot of magic that has to happen under the hood for generic container types to work properly. If you're trying to replicate the same kind of functionality that you get with the C++ std::stack container type, you're going to be writing a lot of code.

于 2012-04-09T15:58:21.087 に答える