静态结构数组在加载lua文件后打印垃圾

时间:2015-07-04 00:22:32

标签: c arrays memory-management lua

我有一个静态struct数组,其中包含从lua文件解析的数据。

我以为我做得很对,但是当我去加载另一个lua文件时,静态数组就开始打印垃圾了。我不确定加载lua文件后幕后会发生什么,但我无法以其他方式重现它。

这是我的代码和我正在加载的lua文件。

#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define MAX_FILES 5
#define MAX_BOXES 25

struct Box
{
  const char *name;
  int count;
  const char *files[MAX_FILES];
};

static struct Box boxes[MAX_BOXES];
static int box_index = 0;

void script_bail (lua_State * S, const char *fmt, ...)
{
  va_list argp;
  va_start(argp, fmt);
    vfprintf(stderr, fmt, argp);
  va_end(argp);
  lua_close(S);
  exit(EXIT_FAILURE);
}

int box_create (const char* name, int count, const char **files)
{
  if (box_index + 1 >= MAX_BOXES)
    return 1;

  boxes[box_index].name = name;
  boxes[box_index].count = count;
  memcpy(boxes[box_index].files, files, count * sizeof(char*));

  box_index++;

  return 0;
}

void load_boxes (lua_State* S)
{
  const char * name;
  const char * files[MAX_FILES];

  int element_index = 1;
  int file_index = 0;

  lua_getglobal(S, "boxes");

  if (!lua_istable(S, -1))
    script_bail (S, "'%s' is not a table\n", "boxes");

  /* each element has no key */
  lua_pushnil(S);

  /* iterate through this table of tables */
  while (lua_next(S, -2)) {

    if (!lua_istable(S, -1))
      script_bail (S,
          "Element %d of table `classes' is not a table!\n",
          element_index);

    /* find variable by name `name' and make sure it's a string */
    lua_pushstring(S, "name");
    lua_gettable(S, -2);

    if (!lua_isstring(S, -1))
      script_bail (S, "invalid field in table for key: %s", "name");

    name = lua_tostring(S, -1);

    lua_pop(S, 1);

    /* get the table where that's named `components' */
    lua_pushstring(S, "files");
    lua_gettable(S, -2);

    if (!lua_istable(S, -1))
      script_bail (S,
          "files of element %d is not a table!\n",
          element_index);

    /* each component has no key */
    lua_pushnil(S);

    /* go through each component */
    while (lua_next(S, -2)) {

      if (!lua_isstring(S, -1))
        script_bail (S,
            "Element %d of files of box %d is not a string!\n",
            file_index, element_index);

      /* add the component file to our index and increment the index */
      files[file_index++] = lua_tostring(S, -1);

      /* pop current to move to next */
      lua_pop(S, 1);
    }

    if (box_create(name, file_index, files) != 0)
      script_bail(S, "boxes exceeds limit of %d\n", MAX_BOXES);

    /* pop the files table */
    /* pop the current table to make room for the next */
    lua_pop(S, 2);

    element_index++;
    file_index = 0;
  }

  lua_pop(S, 1);
}

lua_State * load_lua_file (const char *filename)
{
  lua_State * S = luaL_newstate();
  luaL_openlibs(S);

  if (luaL_loadfile(S, filename) || lua_pcall(S, 0, 0, 0))
    script_bail (S, "Can't load %s into memory\n", filename);

  return S;
}

void print_boxes()
{
  struct Box *box;

  printf("index: %d\n", box_index);

  int i, j;
  for (i = 0; i < box_index; i++) {
    box = &boxes[i];

    printf("%p: %s => {", box, box->name);

    for (j = 0; j < box->count; j++) {
      printf(" %s ", box->files[j]);
    }

    printf("}\n");
  }
}

int main (void)
{
  lua_State * S = load_lua_file ("boxes.lua");
  load_boxes(S);
  lua_close(S);

  print_boxes();

  lua_State * N = load_lua_file ("boxes.lua");
  lua_close(N);

  print_boxes();

  return 0;
}
boxes = { 
  { name = "first", files = { "one.lua" } },
  { name = "second", files = { "two.lua", "three.lua", "four.lua" } }
};

以下是我得到的输出:

0x10f985330: first => { one.lu }
0x10f985368: second => { two.lu  three.lua  four.lua }

0x10f985330: second => { D }
0x10f985368: D => { J?????  ?
                        (?   }

我想要注意到这种情况偶尔会发生。有时它会打印两次相同的数据(暗示它正在工作)。大部分时间我得到上述内容。我做错了什么导致数组内存损坏?

1 个答案:

答案 0 :(得分:3)

似乎你创建了一个指向某个内存块的指针,这个内存块在某个时候被解除分配,我想这里

lua_close(S);

然后,当您尝试访问结构中的filesname时,指针指向垃圾。

您需要复制字符串,您可以使用strdup()或任何等效函数,保存指针的每个字符串在打印框时仍必须有效。

更好的解决方案是在打印框之前不释放lua库分配的内存,你可以在lua_close(S);调用后移动print_boxes()来实现。

因为如果你使用strdup(),那么你不再需要访问它们就必须在指针上调用free(),这不会直接起作用,因为poitner符合{{1}的条件},所以如果你使用const,你需要

  1. 从结构成员定义中删除strdup()
  2. 在指向const返回的值的每个指针上调用free()