Как вернуть два значения из метода c
Метод может возвращать значение, какой-либо результат. В примере выше были определены два метода, которые имели тип void . Методы с таким типом не возвращают никакого значения. Они просто выполняют некоторые действия.
Но методы также могут возвращать некоторое значение. Для этого применяется оператор return , после которого идет возвращаемое значение:
return возвращаемое значение;
Например, определим метод, который возвращает значение типа string :
string GetMessage()
Метод GetMessage имеет тип string , следовательно, он должен возвратить строку. Поэтому в теле метода используется оператор return , после которого указана возвращаемая строка.
При этом методы, которые в качестве возвращаемого типа имеют любой тип, кроме void , обязательно должны использовать оператор return для возвращения значения. Например, следующее определение метода некорректно:
string GetMessage()
Также между возвращаемым типом метода и возвращаемым значением после оператора return должно быть соответствие. Например, в следующем случае возвращаемый тип — string , но метод возвращает число (тип int), поэтому такое определение метода некорректно:
string GetMessage() < return 3; // Ошибка! Метод должен возвращать строку, а не число >
Результат методов, который возвращают значение, мы можем присвоить переменным или использовать иным образом в программе:
string GetMessage() < return "Hello"; >string message = GetMessage(); // получаем результат метода в переменную message Console.WriteLine(message); // Hello
Метод GetMessage() возвращает значение типа string . Поэтому мы можем присвоить это значение какой-нибудь переменной типа string: string message = GetMessage();
Либо даже передать в качестве значения параметру другого метода:
string GetMessage() < return "Hello"; >void PrintMessage(string message) < Console.WriteLine(message); >PrintMessage(GetMessage());
В вызове PrintMessage(GetMessage()) сначада вызывается метод GetMessage() и его результат передается параметру message метода PrintMessage
После оператора return также можно указывать сложные выражения или вызовы других методов, которые возвращают определенный результат. Например, определим метод, который возвращает сумму чисел:
int Sum(int x, int y) < return x + y; >int result = Sum(10, 15); // 25 Console.WriteLine(result); // 25 Console.WriteLine(Sum(5, 6)); // 11
Метод Sum() имеет тип int , следовательно, он должен возвратить значение типа int — целое число. Поэтому в теле метода используется оператор return , после которого указано возвращаемое число (в данном случае результат суммы переменных x и y).
Сокращенная версия методов с результатом
Также мы можем сокращать методы, которые возвращают значение:
string GetMessage()
аналогичен следующему методу:
string GetMessage() => "hello";
int Sum(int x, int y)
аналогичен следующему методу:
int Sum(int x, int y) => x + y;
Выход из метода
Оператор return не только возвращает значение, но и производит выход из метода. Поэтому он должен определяться после остальных инструкций. Например:
string GetHello()
С точки зрения синтаксиса данный метод корректен, однако его инструкция Console.WriteLine(«After return») не имеет смысла — она никогда не выполнится, так как до ее выполнения оператор return возвратит значение и произведет выход из метода.
Однако мы можем использовать оператор return и в методах с типом void . В этом случае после оператора return не ставится никакого возвращаемого значения (ведь метод ничего не возвращает). Типичная ситуация — в зависимости от опеределенных условий произвести выход из метода:
void PrintPerson(string name, int age) < if(age >120 || age < 1) < Console.WriteLine("Недопустимый возраст"); return; >Console.WriteLine($"Имя: Возраст: "); > PrintPerson("Tom", 37); // Имя: Tom Возраст: 37 PrintPerson("Dunkan", 1234); // Недопустимый возраст
Здесь метод PrintPerson() в качестве параметров принимает имя и возраст пользователя. Однако в методе вначале мы проверяем, соответствует ли возраст некоторому диапазону (меньше 120 и больше 0). Если возраст находится вне этого диапазона, то выводим сообщение о недопустимом возрасте и с помощью оператора return выходим из метода. После этого метод заканчивает свою работу.
Однако если возраст корректен, то выводим информацию о пользователе на консоль. Консольный вывод:
Имя: Tom Возраст: 37 Недопустимый возраст
C#: Возврат значений
Методы, которые мы определяли в предыдущих уроках, заканчивали свою работу тем, что печатали на экран какие-то данные:
class App < public static void Greeting() < Console.WriteLine("Winter is coming"); >>
Пользы от таких методов не очень много, так как результатом их работы невозможно воспользоваться внутри программы. Рассмотрим это на примере.
Возьмем задачу обработки электронной почты. Когда пользователь регистрируется на каком-то сайте, то он может ввести email любым способом:
- Добавив случайно пробелы в начале или в конце _support@hexlet.io__
- Использовав буквы в разном регистре SUPPORT@hexlet.io
Если мы сохраним его в таком виде в базу данных, то пользователь, скорее всего, не сможет войти на сайт, так как будет вбивать адрес без пробелов и используя другой регистр символов. Чтобы этого не произошло, email нужно подготовить к записи в базу, привести его к нижнему регистру и обрезать пробельные символы по краям строки. Вся задача решается в несколько строчек:
class App < public static void Main(string[] args) < // В реальности email приходит из формы var email = " SuppORT@hexlet.IO"; // обрезаем пробельные символы var trimmedEmail = email.Trim(); // приводим к нижнему регистру var preparedEmail = trimmedEmail.ToLower(); Console.WriteLine(preparedEmail); // =>"support@hexlet.io" // здесь будет запись в базу данных > >
Этот код стал возможен только благодаря возврату значения. Методы Trim() и ToLower() ничего не печатают на экран (в консоль), они возвращают результат своей работы и поэтому мы можем записать его в переменные. Если бы они вместо этого печатали на экран, мы бы не могли присвоить результат их работы переменной. Как мы не можем сделать с определенным выше методом greeting() :
// C# будет ругаться что `Greeting()` ничего не возвращает // Код не заработает var message = App.Greeting();
Изменим метод Greeting() таким образом, чтобы он начал возвращать данные, вместо их печати. Для этого нам понадобится выполнить две правки:
- Описать тип возвращаемых данных. В нашем случае это строка string
- Выполнить возврат вместо печати на экран
class App < public static string Greeting() < return "Winter is coming!"; >>
Вместо void теперь написано string , потому что у метода есть возврат. Так мы указали C#, что результатом работы метода будет строка.
return – особая инструкция, которая берет выражение, записанное справа и отдает его наружу, тому коду, который вызвал метод. Как только C# натыкается на return , выполнение метода на этом завершается.
// Теперь этот код работает var message = App.Greeting(); // Мы можем выполнить какие-то действия над результатом Console.WriteLine(message.ToUpper()); // => "WINTER IS COMING!"
Любой код после return не выполняется:
class App < public static string Greeting() < return "Winter is coming!"; // Любой код ниже не выполнится никогда Console.WriteLine("Я никогда не выполнюсь"); >>
Даже если метод возвращает данные, это не ограничивает его в том, что он печатает. Кроме возврата данных мы можем и печатать:
class App < public static string Greeting() < Console.WriteLine("Я появлюсь в консоли"); return "Winter is coming!"; >> // Где-то в другом методе // И напечатает текст на экран и вернет значение var value = App.Greeting();
Возвращать можно не только конкретное значение. Так как return работает с выражениями, то справа от него может появиться почти все что угодно. Здесь нужно руководствоваться принципами читаемости кода:
class App < public static string Greeting() < var message = "Winter is coming!"; return message; >>
Здесь мы не возвращаем переменную, возвращается всегда значение, которое находится в этой переменной. Ниже пример с вычислениями:
class App < public static long DoubleFive() < // или return 5 + 5; var result = 5 + 5; return result; >>
В этом примере в определении метода использовался long так как возвращается целое число.
Вопрос на самопроверку. Что вернёт этот метод?
// Определение class App < public static int Run() < return 5; return 10; >> // Использование App.Run(); // ?
Задание
Реализуйте статический метод GetCurrentYear() в классе App , который возвращает наружу текущий год в виде числа
var year = App.GetCurrentYear(); Console.WriteLine(year); // выведет текущий год
Для выполнения этого задания, вам понадобится выполнить несколько действий:
- Получить текущую дату с помощью свойства DateTime.Now . Это свойство возвращает объект даты. В реальности у даты есть свойство Year , который выполняет нашу задачу. Но здесь мы хотим потренироваться
- Преобразовать дату в строку с помощью метода ToString(«yyyy-MM-dd») . В параметрах нужно указать желаемый формат строки: yyyy-mm-dd, например, 2021-11-05
- Извлечь из нее год с помощью метода Substring()
- Преобразовать год из строки в число с помощью метода Convert.ToInt32() и вернуть наружу
Упражнение не проходит проверку — что делать?
Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:
- Обязательно приложите вывод тестов, без него практически невозможно понять что не так, даже если вы покажете свой код. Программисты плохо исполняют код в голове, но по полученной ошибке почти всегда понятно, куда смотреть.
В моей среде код работает, а здесь нет
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Мой код отличается от решения учителя
Это нормально , в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.
В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Прочитал урок — ничего не понятно
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.
Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.
Как вернуть несколько значений из функции?
Здравствуйте, пытаюсь написать функцию для генерации чисел, и надо вернуть 3 переменные из функции. Но получается вернуть только одну. Как вернуть несколько переменных из функции в С++?
#include #include using namespace std; int generator() < random_device random_device; mt19937 generator(random_device()); uniform_int_distribution<>distribution(1, 10); int x = distribution(generator); int c = distribution(generator); int answer = x * c; return answer, x, c; > int main()
- Вопрос задан 03 дек. 2022
- 528 просмотров
Комментировать
Решения вопроса 1
Wataru @wataru Куратор тега C++
Разработчик на С++, экс-олимпиадник.
Кроме параметров функции, можно возвращать структуру с именованными значениями или std::vector или std::touple.
Ответ написан 03 дек. 2022
Нравится 2 6 комментариев
Anonymous @Nikita1244 Автор вопроса
Проблема в том, что предложенное ранее решение не работает.
Про ваше решение можете немного понятнее объяснить, пожалуйста?
Wataru @wataru Куратор тега C++
Никита Савченко, Чего там не работает-то?
Тип функции сделайте s td::vector . Возвращайте
Anonymous @Nikita1244 Автор вопроса
Wataru, я как новичок. Не пойму все равно, что означает ваш std::vector? Погуглил, не понял.
Wataru @wataru Куратор тега C++
Никита Савченко, Это тип. Как int, bool, или char*. std::vector — это класс, который хранит массив int в c++.
Anonymous @Nikita1244 Автор вопроса
Wataru, спасибо, попробую обязательно.
Anonymous @Nikita1244 Автор вопроса
Дошли руки посмотреть Ваше решение, и действительно, решение Александра Ананьева выглядит не элегантно, и оно устарело(Использовалось в последний раз как не-легаси код, судя по всему, в С++ 11).
Сейчас действительно используют std::vector, std::touple
Ответы на вопрос 1
Можно вернуть через параметры функции
void generator(int& answer, int& x, int& c)
#include #include using namespace std; void generator(int& answer, int& x, int& c) < random_device random_device; mt19937 generator(random_device()); uniform_int_distribution<>distribution(1, 10); x = distribution(generator); c = distribution(generator); answer = x * c; > int main()
Ответ написан 03 дек. 2022
Нравится 2 11 комментариев
Anonymous @Nikita1244 Автор вопроса
возвращает в любом случае тогда 1. И ничего более.
Anonymous @Nikita1244 Автор вопроса
не работает в общем-то ваше решение, к сожалению 🙁
Никита Савченко, оно не может не работать. Покажи свой код.
Anonymous @Nikita1244 Автор вопроса
#include #include using namespace std; void generator(int& answer, int& x, int& c) < random_device random_device; mt19937 generator(random_device()); uniform_int_distribution<>distribution(1, 10); int x = distribution(generator); int c = distribution(generator); int answer = x * c; return answer, x, c; > int main()
Евгений Шатунов @MarkusD Куратор тега C++
не работает в общем-то ваше решение
Да нет, решение работает. Только Саша, по своему обыкновению, не подумав написал первое что ему в гугле попалось.
При передаче по ссылке тебе не надо возвращать значения, они доступны внутри функции для прямого изменения. Это — сублимация возврата нескольких значений, используемая в палеозойской древности стандарта C++98.
Настоящий возврат набора значений описан только в ответе Wataru.
Но вот в чем дело.
Код return answer, x, c; не должен был родиться в твоем мозгу для функции с типом результата void . Написанное тобой в примере выдает твою полную безграмотность в языке. Даже большую, чем у Саши.
И в этом плане настоящий возврат нескольких значений для тебя просто недосягаем, потому что ты просто не проходишь по знаниям для его использования. Ты ведь даже не знаешь, какой конкретно стандарт C++ ты используешь. А ведь именно от этого зависит решение твоего вопроса.
#include #include using namespace std; void generator(int& answer, int& x, int& c) < random_device random_device; mt19937 generator(random_device()); uniform_int_distribution<>distribution(1, 10); x = distribution(generator); c = distribution(generator); answer = x * c; > int main()
Anonymous @Nikita1244 Автор вопроса
Александр Ананьев, Отредактируй немного ответ, добавив этот код(пусть чисто пример будет в ответе), чтобы людям не копаться в комментариях. Отмечу решением.
Anonymous @Nikita1244 Автор вопроса
Ты ведь даже не знаешь, какой конкретно стандарт C++ ты используешь.
Никогда не думал, что стандарты влияют настолько сильно. Стандарт использую — С++ 17. Хорошо, посмотрю ответ Wataru. Как я понял, решение, которое написал Александр Ананьев, является устаревшим.
Anonymous @Nikita1244 Автор вопроса
Код return answer, x, c; не должен был родиться в твоем мозгу для функции с типом результата void
Тут уже мой косяк, да, но я удалял и код все равно не работал 🙂
Только вот я пробовал по разному писать и всю эту чепуху вам прислал. Так-то да, ретурна судя по всему не должно быть, ибо компилятор и IDE ругаются на него и говорят что ретурна не может быть в void-функции.
Евгений Шатунов @MarkusD Куратор тега C++
Стандарт использую — С++ 17.
Да, стандарт языка кардинально влияет на доступные возможности. Смотри вот.
Допустим у тебя есть твоя std::tuple generator() . Это то, о чем написал Wataru. Принять результат ты можешь в такой же кортеж (C++11), можешь воспользоваться обобщением и инициализацией копией (C++11), а можешь воспользоваться std::tie [?] для C++14 или структурным связыванием из C++17.
И все будет зависеть именно от используемого тобой стандарта языка.
И вот, в C++17 у тебя получится такой код:
int main()
При том условии, что ты правильно воспользуешься техникой NRVO, структурное связывание у тебя не приведет к скрытому копированию значения, а все три поля из main будут сразу инициализированы внутри generator .
вернуть Несколько значений из функции в C
Нужно возвратить из функции значения 2х переменных. На ум приходит только идея сделать массив с этими значениями и через return выдать указатель на него. Но может есть другой способ?
vdm ★★
28.12.06 05:20:13 MSK
Re: вернуть Несколько значений из функции в C
Не нравится мне твоё «сделать массив», сдаётся мне что ты собрался ссылку на локальный массив возвращать. 🙂 Очень не рекомендую. 🙂
Вообще обычно в таких случаях функции передают указатель на массив или структуру, в которую она пишет результаты. А возвращает она в таком случае просто код завершения (типа успешно/неуспешно). См., например, man 2 fstat.
Teak ★★★★★
( 28.12.06 05:25:30 MSK )
Ответ на: Re: вернуть Несколько значений из функции в C от Teak 28.12.06 05:25:30 MSK

