【问题标题】:C: Algorithm to cut rectangle into squaresC:将矩形切成正方形的算法
【发布时间】:2018-08-26 14:06:01
【问题描述】:

我尝试从 Codewars 解决这个问题,并通过编译器运行我的代码。它表明存在分段错误,但我不知道哪里出错了。问题集如下:

下图展示了如何将给定的“真实”矩形切割成正方形(“真实”矩形意味着两个维度不同)。

你能把这张图翻译成算法吗?

您将获得两个维度 - 一个正整数长度(名为 lng 的参数) 一个正整数宽度(名为 wdth 的参数)。 您将返回一个数组。

我的代码如下:

typedef struct Data Data;
struct Data {
     int *array;
     int sz;
};

Data* sqInRect(int lng, int wdth) {
  Data* ptr = (Data*) malloc(sizeof(Data));
  // if square length == square width
  if(lng == wdth){
    ptr->array = NULL;
    ptr->sz = 0;
    return 1;
  }
  //initialise variables
  int rmdLength,rmdWidth,rmdSmallSquares,rmdLengthTimes,rmdWidthTimes,SIZE,temp=0;

  //assign length to temporary rmd variable
  rmdLength = lng;
  //calc how many squares of side *wdth* inside rect
  while((lng-wdth)>wdth){
    rmdLength -= wdth;
    rmdLengthTimes++;
  }
  rmdLength -= wdth;
  rmdLengthTimes++;
  //assign width to temporary rmdWidth variable
  rmdWidth = wdth;
  //calc how many squares of side *rmdWidth* inside rect (remaining area)
  while(rmdWidth>rmdLength){
    rmdWidth -= rmdLength;
    rmdWidthTimes++;
  }
  rmdWidth -= rmdLength;
  rmdWidthTimes++;
  //calculate final number of remaining squares
  rmdSmallSquares = rmdLength/rmdWidth;
  //calculate SIZE
  SIZE = rmdLengthTimes + rmdWidthTimes + rmdSmallSquares;
  //declaration of array
  int arr[SIZE];
  //for loop to put square values in array
  temp = rmdLengthTimes + rmdWidthTimes;
  for(int i=0;i<rmdLengthTimes;i++){
    arr[i] = wdth;
  }
  for(int j=rmdLengthTimes;j<temp;j++){
    arr[j] = rmdLength;
  }
  for(int k=temp;k<SIZE;k++){
    arr[k]= rmdWidth;
  }
  //get Data* ptr to store array AND size of that array
  ptr->array = arr;
  ptr->sz = SIZE;
  return ptr;
}

如果有人能与我澄清我哪里出错了,我将不胜感激。我在这个问题上被困了太久了。谢谢。

【问题讨论】:

  • 对于分段错误,在调试器中运行代码总是一个好的开始。它会告诉你问题发生了。
  • 你的数据结构应该包含什么?您只能用 3 个不同的值填充它。
  • 不会导致 SEGFAULT,陷入无限循环:while((lng-wdth)&gt;wdth){rmdLength -= wdth; rmdLengthTimes++;}。您永远不会更改循环条件中的变量。

标签: c arrays pointers segmentation-fault


【解决方案1】:

您在以下行中有很多未初始化的变量:

  int rmdLength,rmdWidth,rmdSmallSquares,rmdLengthTimes,rmdWidthTimes,SIZE,temp=0;

注意:以上行不会将所有变量初始化为0。它只将temp 初始化为0

要将所有变量初始化为0,您必须先声明它们,然后像​​这样初始化它们:

int rmdLength, rmdWidth, rmdSmallSquares, rmdLengthTimes, rmdWidthTimes, SIZE, temp;  
rmdLength = rmdWidth = rmdSmallSquares = rmdLengthTimes = rmdWidthTimes = SIZE = temp = 0;

使用未初始化的变量会导致未定义的行为:
来自online cpp reference on Uninitialized variables

未初始化变量中的值可以是任何值——它是不可预测的,并且每次运行程序时都可能不同。 读取未初始化变量的值是未定义的行为——这总是一个坏主意。它必须先用一个值初始化,然后才能使用它。

此外,在以下代码中,您使用未初始化的变量 rmdLengthTimes 作为检查以遍历数组:

 for(int i=0;i<rmdLengthTimes;i++){
    arr[i] = wdth;
  }

这将导致访问越界内存地址,这也是未定义的行为:

来自wiki

某些编程语言(最著名的是 C 和 C++)的行为在某些情况下是未定义的。在这些语言的标准中,某些操作的语义被描述为未定义。这些情况通常代表代码中的明确错误,例如索引超出其边界的数组

因此,在使用它们之前正确初始化所有变量将解决您的问题。

【讨论】:

  • 感谢您指出我哪里出错了。我初始化了变量并再次通过编译器运行代码,只是为了表明我仍在访问数组中的越界内存地址。我还没有更正其他的东西吗?
  • 在通过指针访问任何变量之前,最好检查一下指针是否不为NULL。在这种情况下,请检查ptr。还要打印 SIZE 的值,看看它是否符合预期。尽可能使用调试器。
【解决方案2】:

您正在越界访问 arr 数组。

arr[i] = wdth;

因为你还没有初始化下面的变量;

  int rmdLength,rmdWidth,rmdSmallSquares,rmdLengthTimes,rmdWidthTimes,SIZE,temp=0;

并且将它们用作数组的index 将导致未定义的行为。

  SIZE = rmdLengthTimes + rmdWidthTimes + rmdSmallSquares;

  for(int k=temp;k<SIZE;k++){
    arr[k]= rmdWidth;
  }

如下初始化。

  int rmdLength=0,rmdWidth=0,rmdSmallSquares=0,rmdLengthTimes=0,rmdWidthTimes=0,SIZE=0,temp=0;

【讨论】:

  • 感谢您指出我哪里出错了。我初始化了变量并再次通过编译器运行代码,只是为了表明我仍在访问数组中的越界内存地址。我还没有更正其他的东西吗?
猜你喜欢
  • 2015-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多