동적배열은 실행중 배열의 크기를 유연하게 바꿀수 있는 배열이다. 이전에 대략적으로 다뤘지만, 개인적으로 이 동적배열을 잘 다루면 앞으로 나오는 자료구조를 이해하고 적응하는데 많은 도움이 되기 때문에, 몇가지 중요한 포인트를 정리하고자 한다.
아니면 아주 동적배열에서 특정 데이타를 삽입하는 코드를 외우는 것도 괜찮다 생각된다.
memmove 함수의 선언을 써보자.
void *memmove(void *dest, const void *src, size_t n); // src부터 n만큼을 dest로 이동
memmove함수의 특징은 메모리상에서 dest와 src의 위치가 겹쳐 있어도 데이타의 손실없이 이동이 이루어 진다는데 있다.
memcpy와 동작을 비교하기도 하지만 컴파일러에 따라서(gcc,vc)는 memcpy와 동작이 같게 작동한다.
원래는 memcpy의 동작은 이렇다.
memcpy(dest,src,sizeof(src)-sizeof(int));
위 그림같이 memcpy경우 배열 src의 모든 요소는 0으로 초기화된다. 이런 문제를 해결하기 위해 memmove를 사용하면 원하는 대로 복사가 되어 0,0,1,2,3,4,5,6,7,8 이 된다.
그런데 앞서 말했듯이 어떤 컴파일러는 memcpy의 특성을 그대로 용인해주는 것도 있다. 컴파일러가 혼용될 우려가 있는 경우를 생각해서 memmove사용하자.
그러면 memmove함수를 이용하여 동적배열의 삽입코드를 작성해보자.
동적배열에 삽입을 하게될때 생각해야할 문제들을 흐름에 따라 정리해보면 다음과 같다.
1. 어디에 무엇을 삽입할 것인가?
2. 삽입시 공간이 충분한가?
3. 공간이 충분하지 않다면, 얼만큼 늘려야하는가?(realloc)
4. 공간을 늘렸다면 memmove를 이용하여 삽입할 공간을 마련한다.
기본적으로 malloc으로 초기화를 한후 위 1~4에 대한 데이터를 작성한다.
공간이 충분한지를 파악하기 위하여 삽입되는 메커니즘에 삽입되는 데이터의 크기만큼의 지표로 삼을 변수가 있어야한다.
cur 변수가 현재 데이터의 개수를 가리킨다.
(cur와 size는 물과 그릇의 관계다. 물은 데이터를 나타내고, 물과 그릇의 크기를 항상 비교하면서 물을 부어 넣어야한다.
만약 물이 꽉 차있다면 그릇의 크기를 늘리는 작업을 먼저해야한다. 정해진 lmt 변수에 따라 정해진 크기만큼 그릇을 늘린다.(realloc) size변수는 잘 다루어야한다. size변수를 기준으로 그릇을 늘리기 때문에, size변수는 먼저 체크되고 먼저 변해서 재할당과 다음 데이터의 삽입시 비교의 기준이 되어주어야한다.)
memmove 함수를 다룰 때는 항상 메모리를 머리속에 그려넣는 것이 좋다.
위 그림을 보고 직접 두 코드의 차이를 느껴보자. 위의 코드는 삭입, 아래코드의 경우는 삭제코드다.
사실 처음부터 자세히 공부할 필요는 없지만,어느정도 세세하게 다 알아야한다. 메모리의 복사, 그리고 배열을 자유자제로 다루고, 삽입 삭제의 위치를 정확하게 코드로 표현해야 한다. 그래야 자료구조의 여러 형태를 쉽게 이해할 수 있다. 외울 필요는 없지만, 익숙해져야한다. 자료구조의 형태를 조금씩 올려야겠다.