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

static struct array prints garbage after loading lua file

我有一个静态结构数组,其中填充了从 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?????  ?
                        (?   }

我想指出,这有时会起作用。有时它会打印两次相同的数据(暗示它正在工作)。大多数时候我得到以上。我做错了什么导致数组内存损坏?

我认为这里似乎是指向某个时候被释放的内存块的指针

lua_close(S);

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

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

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

因为如果你使用 strdup() 那么你必须在你不再需要访问它们之后调用 free() ,这不会直接工作,因为指针符合 const,所以如果你使用 strdup(),你需要

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