打印数组时有额外的行和数组更改未知原因

When printing array there is a extra line and array changing unknown reason

这是我的 class

#include <fstream>
#include <cstdlib>
#include <math.h>
#include <iomanip>
#include <iostream>
using namespace std;

class Point {
  protected:
    int x, y;
    double operator-(const Point &def){ 
        return sqrt(pow((x-def.x),2.0)+ 
                  pow((y-def.y),2.0));
    }

};

class Circle: public Point {
  private:
    int radius;

  public:
  Circle(){     
    this->x=x;
    this->y=y;
    this->radius=radius;
  }

  Circle(int x, int y, int radius){
this->x=x;
this->y=y;
this->radius=radius;
}
    void printCircleInfo() {
      cout << x << " " << y << " " << radius << " " ;
    }
bool operator==(const Circle &def){ 
  return (x==def.x) & (y==def.y) & (radius==def.radius);
}
    bool doIBumpIntoAnotherCircle(Circle anotherCircle){
      if (anotherCircle.radius + radius >=   *this - anotherCircle    )
    return true;
      return false;
    }

};

这是主要内容

int main(){
  int x,y,radius;
  const int SIZE = 13;
  Circle myCircleArry[SIZE];

这里我加载5 9 3到数组的第13位

  myCircleArry[13] = Circle(5,9,3);
   cout << endl;
   myCircleArry[13].printCircleInfo(); cout << " : ";
  ifstream Lab6DataFileHandle;

  Lab6DataFileHandle.open("Lab6Data.txt");

这是我将文本文件加载到它包含的数组中的地方

7 2 3
2 6 8
1 5 10
5 2 2
5 9 3
5 10 5
3 2 3
2 5 9
5 9 3
3 5 1
1 5 3
5 8 3
  while (!Lab6DataFileHandle.eof( )) {
 for (int i = 0; i < SIZE; i++) {
Lab6DataFileHandle>>x;
Lab6DataFileHandle>>y;
Lab6DataFileHandle>>radius;
 myCircleArry[i] = Circle(x,y,radius);
}
for (int i = 0; i < SIZE; i++) {
 if (myCircleArry[13].doIBumpIntoAnotherCircle(myCircleArry[i])) {
      myCircleArry[i].printCircleInfo();

到达此处时输出5 9 3 : 7 2 3 ; 2 6 8 ; 1 5 10 ; 5 2 2 ; 5 9 3 ; 5 10 5 ; 3 2 3 ; 2 5 9 ; 5 9 3 ; 3 5 1 ; 1 5 3 ; 5 8 3 ; 5 8 3

 if ( myCircleArry[13]==myCircleArry[i])
 {cout <<"*";}

cout << " ; ";
  }

}    
}
  Lab6DataFileHandle.close();

当我尝试再次打印数组的第 13 位时 5 3 8 被打印

 myCircleArry[13].printCircleInfo();

}

为什么多了一个输出,为什么13位变了?请在您的回答中包含一个示例。谢谢你的时间。

当您定义一个包含 13 个元素的 array 时。

你真的只有 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 (0-12) 个索引。

index 访问 array 中的特定 element

这里的这一行 myCircleArry[13].printCircleInfo();其实应该说,

 myCircleArry[0].printCircleInfo();

0 是 array 实际开始的位置。

最小修复

正如其他人已经指出的那样,主要问题之一是您分配了一个由 13 个圆圈组成的内置数组,并且您尝试访问位置 13,它就在您分配的内存之外。

从你的代码中我了解到你的目的是读取你的文件,它实际上有 12 个元素,所以接下来的所有循环都试图读取一个 Circle 太多并且使用一个 Circle 太多。为您的“参考”圈子使用一个单独的变量可能会更好。

此外,您正在使用“while not eof()”循环,这通常(总是)是错误的,但在这种情况下它没有任何意义,因为您已经知道并决定该文件将包含 12元素。因此,对您的 main 的最小修复可能是:

int main() {
    int x, y, radius;
    const int SIZE = 12;
    Circle myCircleArry[SIZE + 1];

    myCircleArry[SIZE] = Circle(5, 9, 3);
    cout << endl;
    myCircleArry[SIZE].printCircleInfo(); cout << " : ";
    ifstream Lab6DataFileHandle;

    Lab6DataFileHandle.open("Lab6Data.txt");
    for (int i = 0; i < SIZE; i++) {
        Lab6DataFileHandle >> x;
        Lab6DataFileHandle >> y;
        Lab6DataFileHandle >> radius;
        myCircleArry[i] = Circle(x, y, radius);
    }
    for (int i = 0; i < SIZE; i++) {
        if (myCircleArry[SIZE].doIBumpIntoAnotherCircle(myCircleArry[i])) {
            myCircleArry[i].printCircleInfo();

            if (myCircleArry[SIZE] == myCircleArry[i])
            {
                cout << "*";
            }

            cout << " ; ";
        }

    }
    Lab6DataFileHandle.close();

    myCircleArry[SIZE].printCircleInfo();
}

注意我们知道文件中有SIZE个元素,我们分配了SIZE+1个槽,并使用SIZE位置的那个作为参考.循环从 0 到 SIZE(排除)。

重大重组

这应该去 Code Review,但既然我们在这里...

旧包括

这些

#include <cstdlib>
#include <math.h>

可能会变成

#include <cmath>

您不需要旧的 C 标准库。

避免using namespace std;

很多回答here解释原因。

我对你的看法Point

这更多是我的意见,而不是实际问题。你的class

class Point {
protected:
    int x, y;
    double operator-(const Point &def) {
        return sqrt(pow((x - def.x), 2.0) +
            pow((y - def.y), 2.0));
    }
};

使用受保护的属性,看起来无用的过度设计。此外,它禁用了用大括号初始化的能力。

