从用C多维数组问题释放存储器,免费()崩溃程序

时间:2019-02-02 17:45:32

标签: c

我正在创建一个双端队列以将st存储在C中,当我调用free()函数时,程序崩溃。我已经实现了类似的结构,但只存储整数,并且没有遇到任何问题,但这似乎使我有些麻烦。我创建了一个包含多维数组或字符的结构,我想也许我没有正确使用指针?我已经搜索了很多,无法解决它。主要的关注领域是当我从ain主体调用clear()时。依次调用free(),程序将停止。 :-(任何帮助都将非常有用。

#include <stdio.h>

#define MAX 20 // number of characters for word

typedef struct {
  char **deque;
  int   size;
  int pFront;
  int pRear;
} deque;

typedef int bool;
enum { false, true };

void initDeque(deque *d, int initialSize) 
{
  d->size = initialSize;
  d->pFront = -1;
  d->pRear = -1;
  d->deque = (char **)malloc(sizeof(char*)*initialSize);
  int idx;
  for(int idx = 0; idx < d->size; idx++)
  {
    d->deque[idx] = (char *)malloc((MAX+1) * sizeof(char));
    d->deque[idx] = "";
  } 
  printf("d->size: %zu\n", d->size);
}

void clear(deque *d) {
  if(d->pFront == -1)
  {
    printf("Queue is empty\n");
  }
  else
  {
    printf("Attempting to clear...\n");
    for(int idx = 0; idx < d->size; idx++)
    {
      printf("Attempting to clear columns...");
      free(d->deque[idx]);
    }
    printf("Attempting to clear rows...");
    free(d->deque);
    printf("Freed!!!!\n");
    d->deque = NULL;
    d->size = 0;
    d->pFront = -1;
    d->pRear = -1;
  } 
}


bool isEmpty(deque *d)
{
  if(d->pFront == -1){
    return true;
  }
  else
  {
    return false;
  }
}
bool isFull(deque *d)
{
  if(d->size == d->pRear+1)
  {
    return true;
  }
  else
  {
    return false;
  }
}

void display(deque *d)
{
  if(isEmpty(d)){
    printf("empty\n");
  }
  else{
    printf("Deque Values:\n");
    int idx;
    for(int idx = 0; idx <= d->pRear; idx++)
    {
      printf("Index: %zu\tValue: %s\n", idx, d->deque[idx]);
    } 
    printf("Size: %zu\n", d->size);
  } 
}
void rAppend(deque *d, char item[]) // as in rear append - same enqueue for queue structure.
{ 
  if(isFull(d))
  {
    printf("Is Full\n");
    int idx;
    deque dTemp;
    initDeque(&dTemp, d->size);
    printf("dTemp Initialised\n");
    for(idx = 0; idx < d->size; idx++)
    {
      dTemp.deque[idx] = d->deque[idx];
    }
    printf("deque copied to dTemp:\n");
    for(idx = 0; idx < d->size; idx++)
    {
      printf("dTemp[%zu]: %s\n", idx, dTemp.deque[idx]);
    }
    clear(&d);
    printf("d cleared\n");
    initDeque(&d, dTemp.size*2);
    printf("New deque of double length initialised\n");
    for(idx = 0; idx < dTemp.size; idx++)
    {
      d->deque[idx] = d->deque[idx];
    }
    printf("dTemp Copied to new deque\n");
    clear(&dTemp);
    printf("dTemp Cleared\n");
    char **tmp = realloc( d->deque, sizeof (d->deque) * (d->size*2) );
    if (tmp)
    {
        d->deque = tmp;
        for (int i = 0; i < d->size; i++)
        {   
            d->deque[d->size + i] = malloc( sizeof(char) * MAX );
        }
    }
  }
  printf("Appending to rear.. %s\n", item);
  d->pRear++;
  d->deque[d->pRear] = item;
  if(d->pFront == -1)
      d->pFront = 0;
}
int main(void)
{
    deque d;
    initDeque(&d, 5);
    rAppend(&d, "when");
    rAppend(&d, "will");
    rAppend(&d, "wendy");
    rAppend(&d, "walk");
    rAppend(&d, "with");
    display(&d);
    clear(&d);
  return 0;
}

3 个答案:

答案 0 :(得分:1)

问题在于您正在静态链“ when”,“ will”,...上调用free()

您可以在函数void rAppend(deque *d, char item[])中替换插入:

  d->deque[d->pRear] = item;

具有:

  d->deque[d->pRear] = strdup(item);

这样做是在堆中分配链,并从堆中释放链。
在代码中还有其他问题之后,但是它运行时没有崩溃。

答案 1 :(得分:1)

主要问题似乎是您不了解复制/分配指针与复制/分配指针所指向的数据之间的区别。其次,似乎您可能不喜欢不指向任何东西的指针的实用程序,尤其是空指针。一些细节如下。


您正在为一堆字符串动态分配空间...

  for(int idx = 0; idx < d->size; idx++)
  {
    d->deque[idx] = (char *)malloc((MAX+1) * sizeof(char));

...然后通过将指向每个指针的指针替换为指向空字符串文字的指针来泄漏所有空间:

    d->deque[idx] = "";
  }

如果泄漏还不够严重,则不允许您释放字符串文字或修改其内容,但是无论何时clear(),您都尝试对保留在出队中的任何指针进行操作。这可能是你的一些错误的原因。

如果您想设置每个分配的字符串空单然后修改它的内容的而不是替换指针。例如:

    d->deque[idx][0] = '\0';

但是,实际上,您可能甚至不需要这样做。您已经簿记知道哪些阵列包含有效(串)的数据,哪些没有,这应该足以做正确的事。假设您首先维护了字符串的副本。

但这还不是全部。当您rAppend()元素的双端队列你有类似的问题。您创建一个临时的双端队列,然后复制字符串的指针的从原来的双端队列到临时:

dTemp.deque[idx] = d->deque[idx];

这不仅会泄漏临时双端队列中的原始(空)数据,还会使该双端队列的内容与主双端队列的别名相同。当您稍后清除临时双端队列,因此,您释放在原有的所有字符串指针。随后使用或释放​​它们产生未定义的行为。

也许您想将主双端队列的所有元素strcpy()放入临时目录并返回,但是我建议改为跳过临时双端队列以及以下内容:

void rAppend(deque *d, char item[]) // as in rear append - same enqueue for queue structure.
{ 
  if(isFull(d))
  {
    printf("Is Full\n");
    char **tmp = realloc(d.deque, d->size * 2);

    if (tmp)
    {
        d->deque = tmp;
        for (int i = 0; i < d->size; i++)
        {   
            // Copied from the original, but see below
            d->deque[d->size + i] = malloc( sizeof(char) * MAX );
        }
        d->size * 2;
    }  // else?
  }
  printf("Appending to rear.. %s\n", item);
  d->pRear++;
  // Oops, this is another leak / aliasing issue:
  d->deque[d->pRear] = item;
  if(d->pFront == -1)
      d->pFront = 0;
}

临时双端队列的全部内容都丢给了我,因为您需要做的realloc()仍然保留原始数据(只要成功,无论如何)。

但是,也请注意,这仍然存在一个别名问题:您已经为带有双引号的元素加上了双端队列元素的别名,并泄漏了为该元素分配的内存。此外,当您清除双端队列,则释放该字符串为大家抱着一个指针。或者至少您尝试这样做。你不允许这样对字符串文字。

我建议不要在双端队列中为单个字符串分配空间,也不要释放它。继续使用赋值将元素存储在双端队列中,理解并接受这些是别名。这将更类似于您int的实现。

答案 2 :(得分:-1)

current