即使(我认为)它们是空终止的,打印字符串也会产生垃圾

时间:2015-10-14 09:23:47

标签: c arrays string garbage null-terminated

当我运行print_puzzle(create_puzzle(input))时,我在输出的底部得到一堆gobbledegook,只在最后一行。我不知道为什么会这样。输出应该是9行9个数字(输入是一个数独拼图,零代表空格)。

这一堆代码应该接受输入,制作一个二维的字符串数组,然后使用print_puzzle在网格中输出这些字符串。它们是字符串,因为最终我将实现一种方法来显示正方形可能的所有值。但就目前而言,当我打印出来时,事情就搞砸了。我甚至尝试将null值放在所有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 个答案:

答案 0 :(得分:1)

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

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

您可以将puz设为全局变量,并按照您现在的方式使用它。

答案 1 :(得分:1)

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

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

这个答案非常棒: Can a local variable's memory be accessed outside its scope?

答案 2 :(得分:0)

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

return p;

在函数外部声明ppuz,然后它应该可以正常工作。

答案 3 :(得分:0)

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

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

请确保在调用代码完成后使用free()内存。