해결된 질문
작성
·
28
0
func 매서드에서 while문 마지막 실행문인
node = node -> next -> next; 가 이해가 잘 안되었는데요.
해당 실행문 위에 있는 다른 실행문은 node->value 또는 node->next를 통해서 n1메모리에 참조해서 그 값을 가르키기 때문에 =을 통해 값변화가 일어난다.
하지만 node = node -> next -> next; 의 경우에 node는 func메서드가 가지고 있는 지역변수이기 때문에 main에서부터 참조받은 n1 변수를 변경하지 않는다. 이게 맞을까요?
저말고도 다른분들도 여럿 같은 질문을 했는데 정확한 답변이 없어서 제가 이해한게 맞는지 올려봅니다.. 그럼에도 확실하게 개념이 잡히지 않네요. node -> value 또는 node -> next조차도 func메서드 안에 있는 지역변수의 요소들인 건 매한가지 아닌가요...ㅠㅠ
node도 메모리주소.. node->next->next도 메모리주소인데.. 왜 지역변수로 얕은복사(?)가 되는 것인지..ㅠㅠ
답변 2
0
안녕하세요, 질문 내용이 제가 설명드린 것과 아예 달라서 어떻게 생각하시는 것인지 정확히 이해가 어렵습니다.
저는 해당 문제에서 지역변수인지 얕은 복사인지를 말씀드린 적이 아예 없습니다. 해당 문제는 모두 메모리 주소를 주고 있기 때문에 지역변수와 상관없이 전부 반영됩니다.
말씀하신 "main에서부터 참조받은 n1 변수"가 뭘 말씀하시는 걸까요?
이 중에 1번인 전체 노드의 n1를 뜻하는 것이라면, 해당 노드의 value만 바꾸는 코드가 있습니다.
처음에 while에 들어가면 두번째 줄에서 node->value에 3을 할당하게 됩니다. 그러니까 1이 3으로 바뀌는 것이죠. (n1.value가 바뀜)
"지역변수이기 때문에 main에서부터 참조받은 n1 변수를 변경하지 않는다."
-> 이 질문이 어떤 말씀인지 이해가 어렵습니다. 대댓글로 이해가 어려운 부분을 다시 설명 부탁드립니다.
while의 가장 마지막 줄을 설명드리자면,
node -> next -> next는 현재 func라는 함수 안에서 node라는 포인터 변수는 n1을 가리키고 있습니다. 이 이야기는, node->next는 n1의 next입니다.
거기서 한 번 더 가면 (node -> next -> next)
한 번 더 가야하므로
n1.next가 가지고 있는 주소(n3)가 가지고 있는 next(n2)가 됩니다.
지금 n2.next는 main의 2번째 줄을 보면 NULL을 가리키고 있고,
그것을 node라는 함수 내에서 사용되는 포인터 변수가 가리키라고 하는 것입니다. 최종적으로는 node 변수는 n2 그 자체를 가리키게 됩니다.
그 다음 반복에서는 node->next가 현재 NULL이므로 전체가 false가 되어 반복을 진행하지 않습니다.
문제의 의도와 질문 방향이 아예 달라서.. 어떻게 문제를 접근하고 계신지 한 번 더 설명이 필요합니다..
먼저 해설을 다시 드리고 설명해보겠습니다.
이 코드는 크게 세 부분으로 나눌 수 있습니다.
struct Node
정의: 연결 리스트를 구성하는 기본 단위인 노드(Node)를 정의합니다. 각 노드는 정수 값을 저장하는 value
와 다음 노드를 가리키는 포인터 next
로 구성됩니다.
func
함수: 노드를 인자로 받아 연결 리스트를 순회하며, 인접한 두 노드의 값을 서로 교환(swap)합니다. 중요한 점은 노드의 연결 순서 자체를 바꾸는 것이 아니라, 노드 안에 들어있는 value
만 교환한다는 것입니다. 값 교환이 끝나면 포인터를 두 칸씩 건너뛰며 다음 작업을 수행할 노드로 이동합니다.
main
함수:
n1
, n2
, n3
세 개의 노드를 생성합니다.
n1 -> n3 -> n2
순서로 노드들을 연결하여 연결 리스트를 만듭니다.
func
함수를 호출하여 리스트의 값을 변경합니다.
마지막으로, 리스트의 첫 번째 노드(n1
)부터 시작하여 각 노드의 value
를 순서대로 화면에 출력합니다.
코드가 실행되는 과정을 구조체 시각화와 함께 단계별로 살펴보겠습니다.
main
함수 시작 및 초기 상태
main
함수에서 n1
, n2
, n3
노드가 생성되고, 포인터 next
를 통해 다음과 같이 연결됩니다.
n1.next
는 n3
를 가리킵니다.
n3.next
는 n2
를 가리킵니다.
n2.next
는 NULL
입니다.
따라서 초기 연결 리스트의 상태는 다음과 같습니다.
[ n1 ] [ n3 ] [ n2 ]
+-------+ +-------+ +-------+
| 값: 1 | ---> | 값: 3 | ---> | 값: 2 | ---> NULL
+-------+ +-------+ +-------+
func(&n1)
호출
func
함수가 n1
의 주소값을 인자로 받아 호출됩니다. 이제 func
함수 내의 node
포인터는 n1
을 가리킵니다.
while
루프 - 첫 번째 반복
조건 확인: node != NULL
(n1
이라서 참) && node->next != NULL
(n3
이라서 참). 루프가 실행됩니다.
값 교환:
int t = node->value;
t
에 node
(즉, n1
)의 값인 1
이 저장됩니다. (t = 1
)
node->value = node->next->value;
n1
의 값은 n1->next
(즉, n3
)의 값인 3
으로 변경됩니다. (n1.value
는 이제 3
)
node->next->value = t;
n3
의 값은 t
에 저장해 둔 1
로 변경됩니다. (n3.value
는 이제 1
)
값 교환 후 리스트의 상태는 다음과 같습니다. 노드의 연결 순서는 그대로이고 값만 바뀌었습니다.
[ n1 ] [ n3 ] [ n2 ]
+-------+ +-------+ +-------+
| 값: 3 | ---> | 값: 1 | ---> | 값: 2 | ---> NULL
+-------+ +-------+ +-------+
포인터 이동:
node = node->next->next;
현재 node
는 n1
을 가리킵니다. node->next
는 n3
, node->next->next
는 n2
입니다.
따라서 node
포인터는 이제 n2
를 가리키게 됩니다.
while
루프 - 두 번째 반복
조건 확인: node != NULL
(n2
라서 참) && node->next != NULL
(NULL
이라서 거짓).
두 번째 조건이 거짓이므로 while
루프가 종료됩니다. func
함수가 끝납니다.
main
함수로 복귀 및 출력
main
함수로 돌아와 printf
가 포함된 while
루프를 실행합니다.
current
포인터는 리스트의 시작인 n1
을 가리킵니다.
첫 번째 출력: current
가 가리키는 n1
의 값 3
을 출력합니다. current
는 다음 노드인 n3
로 이동합니다.
두 번째 출력: current
가 가리키는 n3
의 값 1
을 출력합니다. current
는 다음 노드인 n2
로 이동합니다.
세 번째 출력: current
가 가리키는 n2
의 값 2
를 출력합니다. current
는 다음 노드인 NULL
로 이동합니다.
current
가 NULL
이 되었으므로 while
루프가 종료됩니다.
위의 흐름에 따라 printf
함수는 3
, 1
, 2
를 순서대로 출력합니다. 코드에는 공백이나 줄바꿈 문자가 없으므로 모든 숫자가 붙어서 출력됩니다.
따라서 최종 출력값은 312
입니다.
전체 코드의 흐름은 위에서 설명한 것으로 이해하시면 됩니다.
그리고 질문의 요지를 다시 살펴보겠습니다.
node->value = node->next->value; 이 실행문을 통해서 n1.value 값은 바뀌는데 node = node -> next -> next; 이 실행문을 통해서 n1.*next 는 왜 안 바뀌는가? 이게 제 질문의 요지였습니다.
node->value는 node라고 새로 생긴 함수 내에 Node 형태의 구조체
를 가리킬 수 있는 포인터 변수입니다. 그 변수가 가리키고 있는 것의 value는 n1.value이고 거기에다가 뭔가를 대입하라고 하니 바뀌는 것입니다.
node = node -> next -> next
는 대입을 통해서 바뀌는 값이 node->next
가 아니라 포인터 변수 그 자체입니다.
=
기준으로 왼쪽부터 봅시다. 원래 node가 어떤 메모리 주소를 가지고 있었든지 상관없이 메모리 주소(node)에 다시 대입하라는 겁니다.
이건 기존에 뭘 가리키고 있든지 상관 없습니다. 함수 내에서 생긴 포인터 변수가 뭘 새로 가리킬지 정하는 것이지 n1.next와 상관 없습니다.
이제 오른쪽을 보시면 node -> next -> next입니다.
node -> next는 n3고, node -> next -> next는 n2입니다.
node 포인터는 n2를 가리키게 됩니다.
위의 코드에서 n1.next를 바꾸려는 것은 아예 없습니다.
n1.next를 바꾸려고 했다면 =
앞에 node->next가 되었어야 합니다.
완전히.. 이해했습니다...!!!!
node =&n1 이 아니라 node=n1으로 머리 속에서 이해했던 것 같아요. node와 n1을 동일시여겼던게 패착이었나보네요.
포인터가 아직 완벽히 숙지가 안 되어서 이해를 못했나봅니다. 상세한 설명 정말 감사합니다 !!
0
안녕하세요, 인프런 AI 인턴입니다. 민혁님.
질문해주신 내용은 링크드 리스트에서의 포인터 사용과 관련되어 있습니다. 특히, 주어진 코드에서의 node = node -> next -> next;
구문이 핵심이 되는 부분입니다. 이 구문은 현재의 node
포인터를 두 번 다음 노드를 가리키도록 하는 것입니다.
먼저, 함수 func(struct Node* node)
에서 전달받은 node
는 링크드 리스트의 특정 노드를 가리키는 포인터입니다. 이 함수에서 수행하는 작업은 node
포인터를 이동시켜 리스트 내의 다른 노드를 가리키도록 하는 것이며, 실제로 node
자체가 가리키는 메모리의 내용이나 연결을 변경하는 것은 아닙니다.
node = node -> next -> next;
: 이 줄은 현재의 node
포인터를 두 칸 앞으로 이동시킵니다. 그러나 중요한 점은 node
변수 자체가 함수 내부의 지역 변수라는 것입니다. 따라서 이 변수를 변경하는 것은 원래의 리스트에 영향을 주지 않고, 단지 함수 내부에서 node
가 가리키는 대상을 변경하는 것에 불과합니다.즉, node
가 가리키는 메모리 주소를 변경할 뿐이고, 실제 원본 노드나 리스트의 구조에는 영향을 미치지 않습니다. 따라서, 함수가 종료된 후에는 node
에 이루어졌던 변경은 사라지고, 원래의 노드 상태는 변하지 않습니다.
실제 node->value
또는 node->next
와 같은 접근이 가능했던 이유는 함수에 전달된 초기 node
포인터가 특정 노드의 위치를 기반으로 참조되었기 때문입니다. 하지만 node
의 값 자체를 변경하는 것은 해당 리스트나 노드의 상태를 변경하지 않습니다.
또한 유사한 질문 및 답변을 확인하면 더 많은 도움이 될 것입니다:
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.
매서드에 매개변수 struct Node*node에 전달인자 &n1 받았다
-> 반복문이 실행된다
->node->value = node->next->value; 를 통해 n1의 value값이 변경되었다 1->3으로
->그렇기 때문에 마지막 실행문인 node = node -> next -> next; 가 실행되었을 때 n1의 포인터값도 n2가 가르키는 null 로 바뀌어야 한다.
-> 그로인해 node->next 가 null바뀌어서 반복문을 탈출한다.
저는 문제를 풀 때 이렇게 이해를 했습니다. 그래서 다시 main으로 돌아와서 while반복문을 돌 때 3만 출력하고 current->next 가 null을 가리키게 되어 탈출하 그런 생각을 했었습니다...
다른 분 질문도 보니 저랑 똑같이 이해하셨더라구요. node = node -> next -> next; 실행문을 통해 node->next가 null을 가리키는 건 이해가 되는데 이 실행문을 통해 n1.next가 null이 아닌 그대로 n3를 가리킨다는 게 이해가 안되어요..
근데 실제론 매서드에서 전달인자를 받아와 선언된 Node node 에 있는 Node* next 의 값만 바뀌어서 반복문에서 탈출되고 메인에선 똑같이 n1.next = &n3 가 된다 이렇게 이해했습니다.
여기서, node->value = node->next->value; 이 실행문을 통해서 n1.value 값은 바뀌는데 node = node -> next -> next; 이 실행문을 통해서 n1.*next 는 왜 안 바뀌는가? 이게 제 질문의 요지였습니다.
"지역변수이기 때문에 main에서부터 참조받은 n1 변수를 변경하지 않는다."
이 말은 강사님께 질문드리기 전에 gpt랑 여러번 대화를 시도한 끝에 도출해낸 설명입니다. 저도 이 설명이 의아해서 강사님께 똑같이 물어보게 되었습니다 ..ㅠㅠ 여러 수업을 듣다보니 개념이 확실하게 정립되지 않아 질문이 난잡하네요.. 죄송합니다..