기본 콘텐츠로 건너뛰기

방송대 방통대 프로그래밍언어론 10강 - 배열과 복합 데이터형 - 요약 노트 시험족보 예상문제 - 올에이클래스

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

프로그래밍언어론 10강 - 배열과 복합 데이터형

여러 데이터를 묶어 다루는 배열, 문자열형, 연관배열, 구조체와 공용체의 데이터 집합과 연산을 학습한다. 배열의 주소 계산과 저장 순서, 공용체의 저장공간 공유, 포인터형과 참조형의 의미를 비교하여 각 복합 데이터형의 설계 원리를 이해한다.

제1장 배열의 개념과 구성

1. 배열과 원소

배열(array)은 같은 타입, 즉 동질형 데이터의 모음으로 구성된 타입이다. 배열을 이루는 각각의 데이터를 원소(element)라 하고, 배열이 가질 수 있는 원소의 개수를 배열의 크기라고 한다. 사용자는 원소의 타입과 배열의 크기를 지정하므로 원시타입이나 사용자 정의 타입을 원소로 하는 다양한 복합타입을 만들 수 있다.

각 원소는 첨자(subscript)로 구별한다. 첨자는 첫 원소에서 얼마나 떨어져 있는지를 나타내는 상대적 위치이다. 첨자가 0부터 시작하는 배열에서 arr[0]은 첫 원소, arr[3]은 첫 원소에서 세 칸 떨어진 네 번째 원소이다.

핵심: 배열은 원소의 순서와 위치가 의미를 가지며, 같은 타입의 원소를 첨자로 구분한다. 배열의 데이터 집합은 원소 타입의 데이터 집합이 배열 크기만큼 모인 집합이다.

2. 원소 타입과 크기

배열의 크기는 양의 정수 범위에서 정하며, 원소 타입에는 단순타입뿐 아니라 배열이나 구조체 같은 복합타입도 올 수 있다. C와 C++의 double arr[4];와 Java의 double[] arr = new double[4];는 모두 double 원소 네 개를 가지는 배열을 만든다. 선언 문법과 저장공간 확보 시점은 언어마다 다르지만, 원소 타입과 개수로 배열 타입이 결정된다는 원리는 같다.

3. 배열의 차원

차원(dimension)은 배열 원소를 지정할 때 사용하는 첨자의 개수이다. 1차원 배열은 하나의 첨자 [크기], 2차원 배열은 행과 열을 나타내는 두 첨자 [행][열], 3차원 배열은 면·행·열을 나타내는 세 첨자 [면][행][열]를 사용한다.

char a[4]는 1차원 배열, char b[3][4]는 3행 4열의 2차원 배열, char c[5][3][4]는 5개의 면마다 3행 4열을 가지는 3차원 배열이다. 대부분의 프로그래밍 언어는 차원을 특별히 제한하지 않지만, 강의에서 제시한 Fortran 77은 7차원, Fortran 2018은 15차원까지 허용한다.

차원은 원소 수가 아니라 원소를 찾는 데 필요한 첨자의 개수이다. c[1][2][3]처럼 첨자가 세 개이면 3차원 배열이다.

제2장 배열의 구현과 연산

1. 저장공간 확보

배열 구현에서 첫 번째 고려사항은 연속된 원소를 담을 저장공간의 확보이다. 필요한 저장공간의 크기는 원소 타입의 크기 × 배열의 크기로 계산한다. 예를 들어 크기가 1바이트인 char 원소 다섯 개의 배열은 원소 저장에 5바이트가 필요하다.

배열 크기의 바인딩 시점은 변수의 저장 방식과 언어에 따라 달라진다. 초기 Fortran의 정적변수는 배열 크기가 정적으로 바인딩된다. 스택 동적변수에서는 언어에 따라 크기가 정적 또는 동적으로 바인딩될 수 있다. 강의 예에서 C++의 char arr[5]는 고정된 크기를 사용하고, C의 int n=5; char arr[n];은 실행 시 정해진 크기를 사용할 수 있다. Java의 new char[5]와 같은 힙 동적 배열은 크기도 동적으로 바인딩된다.

