Как правильно использовать указатели и ссылки на целые числа в функции (C++)?

У меня возникли проблемы с пониманием того, как получить правильные значения, выдаваемые следующим кодом C++, при попытке решить его вручную.

#include <iostream>
using namespace std;

int f(int a, int & b,int *c){
    a += 1;
    b += 3;
    *c += 4;
    return a+b+(*c);
}
int main() {
    int a = 3, b = 4,c = 5;
    cout << "total: " << f(b,c,&a) << endl;
    cout << "a= " << a << " b= " << b << " c= " << c << endl;
    
    a = 3, b = 4,c = 5;
    cout << "total: " << f(a,a,&a) << endl;
    cout << "a= " << a << " b= " << b << " c= " << c << endl;
    return 0;
}

Я знаю, что результат должен быть:

total: 20
a= 7 b= 4 c= 8
total: 24
a= 10 b= 4 c= 5

Но каждый раз, когда я пытаюсь решить этот код вручную (попытка записать шаги и задания на листе бумаги), я не могу получить правильную сумму или значения. Может ли кто-нибудь помочь мне понять, что происходит внутри функции с a, b и c (может быть, пошаговое объяснение?). Должно быть что-то, чего я не понимаю со ссылками/разыменованиями или указателями, что вызывает ошибки в моей логике. Даже

Например, если я попробую первый набор входных данных внутри функции, вот что я понимаю:

  • инт а = 4;
  • интервал &b = 5; //поскольку с = 5
  • интервал *с = &а; //&а = 3

Затем я начинаю выполнять тело функции:

  • a += 1 теперь дает мне a = 5;
  • b += 3 теперь дает мне c = 8, поскольку b является ссылкой на c, поэтому на самом деле изменяется только c;
  • *c += 4 теперь принимает значение, хранящееся в &a, инициализированное как 3, и добавляет 4, так что новое значение a равно 7;

Окончательный результат: a = 7, b = 4 (не изменилось) и c = 8. Эти значения верны, но возвращаемая часть функции не работает с этими значениями:

a+b+(*c) должно быть 7+4+(7), но в результате получается 18, а правильный ответ 20.

Хуже всего то, что если я использую ту же логику во второй раз, когда функция вызывается, мои значения неверны, но моя сумма верна... Я потерян.

Мы не можем отлаживать вашу программу за вас. Используйте отладчик. Что такое отладчик и как он может помочь мне в диагностике проблем?

Jason Liam 20.02.2023 04:58
a = 3, b = 4,c = 5; Это... подозрительно
Nicol Bolas 20.02.2023 04:59

@NicolBolas Я думаю, что это просто сбросить значения int обратно в исходное состояние во второй раз, когда функция вызывается, поскольку функция изменяет значения после выполнения.

user21247827 20.02.2023 05:02

Кстати, int &b = 5; недействителен в С++. Вы можете/должны использовать отладчик вместо того, чтобы делать это вручную.

Jason Liam 20.02.2023 05:02

@JasonLiam Я не прошу кого-то отлаживать мой код, я прошу кого-нибудь объяснить результаты, так как я пытаюсь лучше понять, что происходит под капотом с этой функцией. Код не содержит ошибок, но моя логика есть.

user21247827 20.02.2023 05:04

@user21247827 user21247827 программисты обычно понимают поведение программы, которое их сбивает с толку, используя отладчик. Отладчик точно покажет вам, что происходит во время работы вашей программы.

Drew Dormann 20.02.2023 05:05

Ну, мы не можем сказать вам, что не так с «шагами и заданиями на листе бумаги», которые вы записали, если вы не покажете, что именно, эти шаги и задания. Можете ли вы отредактировать свой вопрос и указать, что, по вашему мнению, происходит, и я уверен, что кто-то укажет точную ошибку. Если вы хотите, чтобы кто-то «объяснил» и помог вам «понять, что происходит», тогда вам нужно показать, во что, по вашему мнению, «происходит», чтобы другие могли помочь вам «понять».

Sam Varshavchik 20.02.2023 05:05

@SamVarshavchik, вторая часть моего поста пытается показать, какие шаги я делаю, пытаясь найти решение. Я не уверен, что еще добавить в этот пост, чтобы лучше показать мои шаги.

user21247827 20.02.2023 05:07

@ user21247827: «Я не прошу кого-то отлаживать мой код, я прошу кого-нибудь объяснить результаты». Вот что такое «отладка»: это то, что вы делаете, когда ваш код дает результат, несовместимый с ожидаемым.

Nicol Bolas 20.02.2023 05:11

Я подозреваю, что ОП вызвал путаницу, используя одни и те же имена как в main(), так и в аргументах функции. Например, вызов f(b,c,&a) приводит к тому, что b становится a (в функции f()), c становится b, а a становится *c.

Peter 20.02.2023 05:15

@SamVarshavchik и Петр большое спасибо за ваши комментарии! Изменение имен переменных в функции на x, y, z значительно упростило понимание! Спасибо, что нашли время, чтобы сломать то, что я делал неправильно!

user21247827 20.02.2023 05:28
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
11
66
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Окончательный результат: a = 7, b = 4 (не изменилось) и c = 8. Эти значения верны, но возвращаемая часть функции не работать с этими значениями:

Что вас сбивает с толку, так это то, что a, b и c в вашем main не то же самое, что a, b и c в f().

return a+b+(*c);

Использует то, что f() знает как a, b и c. Это часть f(). Переменные f() — это единственное, о чем этот оператор return знает что-либо, и он вообще ничего не знает ни о каких переменных в main. Итак, чтобы узнать, что это за переменные, вам просто нужно перечитать то, что вы написали сами:

a += 1 теперь дает мне a = 5;

b += 3 теперь дает мне c = 8, так как b является ссылкой

но это b, вот оно, то самое b, что и в выражении return.

*c += 4 теперь принимает значение, хранящееся в &a, инициализированное как 3, и добавляет 4, так что новое значение a равно 7;

Но это c в выражении. Так

return a+b+(*c);

вычисляет 5+8+7 или 20, как вы заметили.

Второе выражение работает так же.

Вас сбивает с толку тот факт, что переменные f() используют те же имена, что и переменные в main(). Также не помогает то, что указатели и ссылки из одного ссылаются на переменные в другом.

Вам может быть полезно переименовать переменные в f():

int f(int x, int & y,int *z){
    x += 1;
    y += 3;
    *z += 4;
    return x+y+(*z);
}

Это должно быть логически эквивалентно исходной функции, но с меньшей путаницей.

Проще всего это сделать с картинками, поэтому я постараюсь сделать ASCII-арт, показывающий, что происходит.

Вот ситуация сразу после того, как первый вызов вошел в f:

main   a:3   b:4   c:5
         ^           ^
         |       /---/
         |      /
 f     c:*   b:*   a:4

Здесь «main» и «f» имеют свои собственные «a», «b» и «c»; а «b» и «c» в «f» указывают/относятся к вещам в фрейме основного стека. Я изменил порядок c/b/a в 'f', чтобы не было пересекающихся линий.

После трех сложений в f мы имеем

main   a:7   b:4   c:8
         ^           ^
         |       /---/
         |      /
 f     c:*   b:*   a:5

Во втором вызове f все выглядит так:

main   a:3   b:4   c:5
         ^
         |\--\
         |    \
 f     c:*   b:*   a:3

и после добавления:

main   a:10   b:4   c:5
         ^
         |\--\
         |    \
 f     c:*   b:*   a:4

Другие вопросы по теме