Я пытаюсь вычислить расстояние между двумя точками. Две точки я сохранил в векторе в C++: (0,0) и (1,1).
Я, как предполагается, получаю результаты как
0
1.4
1.4
0
Но фактический результат, который я получил,
0
1
-1
0
Я думаю, что существует что-то не так со способом, которым я использую итератор в векторе. Как я могу решить эту проблему?
Я отправил код ниже.
typedef struct point {
float x;
float y;
} point;
float distance(point *p1, point *p2)
{
return sqrt((p1->x - p2->x)*(p1->x - p2->x) +
(p1->y - p2->y)*(p1->y - p2->y));
}
int main()
{
vector <point> po;
point p1; p1.x = 0; p1.y = 0;
point p2; p2.x = 1; p2.y = 1;
po.push_back(p1);
po.push_back(p2);
vector <point>::iterator ii;
vector <point>::iterator jj;
for (ii = po.begin(); ii != po.end(); ii++)
{
for (jj = po.begin(); jj != po.end(); jj++)
{
cout << distance(ii,jj) << " ";
}
}
return 0;
}
Ваш код вообще компилируется, вероятно, потому, что у вас где-то есть using namespace std
. (В противном случае вектор
должен был бы быть std :: vector
.) Я бы посоветовал не использовать , и вы только что объяснили, почему:
Случайно ваш вызов забирает std :: distance ()
, который принимает два итератора и вычисляет расстояние между ними. Удалите директиву using и префикс всех типов стандартных библиотек с помощью std ::
, и компилятор сообщит вам, что вы пытались передать vector
, где точка *
обязательна.
Чтобы получить указатель на объект, на который указывает итератор, вам нужно разыменовать итератор, который дает ссылку на объект, и взять адрес результата: & * ii
.
(Обратите внимание, что указатель полностью удовлетворяет всем требованиям для итератора std :: vector
, и некоторые более ранние реализации стандартной библиотеки действительно использовали указатели для этого, что позволяло рассматривать Итераторы std :: vector
как указатели. Но современные реализации используют для этого специальный класс итератора. Я полагаю, причина в том, что использование класса позволяет перегрузить функции для указателей и итераторов. Кроме того, указатели используются как std :: vector
итераторы поощряют смешивание указателей и итераторов, что предотвратит компиляцию кода при изменении контейнера.)
Но вместо этого я предлагаю вам изменить свою функцию так, чтобы она принимала ссылки ( см. этот ответ , чтобы узнать, почему это в любом случае хорошая идея.):
float distance(const point& p1, const point& p2)
{
return sqrt((p1.x - p2.x)*(p1.x - p2.x) +
(p1.y - p2.y)*(p1.y - p2.y));
}
Обратите внимание, что точки берутся из ссылок const
.Это указывает вызывающей стороне, что функция не изменит передаваемые ей баллы.
Тогда вы можете назвать это так: расстояние (* ii, * jj)
.
Кстати, это
typedef struct point {
float x;
float y;
} point;
- C-ism, ненужный в C ++. Просто напишите это
struct point {
float x;
float y;
};
. Это вызовет проблемы, если это определение struct
когда-либо будет анализироваться компилятором C (тогда код должен ссылаться на struct point
, а не просто ] point
), но я полагаю, что std :: vector
и т.п. в любом случае будут гораздо более сложной задачей для компилятора C.
Вы можете сделать несколько вещей:
distance ()
использовала ссылки на точку
объекты. Это сделано только для того, чтобы сделать вещи более удобочитаемыми при вызове функции distance ()
:
float distance (const point & p1, const point & p2) {{1 }} {
return sqrt ((p1.x - p2.x) * (p1.x - p2.x) +
(p1.y - p2.y) * (p1.y - p2.y));
}
distance ()
, чтобы передать объекты point
:
distance (* ii, * jj)
Если вы не измените интерфейс функции distance ()
, вам может потребоваться
вызвать его, используя что-то вроде следующего, чтобы получить подходящие
указатели:
distance (& * ii, & * jj) { {1}}
По совпадению, вы фактически используете встроенную функцию STL "distance" , которая вычисляет расстояние между итераторами, вместо вызова вашей собственной функции расстояния. Вам нужно «разыменовать» ваши итераторы, чтобы получить содержащийся объект.
cout << distance(&(*ii), &(*jj)) << " ";
Как видно из синтаксиса выше, «итератор» во многом похож на обобщенный «указатель». Итератор нельзя использовать напрямую как «свой» объектный тип. На самом деле итераторы настолько похожи на указатели, что многие стандартные алгоритмы, работающие с итераторами, отлично работают и с указателями.
Как заметил Sbi: ваша функция расстояния принимает указатели. Было бы лучше переписать вместо этого использование константных ссылок, что сделало бы функцию более «канонической» C ++ и сделало бы синтаксис разыменования итератора менее болезненным.
float distance(const point& i_p1, const point& i_p2)
{
return sqrt((p1.x - p2.x)*(p1.x - p2.x) +
(p1.y - p2.y)*(p1.y - p2.y));
}
cout << distance(*ii, *jj) << " ";