Re: вернуть Несколько значений из функции в C
typedef struct < int one, int two >retval2; retval2 * f(. ) < retval2 * retval = NULL; . if (!error) < retval = malloc(sizeof(retval2)); retval->one = one; retval->two = two; > return retval; > int main(. ) < retval2 * retval; if (retval = f(. )) < printf("one = %i, two = %i\n", retval->one, retval->two); free(retval); > > --- что нить типа такого в голову не приходило. )))
Ex ★★
( 28.12.06 09:01:16 MSK )
Re: вернуть Несколько значений из функции в C
> Нужно возвратить из функции значения 2х переменных. На ум приходит > только идея сделать массив с этими значениями и через return выдать > указатель на него. Но может есть другой способ? Так можно делать только если массив статический: int *foo() < static int a[] = ; return a; > Второй способ вернуть структуру: struct S foo(char c, double d) < struct S s; s.ch = c; s.dl = d; return s; >Третий способ, который обычно применяется во всех библиотеках, объявить массив или структуру во внешнем блоке и передавать в функцию их адреса.
shumer ★
( 28.12.06 09:40:31 MSK )

Re: вернуть Несколько значений из функции в C
Можно возвращать структуру, но считается, что это не оч. хорошо, т.к. вся структура укладывается в стек: typedef struct < int one; int two; >retval2; retval2 f() < retval2 x; x.one=1; x.two=2; return x; >int main(int argc, char **argv) < retval2 y; y=f(); >Выделять память внутри функции считается не оч. правильным путём, насколько я понимаю. Так что наиболее правильным является передача функции указателя на структуру (или массив): typedef struct < int one; int two; >retval2; int f(reval2 *x) < x->one=1; x->two=2; return 1; //код возврата=всё ок > int main(int argc, char **argv) < retval2 y; if (!f(&y)) //обработка ошибки >
Davidov ★★★★
( 28.12.06 10:17:07 MSK )
Ответ на: Re: вернуть Несколько значений из функции в C от Davidov 28.12.06 10:17:07 MSK

