使用void指针在C中进行泛型堆栈实现

时间:2017-01-19 10:42:17

标签: c stack void-pointers

尝试实现一个简单的通用堆栈,我写了一堆堆栈溢出和分段错误:

21

一切正常但无法从void指针恢复我的int ... 分析其他实现我仍然不明白为什么我的工作不起作用。 在这里,我希望看到0 8240 842539056 842539056 842539056 842539056 842539056 842539056 842539056 842539056 842539056 842539056 842539056 842539056 842539056 842539056 842539056 842539056 842539056 842539056 842539056次,但我得到了

Microsoft.SqlServer.Management.Smo.FailedOperationException: Apply to target server failed for Job 'Job1'. ---> Microsoft.SqlServer.Management.Common.ExecutionFailureException: An exception occurred while executing a Transact-SQL statement or batch. ---> System.Data.SqlClient.SqlException: The specified @server_name ('10.1.1.202') does not exist.

对于i大于20的每个值,如果i低于20

,则会出现漂亮的分段错误

3 个答案:

答案 0 :(得分:2)

您实际上并没有分配任何空间来保存实际数据,您只是为指向其他位置的指针分配空间。这不是一个非常有用的ADT。

我要做的是创建一个包含数据硬拷贝的堆栈:

typedef struct S {
    void*     data;
    size_t    size;
    struct S* next;
} Stack;

然后必须更改这些功能:

Stack *pushStack(Stack *ptr, void *data, size_t size);
Stack *popStack(Stack *ptr, void *data, size_t* size); // return data and size

您可以改为创建一个这样的项目:

Stack *createStack (void* data, size_t size) {
    Stack *tmp = malloc(sizeof(Stack));

    tmp->data = malloc(size);
    memcpy(tmp->data, data, size);
    tmp->size = size;
    tmp->next = NULL;

    return tmp;
}

一旦你将设计改为如上所述,你就可以开始担心清除错误了。

答案 1 :(得分:2)

在此代码中:

for(i=0; i <= 21; i++) {
    stackHandle = pushStack(stackHandle, &i);
}

你正在推动变量的地址(而不是值)&#34; i&#34; 21次。当您弹出弹出窗口时,您将检索此地址,当您打印它时,您可能达到22(当前值为&#34; i&#34;)。

答案 2 :(得分:1)

您会得到一些奇怪的值,因为您的ptr->content值超出了范围。您应该为内容值分配内存。 试试这个:

    for(i=0; i <= 21; i++) {
        int* pi = new int;
        *pi = i;
        stackHandle = pushStack(stackHandle, pi);
    }

<强>更新: 下面是更正的源代码(我测试了它并且它可以工作):

    #include <stdlib.h>
    #include <stdio.h>

    #define nullptr NULL;

   struct S {
     void *content;
     struct S *next;
   };
   typedef struct S Stack;
   Stack *createStack() {
      Stack *tmp = (Stack *)malloc(sizeof(Stack));

       tmp->content = nullptr;
       tmp->next = nullptr;

       return tmp;
   }

   Stack *pushStack(Stack *ptr, void *content) {
      Stack *newStr = createStack();
      newStr->content = content;
      newStr->next = ptr;
      ptr = newStr;
      return (ptr);
    }
    // parameter value is of type (void**) !!!
    Stack *popStack(Stack *ptr, void **value) {
       Stack *toDelete = ptr;

       // In such a way we can return 'content' from the function.
       // 'content' is a pointer and to return it from the function
       // we should dereference pointer to a pointer 'value'
       *value = (ptr->content); 

       ptr = ptr->next;
       free(toDelete);
      return (ptr);
   }

   Stack *stackHandle = nullptr;

   void printStack(Stack *ptr) {
       int *element;
       int i;
       for (i = 0; i <= 20; i++) {
          ptr = popStack(ptr, (void**)&element); // pointer to apointer !!!
          if (element) {
             printf("%d ", *element);
             // deallocate memory and escape memory leaks !!!
             delete(element);
          }
       }
       printf("\n");
  }

  int main() {
     stackHandle = createStack();
     int i;
     for (i = 0; i <= 21; i++) {
         int* pi = new int(i); // allocate memory !!!
         stackHandle = pushStack(stackHandle, pi);
     }
     printStack(stackHandle);
 }

主要修正。

  1. 我们为i分配内存int* pi = new int(i);
  2. popStack 函数的 value 参数类型从(void *)更改为(void **)。