operator- 点之间不应该给出距离。这真的与每个人在学校学习的数学有悖常理。

稍后您将比较圆心,因此 operator== 很有用。

最后为什么不使用 double 坐标?

结果:

struct Point {
    double x, y;

    friend double distance(const Point &a, const Point &b) {
        return sqrt(pow(a.x - b.x, 2.0) + pow(a.y - b.y, 2.0));
    }

    bool operator==(const Point &rhs) const {
        return x == rhs.x && y == rhs.y;
    }
};

我对你的看法 Circle

这是你的 Circle:

class Circle : public Point {

老实说,圆不是点,所以我认为继承不是正确的选择。

private:
    int radius;

这真的很私人:我会避免保护 radius 属性,允许用户访问它。

public:
    Circle() {
        this->x = x;
        this->y = y;
        this->radius = radius;
    }

这是完全错误的。它告诉编译器默认初始化必须采用 class (未初始化)属性并使用它们来初始化相同的东西,因为这里 this->xx 相同(同样适用于yradius)。丢掉这个没用的东西。

    Circle(int x, int y, int radius) {
        this->x = x;
        this->y = y;
        this->radius = radius;
    }

这是有道理的,但我的个人选择是遵循Google样式并在名称后用下划线指定对象属性。其他人更喜欢在名字前面加上 m_。这使我可以避免 this-> 混乱和意外使用这些成员。

    void printCircleInfo() {
        cout << x << " " << y << " " << radius << " ";
    }

这很好,但我会选择更标准的 inserter/extractor 对。

    bool operator==(const Circle &def) {
        return (x == def.x) & (y == def.y) & (radius == def.radius);
    }

错误使用&。你肯定想要 &&.

    bool doIBumpIntoAnotherCircle(Circle anotherCircle) {
        if (anotherCircle.radius + radius >= *this - anotherCircle)
            return true;
        return false;
    }
};

糟糕的名字(再次:个人意见)。方法应该谈论它们所应用的对象。

anotherCircle被无故复制

经典 if (something) return true; else return false; 很容易被 return something; 替代。

所以我会选择:

struct Circle {
    Point center_;
    double radius_;

    friend std::ostream& operator<<(std::ostream& os, const Circle& c) {
        return os << c.center_.x << " " << c.center_.y << " " << c.radius_;
    }

    friend std::istream& operator>>(std::istream& is, Circle& c) {
        return is >> c.center_.x >> c.center_.y >> c.radius_;
    }

    bool operator==(const Circle &rhs) {
        return center_ == rhs.center_ && radius_ == rhs.radius_;
    }

    bool touches(const Circle& other) {
        return radius_ + other.radius_ >= distance(center_, other.center_);
    }
};

现在main函数

让我们的程序能够读取任意数量的圆圈并将它们与您的参考进行比较。停止使用内置数组并跳转到 std::vector<>.

int main() 
{
    Circle ref = { 5, 9, 3 };
    std::cout << ref << " : ";

    std::vector<Circle> circles;

    std::ifstream is("Lab6Data.txt");
    Circle cur;
    while (is >> cur) {
        circles.push_back(cur);
    }

    for (const auto& c : circles) {
        if (ref.touches(c)) {
            std::cout << c;
            if (ref == c) {
                std::cout << " *";
            }
            std::cout << " ; ";
        }
    }
}

注意我们可以用大括号初始化 Circle。您也可以删除 = 并进行统一初始化。

打开流只是调用构造函数。关闭将在对象销毁时自动完成。

循环现在使用提取器读取 Circle。老实说,这是紧凑的,但我认为最具有教育意义的版本是:

while (true) {
    // Read
    Circle cur;
    is >> cur;
    // Check
    if (!is) {
        break;
    }
    // Use
    circles.push_back(cur);
}

注意模式:无限 循环 Read/Check/Use。检查是我们可以退出循环的地方。首先你读取,然后检查读取操作是成功还是失败,然后你可以使用数据或基于它退出。相信我:像这样写你的循环,而不是,如果你真的必须,把它们改成其他形式。

好的,我们读取了文件中的所有圈子。现在对于所有圆圈(注意使用 range-based for 循环和 const auto reference)如果引用触及当前圆我们打印它(如果它等于引用则使用 * ).

希望这篇长文有一些用处...

更容易复制和粘贴的完整代码

#include <fstream>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <vector>

struct Point {
    double x, y;

    friend double distance(const Point &a, const Point &b) {
        return sqrt(pow(a.x - b.x, 2.0) + pow(a.y - b.y, 2.0));
    }

    bool operator==(const Point &rhs) const {
        return x == rhs.x && y == rhs.y;
    }
};

struct Circle {
    Point center_;
    double radius_;

    friend std::ostream& operator<<(std::ostream& os, const Circle& c) {
        return os << c.center_.x << " " << c.center_.y << " " << c.radius_;
    }

    friend std::istream& operator>>(std::istream& is, Circle& c) {
        return is >> c.center_.x >> c.center_.y >> c.radius_;
    }

    bool operator==(const Circle &rhs) const {
        return center_ == rhs.center_ && radius_ == rhs.radius_;
    }

    bool touches(const Circle& other) const {
        return radius_ + other.radius_ >= distance(center_, other.center_);
    }
};

int main() 
{
    Circle ref = { 5, 9, 3 };
    std::cout << ref << " : ";

    std::vector<Circle> circles;

    std::ifstream is("Lab6Data.txt");
    Circle cur;
    while (is >> cur) {
        circles.push_back(cur);
    }

    for (const auto& c : circles) {
        if (ref.touches(c)) {
            std::cout << c;
            if (ref == c) {
                std::cout << " *";
            }
            std::cout << " ; ";
        }
    }
}