'Programming'에 해당되는 글 41건

  1. 2011.12.08 20111208_배열과 포인터, 동적배열 할당
오늘부터 매일매일 공부 한 걸 기록해둘 생각이다.
공부하면 그 기억이 3일을 못 감ㅡㅡ... 좌우지간,



배열은 다음과 같이 생성한다

type 배열명[크기][크기]...;
* 타입에는 구조체, 클래스로도 정의할 수 있다
* 크기에는 반드시 상수가 들어간다
* 배열의 index는 0부터 시작한다

ex) int ar[3];  // ar라는 이름의 int형 3칸짜리 배열을 만든다
 ar[0]  ar[1]   ar[2] 
1900272 1900276 190027A (<< adress )

int는 4Byte라서 각 배열 당 4Byte씩 할당되기 때문에 주소값도 4씩 차이가 난다.
(type형 포인터를 대상으로 n의 크기만큼 값을 증가 및 감소 시 n*sizeof(type)의 크기만큼 주소 값이 증가 및 감소함.)
이걸 응용하면
arr[i] == *(arr+i)
라는 공식을 성립시킬 수 있다.

또, ar는 ar배열의 인덱스를 가르킨다. 즉 &ar[0] 과 같다.





이젠 다차원 배열을 써먹어보자.
선언 int arr[2][4];
 arr[0][0]   arr[0][1]   arr[0][2]   arr[0][3]
 arr[1][0]    arr[1][1]   arr[1][2]   arr[1][3]

선언&초기화


① 한 괄호안에 초기화
int arr[2][4] = {1, 2, 3, 4, 5, 6, 7, 8};

② 괄호 여러 개 만들고 초기화
int arr[2][4] = {
 {1, 2, 3, 4},
 {5, 6, 7, 8}
};

③ 배열 크기 안 쓰고 초기화
int arr[][4] = {1, 2, 3, 4, 5, 6, 7, 8};
int arr[2][] = {1, 2, 3, 4, 5, 6, 7, 8};
하나만 채워넣으면 알아서 계산해준다.

* int arr[][] = {1, 2, 3, 4, 5, 6, 7, 8};
-> 이런 초기화는 [1][8] 인지 [2][4] 인지 [4][2] 인지 모르기 때문에 불가능하다.

물론, 비워놓고 안 쓰면 0으로 초기화시킨다.


2차원배열이라고 2차원으로 메모리를 할당할 리는 없고, 다음과 같이 순차적으로 할당된다
0x1000 arr[0][0]
0x1004 arr[0][1]
0
x1008 arr[0][2]
0x100C arr[0][3]
0x1010 arr[1][0]
0x1014 arr[1][1]
0x1018 arr[1][2]
0x101C arr[1][3]

2차원 배열을 가지고 이래저래 출력을 해보면 다음과 같은 결과가 나온다.
printf("%d \n", arr);                      // 3079336
printf("%d \n", arr[0]);                   // 3079336
printf("%d \n", &arr[0][0]);               // 3076336

printf("%d \n", arr[1]);                   // 3079352
printf("%d \n", &arr[1][0]);               // 3079352

printf("%d \n", sizeof(arr));              // 32
printf("%d \n", sizeof(arr[0]));           // 16
printf("%d \n", sizeof(arr[1]));           // 16
printf("%d \n", sizeof(arr[0][0]));        // 4

뭐라뭐라 길게 설명하하고 정리하는 것보다 눈에 보이는 출력결과가 더 이해가 잘 되는 듯 하다(..)
암튼 2차원배열에서 배열이름에 1씩 더할 때 위의 배열로 예를 든다면 
sizeof(int) * 4(두번째요소) 가 더해진다.

그리고, 더불어 이러한 유형의 배열의 포인터 변수 선언은 이렇게 한다.
int (*ptr) [4];
[] 안에 들어가는 값을 쉽게 설명하자면 한 번에 건너 뛸 개수로 생각하면 적절함.
int (*ptr) [4]; 는 가로가 4인(0~3) 배열이다.
접근 시 ptr[1][2]; 이렇게 하면 댐!

2차원 배열을 함수의 인자로 전달할 땐 이렇게 한다.
void func(int (*ptr)[3]) { ....... }
void func(int ptr[][3]) { ....... }
둘 다 같은 의미임. (배열 가로가 3인 배열을 전달)

* 다음은 헷갈리지 말자.
-> 포인터 배열은 int *ptr[4];
-> 배열 포인터는 int (*ptr)[4];




...동적배열 할당이 헷갈려서 배열 복습을 하였고, 본론!
동적배열을 생성하기 위해서는 malloc이나 new를 사용하면 된다.
C에서는 malloc으로 동적할당을 하며 free로 해제한다.
C++에서는 new로 동적할당을 하며 delete로 해제한다.
int n;
cin>>n;
int *point = new int[n];

delete [] point; // 동적으로 할당한 배열 삭제

나는 크기 n의 배열을 만들고 싶었고 n은 cin으로 사용자에게 입력받으며 어떤 값이 들어올 지 알 수 없다.
이 때 new 함수로 동적으로 배열을 생성하면 된다.
new 함수는 int형의 크기 n 배열로 메모리를 할당하고, 첫번째 인덱스 값을 반환한다.
그리고 point는 new에서 반환한 주소값을 저장하면 끝!

다 쓰면 delete [] point; 를 꼭 해 주어야 한답.1차원배열 동적할당 끝.



이제 '2차원 동적배열 할당'.
int w = 1024; int h = 768;
unsigned char **p;
p = new unsigned char* [h];
for(int i=0;i<h;i++)
 p[i] = new unsigned char[w];

좀 이해하기 어려운 개념이라 골머리 썩다가,
http://blog.naver.com/gigar/60099872581
여기서 한번에 이해해버렸다:D..

요약하자면 2차원배열의 각각의 시작주소값을 알고 있는 1차원배열이 필요하고
1차원배열의 시작값을 담고있는 포인터배열의 시작주소값을 알고 있는 변수포인터가 필요하다는...
그림 보면서, 그려가면서 읽다보니 어느정도 이해할 수 있었다.


내부값을 0으로 초기화하고 싶다면 이렇게 하고

int w = 1024; int h = 768;
unsigned char** p
p = new unsigned char* [h];
for(i=0;i<h;i++)
{
 p[i] = new unsigned char[w];
 memset(p[i], 0, sizeof(unsigned char)*w);
}

*참고, memset 함수는 특정 메모리 주소로부터 일정 크기만큼 메모리 공간의 값을 설정하는 함수.

출처 winApi

무사히 사용하고 메모리는 이렇게 돌려준다.
for(i=0;i<h;i++)
 delete [] p[i];
delete [] p;







※ 참고
윤성우의 열혈 C 프로그래밍
http://www.winapi.co.kr/
[네이버지식IN]C++ 동적배열

Posted by HUEJI
: