기본 콘텐츠로 건너뛰기

방송대 프로그래밍언어론 13강: 서브프로그램 프로토콜과 인수 전달 모델

0-썸네일-요약노트-프로그래밍언어론-13강

방송대 프로그래밍언어론 13강: 서브프로그램 프로토콜과 인수 전달 모델

함수를 호출했는데 원래 변수가 그대로 남기도 하고, 피호출자에서 바꾼 값이 호출자에게 되돌아오기도 합니다. 차이는 단순히 “값인가 주소인가”에만 있지 않습니다. 호출 전에는 프로토콜로 연결 가능성을 검사하고, 호출 중에는 인수와 제어가 피호출자로 이동하며, 복귀할 때는 전달 모델에 따라 결과가 되돌아옵니다. 이 흐름을 이해하면 형식인수와 실인수, 값·결과·값-결과·참조·이름 전달, 별칭 문제를 하나의 호출 지도에서 설명할 수 있습니다.

호출 경계에서는 제어와 데이터가 서로 다른 길로 이동한다

프로그램은 입력을 출력으로 바꾸도록 명령어를 나열한 것입니다. 서브프로그램은 그 안에서 독자적인 입력과 출력을 갖춘 프로그램 조각입니다. 입력은 인수(argument)로 들어오고, 명시적 출력이 있는 함수라면 반환값이 나옵니다. 서브프로그램을 이용하면 큰 프로그램을 역할별 조각으로 나누어 모듈화할 수 있습니다.

호출자(caller)가 서브프로그램 수행을 요구하면 제어 흐름이 피호출자(callee)로 넘어갑니다. 피호출자는 하나의 입구로 진입하고, 본체를 수행한 뒤 기본 출구 또는 별도의 return문이 지정한 출구를 통해 호출자로 복귀합니다. 출구는 여러 개일 수 있어도 호출을 시작하는 입구는 하나라는 점이 초기의 여러 입구를 가질 수 있던 서브루틴과 구분됩니다.

시점제어 흐름데이터 흐름확인할 정보
호출 전호출자에 머무름실인수를 계산할 준비이름·매개변수 프로파일·반환 타입
호출호출자에서 피호출자로 이동전달 모델에 따라 실인수에서 형식인수로 이동위치 또는 키워드 대응, 기본·가변 인수
본체 수행피호출자 내부에서 진행형식인수를 읽거나 변경값의 복사본인지, 원본의 참조인지, 이름인지
복귀피호출자에서 호출자로 돌아감반환값 또는 출력 방향의 인수가 이동할 수 있음결과·값-결과 전달의 복사, 별칭과 충돌

판단 핵심: 서브프로그램 문제는 “누가 누구를 호출했는가”, “호출 경계를 넘는 정보는 무엇인가”, “그 정보가 언제 어느 방향으로 움직이는가”의 세 질문으로 시작합니다.

함수·프로시저·서브루틴은 출력과 입구 구조가 다르다

강의에서는 명시적 반환값이 있는 서브프로그램을 함수(function), 명시적 반환값이 없는 서브프로그램을 프로시저(procedure)라고 구분합니다. 함수는 반환값이 있으므로 호출 결과를 수식의 일부로 사용할 수 있습니다. 프로시저는 명시적인 반환값보다 수행 자체가 중심입니다.

서브루틴(subroutine)은 프로그래밍언어 초기의 서브프로그램 형태입니다. 현대적인 함수나 프로시저에 비해 인수와 반환값의 데이터 흐름이 명확하지 않았고, 입구가 여러 개일 수도 있었습니다. 따라서 “함수·프로시저·서브루틴은 이름만 다른 같은 구조”라고 보면 입구 수와 반환값이라는 구분 기준을 놓칩니다.

