최대값을 구하는 것은 초기에 배우는 알고리즘이다.

 

배우지 않아도 누구나 알고리즘을 알고 있다. C언어로 구현하는 약간의 트릭만 알면 된다.

 

예를 들어서 우리는 한 학급에서 누가 가장 키가 큰지 알고 있다. 누가 가장 작은지, 누가 가장 몸무게가 많이 나가는지, 가장 적게 나가는지 이미 알고 있다.

외관상 우열을 가릴 수 없는 경우도 있을 것이다.

 

한학급이 30명 있다면 한명을 기준점으로 설정하고(max 라 한다) 이 기준점을 나머지 29명을 비교해보는 방식으로 기준점보다 큰 사람의 키로 max를 갱신하는 방법으로 최대값을 구할 수 있다. 최소값은 반대로 하면 된다.

 

C에서 배열을 사용하여 표현하면 아래와 같다.

 

배열을 const 로 받는 것은 쓰기를 방지한 "읽기 전용" 데이터이기 때문이다.

 

함수에 배열로 매개변수를 전달하면 실제로는 포인터가 전달된다. 즉 const int array[] 의 실인수의 전달은 아래와 같다.

const int *array = array //array 는 배열의 첫번째 요소의 주소값

이런 부분이 C언어를 혼란스럽게 하는 부분이니 주의해야 한다. 배열을 받는 것은 포인터 선언이다. 함수내에서는 array 에 대해서 sizeof 연산자를 사용할 수 없는데 이것은 배열이 아니라 포인터이기 때문이다. 주는 것은 배열로 줬는데 받은 것은 포인터였다. 그래서 count 를 함수 바깥에서 전달받는다. 함수안에서 sizeof (배열)이 왜 안되는지 의문이었다면 참고한다. 

 

배열의 첫번째 요소를 max 기준점으로 잡는다. 29번 비교하면 최대값이 나온다. for 루프에서 i 를 1로 설정한 것은 i가 0은 max 이기 때문이다. i를 1로 바꾸면 29번 조건식을 비교한다.

 

*소스코드

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int maxIntArray(const int array[], int count);
int minIntArray(const int array[], int count);


int main(int argc, char const *argv[])
{
    srand(time(NULL));

    // 배열의 최대값과 최소값 구하기
    int array[] = {5, 23, 8, 10, 99, 7, 2, 35};
    int max = 0;
    max = maxIntArray(array, sizeof(array)/sizeof(int));
    printf("배열 array의 최대값 : %d\n", max);

    int min = 0;
    min = minIntArray(array, sizeof(array)/sizeof(int));
    printf("배열 array의 최소값 : %d\n", min);

    return 0;
}

int maxIntArray(const int array[], int count){
    int max = array[0];
    for (int i = 1; i < count; i++)
    {
        if(array[i] > max) max = array[i];
    }
    return max;
}

int minIntArray(const int array[], int count){
    int min = array[0];
    for (int i = 1; i < count; i++)
    {
        if(array[i] < min) min = array[i];
    }
    return min;
}

 

* 다음은 동적으로 배열 포인터를 생성하여 무작위로 키를 할당하여 최대, 최소값을 찾아본다.

 

동적이라는 것은 런타임에 히프 메모리(Heap Memory) 영역에 배열을 생성한다는 의미다.

 

기존의 배열은 스택 메모리 (Stack Memory)에 생성된다. 사용하는 것은 비슷해보이지만 메모리 관리 방식의 차이가 난다. C언어는 메모리의 관리를 사용자가 직접해야하는 시스템이다. 이런 특성의 언어를 언매니지드(unmanaged - 가상머신이 관리를 하지 않는다) 언어라고 한다.

 

* 우선 랜덤함수를 만든다, from 에서 to 까지범위를 지정할 수 있다. srand(time(NULL)) 로 시드를 줘야지 매번 다르게 나온다.

 

C++ 이나 자바에서는 난수의 품질이 좋아졌지만 C언어는 성능이 별로다. 그냥 무난하게 사용하고 랜덤 숫자가 중요한 경우는 C++ 이나 자바를 사용하는 것이 좋다.

 

