Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 16.01.2012, 14:03   #1
syrga
Пользователь
 
Регистрация: 05.12.2010
Сообщений: 14
Стрелка указатели и ссылки

я путаюсь в указателях и ссылках, объясните пожалуйста, почему в этой программе они используются? как они взаимодействуют?

Код:
#include <iostream>
#include <math.h>
using namespace std;
int getSqrRoot(double a, double b, double c, double *x1, double *x2)
{
	double D;
	int n;
	D = b*b-4*a*c;
	if (a == 0) {
		if (b == 0) {
			if (c == 0) n = 3;
			else n = 0;
		}
		else if (c == 0) {
			n = 1;
			*x1 = *x2 = 0;
		}
		else {
			n = 1;
			*x1 = *x2 = -c/b;
		}
	}
	else {
		if (c == 0) D = b*b;
		else D = b*b-4*a*c;
		if (D < 0) n = 0;
		else if (D == 0) {
			n = 1;
			*x1 = *x2 = -b/2*a;
		}
		else {
			n = 2;
			*x1 = (-b+sqrt(D))/(2*a);
			*x2 = (-b-sqrt(D))/(2*a);
		}
	}
	return n;
}
int main() {
	double a,b,c,x1,x2;
	cout << "vvedite a,b,c: ";
	cin >> a >> b >> c;
	switch(getSqrRoot(a,b,c,&x1,&x2)) {
		case 0:
			cout << "net korney" << endl;
			break;
		case 1:
			cout << "odin koren: " << x1 << endl;
			break;
		case 2:
			cout << "dva kornay: " << x1 << " and " << x2 << endl;
			break;
		case 3:
			cout << "koren lyboe chislo" << endl;
			break;
	}
	return 0;
}
syrga вне форума Ответить с цитированием
Старый 16.01.2012, 14:36   #2
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

что именно, не понятно?
_Bers вне форума Ответить с цитированием
Старый 16.01.2012, 16:10   #3
syrga
Пользователь
 
Регистрация: 05.12.2010
Сообщений: 14
По умолчанию

почему тут используются указатели? что они делают?

Код:
int getSqrRoot(double a, double b, double c, double *x1, double *x2)
syrga вне форума Ответить с цитированием
Старый 16.01.2012, 16:35   #4
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

Цитата:
Сообщение от syrga Посмотреть сообщение
почему тут используются указатели?
Код:
int getSqrRoot(double a, double b, double c, double *x1, double *x2)
1. Может быть автору по заданию нужно было юзать именно указатели (допустим, чистый си с ссылками не работает)

Может быть у автора - шизофрения.

Спроси у автора кода.


Цитата:
Сообщение от syrga Посмотреть сообщение
что они делают?
Учи тему "указатели си/с++"

Последний раз редактировалось _Bers; 16.01.2012 в 16:39.
_Bers вне форума Ответить с цитированием
Старый 17.01.2012, 11:07   #5
8Observer8
Старожил
 
Аватар для 8Observer8
 
Регистрация: 02.01.2011
Сообщений: 3,323
По умолчанию

Цитата:
Сообщение от syrga Посмотреть сообщение
почему тут используются указатели?
Код:
int getSqrRoot(double a, double b, double c, double *x1, double *x2)
Указатели здесь используются для того, чтобы функция могла вернуть три значения: число корней (n) и два корня уравнения (x1, x2)

Цитата:
Сообщение от syrga Посмотреть сообщение
что они делают?
Указатели хранят адреса других переменных.

P.S. Советую почитать об указателях в какой-нибудь умной книжке. Например, в книге Кернигана и Ритчи "Язык программирования Си" (глава 5. Указатели и массивы), написано просто и подробно.
8Observer8 вне форума Ответить с цитированием
Старый 17.01.2012, 11:38   #6
Blade
Software Engineer
Участник клуба
 
Аватар для Blade
 
Регистрация: 07.04.2007
Сообщений: 1,618
По умолчанию

Цитата:
Сообщение от 8Observer8 Посмотреть сообщение
Указатели здесь используются для того, чтобы функция могла вернуть три значения
Функция не может возвращать больше одного значения.
Мужество есть лишь у тех, кто ощутил сердцем страх, кто смотрит в пропасть, но смотрит с гордостью в глазах. (с) Ария
Blade вне форума Ответить с цитированием
Старый 17.01.2012, 11:47   #7
8Observer8
Старожил
 
Аватар для 8Observer8
 
Регистрация: 02.01.2011
Сообщений: 3,323
По умолчанию

Цитата:
Сообщение от Blade Посмотреть сообщение
Функция не может возвращать больше одного значения.
Да, я некорректно выразился. Я имел ввиду, что у функции 3 выходных значения (к слову, для автора темы, три входных)
8Observer8 вне форума Ответить с цитированием
Старый 17.01.2012, 13:06   #8
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

8Observer8, специально для вас я включил телепатию, и постараюсь вам объяснить наглядно.

Рассмотрим выше представленный код:

Код:
#include <iostream> //намекает проницательному читателю, 
                            //что код использует c++ style, а не c-ctyle
...

cout << "vvedite a,b,c: "; //транслит намекает читателю, 
                                    //что автор кода - ещё дилетант.
