사전 변수
개념

변수

gabury1고친 사람 github-actions[bot]

변수는 값에 이름을 붙여 두고 그 이름으로 값을 꺼내 쓰게 해 줍니다. 이름은 그대로 두고 담긴 값만 바꿔 넣을 수 있어서 변수라고 부릅니다. 수학과 통계에서도 같은 말을 쓰지만 가리키는 것이 조금씩 다릅니다. 이 항목은 프로그래밍 언어의 변수를 중심으로 다룹니다.

쉽고 빠른 이해

무슨 일을 하는 물건인가 — 값에 이름을 붙여 둡니다. 장바구니 합계를 total 이라는 변수에 넣어 두면 뒤에서 total 이라고만 적어도 그 금액을 씁니다.

왜 이렇게 하나 — 프로그램이 다루는 값은 코드를 쓸 때가 아니라 돌 때 정해집니다. 손님이 무엇을 몇 개 담을지는 주문이 들어와야 압니다. 그 값을 받아 둘 이름이 있어야 계산을 미리 적어 둘 수 있습니다.

어떻게 도나

  1. 이름을 만들고 처음 값을 넣습니다
  2. 코드가 그 이름을 부르면 지금 담긴 값이 나옵니다
  3. 새 값을 넣으면 옛 값은 사라지고 그 뒤로는 새 값이 나옵니다

대가 — 값이 바뀔 수 있으니 어느 줄에서 무슨 값이 들어 있는지 코드를 거슬러 따라가야 압니다. 여러 곳에서 한 변수를 바꾸면 누가 바꿨는지 찾기 어려워집니다.

상세

도서관 사물함에 이름표를 붙여 두는 장면을 떠올려 봅시다. 오늘은 책을 넣고 내일은 우산을 넣어도 이름표는 바뀌지 않습니다. 누구든 이름표만 보고 그 사물함을 찾아가 안에 든 것을 꺼냅니다.

변수는 값을 담아 두는 곳에 이름을 붙인 것입니다. 코드는 그 이름으로 값을 읽고, 같은 이름으로 새 값을 넣습니다. 쇼핑몰 코드가 장바구니 합계를 total 에 담아 두면, 할인을 계산하는 줄도 결제를 부르는 줄도 total 이라고만 적어 같은 금액을 씁니다.

변수가 필요한 까닭은 값이 코드를 쓸 때가 아니라 돌 때 정해지기 때문입니다. 손님이 몇 개를 담을지, 할인이 얼마일지는 요청이 들어와야 압니다. 코드는 아직 모르는 값에 이름부터 붙이고 그 이름으로 계산을 적어 둡니다. 값이 들어오면 적어 둔 계산이 그 값으로 돕니다.

이 절은 변수를 만들고 값을 넣는 기본 동작부터 봅니다. 이어서 변수가 무엇을 담는지, 어디서 통하고 언제 사라지는지, 값을 못 바꾸게 막는 법을 봅니다. 마지막에 다른 분야에서 쓰는 변수를 짚습니다.

선언과 대입

변수를 쓰려면 먼저 이름을 만들어야 합니다. 이 일이 선언입니다. 코드를 읽어 실행에 옮기는 프로그램은 선언을 보면 그 이름을 기억해 두고 값을 담을 칸을 마련합니다. 선언한 적 없는 이름을 부르면 이 프로그램은 무엇을 가리키는지 몰라 오류를 냅니다.

변수에 값을 넣는 일이 대입입니다. 대입은 몇 번이든 할 수 있습니다. 새 값을 넣으면 옛 값은 사라집니다. 아래 Java 코드는 한 변수에 값을 세 번 넣습니다.

Java
int count = 0;       // 0
count = count + 1;   // 1
count = count + 1;   // 2

첫 줄은 선언과 대입을 한 번에 합니다. int 는 이 변수에 정수를 담겠다는 표시입니다. 둘째 줄부터는 이미 있는 count 에 새 값을 넣습니다.

= 는 수학의 등호가 아닙니다. 오른쪽을 먼저 계산하고 그 결과를 왼쪽 이름에 넣으라는 뜻입니다. 그래서 count = count + 1 은 「지금 값에 1을 더해 다시 넣어라」로 읽습니다. 수학의 등식으로 읽으면 성립할 수 없는 식입니다.

변수 이름처럼 코드 속 무언가를 가리키려고 붙인 이름이 식별자입니다. 언어마다 식별자를 짓는 규칙이 있습니다. 대개 숫자로 시작할 수 없습니다.

if 나 class 처럼 언어가 미리 뜻을 정해 둔 낱말도 이름으로 쓸 수 없습니다. 이런 낱말이 예약어입니다. 이름으로 쓰게 두면 코드를 읽는 프로그램이 그 낱말을 명령으로 읽을지 이름으로 읽을지 가릴 수 없습니다.

이름과 값이 놓이는 곳

변수 이름은 사람이 읽으라고 붙인 것입니다. 컴퓨터는 값을 메모리의 어느 칸에 둡니다. 메모리의 칸마다 번호가 있습니다. 이 번호를 메모리 주소라고 부릅니다.