구분명시적 반환값입구와 데이터 흐름판단 기준
함수있음하나의 입구, 인수 입력과 반환값 출력호출 결과값을 명시적으로 돌려주는가
프로시저없음하나의 입구, 수행과 인수 효과가 중심명시적 반환값 없이 처리를 수행하는가
초기의 서브루틴전달 구조가 불명확할 수 있음여러 입구가 가능현대적 호출·복귀 규약이 정리되기 전의 형태인가

정의·호출·헤더·본체는 코드에서 맡은 위치가 다르다

서브프로그램 정의는 서브프로그램이 어떻게 작동하는지를 기술한 부분이고, 호출은 그 서브프로그램의 수행을 요구하는 부분입니다. 정의 안에서도 첫 줄에 놓이는 헤더와 실제로 실행되는 본체를 구분해야 합니다.

int sub(int i, int j) {   /* 헤더 */
    return i - j;         /* 본체 */
}

int main(void) {
    int x = 3;
    x = sub(x * x, x);    /* 호출 */
    return x - 1;
}

sub의 헤더는 이름, 반환 타입, 형식인수의 선언을 보여 줍니다. 본체는 호출될 때 실행되는 부분입니다. main에서 실인수 x * xx가 각각 9와 3으로 계산되어 전달되므로 sub는 6을 반환하고, x에는 6이 저장됩니다. 마지막 return x - 1은 5를 반환합니다.

여기서 “정의가 곧 호출”이라는 오개념을 피해야 합니다. 정의는 동작을 마련한 코드이고, 호출은 그 동작을 실제로 수행하라고 요구하는 코드입니다. 한 번 정의한 서브프로그램은 여러 호출 지점에서 사용할 수 있습니다.

시그니처와 프로토콜은 호출 가능한 대상을 좁혀 간다

강의의 용어 체계에서 매개변수 프로파일은 매개변수의 개수·순서·타입을 뜻하며 시그니처(signature)라고도 합니다. 같은 이름의 서브프로그램이 여러 개 오버로딩되어 있으면 호출의 실인수와 시그니처를 맞춰 어느 정의를 사용할지 결정합니다.

서브프로그램 프로토콜은 매개변수 프로파일에 함수의 반환 타입을 더한 정보입니다. 정적 타입 언어에서는 호출 전에 프로토콜이 명시되어 있어야 호출의 타입을 검사할 수 있습니다. C의 서브프로그램 선언은 본체 없이 프로토콜만 제공합니다.

int sub(int, int);  /* 선언: 프로토콜만 명시 */

int main(void) {
    int x = 3;
    x = sub(x * x, x);
    return x - 1;
}

int sub(int i, int j) {  /* 정의: 헤더와 본체 */
    return i - j;
}

검사 순서: 이름이 맞는 후보를 찾고, 실인수의 개수·순서·타입을 시그니처와 대조한 다음, 반환값이 사용되는 문맥을 반환 타입과 확인합니다. 선언은 이 검사를 정의보다 먼저 가능하게 하는 인터페이스 정보입니다.

형식인수는 받는 자리이고 실인수는 호출자가 보내는 표현이다

형식인수(formal argument) 또는 형식매개변수는 정의에서 외부 정보를 받기 위해 선언한 변수입니다. 실인수(actual argument) 또는 실매개변수는 호출할 때 그 자리에 전달하려고 사용한 실제 값·주소·수식입니다. 앞의 예에서 i와 j가 형식인수이고, x * x와 x가 실인수입니다.

대응 방식은 크게 위치와 키워드 방식으로 구분됩니다. 위치에 의한 대응은 첫 실인수를 첫 형식인수에, 둘째 실인수를 둘째 형식인수에 연결합니다. C·Java·Pascal 등에서 일반적입니다. 키워드에 의한 대응은 형식인수 이름을 직접 적으므로 순서를 외우지 않아도 되지만, 이름을 정확히 알아야 합니다. 강의에서는 Ada·Fortran 90·Python 등이 두 방식을 함께 사용할 수 있는 사례로 제시됩니다.

def sort(length, items):
    pass