2. 1차원 배열의 주소 계산

배열 구현의 두 번째 고려사항은 첨자를 실제 메모리 주소로 바꾸는 것이다. 크기 N인 1차원 배열 A의 원소가 연속해서 저장된다면 다음 공식으로 주소를 계산한다.

주소(A[i]) = 주소(A[0]) + i × 원소크기

첫 원소의 기준 주소에서 원소 크기만큼 i번 이동하면 A[i]의 주소가 된다. 이 계산이 가능한 이유는 모든 원소가 같은 타입이라 크기가 같고, 첨자가 첫 원소에 대한 상대적 위치를 나타내기 때문이다.

3. 행 우선 저장

크기 M×N인 2차원 배열 B를 1차원 메모리에 배치하려면 어느 방향의 원소를 먼저 연속 저장할지 정해야 한다. 대부분의 프로그래밍 언어는 한 행의 원소를 차례로 저장한 뒤 다음 행으로 넘어가는 행 우선 저장을 사용한다.

행 우선 주소(B[i][j]) = 주소(B[0][0]) + i × N × 원소크기 + j × 원소크기

i개의 완전한 행을 건너뛰려면 한 행의 원소 수 N에 i를 곱하고, 현재 행 안에서 j개 원소를 더 건너뛴다. char B[3][4]에서 char 크기가 1바이트일 때 B[1][2]의 오프셋은 1×4×1 + 2×1 = 6바이트이다.

4. 열 우선 저장

Fortran은 한 열의 원소를 차례로 저장한 뒤 다음 열로 넘어가는 열 우선 저장을 사용한다. 같은 M×N 배열이라도 주소 계산 공식이 달라진다.

열 우선 주소(B[i][j]) = 주소(B[0][0]) + j × M × 원소크기 + i × 원소크기

j개의 완전한 열을 건너뛸 때 각 열의 원소 수 M을 사용한다. char B[3][4]에서 B[1][2]의 열 우선 오프셋은 2×3×1 + 1×1 = 7바이트이다. 따라서 논리적 첨자가 같아도 저장 순서에 따라 실제 주소가 달라진다.

구분행 우선열 우선
연속 저장 단위한 행을 먼저 저장한 열을 먼저 저장
대표 적용대부분의 프로그래밍 언어Fortran
주요 계수행 첨자 i에 열 개수 N을 곱함열 첨자 j에 행 개수 M을 곱함

5. 배열의 연산집합

배열의 연산집합에는 배열 전체를 다루는 연산과 개별 원소에 적용하는 연산이 있다. 배열 전체 연산은 언어마다 차이가 크다. C, C++, Java는 기본적으로 초기화 연산을 제공하지만 배열 전체에 대한 일반 대입이나 사칙연산을 폭넓게 제공하지 않는다. Ada, Perl, Python은 배열 전체 대입을 비롯해 언어에 따라 비교나 사칙연산도 지원한다. 개별 원소에 가능한 연산은 원소 타입의 연산집합에 의존한다.

제3장 문자열형

1. 문자열과 문자열형

문자열은 문자들의 나열이며, 문자열형(string type)은 문자열 데이터를 다루는 타입이다. "KNOU", "good morning", "123", "a"는 모두 문자열이다. 문자열형의 데이터 집합은 가능한 모든 문자열이 모인 집합이다.

2. 언어별 문자열 표현

C는 문자열을 문자형 1차원 배열로 표현한다. char str[] = "abc";는 내부적으로 'a', 'b', 'c', 문자열의 끝을 알리는 '\0'을 가진다. Java는 문자열을 String 클래스 타입으로 제공한다. C++는 C 방식의 문자 배열과 string 클래스를 모두 사용할 수 있다.