변수 이름을 이 칸과 이어 두는 것은 앞에서 말한, 코드를 읽어 실행에 옮기는 프로그램입니다. 컴파일러와 인터프리터가 이런 프로그램입니다. count 를 읽으라는 코드는 「이 칸에 든 값을 읽어라」가 됩니다. 덕분에 사람은 칸 번호를 외우지 않고 이름만 쓰면 됩니다.

변수에 붙는 타입

값에는 종류가 있습니다. 정수, 소수, 글자, 참과 거짓이 서로 다른 종류입니다. 이 종류를 데이터 타입이라 부르고 줄여서 타입이라고 합니다. 컴파일러나 인터프리터는 타입을 보고 칸을 얼마나 잡을지, 어떤 계산을 허락할지 정합니다.

언어는 타입을 어디에 붙이느냐로 갈립니다. 변수에 붙이는 언어가 있고, 값에만 붙이는 언어가 있습니다. 아래 표가 두 쪽을 견줍니다.

변수에 타입을 붙이는 언어 값에만 타입을 붙이는 언어
예 Java · Kotlin · Go Python · JavaScript
선언 int count = 0; count = 0
다른 종류를 넣으면 실행 전에 오류가 납니다 오류 없이 들어갑니다
부르는 이름 정적 타입 동적 타입

Python 은 선언을 따로 적지 않습니다. 처음 값을 넣는 줄이 선언을 겸합니다.

count = 0 다음에 count = "zero" 를 적어도 오류가 나지 않습니다. 이름은 두고 담긴 값의 타입만 바뀝니다. 대신 count 가 정수라고 믿고 더하기를 하던 줄이 실행 중에 멈출 수 있습니다.

이름이 통하는 범위와 사는 기간

변수 이름은 코드 어디서나 통하지 않습니다. 이름이 통하는 코드의 범위를 스코프라고 부릅니다. 함수 안에서 선언한 변수는 그 함수 안에서만 부를 수 있습니다.

범위를 좁혀 두는 까닭은 이름끼리 부딪히지 않게 하려는 것입니다. 함수 열 개가 저마다 i 라는 변수를 써도 각자 자기 범위 안에만 있으니 서로의 값을 건드리지 않습니다.

함수 안에서 선언한 변수가 지역 변수입니다. 어느 함수에도 속하지 않고 프로그램 전체에서 통하는 변수는 전역 변수입니다. 아래 그림은 두 함수가 같은 이름의 지역 변수를 따로 갖고, 전역 변수 하나를 함께 보는 모양입니다.

flowchart TD
    subgraph P["프로그램 전체"]
        G["전역 변수 total"]
        subgraph A["함수 A"]
            A1["지역 변수 i"]
        end
        subgraph B["함수 B"]
            B1["지역 변수 i"]
        end
    end

두 i 는 이름만 같고 서로 다른 변수입니다. total 은 두 함수 어디서든 부르고 바꿀 수 있습니다. 그래서 전역 변수의 값이 틀어지면 누가 바꿨는지 프로그램 전체를 뒤져야 합니다.

변수에는 사는 기간도 있습니다. 지역 변수는 함수가 불릴 때 생기고 함수가 끝나면 사라집니다. 같은 함수를 다시 부르면 새 변수가 처음부터 다시 생깁니다. 함수 한 번에 쓰는 지역 변수들은 대개 스택이라는 메모리 영역에 함께 놓였다가 함수가 끝날 때 한꺼번에 치워집니다.

값을 담는 변수와 참조를 담는 변수

변수가 담는 것은 두 가지입니다. 값 자체를 담기도 하고, 값이 놓인 곳을 가리키는 표시를 담기도 합니다. 이 차이는 한 변수를 다른 변수에 대입할 때 드러납니다.

Java 의 int 같은 기본 타입 변수는 값 자체를 담습니다. 대입하면 값이 복사되어 두 변수가 따로 놉니다.

Java
int a = 1;
int b = a;   // b: 1
b = 2;       // a: 1, b: 2

배열이나 객체를 담는 변수는 다릅니다. 변수에는 그 객체가 놓인 곳을 가리키는 값이 들어 있습니다. 이 값을 참조라고 부릅니다. 대입하면 참조만 복사되어 두 변수가 한 객체를 함께 가리킵니다.

Java
int[] x = {1, 2};
int[] y = x;
y[0] = 9;          // x[0]: 9

y 를 고쳤는데 x 로 읽은 값도 바뀌었습니다. 배열이 두 벌이 아니라 한 벌뿐이기 때문입니다. 아래 그림이 셋째 줄을 마친 뒤의 상태입니다.

flowchart TD
    X["변수 x"] --> ARR["배열 · 9, 2"]
    Y["변수 y"] --> ARR

함수에 배열이나 객체를 넘길 때도 같은 일이 일어납니다. 함수가 받는 것은 참조의 복사본이라 넘긴 쪽과 같은 객체를 가리킵니다. 그래서 받은 쪽이 객체의 속을 고치면 넘긴 쪽에서도 바뀐 값이 보입니다.