* 처음엔 int 형 포인터로 시작해서 calloc 으로 메모리를 할당하니 배열이 생성되었다. count 는 배열 요소의 개수이다. 7개를 생성했다. int 가 4바이트니까 28 byte의 히프 메모리를 할당했다. calloc 과 malloc 은 C++과 자바같은 OOP에서 new 키워드로 대체된다. 나중에 C++ 코드를 보면 똑같은데 new 와 클래스 생성자만 바뀐 것을 볼 수 있을 것이다. 클래스를 생성할 때 동적 메모리 할당이라는 것은 calloc 과 malloc 에서 시작되었다.

 

 

랜덤 함수로 145에서 200까지의 키를 생성한다. 최대값과 최소값도 각각 함수로 구할 수 있다.

 

여기서 눈여겨 볼 것은 포인터를 마치 배열처럼 사용하고 있다는 것이다.

 

int *height 가 height[0] 이렇게 사용하고 있다. 또 아래와 같이 포인터 연산자로 배열의 요소에 접근 가능하다. 

printf("%d cm at 0x%p\n", *(height+i), (height+i));

포인터의 동작 방식이 배열처럼 작동하는게 핵심이다. 포인터의 주소를 보면 끝자리가 0, 4, 8, C(12) 로 4단위로 변하는 것을 볼 수 있다. 이는 calloc에서 연속적으로 메모리에 할당한 포인터 배열임을 알 수 있다. 데이터는 연속적으로 할당하는 것이 좋다. 포인터로 무엇을 하던 가장 빠른 접근이 가능하다.

 

데이터가 띄엄띄엄 떨어져 있다고 생각해보면 왜 인지 이해가 간다. 예를 들어 사람도 물건을 배달할 때 여러 장소에 배달하는 것 보다 한 곳에 집중적으로 배달하는 것이 더 빠르댜.

 

포인터 할당과 연산의 특징은 저 포인터 연산자의 연속성에 있다. 범위가 어디까지인지 확실히 파악하는게 중요하다. 안그러면 프로그램을 망치기도 쉬운 양날의 검이다. C언어 이후 나온 언어들이 대부분 메모리 관리를 가상머신에서 한다는 것을 생각하면 언어의 설계자들은 보통의 애플리케이션 수준에서 메모리를 직접 조작하는 것이 좋은 아이디어가 아니라고 생각하는 것 같다.

 

메모리를 원초적으로 취급하는 것이 C와 다른 언어를 구분하는 중요한 차이점의 하나이다.

 

*소스코드

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int randomInt(int rangeFrom, int rangeTo);
int maxIntArray(const int array[], int count);
int minIntArray(const int array[], int count);

int main(int argc, char const *argv[])
{
    srand(time(NULL));

    // 랜덤으로 키를 생성

    int *height; // 키를 저장하는 배열
    int count = 7; // 인원 7명
    int random;

    height = calloc(count, sizeof(int));
    for (int i = 0; i < count; i++)
    {
        height[i] = randomInt(145, 200); // 145cm 에서 200cm 까지 무작위로 키를 생성
        printf("height[%d] : %d cm\n",i ,height[i]);
    }
    printf("가장 키가 큰 사람은 %d cm 이다.\n", maxIntArray(height, count));
    printf("가장 키가 작은 사람은 %d cm 이다.\n", minIntArray(height, count));
    free(height);

    return 0;
}

int randomInt(int rangeFrom, int rangeTo){
    int random = rand() % (rangeTo-rangeFrom+1) + rangeFrom;
    return random;
}
int maxIntArray(const int array[], int count){
    int max = array[0];
    for (int i = 1; i < count; i++)
    {
        if(array[i] > max) max = array[i];
    }
    return max;
}

int minIntArray(const int array[], int count){
    int min = array[0];
    for (int i = 1; i < count; i++)
    {
        if(array[i] < min) min = array[i];
    }
    return min;
}

 

공유하기

facebook twitter kakaoTalk kakaostory naver band