1

当我运行时print_puzzle(create_puzzle(input)),我在输出的底部得到一堆 gobbledegook,只在最后一行。我不知道为什么这种情况不断发生。输出应该是 9 行,每行 9 个数字(输入是一个数独游戏,零代表空格)。

这一堆代码应该接受该输入,创建一个二维字符串数组,然后使用 print_puzzle 将这些字符串打印在一个网格中。它们是字符串,因为最终我将实现一种方法来显示正方形可能的所有值。但是现在,当我把它打印出来时,事情就搞砸了。我什至尝试将空值放在所有 81 个字符串的每个元素中,但是在打印字符串时它仍然搞砸了。我迷路了!

typedef struct square {
  char vals[10]; // string of possible values
} square_t;

typedef struct puzzle {
  square_t squares[9][9];
} puzzle_t;

static puzzle_t *create_puzzle(unsigned char vals[9][9]) {
  puzzle_t puz;
  puzzle_t *p = &puz;
  int i, j, k, valnum;
  for (i = 0; i < 9; i++) {
    for (j = 0; j < 9; j++) {
      puz.squares[i][j].vals[0] = '\0';
      puz.squares[i][j].vals[1] = '\0';
      puz.squares[i][j].vals[2] = '\0';
      puz.squares[i][j].vals[3] = '\0';
      puz.squares[i][j].vals[4] = '\0';
      puz.squares[i][j].vals[5] = '\0';
      puz.squares[i][j].vals[6] = '\0';
      puz.squares[i][j].vals[7] = '\0';
      puz.squares[i][j].vals[8] = '\0';
      puz.squares[i][j].vals[9] = '\0';
      valnum = vals[i][j] -'0';
      for (k = 0; k < 10; k++){
        if ((char)(k + '0') == (char)(valnum + '0')){
          char tmpStr[2] = {(char)(valnum +'0'),'\0'};
          strcat(puz.squares[i][j].vals, tmpStr);
        }
      }
    }
  }
  return p;
}

void print_puzzle(puzzle_t *p) {
  int i, j;
  for (i=0; i<9; i++) {
    for (j=0; j<9; j++) {
      printf(" %2s", p->squares[i][j].vals);
    }
    printf("\n");
  }
}
4

4 回答 4

1

在函数create_puzzle()中,您将返回一个类型的指针puzzle_t。但是,一旦从函数返回puz,该类型变量的地址puzzle_t就无效了。

在函数内部声明的变量是局部变量。它们只能由该函数内部的语句使用。这些局部变量对于它们自己之外的函数是不知道的,因此返回局部变量的地址没有意义,因为当函数返回时,它在堆栈上使用的局部存储被程序认为是无效的,尽管它可能不会马上被清除。从逻辑上讲, at 的值puz是不确定的,访问它会导致未定义的行为。

您可以创建puz一个全局变量,并按照您现在的方式使用它。

于 2015-10-14T09:36:15.593 回答
1

简而言之:在函数create_puzzle()中,您将返回一个指向局部变量的指针puz。局部变量只知道在它们自己的内部起作用。所以create_puzzle返回的指针所引用的内容是不确定的。

更多细节:在 C++ 中,局部变量通常作为存储在“堆栈”数据结构上生成。当create_puzzle()方法被输入时,它的局部变量就会活跃起来。当方法结束时,函数的局部变量将失效。C++ 的实现不需要让您留在堆栈上的垃圾保持不变,以便您可以访问它的原始内容。C++ 不是一种安全的语言,实现会让你犯错并逃脱惩罚。其他内存安全语言通过限制你的能力来解决这个问题。例如,在 C# 中,您可以获取本地地址,但该语言设计巧妙,因此在本地生命周期结束后无法使用它。

这个答案非常棒: 可以在其范围之外访问局部变量的内存吗?

于 2015-10-14T15:35:36.793 回答
0

p指向函数结束后不可用的本地内存。返回会导致问题。而是分配内存。

// puzzle_t puz;
// puzzle_t *p = &puz;
puzzle_t *p = malloc(sizeof *p);
assert(p);

free()调用代码完成使用后一定要内存。

于 2015-10-14T11:32:38.257 回答
0

您在这里返回一个局部变量:

return p;

在函数之外声明p,然后它应该可以工作。puz

于 2015-10-14T09:37:33.133 回答