삽질의 현장/- C

곱씹어보자 C!_#015_삽잡이의 두서없이 막하는 2차원 배열

shovelman 2015. 6. 26. 22:49

안녕하세요 삽잡이입니다~

오늘도 폭발적인 하루의 끝인 밤이 찾아왔습니다...

요즘 폭발적으로 살고 있습니다...

하하...


지금까지 제가 살펴본 배열은 모두 1차원 배열이었습니다.


1차원 배열은 간단하게 말하자면,

순차적인 인덱스 하나를 가지고 메모리를 접근하는 방식입니다.


그렇다면, 1차원 배열과 다차원 배열의 차이는 뭘까요?

1차원 배열은 논리적으로 표현하면 '순차적' 이고,

다차원 배열은 논리적으로 표현하면 '행'과 '열'로 표현해낼 수 있습니다.


다차원 배열은 아마도... 일차적으로 표현하기 힘든 상황들을 위해 만들어진 것 같습니다. 


다차원 배열이나 1차원 배열이나

메모리는 어차피 선형성을 가지고 있어서 주소가 순차적으로 붙습니다...


그러니까 즉, 뭔 배열이라 해도 컴퓨터는 똑같은거죠...

사용자인 우리에게만 다른것이지...


이론적으로는 2, 3, 4 .... n차 배열 같이 쭉쭉 나갈 수 있다지만, 

일반적으로 3차 이상 사용하는 경우는 없다고들 합니다. 물론 3차도 많이 없지만...

어차피 몇차 배열이던지 배열은 같은 메모리 상에 연속된 집합입니다...


가장 일반적으로 사용한다는 2차 배열에 대해서 알아보도록 하죠.

연속하는 메모리이게 초기화 할때는 {}를 사용한다는 것~


1
 char arr[2][3= {1,2,310,20,30};
cs


이렇게 말입니다~ 계속해서 진행해보도록 하죠...


배열의 이름은 배열 전체의 시작주소라고 했습니다.


1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
void main()
{
    int arr[2][2= {10203040};
    
    printf("%d %d %d %d\n",
        arr[0][0], arr[0][1], arr[1][0], arr[1][1]);
    printf("%p\n", arr);
    printf("%p %p %p %p\n",
        &arr[0][0], &arr[0][1], &arr[1][0], &arr[1][1]); 
}
 
cs


위의 코드를 살펴보도록 하겠습니다.

2차원 배열 arr 각각 행열의 내용들을 출력하고 있습니다.

출력은 예상대로 '10', '20', '30', '40' 이 나오군요.


두번째 printf문 에서는 arr 즉, 배열 이름의 주소를 출력하고 있습니다.

마지막으로는 각각의 2차원 배열 요소들의 주소를 출력하고 있군요.


배열은 동일한 데이터 형을 가진 연속된 변수들의 집합이라고도 정의할 수 있는 것이

마지막 printf의 출력 결과는 모두 4 byte 차이가 나는 것을 확인할 수 있었습니다.


이 글을 읽고 있는 분들 중에

혹여나 결과에 대하여 궁금하시다면 직접 출력해 보시기를.... (지금은 제가 정신이 없어서 푸하하....)


그런데 말입니다... 정말 헷갈리는 것이...

arr 즉, 배열의 시작주소와 arr[0][0] 의 주소는 같게 출력됩니다...


예전에 배열에서 배웠던 내용을 조금 생각해보도록 하죠... 일차 배열입니다... 


int arr[3] = {1, 2, 3};

이라는 배열이 있다면 arr과 arr[0]의 주소 즉, &a[0]의 주소는 같았습니다.


그렇다면 위에서 말씀드렸다시피, 

2차원 배열에서 arr와 arr[0][0]은 같은 주소를 가지고 있다 했지만...

생각해보면 그럼 arr[0]은 뭔가요... 흠... 애매하죠잉... 뭘까요...

값만 놓고 보면 모두 같을터인데...


2차원 배열의 요소들 즉, int arr[2][2] 는 4개짜리 요소의 1차원 배열이 아닙니다...

사용자의 편의상 2차원 배열을 만들었고, 

컴퓨터는 어차피 연속된 메모리의 집합이라고만 생각할지라도...

음... 저 2차원 배열은 2칸짜리 배열이라고 생각하시면 됩니다.


2칸짜리 배열이지만, 

그 안에는 arr[0][0], arr[0][1] 과 arr[1][0], arr[1][1]들이 각각의 칸마다 들어있다는 것이죠.

즉, 2차원 배열에서의 arr은 arr[0]의 주소라는 것입니다.



이번에 살펴 볼 코드는 2차 배열의 구조 파악을 하는데 

도움이 될만한 코드입니다.


1
2
3
4
5
6
7
8
#include <stdio.h>
void main()
{
int arr[2][2= {10203040};
 
printf("%p %p %p\n", arr, arr[0], arr[1]); 
printf("%p %p %p\n", arr+1, arr[0]+1, arr[1]+1);
}
cs

arr = arr[0] 시작주소는 같다고 바로 위에서 말씀 드렸습니다. 

arr[0]과 arr[1]은 각각 3473064, 3473072 (10진수로 변환)의 주소가 출력됩니다.
즉, 8 byte가 차이가 난다는 것죠.

아하... 열의 개수를 아에 뛰어버리는구나...
arr[0]의 다음 주소는 arr[0][0], arr[0][1]을 건너 뛴 
arr[1] 즉, arr[1][0] 이라는 것입니다...

그렇다면 아까 위에서 말씀드렸다 싶이 
저 배열은 4개의 연속 된 메모리를 가지고 있지만, 
우선은 두덩어리로 나뉜 2차원 배열이라는 것을 더욱 확신할 수 있게 됬습니다.

이를 증명해주는 것이 바로 다음 코드에서 볼 수 있는 arr+1 인데요. 

정리한다면 이렇습니다...
arr은 arr[0]과 같고, arr+1은 arr[1]과 같다는 것.

또한, 각각의 arr[0][0], arr[0][1] 과 arr[1][0], arr[1][1]은 
arr[0]과 arr[1]의 시작주소를 기준으로 한다는 것.

2차원 배열의 이름은 2차적인 주소의 역할을 한다고 볼 수 있습니다.
즉, 2차적인 주소의 역할을 한다는 것은 

2차원 배열 이름인 arr은 2차원 배열의 주소값,
arr[0]의 경우에는 arr[0]이라는 배열의 이름 안에 
데이터 타입에 맞는 정수형 변수들이 있죠... 그러니 이는 곧 1차원 배열의 주소값이라 할 수 있습니다.

덩어리 개념으로 생각해보시면 훨씬 이해하기 쉬우실 것 같습니다...
덩어리 안에 덩어리, 2차원 배열안에 1차원... 까고 까는....
뭐라는지...

아... 어렵다~! 하지만 이 모든 것이 정의라는 점... 
더욱 하지만... 이 모든 것이 정의이지만 삽잡이는 야매로 설명하고 있다는... 점...