sort(n, a)                    # 위치에 의한 대응
sort(items=a, length=n)       # 키워드에 의한 대응

기본인수는 실인수가 생략될 때 사용하는 형식인수의 기본값입니다. 반대로 가변인수 서브프로그램은 받을 수 있는 인수 개수가 여러 가지입니다. 둘은 “인수 개수가 고정되지 않을 수 있다”는 겉모습은 비슷하지만, 기본인수는 생략된 자리를 정해진 값으로 채우고 가변인수는 실제로 전달된 여러 개의 값을 모아 받는다는 차이가 있습니다.

대응 핵심: 형식인수는 정의 쪽의 빈 자리, 실인수는 호출 쪽의 실제 표현입니다. 먼저 위치·키워드로 자리를 연결하고, 그다음 기본값 적용이나 가변 개수 처리를 판단합니다.

인수 전달은 의미·개념·구현의 세 렌즈로 읽는다

인수 전달을 한 가지 분류표로만 외우면 입력 모드와 값 전달, 참조 경로와 참조 전달을 뒤섞기 쉽습니다. 강의는 서로 다른 질문을 답하는 세 모델을 제시합니다.

모델묻는 질문주요 분류
의미적 모델프로그래머가 인수를 어떤 용도로 사용하는가?입력·출력·입출력 모드
개념적 모델자료가 도식적으로 무엇으로 이동하는가?값 복사·참조 경로 전달
구현 모델언어가 호출과 복귀를 어떤 규칙으로 구현하는가?값·결과·값-결과·참조·이름 전달

입력 모드는 호출자의 실인수에서 피호출자의 형식인수로 정보가 갑니다. 출력 모드는 반대 방향이고, 입출력 모드는 두 방향이 모두 발생합니다. 개념적 모델에서는 값 자체를 복사하는 방식과 원래 값을 찾아갈 참조 경로를 전달하는 방식을 구분합니다. 구현 모델은 이 의미를 실제 언어가 언제 복사하고 언제 공유하는지로 구체화합니다.

따라서 “입력 모드와 값 전달은 완전히 같은 분류”라고 하면 층위를 놓칩니다. 값 전달은 입력 모드를 구현하는 대표 방법이지만, 강의에서는 참조 경로를 전달하고 쓰기를 금지해 입력 의미를 구현하는 방법도 함께 설명합니다. 목적과 구현을 분리해야 최적화된 구현도 올바르게 해석할 수 있습니다.

다섯 구현 모델은 복사 시점과 원본 접근 여부로 구분된다

전달 방식호출할 때수행 중 원본과의 관계복귀할 때의미적 모드
값 전달실인수값을 형식인수로 복사형식인수는 복사본되돌려 복사하지 않음입력
결과 전달출력용 형식인수를 마련실인수 초깃값을 사용하지 않음형식인수값을 실인수로 복사출력
값-결과 전달실인수값을 형식인수로 복사형식인수는 별도 복사본형식인수값을 실인수로 다시 복사입출력
참조 전달실인수의 주소 또는 참조 경로 전달형식인수와 실인수가 같은 대상을 지칭별도 복사 없이 이미 원본이 변경됨입출력
이름 전달실인수 이름을 전달형식인수를 쓸 때마다 실인수 이름을 사용이름 평가의 결과가 반영됨특정 의미 모델에 고정되지 않음

이 표의 중심 축은 “주소냐 값이냐” 하나가 아닙니다. 호출 시 복사가 있는지, 수행 중 형식인수가 원본과 같은 대상을 보는지, 복귀 시 다시 복사하는지를 시간 순서로 확인해야 합니다. 특히 값-결과 전달과 참조 전달은 호출 전후에 원본이 바뀔 수 있다는 결과만 보면 비슷해 보이지만, 수행 중 별도 복사본을 쓰는지 같은 변수를 공유하는지가 다릅니다.

값 전달은 원본을 분리하지만 큰 데이터의 비용을 고려한다