언어문자열 표현
C널 문자로 끝나는 문자형 1차원 배열
C++C 문자열과 string 클래스
JavaString 클래스 타입

3. 문자열의 연산집합

문자열 연산은 프로그래밍 언어마다 큰 차이가 있다. 강의 범위에서 C와 C++는 기본적인 문자열 연산을 언어의 배열 연산으로 직접 제공하지 않는다. Java의 String은 str2 = str 같은 대입과 "Good" + " morning""Good morning"으로 만드는 연결 연산을 지원한다.

제4장 연관배열과 키

1. 연관배열의 정의

연관배열(associative array)은 동질형 데이터의 순서 없는 모음으로 구성된 타입이다. 일반 배열에서는 원소의 선후관계와 첨자 위치가 중요하지만, 연관배열에서는 원소 사이의 순서나 상대 위치가 의미가 없다. 각 원소는 사용자가 직접 지정하는 키(key)로 구별한다.

키는 각 원소의 절대적인 식별 위치 역할을 하며 중복될 수 없다. 반면 원소의 값은 서로 같아도 된다. 요일별 보행량을 저장하는 예에서 "Tue""Mon"이라는 키는 서로 달라야 하지만, 두 키에 대응하는 값이 모두 2000인 것은 허용된다.

배열과의 구분: 배열은 상대 위치인 첨자로 순서 있는 원소를 찾고, 연관배열은 사용자가 지정한 고유한 키로 순서 없는 원소를 찾는다.

2. 데이터 집합과 언어별 타입

연관배열의 데이터 집합은 키 타입의 데이터와 원소 타입의 데이터가 이루는 쌍들의 모음이다. 키 타입과 원소 타입의 조합에 따라 다양한 연관배열 타입이 존재한다. Perl은 이를 해시(hash) 타입으로 제공하고, C++는 map 타입으로 제공한다.

3. 연관배열의 연산

대표 연산에는 키를 이용한 원소 참조, 새로운 키-값 쌍의 추가, 기존 원소의 삭제가 있다. Perl에서는 $walk{'Sun'}으로 참조하고 $walk{'Thu'} = 3000으로 추가하며 delete $walk{'Mon'}으로 삭제한다. C++ map에서는 walk["Sun"], walk.insert({"Thu", 3000}), walk.erase("Mon")이 각각 대응한다.

제5장 구조체와 공용체

1. 구조체의 정의

구조체(structure type)는 다양한 타입의 데이터를 한 묶음으로 구성하는 타입이며 레코드형(record type)이라고도 한다. 배열과 달리 구성 데이터가 반드시 동질형일 필요가 없다. 이름, 출생연도, 키, 몸무게처럼 문자열·정수·실수를 함께 묶을 수 있다.

구조체에서는 구성 데이터를 원소 대신 필드(field)라고 하며 C++에서는 멤버라고도 한다. 각 필드는 이름으로 구별하고, 필드 이름은 해당 타입으로 선언된 변수명이다. 필드 타입에는 단순타입과 복합타입이 모두 올 수 있다. 구조체의 데이터 집합은 각 필드 타입에 해당하는 데이터 집합들이 함께 모인 집합이다.

2. 구조체의 연산

C에서 struct person을 정의한 뒤 {"ABC", 1980, 175.3, 69.8}처럼 필드 값을 차례로 초기화할 수 있다. 같은 구조체 타입의 변수 사이에는 m2 = m1과 같은 대입 연산을 적용할 수 있다. 개별 필드는 점 연산자를 사용해 m2.birth처럼 접근한다.

3. 공용체의 정의와 저장공간 공유

공용체(union type)는 저장공간을 공유하는 데이터의 모음으로 구성된 타입이다. 정의와 필드 접근 방법은 구조체와 비슷하지만, 구조체는 각 필드가 독립적인 저장공간을 갖는 반면 공용체의 필드들은 같은 저장공간을 서로 다른 타입의 관점으로 해석한다.