Можно сделать смелое предположение, что код был написан студентом. И судя по поведению самого кода - ему по заданию нужно было юзать именно указатели. Ну то есть, они проходили тему указателей, и задача была: "испечь выходные данные, при помощи указателей".

Теперь, видимо, они дошли до ссылок, и получили новое задание - сделать все тоже самое, только с использованием ссылок.
Но поскольку автор темы не знает ни ссылок, ни указателей, то у него возник ступор.

Указатели и ссылки в функциях используются по двум главным причинам:
1. Экономия на конструкторах копирования.
2. Возможность для функций приготовить несколько выходных значений.

Это как бы понятно всем, кто хотя бы чуть чуть знаком с принципами работы указателей и ссылок.

А теперь главный вопрос: На языке с++ когда идеологически предпочтительнее использовать ссылки, а когда указатели?

Вот я заметил, люди перешедшие на с++ с чистого си, не всегда это осознают, и по старинке продолжают шлёпать указатели.

Рассмотрим пример:

Код:
void Foo1( int* arg) { ... }
void Foo2( int& arg) { ... }
Прототип первой функции говорит проницательному читателю:
Что данная функция допускает в качестве аргумента не_валидный указатель
Код:
Foo1( NULL); //функция допускает, что возможно аргумент будет нулём
Но прототип второй функции это исключает:

Код:
Foo2( NULL); //ошибка компиляции
Прототип второй функции намекает проницательному читателю, что функция ожидает только реально существующие данные. И черти-что ей на вход подать не получится.

То есть ничайно ошибиться, и подать на вход черти-что уже не получится. Только реальные данные.

Код:
int test; Foo2(test); //Требует реальных данных
Обмануть функцию конечно можно. И скормить ей черти-что тоже можно. Но нужно ещё догадаться, как это можно сделать (я специально не буду писать рецепт, как можно отстрелить себе ногу). Функция превентивно защищается от "ничайных" ошибок.

Далее, в теле самой функции стоит ассерт на "нулевую ссылку".
Обычно, этого бывает достаточно для безопасности. Ибо нечайно инициализировать ссылку нулевым объектом - в это ещё можно поверить. Но ничайно инициализировать ссылку, непойми чем, но чем то нереальным - это уже паранойя. Ну или откровенное вредительство.

Проверка внутри функции может выглядеть вот так:
Код:
void Foo(int& val)
{
     ASSERT_ME( (&val!=NULL), "void Foo(int& val)", "Нельзя передавать в функцию несуществующий объект"); 
     //дальше идет боевой код
}
Проверка не войдёт в релиз, ибо ситуация, когда функция ожидающая реальные данные получает чачу - откровенная и грубая ошибка программиста. Все ошибки программиста должны быть отловлены в дебаг-версии, поэтому в релизе подобная проверка уже не нужна.


Резюмируя:

1. В ситуациях, когда идеологически, функция должна уметь работать с не_валидными указателями - работают с указателями.

При этом функция обязана проверить все входящие данные, и если пофиксит ноль - ну допустим, будет считать, что нужно юзать аргумент по умолчанию (например, такой подход используется в WINAPI).
Причем, поскольку не_валидные указатели по замыслу могут быть в любой момент, то проверка входных данных должна войти и в релиз тоже.

2. В ситуациях, когда идеологически, функция должна работать только с реальными данными - работают с ссылками, превентивно защищая тем самым инвариант функций, и облегчая процесс проверки входных данных.

/ps Поскольку во втором варианте проверок валидности входящих данных меньше, то второй вариант для релиз-версии работает быстрее.

Последний раз редактировалось _Bers; 17.01.2012 в 17:05.
_Bers вне форума Ответить с цитированием
Старый 17.01.2012, 16:52   #9
8Observer8
Старожил
 
Аватар для 8Observer8
 
Регистрация: 02.01.2011
Сообщений: 3,323
По умолчанию

Спасибо, _Bers. Я раньше думал, что ссылки на переменные стандартных типов - это лишь удобство ("синтаксический сахар").

Интересно, а функции наподобие ASSERT_ME стандартные или их самому надо писать?
8Observer8 вне форума Ответить с цитированием
Старый 17.01.2012, 16:56   #10
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

Цитата:
Сообщение от 8Observer8 Посмотреть сообщение
Спасибо, _Bers. Я раньше думал, что ссылки на переменные стандартных типов - это лишь удобство ("синтаксический сахар").

Интересно, а функции наподобие ASSERT_ME стандартные или их самому надо писать?
О стандартном ассерте можно почитать здесь:
http://www.cplusplus.com/reference/c...assert/assert/

Но, лично я использую более удобную надстройку над стандартным ассертом.

А так вообще, изготовить собственный ассерт не сложно.
_Bers вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Переменные, ссылки и указатели. Правильно ли я их понимаю? over96 Общие вопросы C/C++ 4 11.01.2012 02:04
указатели vs ссылки Aistn Общие вопросы C/C++ 9 01.06.2011 23:02
ссылки и указатели. mojohead Помощь студентам 13 14.01.2011 16:00
Найти и исправить ошибку. (Ссылки, указатели, утечка памяти) С,С++ ZanLeO Общие вопросы C/C++ 8 09.08.2010 13:00
C++ Указатели и ссылки - Вычислить площадь квадрата. Scarletred Помощь студентам 2 24.05.2010 03:49