값 전달(pass-by-value)은 실인수값을 형식인수로 복사하며 입력 모드를 구현합니다. 형식인수를 바꾸어도 호출자의 원본은 직접 바뀌지 않는다는 점이 핵심입니다. 대부분의 언어가 채택하는 기본 방식입니다.

데이터를 물리적으로 모두 복사하면 큰 배열이나 행렬에서 전달 비용이 커질 수 있습니다. 이를 줄이기 위해 참조 경로를 전달하되 피호출자가 쓰지 못하게 금지하여 값 전달과 같은 입력 의미를 보존할 수 있습니다. 이 경우 복사는 줄지만 간접참조의 시간 부담이 생깁니다.

int elem(const Matrix *mp, int row, int col);

const로 가리키는 데이터를 변경하지 못하게 제한한 포인터는 큰 Matrix 전체를 물리적으로 복사하지 않고 읽기 전용 입력 의미를 표현하는 강의의 예입니다. 여기서 구현에 주소가 쓰였다는 이유만으로 곧바로 “피호출자가 원본을 자유롭게 바꾸는 참조 전달”이라고 판정해서는 안 됩니다.

결과·값-결과 전달은 복귀 순간의 복사 충돌을 살핀다

결과 전달(pass-by-result)은 형식인수에서 계산된 값을 복귀할 때 실인수로 복사하여 출력 모드를 구현합니다. 호출 시 실인수의 초깃값은 입력으로 사용하지 않습니다. 다음과 같이 같은 변수 a가 두 실인수 자리에 놓이면 복사 순서가 결과를 바꿀 수 있습니다.

void lor(int left, int right) {
    left = 3;
    right = 7;
}

lor(a, a);

복귀할 때 left의 3을 먼저 a에 쓰고 right의 7을 나중에 쓰면 a는 7입니다. 순서를 반대로 하면 a는 3입니다. 피호출자 안에서 두 형식인수는 별도였지만 두 출력 목적지가 같은 실인수에 겹쳤기 때문에 생기는 문제입니다.

값-결과 전달(pass-by-value-result)은 호출 시 실인수값을 복사하고 복귀 시 형식인수값을 다시 복사합니다. 복사에 의한 전달(pass-by-copy)이라고도 하며 입출력 모드를 구현합니다. 수행 중에는 별도 복사본을 사용하므로 참조 전달의 별칭 문제는 피하지만, 두 번의 복사 비용과 값·결과 전달의 단점을 함께 가질 수 있습니다.

주소 결정 시점: 결과 전달을 참조 경로로 구현할 때 실인수의 주소는 대부분 호출 시 결정됩니다. 예를 들어 lor(idx, list[idx])에서는 호출 뒤 idx가 바뀌더라도 출력 목적지로 어느 배열 원소를 잡았는지를 따로 추적해야 합니다.

참조 전달은 효율적인 공유와 별칭 위험을 함께 만든다

참조 전달(pass-by-reference)은 실인수의 주소나 참조를 형식인수에 전달합니다. 형식인수와 실인수가 같은 변수를 지칭하므로 전달 자체는 효율적이고 입출력 모드를 구현할 수 있습니다. 공유에 의한 전달(pass-by-sharing)이라고도 합니다.

단점은 하나의 대상을 여러 이름으로 지칭하는 별칭(alias) 문제입니다. 같은 변수를 두 실인수 자리에 넣는 실인수 충돌, 같은 배열 원소를 두 번 전달하는 배열 원소 충돌, 전역변수와 형식인수가 같은 대상을 가리키는 충돌이 대표적입니다.

int sqSum(int &x1, int &x2) {
    x1 = x1 * x1;
    x2 = x2 * x2;
    return x1 + x2;
}

int a = 2;
int c = sqSum(a, a);