Re: вернуть Несколько значений из функции в C
>> Выделять память внутри функции считается не оч. правильным путём, насколько я понимаю. Так что наиболее правильным является передача функции указателя на структуру (или массив):
не спорю, попросили привести пример, мну привел то что первое в голову пришло )
Ex ★★
( 28.12.06 10:49:02 MSK )
Ответ на: Re: вернуть Несколько значений из функции в C от Ex 28.12.06 10:49:02 MSK

Re: вернуть Несколько значений из функции в C
>не спорю, попросили привести пример, мну привел то что первое в голову пришло )
Да не, никаких претензий. Сам так иногда делаю. Более того, по-моему, в каких-то стандартных вызовах было нечто подобное.
Я так понимаю, что логика состоит в том, что выделением памяти и её освобождением должны быть в логически эквивалентных местах.
То есть, например, в случае наличия функций retval2 *alloc_s1() и int free_s2(retval2 *r), всё уже хорошо. Вот и пример, где это может быть оправдано.
Кстати, всё это уже начинает смахивать на ООП.
Davidov ★★★★
( 28.12.06 10:57:57 MSK )
Ответ на: Re: вернуть Несколько значений из функции в C от Davidov 28.12.06 10:57:57 MSK

Re: вернуть Несколько значений из функции в C
таки ООП это парадигма программирования и не зависит от конкретной реализации в ЯВУ
Ex ★★
( 28.12.06 11:05:00 MSK )
Ответ на: Re: вернуть Несколько значений из функции в C от shumer 28.12.06 09:40:31 MSK

Re: вернуть Несколько значений из функции в C
>Так можно делать только если массив статический: >int *foo() > < >static int a[] = ; > return a; >> Только надо быть очень аккуратным: при повторном вызове будет возвращён тот же указатель.
Davidov ★★★★
( 28.12.06 11:10:25 MSK )
Ответ на: Re: вернуть Несколько значений из функции в C от Davidov 28.12.06 11:10:25 MSK
Re: вернуть Несколько значений из функции в C
>>Так можно делать только если массив статический:
>>int *foo() >>< >> static int a[] = ; >> return a; >>>
>Только надо быть очень аккуратным: при повторном вызове будет возвращён >тот же указатель.
Еще это несколько не thread-safe
anonymous
( 28.12.06 15:08:24 MSK )
Re: вернуть Несколько значений из функции в C
void test_retval (int a,int b, int c, int *ret1,int *ret2) < . *ret1=. ; *ret2=. ; >. int r1,r2 test_reatval(1,2,3,&r1,&r2); .
xnix ★★
( 28.12.06 16:25:14 MSK )
Ответ на: Re: вернуть Несколько значений из функции в C от Ex 28.12.06 09:01:16 MSK

Re: вернуть Несколько значений из функции в C
Ну и нахрена звать malloc без необходимости? Если только чтоб выпендриться.
Teak ★★★★★
( 28.12.06 17:38:44 MSK )
Ответ на: Re: вернуть Несколько значений из функции в C от shumer 28.12.06 09:40:31 MSK

Re: вернуть Несколько значений из функции в C
> Так можно делать только если массив статический:
ужоснах, не слушайте его, дети. 🙂 функция станет нереентрабельной, приглашаю всех в гугль на тему чем это грозит.
Teak ★★★★★
( 28.12.06 17:40:11 MSK )
Ответ на: Re: вернуть Несколько значений из функции в C от Teak 28.12.06 17:40:11 MSK
Re: вернуть Несколько значений из функции в C
> ужоснах, не слушайте его, дети. 🙂 функция станет нереентрабельной, приглашаю всех в гугль на тему чем это грозит.
Конечно так делать не следует, хотя и возможно. Вобщем я сказал «can», а ты имел ввиду «may» 🙂
Блин, простой вопрос растянули уже на чертову дюжину постов. Короче, vdm, передавай в функцию адрес структуры с двумя полями и не парься. Все остальное грязный хак.
shumer ★
( 28.12.06 17:52:21 MSK )
Ответ на: Re: вернуть Несколько значений из функции в C от shumer 28.12.06 17:52:21 MSK

Re: вернуть Несколько значений из функции в C
Согласен, все посты в этой теме, кроме первого, моего, — лишние. 🙂
Teak ★★★★★
( 28.12.06 18:02:01 MSK )
Ответ на: Re: вернуть Несколько значений из функции в C от Teak 28.12.06 17:38:44 MSK

