。공부 。2008.02.27 23:49
우리는 배열을 이용해서 힙영역에 내가 원하는 크기만큼의 배열을 동적할당할수 있습니다.
왜굳이 동적할당을 해야하나? 그냥 넉넉하게 지정해주면 안되나? 하는 분들도 있겠지만 그렇게 되면 메모리손실이 뜻하지 않게 너무커져버릴수 있기 때문입니다.
고등학교를 예로 든다면 반별로 학생수가 다를수가 있습니다 1반에는 30명 2반에는 35명 이렇게 있을수가 있다는 거죠..
이럴땐 그냥 넉넉하게 배열을 50씩 잡아줄수 있겠지만 우리는 동적할당을 이용해서 배열을 크기를 지정해 보도록하죠.

import java.io.*;

public class Exam_array {
    public static void main(String[] args)throws IOException{
        BufferedReader in  = new BufferedReader(new InputStreamReader(System.in));
        int[][] array = null;        //배열을 만들어 주고 널값을 넣어준다.
       
        System.out.print("배열의 행을 입력 : ");
        int x = Integer.parseInt(in.readLine());
        array = new int[x][];        //new 라는 키워드를 이용해 입력받은 값으로 배열의 행을 동적할당한다.
       
        for(int i=0; i<array.length; i++){
            System.out.print("배열의 "+ i +"번째 열을 입력 : ");
            int y = Integer.parseInt(in.readLine());
            array[i] = new int[y];
        }
       

        for(int i=0; i<array.length; i++){
            for(int j=0; j<array[i].length; j++){
                System.out.println("["+ i +"]["+ j +"]");
            }
        }
    }
}

위와 같이 하면 행과 열을 입력 받을수 있습니다.
new라는 키워드를 이용해 배열의 크기를 지정해주면 쉽게 동적할당이 되는데 여기서 주의해서 볼것이 있습니다
array.length 와 array[].length 가 그것인데..
둘의 차이가 무엇이 길래 array뒤에 '[]' 을 붙여줄때도 있고 안붙일때도 있는지 말이죠
length가 있는걸로 봐서는 배열의 크기를 반환한다는것이죠.  맞습니다 분명 배열의 크기를 배환하는것입니다.
하지만 array앞에 '[]' 가 붙지않는다면 바로 행의 크기를 반환하고 '[]'가 붙는다면 열의 크기 반환한다는것입니다.
사용자 삽입 이미지












위의 이미지는 int array[][] = new int[3][2]; 였을때 메모리 영역에 할당되는 것을 그림으로 표현해 본것입니다. int array라는 것은 스텍영역에 4Byte로 할당되는 것을 볼수 있습니다 만약 char형이였다면 몇바이트가 할당될까요? 2Byte라고요? 아니죠 데이터를 힙영역에 할당하고 있기때문에 변수 array는 레퍼런스 변수가 됩니다 즉 주소를 가르키게되는 포인터가 되는것이죠 그렇기때문에 자료형이 무엇이든간에 new라는 키워드로 만들어진 변수의 크기는 4Byte가 됩니다.
이 array라는 녀석은 힙영역에 있는 int[3]을 가리키게 됩니다 자바에선 1차원 배열만을 가르킬수 있기때문에 바로 앞에 있는 공간 즉 그주소를 가르키게 되는것입니다 그리고 그주소는 또다시 바로 앞에 있는 주소를 가르키게 되는것이죠 배열은 레퍼런스이기 때문에 가르키는 주소값은 4Byte 됩니다. 마지막공간은 실제 자료형의 크기를 갖게 되는데 여기서는 이역시 int형이기 때문에 4Byte를 갖게 되는것입니다. 만약 char형이라면파란색세로줄 부분의 4라는 숫자는 2로 표기를 했을겁니다.
우리는 왜 '[]'를 붙여주고 안붙여 주는지를 알았습니다.
그럼 array.length 는 배열 array[3][2]  의 첫번째 값이 3을 반환하게 되는것이죠
array[].length는 2를 반환하게 되는겁니다.

흠.. 제표현이 맞았는지 모르겠네요.. 틀린점있음 바로 수정 들어가겠습니다. ^^;
신고
Posted by kyoe
。공부 。2008.01.18 23:02
배열역시 포인터이기 때문에 포인터변수에 배열이름의 주소값을 대입할수있습니다.
이말은 즉 포인터변수는 배열의 첫번째요소의 주소로 초기화를 시킬수있고 그곳을 가르킬수있다는 겁니다. 또한 포인터는 자료형을 갖고 있기때문에 배열과 마찬가지로 배열의 요소를 포인터연산을 통해 가르키를값을 변경시킬수도 있을 것입니다.
지금부터 그예를 들어 포인터연산을 통해 포인터변수의 값을 변경해보도록하죠.

int array[3] = {1,2,3,};
int형 데이터 3개를 저장할수있는 배열 array를 선언하고 요소를 1,2,3초기화 해줍니다.

int* pp = array;   //배열이름은 배열의 첫번째 요소의 주소를 값으로 갖는다.
int형 포인터변수 pp에 배열 array의 주소값으로 초기화 즉 array의 첫번째 요소의 주소로 초기화합니다.
이렇게 되면 포인터 pp는 array의 첫번째요소를 가르키게 됩니다.

우리가 배열의 요소값을 출력할때 어떻게 했죠? 그렇습니다. array[0],array[1]... 이렇식으로 배열의 값을 출력할수 있었습니다. 포인터역시 배열과 똑같이 사용할수있습니다.
printf("%d, %d, %d \n",pp[0],pp[1],pp[2]);
이렇게 배열과 완전히 같게 쓸수가 있습니다.