참조는 값이 놓인 곳을 가리키지만 Java 는 그 곳을 코드에 숫자로 드러내지 않습니다. C 는 그 곳을 메모리 주소 그대로 변수에 담습니다. 메모리 주소를 담는 이런 변수가 포인터입니다.

값을 못 바꾸게 막은 변수

한 번 넣은 값을 다시 못 바꾸게 막을 수도 있습니다. 대입을 처음 한 번만 허락하는 변수입니다. 언어마다 붙이는 표시가 다릅니다.

언어 값을 바꿀 수 있는 변수 값을 한 번만 넣는 변수
Java int n = 1; final int n = 1;
Kotlin var n = 1 val n = 1
JavaScript let n = 1; const n = 1;

막아 두면 읽는 사람의 짐이 줄어듭니다. 값이 안 바뀐다는 것을 알면 그 변수가 어느 줄에서 무슨 값인지 거슬러 따라갈 필요가 없습니다. 여러 스레드가 한 변수를 함께 읽어도 누가 중간에 바꿀 걱정이 없습니다.

막히는 것은 변수에 다시 대입하는 일뿐입니다. 변수가 참조를 담고 있으면 그 참조가 가리키는 객체의 속은 여전히 고칠 수 있습니다. final int[] x = {1, 2}; 다음에 x = new int[3]; 은 오류가 나지만 x[0] = 9; 는 허락됩니다.

다른 분야에서 쓰는 변수

변수라는 말은 프로그래밍 밖에서도 씁니다. 어느 분야든 값이 하나로 정해지지 않고 바뀔 수 있는 것에 붙인 이름이라는 뜻을 나눕니다. 가리키는 대상은 분야마다 다릅니다.

분야 변수가 가리키는 것 예
수학 아직 정해지지 않은 수를 대신하는 글자 y = 2x + 1 의 x
통계 · 데이터 분석 관찰 대상마다 값이 달라지는 특성 회원 표의 나이 · 가입 경로
운영체제 프로그램 바깥에서 넣어 주는 설정 값 환경 변수 PORT=8080
GraphQL 쿼리에서 비워 두고 따로 넘기는 값 $id

통계의 변수는 표로 치면 열 하나입니다. 행마다 값이 다릅니다. 분석은 그 값들이 어떻게 흩어지고 서로 어떻게 함께 움직이는지를 봅니다.

GraphQL 의 변수는 프로그래밍의 변수와 같은 생각에서 나왔습니다. 쿼리 문자열 안에 값을 직접 적지 않고 $ 로 시작하는 이름만 둡니다. 아래는 사용자 한 명의 이름을 묻는 쿼리입니다.

graphql
query GetUser($id: ID!) {
  user(id: $id) { name }
}

$id 가 변수입니다. ID! 는 여기에 사용자를 가려내는 ID 값이 빠짐없이 와야 한다는 표시입니다. 값은 쿼리와 따로 JSON(JavaScript Object Notation) 으로 싣습니다.

JSON
{ "id": "42" }

사용자가 바뀌어도 쿼리 문자열은 손대지 않고 이 값만 바꿔 보냅니다. 값을 문자열에 이어 붙이지 않으니 값 안의 따옴표 하나 때문에 쿼리가 깨지는 일도 없습니다. SQL(Structured Query Language)의 바인드 변수도 같은 까닭으로 씁니다.

관련 항목

변수를 다루는 기본 동작

선언 · 대입 · 초기화 · 재할당 · 역참조

이름이 통하는 범위를 정하는 규칙

스코프 · 네임스페이스 · 섀도잉 · 클로저 · 호이스팅

범위와 수명으로 가른 변수의 종류

지역 변수 · 전역 변수 · 정적 변수 · 인스턴스 변수 · 매개변수

변수에 담기는 값의 종류를 정하는 체계

데이터 타입 · 타입 시스템 · 정적 타입 · 동적 타입 · 타입 추론 · 기본 타입 · 참조 타입

변수 값이 놓이는 메모리 영역

메모리 · 메모리 주소 · 스택 · 힙 · 스택 프레임 · 가비지 컬렉션

변수가 담은 값을 넘기고 복사하는 방식

참조 · 포인터 · 값에 의한 전달 · 참조에 의한 전달 · 얕은 복사 · 깊은 복사

값을 못 바꾸게 막는 수단

상수 · 불변성 · 불변 객체 · 읽기 전용 · 순수 함수

변수 이름을 붙이고 해석하는 언어 처리 단계

식별자 · 예약어 · 이름 규칙 · 심볼 테이블 · 컴파일러 · 인터프리터

변수와 나란히 프로그램을 이루는 구성 요소

프로그래밍 언어 · 함수 · 배열 · 객체 · 표현식 · 제어 흐름 · 스레드

변수 선언 문법을 견준 언어

Java · Kotlin · Go · Python · JavaScript · C

변수라는 이름을 달고 다른 분야에서 쓰는 개념

환경 변수 · 바인드 변수 · 독립 변수 · 종속 변수 · 확률 변수 · 미지수

변수라는 말을 자기 뜻으로 쓰는 분야

GraphQL · SQL · 데이터 분석 · 통계 · 수학 · 셸

다른 이름: variable · variables