강의의 C++ 예제를 순서대로 추적하면 x1과 x2가 모두 a를 가리킵니다. 첫 대입에서 a는 2²인 4가 됩니다. 둘째 대입은 원래 2가 아니라 이미 바뀐 4를 다시 제곱하므로 a는 16이 됩니다. 반환식도 같은 a를 두 번 읽어 16+16=32를 만듭니다. “두 형식인수가 각각 처음 값 2를 제곱한다”는 계산은 별칭으로 인한 중간 상태 변화를 놓친 것입니다.

별칭 검사: 참조 전달 호출을 보면 먼저 실인수들이 같은 변수·같은 배열 원소·같은 전역 상태를 가리키는지 확인하고, 각 대입 직후 원본의 새 값을 다음 문장에 반영합니다.

이름 전달은 형식인수를 쓸 때 실인수 표현을 다시 적용한다

이름 전달(pass-by-name)은 실인수의 이름을 전달하고, 형식인수가 사용될 때 그 실인수 이름을 사용합니다. 늦은 바인딩으로 유연하지만 인수 참조가 비효율적이고 전달 의미를 이해하기 어렵습니다. 특정 의미적 모델 하나에 고정되지 않는다는 점도 다른 구현 모델과 구분됩니다.

참조 전달과 이름 전달의 차이는 배열 첨자처럼 실인수 표현이 다른 변수에 의존할 때 선명해집니다. 강의의 특정 언어와 무관한 다음 예를 추적해 보겠습니다.

list = [1, 2, 3]
i = 1
swap(i, list[i])

swap 본체가 temp = a; a = b; b = temp;라고 가정합니다. 참조 전달에서는 호출 시 a가 i를, b가 당시의 list[1]을 가리킵니다. temp는 1, a = b 뒤 i는 2, b = temp 뒤 원래 잡아 둔 list[1]은 1이 됩니다. 최종 상태는 i=2, list=[1, 1, 3]입니다.

이름 전달에서는 b가 고정된 list[1] 참조가 아니라 list[i]라는 이름으로 사용됩니다. a = b 뒤 i가 2가 되면 다음 b = temp는 list[2]에 적용됩니다. 최종 상태는 i=2, list=[1, 2, 1]입니다. 호출 시점의 위치를 고정하는가, 사용할 때마다 이름을 다시 적용하는가가 결과를 갈라놓습니다.

이름 전달의 늦은 바인딩은 Algol 60의 젠슨의 기법처럼 범용 서브프로그램을 만들 수 있게 하지만, 같은 이유로 호출 중 다른 변수의 변화가 실인수의 의미를 바꿀 수 있습니다.

참조와 값-결과는 수행 중 원본 공유 여부가 결과를 바꾼다

다음 강의 예시는 참조 전달과 값-결과 전달이 입출력 결과를 만들 수 있어도 같은 방식은 아니라는 점을 보여 줍니다. 전역 i가 1이고 list가 [1, 2, 3]일 때 fun(i, list[i])를 호출하며, 본체는 i = b;를 수행합니다.

i = 1
list = [1, 2, 3]

fun(a, b):
    i = b

fun(i, list[i])

참조 전달에서는 b가 list[1]의 값 2를 가리키므로 본체가 전역 i를 2로 바꿉니다. 별도의 복귀 복사가 없어 최종 i는 2입니다.

값-결과 전달에서는 호출할 때 a=1, b=2를 복사하고 각각의 복귀 목적지를 잡습니다. 본체가 전역 i를 2로 바꾸어도, 복귀하면서 a의 복사본 1을 원래 실인수 i에 다시 쓰므로 최종 i는 1로 돌아갑니다. 같은 호출과 본체라도 수행 중 공유복귀 시 복사의 차이가 최종 상태를 바꿉니다.

범용성은 타입을 넓히는 방법과 계산 목적을 넓히는 방법으로 나뉜다

여러 용도로 사용할 수 있는 서브프로그램을 범용 서브프로그램이라고 합니다. 강의는 이를 다형 서브프로그램과 다목적 서브프로그램으로 나눕니다.