한 필드에 값을 쓰면 공유 메모리의 비트가 바뀌므로 다른 필드로 읽는 값도 영향을 받는다. 강의의 union uniint i, char a, double f를 같은 공간에 둔다. 먼저 f를 쓰고, 이어 i를 쓰고, 마지막으로 a='A'를 쓰면 동일 메모리의 일부가 차례로 덮인다. 따라서 이전에 저장한 fi를 다시 읽은 결과는 원래 값과 달라진다.

구분구조체공용체
구성 데이터동질형·이질형 모두 가능서로 다른 필드 타입 가능
저장공간필드별로 독립모든 필드가 공유
한 필드 변경다른 필드 값에 직접 영향 없음공유 비트가 바뀌어 다른 필드 해석에 영향
데이터 집합 관점필드 데이터 집합들의 모음필드 타입 데이터 집합들의 합집합

4. 태그가 있는 공용체와 익명 공용체

공용체는 어느 필드에 유효한 값이 들어 있는지 저장공간 자체만으로 판단하기 어렵다. 그래서 보통 태그(tag)와 함께 사용한다. 예를 들어 통화 금액을 표현하는 구조체에 KRW 또는 USD를 나타내는 열거형 태그를 두고, 공용체에는 정수형 won과 실수형 dollar 필드를 둔다. 태그가 KRW이면 won을, USD이면 dollar를 사용한다.

구조체의 하위 타입으로 이름 있는 공용체 amount를 정의하면 m.amount.won처럼 접근한다. 이름이 없는 익명 공용체를 사용하면 공용체 이름을 거치지 않고 m.won, m.dollar처럼 직접 접근할 수 있다. 어느 형식을 사용하든 태그와 실제로 기록한 공용 필드가 일치해야 한다.

제6장 포인터형과 참조형

1. 포인터형

포인터형(pointer type)은 특정 데이터가 저장되는 주소 자체를 데이터로 다루는 타입이다. 사용자는 포인터가 가리킬 데이터의 타입을 지정하며 단순타입과 복합타입 모두 지정할 수 있다. C와 C++의 int *ptr;은 ptr이 int 데이터가 저장된 메모리 주소를 값으로 가진다는 뜻이다.

포인터형의 데이터 집합은 시스템에서 사용할 수 있는 주소의 범위이다. 강의에서는 32비트 시스템의 주소 범위를 232 이내, 64비트 시스템을 264 이내로 설명한다.

2. 포인터 연산과 간접참조

포인터에는 주소를 저장하는 대입 연산과 주소 위치를 이동하는 덧셈·뺄셈 연산을 적용할 수 있다. C와 C++에서 간접참조 연산자(dereferencing operator) *를 포인터 변수 앞에 쓰면 그 포인터가 가리키는 주소에 저장된 데이터를 얻는다.

int k[2] = {7, 5}; int *ptr; ptr = k;에서 배열 이름 k는 첫 원소의 주소를 ptr에 대입한다. 첫 *ptr은 7을 출력한다. ptr++은 다음 int 원소의 주소로 이동하므로 그 뒤의 *ptr은 5를 출력한다. 포인터 증가가 단순히 주소값 1만 증가시키는 것이 아니라 가리키는 타입의 다음 원소로 이동한다는 점이 중요하다.

int *ptr의 별표는 포인터 변수 선언에 쓰이고, 표현식 *ptr의 별표는 포인터가 가리키는 데이터를 읽는 간접참조 연산자이다. 모양은 같지만 문맥에 따라 역할이 다르다.

3. 참조형

참조형(reference type)은 사용자가 지정하는 별칭(alias)을 만드는 타입이다. 지정한 타입의 데이터가 저장된 주소 자체를 자신의 주소로 사용하므로 원래 변수와 같은 저장공간을 다른 이름으로 참조한다. C++에서 int k = 11; int &ref = k;라고 하면 ref는 k의 별칭이며 둘은 같은 주소와 같은 값을 나타낸다.