하지만 우리는 이렇게 쓰기전에 아래와같이 포인터연산을 통해 포인터 pp가 가르키는 주소값을 변경할수있다는것 부터 안뒤에 써야겠죠?
printf("%d, %d, %d \n",*(pp+0),*(pp+1),*(pp+2));
포인터는 자료형을 갖는다고 위에서도 설명을 드렸고 우리는 int형 배열을 선었했죠 이렇게 되면 배열의 한개한개 요소는 4byte를 갖게 되고 포인터 pp역시 4byte의 공간을 참조하게 됩니다.
예를 들어 배열의 첫번째 요소의 주소값을 0x0010 이라 해둡시다 그럼 두번째 요소의 주소값을 당연히 4byte증가한 0x0014가 되겠죠?
잠깐 여기서 만약 *(pp+1) 이렇게 써주지 않고 *pp+1을 써주면 어떻게 될까요? 이렇하면 포인터pp의 주소값이 증가되지 않고 포인터pp가 가르키는 값이 증가 될겁니다.
우리는 우선순의에 의해서 괄호안의 값이 먼저 연산되는것을 알고 있습니다. 그럼 pp의 값이 증가되고  즉 pp는 array의 주소를 갖고 있기때문에 주소값을 1증가시킨뒤 * 연산을 하게되는겁니다 이렇게되면 결국엔 증가한 주소의 값을 가르키는것이죠.
여기까지 말하면 대충 아~ 하고 감이 오는분들도 계실겁니다. 
첫번째 *(pp+0) 은 포인터 pp의 값을 0만큼증가시켰기때문에 가르키는곳음 처음과 일치합니다. 하지만 *(pp+1)은 포인터 pp의 값을 1만큼증가시키고 그값을 가르키고 있네요 포인터값이 1증가 됬으니까 포인터 pp는 0x00011을 가르킬거라고요? 아니겠죠.. 포인터 pp는 int형 포인터이기때문에 +1을 해주면 4byte가 증가하게 되는겁니다 즉 배열요소 첫번째 주소 값에서 4byte가 증가한 0x0014를 가르키게 되죠.
만약 char형이라면 값을 +1증가시킬때 1byte씩증가가 되고 double형이면 8byte씩 증가 하게 됩니다.
array[i] == *(pp+i) 가 성립하게 되는것이죠.
배열을 *(array+i)  이렇게 쓸수도 있다는겁니다.

아래와같이 사용해도 무방합니다.
printf("%d, ",*(pp));
printf("%d, ",*(++pp));
printf("%d\n",*(++pp));
참! 여기서 알고 넘어가야 할것이 있는데 왜 여기선 위에서 처럼 한줄로 코딩을 하지 않았을까요?

신고
Posted by kyoe
。공부 。2008.01.17 23:07
배열이란 둘이상의 변수를 동시에 선언하거나 많은 양의 데이터를 일괄적으로 처리할때 주로 쓰인다.
하지만 우린 배열이또다른 의미를 갖고 있다는것을 알면서도 대충알고만 넘어가는 경우가 많다.

배열을 또다른 말로 풀이하면 상수포인터라고 말할수있습니다.
그이유를 알아보자.

int array[5] = {0,1,2,3,4};
다음과 같은 배열이 있고 배열 array의 첫번째 요소의 주소값이 0x1000번지에 할당되었다고 가정하자.
그럼 두번째 요소인 array[1]은 int형 배열이기 때문에 4byte를 건너뛴 0x004번에 할당될것이다. 만 double형이였다면 8byte씩 건너뛰어서 할당이 되겠지요..

아래와같이 배열요소의 결과값을 출력하면 결과값은 당연히 0과 1이 나오겠죠?
printf("array[0] : %d, array[1] : %d \n",array[0],array[1]);

그럼 이번엔 배열 요소의 주소값을 출력해 보죠. 결과값은 위에서 가정한 0x1000과 0x004 가 나올겁니다.
printf("%d 번지, %d 번지\n",&array[0],&array[1]);

마지막으로 배열이름의 주소값을 출력해 보도록하죠 이상하게도 위의 array[0]번째요소의 주소값인
0x000이 출력이 됩니다. 이것으로 우리는 배열의 이름은 배열의 첫번째요소 즉 배열의 0번째 인덱스의 주소값을 갖는것을 알수있습니다.
printf("array배열이름의 주소 : %d \n",a);

포인터로 예로 들자면 포인터 역시 주소값을 가르킬수있고 또한 자료형도 갖고 있습니다.
이렇게 우리는 주소값 + 자료형 을 갖고 있는것을 포인터라 하죠
배열역시 주소값과 자료형을 갖고 있기때문에 우리는 배열역시 포인터라고 정의를 내릴수 있습니다.

하지만 배열과 포인터가 완전히 같지는 않습니다. 포인터는 다른주소 의 값을 가질수 있지만 배열은 처음에 할당된 주소값만을 가르킬수있습니다. 만약 배열의 주소값을 변경할수있다면 백개씩이나 되는 배열을 요소를 갖고있는 배열을 실수로 다른 주소로 변경하게 된다면 난감하겠죠.. 뭐 간단한 예를 든겁니다. 꼭 이래서 그런것이 아니라.
실제로
int oop = 10;
array = &oop;
이렇게 array배열에 변수 opp의 주소값을 넣으면 에러가 발생합니다.

간단히 정리하자면 이렇습니다.
배열의 배열이름은 주소값과 자료형을 갖는 포인터이지만 주소값을 변경할수없는 상수포인터이다.

신고
Posted by kyoe

티스토리 툴바