다형 서브프로그램은 여러 타입의 인수에 적용됩니다. C에서는 매크로 확장이나 void * 타입을 이용할 수 있지만 인수 타입 검사가 어렵습니다. C++의 템플릿과 Java의 제너릭은 타입 인수를 받아 여러 타입을 다루는 매개변수적 다형성의 사례입니다.

#define MIN(A, B) (((A) < (B)) ? (A) : (B))

다목적 서브프로그램은 타입보다 계산 목적을 일반화합니다. 강의의 Algol 60 젠슨의 기법은 이름 전달의 늦은 바인딩을 이용해 합을 구하는 구조는 유지하면서, 항을 나타내는 표현을 바꾸어 제곱합 같은 여러 목적에 적용합니다.

구분무엇을 일반화하는가?강의의 대표 방법구분 질문
다형 서브프로그램인수의 타입매크로·void 포인터·템플릿·제너릭같은 기능을 여러 타입에 적용하는가?
다목적 서브프로그램적용할 계산 목적이름 전달과 젠슨의 기법계산 골격에 다른 표현을 넣어 목적을 바꾸는가?

모듈을 따로 컴파일할 때 인터페이스 정보의 유무가 갈린다

여러 프로그래머가 각 모듈을 작성하면 자신의 소스코드를 다른 부분과 떨어뜨려 컴파일할 수 있어야 합니다. 분리컴파일과 독립컴파일은 모두 프로그램 일부를 나누어 컴파일하지만, 코드 사이의 인터페이스 정보를 사용하는지가 다릅니다.

방식컴파일할 때 인터페이스 정보강의의 언어 사례핵심 판단
분리컴파일사용함Ada·Fortran 90·Modula-2다른 부분과의 연결 규약을 알면서 나누는가?
독립컴파일사용하지 않음Fortran II~77·C·C++다른 부분의 인터페이스 정보 없이 따로 컴파일하는가?

서브프로그램 프로토콜을 호출 전 타입 검사에 쓰는 앞부분과 연결하면 차이가 분명해집니다. 모듈 경계를 넘어 호출을 연결하려면 이름만 아니라 매개변수와 반환 타입 같은 인터페이스가 중요합니다. 분리컴파일은 이 정보를 활용하고, 독립컴파일은 그 정보 없이 각 부분을 컴파일한다는 구분입니다.

핵심 개념 정리

  • 서브프로그램 호출은 제어를 호출자에서 피호출자로 옮기고, 인수 전달 모델에 따라 데이터를 호출 경계 너머로 이동시킵니다.
  • 정의는 동작을 기술하고 호출은 수행을 요구합니다. 헤더는 이름·종류·매개변수를, 본체는 실행할 처리를 담습니다.
  • 시그니처는 매개변수의 개수·순서·타입이며, 프로토콜은 여기에 함수 반환 타입을 더해 호출 전 타입 검사를 돕습니다.
  • 형식인수는 정의 쪽에서 정보를 받을 변수이고, 실인수는 호출 쪽에서 실제로 전달하려는 값·주소·수식입니다.
  • 값·결과·값-결과·참조·이름 전달은 호출 시 복사, 원본 공유, 복귀 시 복사와 이름 재평가 여부로 구분합니다.
  • 참조 전달은 효율적이지만 별칭이 중간 상태를 바꿀 수 있고, 이름 전달은 늦은 바인딩으로 유연하지만 의미와 비용이 복잡합니다.
  • 범용 서브프로그램은 타입을 넓히는 다형 방식과 계산 목적을 넓히는 다목적 방식으로 나뉘며, 분리·독립컴파일은 인터페이스 정보 사용 여부로 갈립니다.

호출 문제를 만나면 먼저 프로토콜로 연결 가능한가를 확인하고, 실인수와 형식인수를 대응시킨 뒤, 호출·수행·복귀의 세 시점에 각각 복사되는 값과 공유되는 대상을 표시하세요. 마지막으로 두 형식인수가 같은 원본을 가리키는지, 배열 첨자가 호출 중 바뀌는지, 복귀 복사 목적지가 겹치는지를 검사합니다. 이 순서를 적용하면 전달 방식의 이름을 암기하는 데서 그치지 않고 최종 변수 상태가 왜 달라지는지 재현할 수 있습니다.