Re: вернуть Несколько значений из функции в C
ув. тов. Teak прочтите пост выше.
Ex ★★
( 28.12.06 18:07:45 MSK )
Ответ на: Re: вернуть Несколько значений из функции в C от Ex 28.12.06 18:07:45 MSK
Re: вернуть Несколько значений из функции в C
> ув. тов. Teak прочтите пост выше.
Не, Ex, извини, но ты там фигню написал. Заморачиваться со структурой в функции стоит только если ты ее всю будешь возращать (структурка небольшая). А создавать ее динамически, а потом возвращать указатель, имхо хреновая идея. Кто-то использующий твою функцию должен знать и помнить о том, что ему где-то free надо втыкать, лишний, тяжелый malloc, и ради чего все?
shumer ★
( 28.12.06 18:51:10 MSK )
Ответ на: Re: вернуть Несколько значений из функции в C от Teak 28.12.06 18:02:01 MSK
Re: вернуть Несколько значений из функции в C
> Согласен, все посты в этой теме, кроме первого, моего, — лишние. 🙂
ты не указал решение с возвратом структуры. Оно непопулярно, потому что этого не было в ранних компиляторах и про это не написано в К&Р Но для 2-х полей оно оптимально
dilmah ★★★★★
( 28.12.06 18:59:37 MSK )
Ответ на: Re: вернуть Несколько значений из функции в C от dilmah 28.12.06 18:59:37 MSK
Re: вернуть Несколько значений из функции в C
> Оно непопулярно, потому что этого не было в ранних компиляторах и про это не написано в К&Р
Вот хохма на эту тему, совершенно случайно наткнулся:
2.2: I heard that structures could be assigned to variables and passed to and from functions, but K&R I says not.
K&R I was wrong; they hadn’t actually learned C very well before writing the book. Later, Ritchie got a job at Bell Labs, and worked closely with the authors of C, allowing the 2nd edition of the book to be much more accurate. (Kernighan already worked at Bell Labs, as a video game developer.)
