AI가 자꾸 붙이는 &와 *: 포인터 이해하기
비개발자가 가장 헷갈려하는 포인터(&, *)의 개념을 실생활에 비유하여 아주 쉽게 이해하고 메모리 참조를 알아봅니다.
바이브코딩으로 Go 언어 코드를 생성하다 보면, 변수 이름 앞에 뜬금없이 앰퍼샌드(`&`)가 붙거나 별표(`*`)가 붙어있는 기괴한 코드를 자주 마주치게 됩니다. 많은 비개발자들이 이 기호들을 외계어처럼 느끼고 포기하곤 합니다. 하지만 이 기호들의 정체인 '포인터(Pointer)'는 백엔드 서버가 엄청나게 큰 데이터를 번개처럼 빠르게 주고받을 수 있게 해주는 핵심 마법입니다. 결재판 서류와 인터넷 링크의 비유를 통해 이 헷갈리는 녀석들의 정체를 명쾌하게 밝혀봅시다.
값 복사(서류 복사) vs 주소 전달(링크 공유)
회사에서 동료에게 100페이지짜리 프로젝트 기획서 문서를 전달해야 한다고 상상해 봅시다.
첫 번째 방법은 복사기에 가서 100페이지를 똑같이 복사본으로 찍어낸 뒤 동료의 책상에 올려놓는 것입니다. 동료가 자기 복사본에 낙서를 해도 내 원본 문서에는 아무런 영향이 없습니다. 하지만 전달할 때마다 100장의 복사용지와 시간이 낭비됩니다. 이것이 프로그래밍 세계의 '값 복사(Copy by Value)' 방식입니다. 일반적인 변수 전달은 다 이렇게 동작합니다.
두 번째 방법은 사내 클라우드에 문서를 올려놓고 동료에게 "구글 드라이브 문서 링크(주소)" 하나만 카카오톡으로 틱 보내는 것입니다. 시간도 0.1초면 충분하고 종이도 낭비되지 않습니다. 만약 동료가 링크를 타고 들어와 문서를 수정하면, 내 원본 문서도 똑같이 수정됩니다. 이것이 바로 '포인터(Pointer) 전달' 방식입니다.
포인터의 탄생 이유
게시글의 내용이 10만 글자라고 해봅시다. 백엔드 안에서 이 게시글 데이터를 조회 함수, 검열 함수, 저장 함수 등 여러 곳으로 전달해야 합니다. 이때마다 10만 글자를 복사기에 넣고 복사하면 서버의 메모리(종이)가 금방 바닥나고 속도는 기어 다니게 됩니다. 대신 "이 게시글 데이터는 302호 캐비닛에 있어"라는 주소(링크)만 쏙쏙 전달하면, 메모리 낭비 없이 쾌적하게 서버를 운영할 수 있습니다.
`&` (주소 알아내기) 와 `*` (알맹이 꺼내기)
그렇다면 AI가 짜준 코드의 암호 같은 기호들은 무슨 뜻일까요? 딱 두 가지만 기억하면 됩니다.
1. `&` (주소 연산자): "이 데이터의 링크(주소) 좀 따줘!"
원본 데이터 앞에 `&`를 붙이면, 복사본을 만드는 대신 구글 드라이브 공유 링크(주소)를 생성해 냅니다.
주소 알아내기
userAge := 30
// ageLink 안에는 30이라는 숫자가 아니라, "메모리 0x1234 번지"라는 주소가 들어갑니다.
ageLink := &userAge 2. `*` (참조 연산자): "이 링크 타고 들어가서 진짜 알맹이 좀 꺼내줘!"
공유 링크를 카톡으로 받았습니다. 화면에 띄우려면 링크를 클릭해야 합니다. 주소 변수 앞에 `*`를 붙이면 "해당 주소로 찾아가서 진짜 원본 데이터를 열어라"는 뜻이 됩니다.
// ageLink 주소로 찾아가서 진짜 값(30)을 31로 바꿔버립니다!
*ageLink = 31 함수 안에서 값을 바꾸려 할 때의 차이
| 코드 형태 | 설명 및 결과 |
|---|---|
| 일단 복사본 넘기기\nfunc UpdateAge(age int) | UpdateAge(userAge) 로 넘깁니다. 함수 안에서 복사본의 나이를 백날 올려봤자 원본 userAge는 영원히 30살 그대로 유지됩니다. |
| 포인터(링크) 넘기기\nfunc UpdateAge(age *int) | UpdateAge(&userAge) 로 주소를 찔러줍니다. 함수 안에서 *age = 31 로 수정하면, 내 원본 userAge도 31살로 확실하게 바뀝니다! |
AI를 감시하는 포인터 실전 수칙
바이브코딩을 하다 보면 AI가 무조건 모든 것을 포인터(`*`)로 만들려는 과잉 친절을 베풀 때가 있습니다.
포인터 사용 시 주의할 점
권장
- 엄청나게 뚱뚱한 데이터(유저의 전체 상세 정보, 긴 게시글 등)를 함수 사이로 넘길 때는 메모리 절약을 위해 포인터(&)를 쓰는 것이 맞습니다.
- 함수 안에서 '원본 데이터'를 꼭 수정해야만 하는 경우(예: DB에서 불러온 정보에 조회수를 +1 하기)에는 반드시 포인터로 넘겨야 합니다.
주의
- 숫자 하나(int), 짧은 글자(string) 같이 깃털처럼 가벼운 데이터는 굳이 링크를 따지 말고 그냥 쿨하게 복사본을 넘기는 것이 오히려 서버 엔진에 좋습니다.
- AI가 별다른 이유 없이 모든 변수에 별표(*)를 덕지덕지 붙여놓았다면, 가벼운 데이터는 포인터를 쓰지 말라고 명확히 지시하세요.
여러분이 직접 `&`와 `*`를 현란하게 타이핑할 일은 드뭅니다. 하지만 화면에 `*User`라는 글자가 보일 때, "아, 이건 유저 정보 복사본이 아니라 유저 정보가 들어있는 캐비닛의 열쇠(링크)구나!"라고 읽어낼 수 있다면 백엔드 구조의 뼈대를 완전히 꿰뚫어 본 것입니다.
개념 퀴즈
퀴즈 답을 맞춰야 학습 완료가 됩니다.여러분은 회원가입 축하로 유저의 원본 포인트를 1000점 올려주는 백엔드 함수를 기획하고 있습니다. AI가 함수를 짜주었는데, 원본 데이터가 업데이트되지 않고 함수가 끝나는 순간 올라간 포인트가 증발해 버립니다. 원본 데이터를 고치기 위해 AI에게 함수의 매개변수 타입을 무엇으로 바꿔달라고 지시해야 할까요?
3줄 요약
- 1Go 언어에서 데이터를 넘길 때 기본적으로는 복사본을 만들어 전달하지만, 크기가 큰 데이터는 주소(링크)만 전달하는 포인터 방식을 사용해 메모리를 아낍니다.
- 2변수 앞에 &를 붙이면 메모리 주소를 얻어내고, 포인터 변수 앞에 *를 붙이면 해당 주소를 타고 들어가 실제 알맹이 데이터를 읽거나 수정합니다.
- 3함수 안에서 밖의 원본 데이터를 조작하려면 반드시 포인터 타입으로 전달해야 하며, 가벼운 숫자나 문자까지 포인터를 남발하는 것은 좋지 않습니다.