예상문제

1. 강의에서 설명한 서브프로그램의 입력과 출력에 대한 연결로 옳은 것은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ③

  • ① 오답: 인수와 반환값의 데이터 방향을 반대로 연결했습니다.
  • ② 오답: 헤더는 인터페이스를 기술하는 부분이며 실제 입력·출력 데이터 자체와 같지 않습니다.
  • ③ 정답: 호출 시 인수가 들어오고 함수의 명시적 결과가 반환값으로 나가는 기본 구조를 정확히 설명합니다.
  • ④ 오답: 호출자와 피호출자는 제어 흐름의 주체이며 입력·출력 데이터의 명칭이 아닙니다.

2. 강의의 용어 체계에서 매개변수 프로파일과 서브프로그램 프로토콜의 차이는?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ①

  • ① 정답: 프로파일의 개수·순서·타입 정보에 함수의 반환 타입까지 포함한 것이 프로토콜입니다.
  • ② 오답: 본체와 호출은 코드 위치의 구분이며 두 인터페이스 용어의 차이가 아닙니다.
  • ③ 오답: 프로파일은 반환 타입이 아니라 매개변수의 개수·순서·타입을 가리킵니다.
  • ④ 오답: 두 정보는 호출 전 후보 결정과 타입 검사에 쓰이며 실행 뒤의 결과만 나타내지 않습니다.

3. def sort(length, items)sort(items=a, length=n)으로 호출했다. 사용한 대응 방식은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ④

  • ① 오답: 생략된 실인수 자리를 기본값으로 채우는 상황이 아닙니다.
  • ② 오답: 여러 개의 실인수를 하나의 가변 형식인수로 모으는 호출이 아닙니다.
  • ③ 오답: 실인수의 나열 순서가 아니라 형식인수 이름을 직접 적어 연결했습니다.
  • ④ 정답: items와 length라는 키워드를 명시해 정의의 순서와 다르게 적어도 대응이 분명합니다.

4. 의미적 모델과 구현 모델을 올바르게 구분한 것은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ②

  • ① 오답: 두 모델의 관점을 반대로 배치했습니다. 사용 목적이 의미적 관점입니다.
  • ② 정답: 프로그래머 관점의 데이터 방향과 언어 구현 관점의 전달 규칙을 층위별로 나눕니다.
  • ③ 오답: 형식인수 이름은 키워드 대응에 관련되며 세 전달 모델의 분류 기준이 아닙니다.
  • ④ 오답: 컴파일과 함수·프로시저 분류를 인수 전달 모델과 혼동했습니다.

5. 값-결과 전달에서 데이터가 이동하는 순서로 옳은 것은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ①

  • ① 정답: 입력 복사와 출력 복사가 한 번씩 일어나 입출력 모드를 구현합니다.
  • ② 오답: 복귀 방향이 반대여야 피호출자에서 바뀐 형식인수값이 호출자에게 반영됩니다.
  • ③ 오답: 원본을 직접 공유하는 참조 전달의 특징을 값-결과 전달에 적용했습니다.
  • ④ 오답: 호출과 복귀의 복사 방향을 모두 거꾸로 설명했습니다.

6. 결과 전달에서 lor(a, a)를 호출하고 left=3, right=7로 만든 뒤 복귀한다. a의 결과가 복사 순서에 따라 달라지는 이유는?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ③

  • ① 오답: left와 right는 같은 타입이며 타입 차이가 충돌 원인이 아닙니다.
  • ② 오답: 반환값이 아니라 두 결과 인수의 복귀 복사가 문제입니다.
  • ③ 정답: 3과 7이 같은 a에 차례로 써지므로 마지막에 복사된 값이 남고 순서가 결론을 바꿉니다.
  • ④ 오답: 결과 전달은 실인수의 초깃값을 입력으로 사용하지 않는 출력 모드입니다.