참조형의 데이터 집합은 지정한 타입의 데이터 집합이고, 연산집합도 지정한 타입의 연산집합이다. 참조를 사용할 때마다 포인터처럼 명시적인 간접참조 연산자를 쓰지 않고 원래 타입의 변수처럼 연산한다.

4. 포인터형과 참조형 비교

구분포인터형참조형
핵심 의미주소를 값으로 가지는 변수기존 변수의 별칭
C++ 선언 예int *ptr;int &ref = k;
데이터 접근*ptr로 간접참조원래 변수처럼 ref를 직접 사용
대표 연산대입, 주소 덧셈·뺄셈, 간접참조지정한 타입의 연산

핵심 개념 정리

배열은 동질형 원소의 순서 있는 모음이며 첨자로 원소를 구별한다. 차원은 첨자의 개수이다. 1차원 주소는 기준 주소에 첨자와 원소 크기의 곱을 더해 구하고, 2차원 배열은 행 우선 또는 열 우선 저장 순서에 맞춰 주소를 계산한다. 문자열형은 문자 나열을 다루며 C의 문자 배열, C++의 C 문자열과 string, Java의 String처럼 언어별 표현과 연산이 다르다.

연관배열은 순서 없는 동질형 원소를 고유한 키로 구별한다. 구조체는 이름 있는 여러 필드를 독립된 공간에 묶고, 공용체는 여러 필드가 한 저장공간을 공유한다. 공용체는 현재 유효한 필드를 나타내는 태그와 함께 사용할 수 있으며 익명 공용체를 쓰면 공용체 이름 없이 필드에 접근할 수 있다.

포인터형은 특정 타입 데이터의 주소를 값으로 다루며 간접참조 연산자로 주소의 데이터를 얻는다. 참조형은 기존 변수의 별칭을 만들어 같은 저장공간을 다른 이름으로 사용한다. 포인터는 주소 대입과 이동을 명시적으로 다루지만 참조는 지정한 타입의 변수처럼 사용한다.

최종 정리: 복합 데이터형을 구분할 때는 구성 데이터의 동질성, 순서와 식별 방법, 저장공간의 독립 또는 공유 여부를 확인한다. 배열은 첨자와 연속 배치, 연관배열은 키, 구조체는 이름 있는 독립 필드, 공용체는 공유 필드, 포인터는 주소값, 참조는 별칭이라는 핵심 차이를 기억해야 한다.

예상문제 20선

1. 배열에 대한 설명으로 옳은 것은?

정답입니다.

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

정답 및 해설 보기

정답: ④
배열은 같은 타입의 원소들을 순서 있게 모으며, 첨자는 첫 원소에서의 상대 위치를 나타낸다.

2. 배열의 차원(dimension)을 결정하는 것은?

정답입니다.

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

정답 및 해설 보기

정답: ②
b[i][j]처럼 첨자 두 개로 원소를 지정하면 2차원 배열이다.

3. 원소 크기가 4바이트이고 크기가 10인 1차원 배열 A에서 A[3]의 기준 주소 대비 오프셋은?

정답입니다.

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

정답 및 해설 보기

정답: ①
1차원 공식에 따라 3×4=12바이트를 기준 주소에 더한다.

4. 3행 4열 char 배열 B를 행 우선으로 저장할 때 B[1][2]의 오프셋은? 단, char는 1바이트이다.

정답입니다.

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

정답 및 해설 보기

정답: ③
행 우선 공식의 오프셋은 1×4×1 + 2×1 = 6이다.

5. 같은 B[1][2]를 열 우선으로 저장할 때 오프셋은?

정답입니다.

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

정답 및 해설 보기

정답: ③
열 우선 공식에서 2×3×1 + 1×1 = 7바이트이다.

6. 배열 전체 연산에 대한 설명으로 옳은 것은?