7. 참조 전달로 sqSum(a, a)를 호출하며 a의 초깃값이 2이다. 본문이 차례로 x1과 x2를 제곱하고 합을 반환하면 결과는?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ②

  • ① 오답: 참조 전달인데도 형식인수 변경이 원본에 반영되지 않는 값 전달처럼 계산했습니다.
  • ② 정답: 첫 제곱으로 a=4, 둘째 제곱으로 같은 a=16이 되고 반환식은 16+16=32입니다.
  • ③ 오답: 두 형식인수를 독립된 복사본으로 보고 둘째 제곱이 이미 바뀐 a를 읽는 사실을 놓쳤습니다.
  • ④ 오답: 최종 a는 맞지만 반환 시 x1과 x2 모두 같은 값 16을 지칭한다는 별칭 효과를 반영하지 않았습니다.

8. i=1, list=[1,2,3]에서 이름 전달로 swap(i, list[i])를 실행한 최종 상태는?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ④

  • ① 오답: swap 본체의 대입으로 i와 배열 원소가 실제로 변경됩니다.
  • ② 오답: 호출 시 list[1] 참조를 고정하는 참조 전달의 결과입니다.
  • ③ 오답: a = b가 이름 i에 적용되어 i가 2로 바뀌는 단계를 누락했습니다.
  • ④ 정답: i가 2가 된 뒤 b의 이름 list[i]가 list[2]로 다시 적용되어 그 원소가 1이 됩니다.

9. “값 전달을 참조 경로로 구현하면 피호출자가 원본을 자유롭게 바꾸므로 언제나 참조 전달이다”라는 주장에 대한 교정은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ③

  • ① 오답: 참조 경로 사용 여부는 명시적 반환값의 존재와 직접 연결되지 않습니다.
  • ② 오답: 강의는 큰 데이터의 복사 비용을 줄이는 두 번째 구현 방법을 제시합니다.
  • ③ 정답: 구현 수단으로 주소를 쓰는 것과 프로그래머에게 원본 쓰기를 허용하는 전달 의미를 구분한 설명입니다.
  • ④ 오답: 구분 기준은 이름이 아니라 복사·공유·쓰기 가능성과 같은 데이터 이동 규칙입니다.

10. 서브프로그램 호출의 최종 상태를 분석하는 절차로 가장 적절한 것은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ④

  • ① 오답: 참조·결과·값-결과·이름 전달에서는 실인수 원본의 상태가 결론을 좌우합니다.
  • ② 오답: 같은 함수 이름이라도 언어와 전달 모델에 따라 복사·공유 규칙이 달라질 수 있습니다.
  • ③ 오답: 이름의 문자 순서는 인수 전달 방향이나 복귀 복사 순서를 결정하지 않습니다.
  • ④ 정답: 호출 가능성, 자리 연결, 시간대별 데이터 이동, 별칭·목적지 충돌을 차례로 확인하는 재현 가능한 절차입니다.

참고 자료와 작성 기준

이 글은 해당 차시 강의자료를 바탕으로 학습 목적에 맞게 재구성한 비공식 학습자료입니다. 호출 관계 지도, 전달 방식 비교, 단계별 상태 추적과 문제 해설은 학습자의 이해를 돕도록 구성하고 검토했습니다.

  • 작성·편집: 올에이클래스 학습연구팀
  • 주요 근거: 한국방송통신대학교 컴퓨터과학과, 「프로그래밍 언어론」 13강 ‘서브프로그램 개요’ 강의자료(2025)
  • 보충 자료: 외부 보충 자료를 사용하지 않았으며, 해당 차시 강의자료의 범위 안에서 재구성했습니다.
  • 편집 원칙: 올에이클래스 편집 정책
  • 최종 내용 검토: 2026-08-30

댓글