정답입니다.

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

정답 및 해설 보기

정답: ①
배열 전체 연산은 언어별 차이가 크고, 개별 원소의 연산은 그 원소 타입의 연산집합을 따른다.

7. C 문자열 "abc"를 문자 배열로 표현할 때 포함되는 문자는?

정답입니다.

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

정답 및 해설 보기

정답: ②
C 문자열은 문자형 1차원 배열이며 끝을 표시하는 널 문자까지 저장한다.

8. 문자열형의 언어별 표현으로 옳지 않은 것은?

정답입니다.

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

정답 및 해설 보기

정답: ④
문자열의 표현과 연산은 언어마다 다르다.

9. 연관배열과 일반 배열의 차이를 옳게 설명한 것은?

정답입니다.

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

정답 및 해설 보기

정답: ①
연관배열의 키는 중복할 수 없지만 서로 다른 키에 같은 값이 저장되는 것은 허용된다.

10. 강의에서 연관배열을 제공하는 타입의 연결로 옳은 것은?

정답입니다.

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

정답 및 해설 보기

정답: ③
Perl은 해시 타입, C++는 map 타입으로 키-값 쌍을 다룬다.

11. 구조체에 대한 설명으로 옳은 것은?

정답입니다.

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

정답 및 해설 보기

정답: ④
구조체는 서로 다른 타입의 필드를 독립된 저장공간에 묶는 레코드형이다.

12. C 구조체 변수 m2의 birth 필드에 접근하는 표현은?

정답입니다.

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

정답 및 해설 보기

정답: ②
일반 구조체 변수의 개별 필드는 변수명과 필드명 사이에 점을 써서 접근한다.

13. 구조체와 공용체의 가장 중요한 저장공간 차이는?

정답입니다.

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

정답 및 해설 보기

정답: ②
공용체에서는 한 필드에 값을 쓰면 공유 메모리가 변경되어 다른 필드의 해석에도 영향을 준다.

14. 공용체를 태그와 함께 사용하는 주된 이유는?

정답입니다.

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

정답 및 해설 보기

정답: ④
공유 메모리만으로는 현재 값을 어떤 타입으로 해석해야 하는지 알기 어려워 태그가 유효 필드를 표시한다.

15. 익명 공용체를 구조체 안에서 사용할 때의 특징은?

정답입니다.

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

정답 및 해설 보기

정답: ③
이름 있는 amount 공용체는 m.amount.won으로, 익명 공용체는 m.won으로 접근한다.

16. 포인터형의 핵심 의미는?

정답입니다.

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

정답 및 해설 보기

정답: ①
포인터 변수에는 지정된 타입의 데이터가 위치한 메모리 주소가 저장된다.

17. C/C++에서 포인터 변수 ptr이 가리키는 주소에 저장된 데이터를 얻는 표현은?

정답입니다.

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

정답 및 해설 보기

정답: ④
별표는 표현식에서 간접참조 연산자로 작용하여 포인터가 가리키는 데이터를 얻는다.

18. int k[2]={7,5}; int *ptr=k; 뒤에 *ptr을 출력하고 ptr++ 후 다시 *ptr을 출력한 결과는?

정답입니다.

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

정답 및 해설 보기

정답: ①
처음에는 첫 원소를 가리키고, ptr++ 뒤에는 다음 int 원소를 가리킨다.

19. C++의 int &ref = k;가 의미하는 것은?

정답입니다.

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

정답 및 해설 보기

정답: ②
참조형은 지정한 변수의 주소를 자신의 주소로 사용하므로 ref와 k는 같은 데이터를 나타낸다.

20. 포인터형과 참조형의 비교로 옳은 것은?

정답입니다.

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

정답 및 해설 보기

정답: ③
포인터는 주소를 값으로 저장하고 *로 간접참조하며, 참조는 초기화한 대상의 별칭으로 원래 타입의 연산을 사용한다.

댓글