C & C++/디딤돌 C언어

Part 19. 함수 만들기 실습

언휴 2024. 1. 15. 15:57

Part 19. 함수 만들기 실습

61. 함수 만들기 실습 시나리오

함수 만들기 실습 - C언어

이번에는 단순한 기능을 수행하는 함수들을 직접 만들고 호출해서 사용하는 실습을 진행할게요.

함수 만들기 실습은 해야 할 일을 분석하는 것부터 시작하며 이런 작업을 도메인(Domain) 분석이라고 불러요.
도메인 분석이 끝나면 적당한 이름을 결정하고 입력 매개변수 리스트와 반환 형식을 결정할 거예요.
그리고 테스트 코드를 작성한 후에 실제 함수를 구현하는 순서로 실습할게요.

여러분은 함수 만들기 과정을 통해 기본적인 알고리즘 논리 전개와 함수 원형을 결정하는 능력을 키워야겠죠.
어떤 종류의 프로그래밍 언어를 사용하더라도 이러한 능력은 필수적으로 필요해요.

여러분은 각 단계별로 진행하고 난 후에 책의 내용과 비교해 보세요.
만약 책의 내용을 본 후에 따라하기 형태로 학습하면 시간은 적게 들지만 실력은 별로 늘지 않을거예요.
그리고 알고리즘 논리를 전개하는 능력은 다양한 프로그래밍을 통해 키울 수 있어요.
따라서 이 책에 소개한 것을 해 보는 것으로는 부족해요.
이 책을 학습한 후에 알고리즘과 자료구조에 관한 책을 추가로 학습할 것을 권해요.
그리고 다양한 형태의 시나리오를 만들어 프로그래밍해 보는 적극적인 자세가 필요하겠죠.

작성할 함수 소개
이번 함수 만들기 실습에서 여러분이 작성할 함수의 기능을 제시할게요.
a. 범위 내의 정수 합계를 구하는 함수
b. 특정 수가 소수(Prime Number)인지 판단하는 함수
c. 범위 내의 정수중에 소수(Prime Number)의 개수를 구하는 함수
d. n 개의 정수의 합계를 구하는 함수
e. 두 수를 바꾸는 함수
f. n 개의 정수에서 제일 큰 정수가 있는 메모리 주소를 구하는 함수
g. n 개의 정수를 크기 순으로 정렬하는 함수(내림차순, 선택 정렬 알고리즘으로 정렬)

여러분은 먼저 도메인 분석부터 해 보세요.

62. 도메인 분석

다음은 이번 실습에서 만들 함수들의 도메인 분석한 결과예요.
각 함수들이 어떨 때 사용하는 것인지 설명할게요.
여러분이 생각한 기능과 차이가 있는지 확인해 보세요.

a. 범위 내의 정수 합계를 구하는 함수
사용 예: 1부터 100까지 합을 구하고자 할 때

b. 특정 수가 소수(Prime Number)인지 판단하는 함수
사용 예: 3이 소수인지 확인하고자 할 때

c. 범위 내의 정수중에 소수(Prime Number)의 개수를 구하는 함수
사용 예: 5에서 20 사이의 소수가 몇 개인지 확인하고자 할 때

d. n 개의 정수의 합계를 구하는 함수
사용 예: {1, 3, 10, 8, 5, 2} 의 원소의 합을 구하고자 할 때

e. 두 수를 바꾸는 함수
사용 예: 두 개의 변수가 갖고 있는 값을 교환하고자 할 때

f. n 개의 정수에서 제일 큰 정수가 있는 메모리 주소를 구하는 함수
사용 예: {10, 1100, 34, 124, 100}의 원소 중에 제일 큰 값을 갖는 원소의 메모리 주소를 구할 때

g. n 개의 정수를 크기 순으로 정렬하는 함수(내림차순, 선택 정렬 알고리즘으로 정렬)
사용 예: {10, 1100, 34, 124, 100}의 원소를 {1100, 124, 100, 34, 10} 순으로 정렬할 때

이제 분석한 결과에 어울리는 함수명을 결정해 보세요.

63. 함수명 결정

함수 이름은 사용하는 개발자가 어떤 기능인지 이해하기 쉽게 만드면 좋은 이름이라고 할 수 있겠죠.
일반적으로 함수 이름은 동사로 만들어 이해하기 쉽게 만들고 있어요.
여러분이 만든 함수를 다른 개발자가 이름만 보고 어떠한 일을 수행하는지 예측할 수 있다면 개발 비용을 줄겠죠.
이제 여러분께서는 해야 할 기능에 알맞는 함수 이름을 결정한 후에 책을 보세요.

다음은 함수 이름을 정한 예입니다.
정답이 있는 것이 아니므로 설명은 생략할게요.

a. 범위 내의 정수 합계를 구하는 함수
GetSumInBoundary
b. 특정 수가 소수(Prime Number)인지 판단하는 함수
IsPrime

c. 범위 내의 정수중에 소수(Prime Number)의 개수를 구하는 함수

GetCountIsPrime

d. n 개의 정수의 합계를 구하는 함수

GetSum

e. 두 수를 바꾸는 함수

Swap

f. n 개의 정수에서 제일 큰 정수가 있는 메모리 주소를 구하는 함수

GetMaxPos

g. n 개의 정수를 크기 순으로 정렬하는 함수(내림차순, 선택 정렬 알고리즘으로 정렬)

SelectionSort

이 책에서 이름을 정할 때는 다음과 같은 규칙을 사용할게요.

이름을 정하는 규칙을 만들면 이해하기 쉬운 코드가 만들 수 있어요.

매크로 상수: 대문자와 _의 조합으로 첫 자는 대문자로 시작

예: #define    MAX_NUM    30

태그: 첫 자는 _로 시작하고 두 번째 문자는 대문자, 나머지 문자는 소문자이며 명사

예: struct _Student

타입: 첫 자는 대문자이고 나머지는 소문자, 명사

예: typedef struct _Student Student

함수: 단어의 시작은 대문자, 나머지는 소문자, 동사

예: GetStr

변수: 소문자와 숫자, _의 조합, 명사

예: int num1; int count_stu;

참고로 많은 개발자가 많이 사용하는 명명법이 있어요.

대표적으로 헝가리식 표기법과 낙타의 등 표기법, 파스칼 표기법이 있답니다.

헝가리식 표기법은 자주 사용하는 단어를 짧게 만들어 사용하는 방법이예요.

가령 문자열을 str, 개수를 cnt 등으로 표기하는 것이죠.

낙타의 등 표기법은 단어의 의미가 바뀌는 부분은 대문자로 나머지는 소문자로 정의하는 방법입니다.

getNum, isPrimeNum 등으로 표기하는 것을 예로 들 수 있습니다.

파스칼 표기법도 낙타의 등 표기법의 하나인데 첫 단어를 대문자로 정의한답니다.

GetNum, IsPrimeNum 등으로 표기하는 것이죠.

낙타의 등 표기법을 카멜 표기법 혹은 단봉낙타 표기법이라고 불러요.

그리고 파스칼 표기법은 쌍봉 낙타 표기법으로 불리죠.

64. 함수 원형 결정

이번에는 함수 원형을 결정해 보세요.
함수 원형은 함수 이름과 입력 매개 변수 리스트와 반환 형식을 말하죠.
앞에서 함수 이름은 결정했으니 입력 매개변수 리스트와 반환 형식을 결정하세요.

입력 매개변수 리스트를 결정할 때는 기능 수행에 영향을 미치는 인자를 판단해야죠.
이를 위해 구체적인 사용 예를 생각하시고 전달할 구체적인 값을 생각하세요.

특히 기능을 수행하기 위해서 호출하는 곳의 지역 변수의 값을 변경해야 한다면 포인터 형식으로 받아야겠죠.
그리고 입력 인자가 필요가 없거나 결과를 반환할 필요가 없는 함수도 있어요.
만얀 인자가 필요 없거나 결과를 반환할 필요가 없을 때는 void로 명시해요.

이제 여러분께서 각 함수의 원형을 결정하세요.
그리고 책의 내용을 살펴보세요.

a. 범위 내의 정수 합계를 구하는 함수
범위 내의 정수 합계를 구하기 위해서는 호출하는 곳에서 범위의 시작 값과 끝 값을 전달해야 되겠죠.
그리고 계산한 합계를 반환해 주어야겠네요.

int GetSumInBoundary(int start, int end);

b. 특정 수가 소수(Prime Number)인지 판단하는 함수
특정 수가 소수인지 판단하려면 호출하는 곳에서 확인하고자 하는 수를 전달해야겠죠.
그리고 소수인지 여부를 반환해 주어야겠죠.
여기에서는 소수일 때 1을 반환하고 소수가 아닐 때는 0을 반환하기로 할게요.

int IsPrime(int num);

c. 범위 내의 정수중에 소수(Prime Number)의 개수를 구하는 함수
범위 내의 정수중에서 소수의 개수를 구하려면 호출하는 곳에서 범위의 시작 값과 끝 값을 전달해야겠죠.
그리고 계산한 소수의 개수를 반환해 주어야겠죠.

int GetCountIsPrime(int start, int end);

d. n 개의 정수의 합계를 구하는 함수
n 개의 정수의 합계를 구하려면 호출하는 곳에서 계산해야 할 정수들과 정수의 개수를 전달해야겠네요.
그런데 계산해야 할 정수의 개수에 관계없이 계산하기 위해 계산할 정수들이 있는 시작 메모리 주소와 개수를 전달하기로 해요.
그리고 합계를 반환하면 되겠죠.

int GetSum(int *base, int n);

e. 두 수를 바꾸는 함수
두 수를 바꾸는 함수는 호출하는 함수에서 변수의 주소를 전달해야 피호출 함수에서 접근할 수 있겠죠.
그리고 함수 내부에서 무엇을 구하는 것이 아니므로 반환 형식은 필요없겠네요.

void Swap(int *a, int *b);

f. n 개의 정수에서 제일 큰 정수가 있는 메모리 주소를 구하는 함수
마찬가지로 n 개의 정수를 전달하기 위해 정수들이 있는 시작 메모리 주소와 개수를 전달하기로 해요.
그리고 함수 내에서 찾은 제일 큰 정수가 있는 원소의 메모리 주소를 반환해야겠죠.

int *GetMaxPos(int *base, int n);

g. n 개의 정수를 크기 순으로 정렬하는 함수(내림차순, 선택 정렬 알고리즘으로 정렬)

void SelectionSort(int *base, int n);

여기에서도 n 개의 정수를 전달하기 위해 정수들이 있는 시작 메모리 주소와 개수를 전달하기로 해요.
그리고 함수 내에서 무엇을 구하는 것이 아니므로 반환 형식은 필요없겠죠.

65. 테스트 코드 작성하기

이제 콘솔 응용 프로젝트를 생성하여 함수 원형에 맞게 비어 있는 함수를 추가하고 테스트 코드를 작성해 보세요.
함수를 먼저 만들고 테스트 코드를 작성할 수도 있지만 테스트 코드를 먼저 작성하면 팀 작업의 신뢰성을 높일 수 있어요.

먼저 콘솔 응용 프로젝트를 생성하세요.

프로젝트에 main 함수와 테스트 코드를 작성할 Program.c 파일을 추가하세요.
그리고 실습 대상인 함수를 작성할 Common.c 파일과 Common.h를 추가하세요.
소스 파일(.c)에는 함수 정의문을 작성하고 헤더 파일(.h)에는 함수 선언문을 작성할 거예요.
테스트 코드를 작성할 Program.c 파일에서 Common.c 파일에 작성한 함수를 호출하려면 함수 선언문이 필요하죠.
Common.h 파일에는 함수 선언문을 작성할 거예요.

먼저 진입점과 테스트 코드를 작성할 Program.c 파일에 빈 상태의 main 함수를 추가하세요.
물론 Common.h 파일을 포함하여 Common.c 파일에 작성할 함수를 사용할 수 있게 해 줍시다.
◈ Program.c

#include "Common.h"
int main()
{
    return 0;
}

이미 앞에서 약속한 함수 원형에 맞게 Common.h 파일에 함수 선언문을 작성하세요.
그리고 Common.c 파일에는 빈 상태의 함수 정의문을 작성하세요.
컴파일 오류가 없는 상태를 유지하기 위해 반환 형식이 있을 때는 0을 반환하는 코드를 작성하세요.

◈ Common.h

#pragma once
 
//a. 범위 내의 정수 합계를 구하는 함수 
int GetSumInBoundary(int start, int end);
//b. 특정 수가 소수(Prime Number)인지 판단하는 함수
int IsPrime(int num);
//c. 범위 내의 정수중에 소수(Prime Number)의 개수를 구하는 함수
int GetCountIsPrime(int start, int end);
//d. n 개의 정수의 합계를 구하는 함수
int GetSum(int *base, int n);
//e. 두 수를 바꾸는 함수
void Swap(int *a, int *b);
//f. n 개의 정수에서 제일 큰 정수가 있는 메모리 주소를 구하는 함수
int *GetMaxPos(int *base, int n);
//g. n 개의 정수를 크기 순으로 정렬하는 함수(내림차순, 선택 정렬 알고리즘으로 정렬)
void SelectionSort(int *base, int n); 

◈ Common.c

#include "Common.h"
 
int GetSumInBoundary(int start, int end)
{
    return 0;
}
int IsPrime(int num)
{
    return 0;
}
 
int GetCountIsPrime(int start, int end)
{
    return 0;
}
int GetSum(int *base, int n)
{
    return 0;
}
void Swap(int *a, int *b)
{
 
}
int *GetMaxPos(int *base, int n)
{
    return 0;
}
void SelectionSort(int *base, int n)
{
 
} 

이제 여러분은 약속한 함수를 호출하여 정상적으로 작성했는지 확인할 수 있게 테스트코드를 작성하세요.
아직 만들지 않은 함수를 사용하는 테스트 코드를 작성하는 것은 처음 경험하는 이들에게는 낯설고 힘든 작업이 될 수 있어요.

이 부분은 여러분이 생각해서 작성하기 힘들다고 생각하시면 책을 보면서 작성하세요.
어느 정도 책을 보면서 하다가 혼자 할 수 있을 것 같다고 생각하시면 그 때부터는 직접 작성해 보세요.
진입점이 있는 테스트 코드를 작성할 소스 파일에서는 함수마다 테스트하는 함수를 만들어서 호출하는 형태로 작성할게요.

◈ Program.c

#include "Common.h"
void TestGetSumInBoundary(void);
void TestIsPrime(void);
void TestGetCountIsPrime(void);
... 중략 ...
int main()
{
    TestGetSumInBoundary();
    TestIsPrime();
    TestGetCountIsPrime();
    return 0;
}
void TestGetSumInBoundary(void)
{
}
void TestIsPrime(void)
{
}
void TestGetCountIsPrime(void)
{
}
... 중략...

a. 범위 내의 정수 합계를 구하는 함수
사용하는 곳에서 GetSumInBoundary(1,10); 처럼 호출하여 반환 값이 5050이 맞다면 테스트 성공을 출력하고 그렇지 않다면 실패를 출력하면 되겠죠.
물론 현재 함수 정의문은 비어있는 상태이므로 실패를 출력하겠죠.
높은 신뢰성을 추구하기 위해 다양한 경우의 테스트 코드를 작성하는 것은 매우 바람직해요.
여기에서는 단순히 어떻게 테스트 코드를 작성하면 좋은지만 설명하는 수준으로 작성할게요.

void TestGetSumInBoundary(void)
{
    if(GetSumInBoundary(1,100) == 5050)
    {
        printf("GetSumInBoundary 함수 테스트 성공\n");
    }
    else
    {
        printf("GetSumInBoundary 함수 테스트 실패\n");
    }
}

b. 특정 수가 소수(Prime Number)인지 판단하는 함수
여기서는 소수가 아닌 9를 입력 인자로 호출하여 테스트 하는 로직을 작성할게요.

void TestIsPrimeNumber(void)
{
    if( IsPrime(9) == 0)
    {
        printf("IsPrime(9) 함수 테스트 성공\n");
    }
    else
    {
        printf("IsPrime(9) 함수 테스트 실패\n");
    }
}

c. 범위 내의 정수중에 소수(Prime Number)의 개수를 구하는 함수
GetCountIsPrime (5, 20);처럼 호출하여 6이 나오는지 확인하는 코드로 테스트할게요.

if( GetCountIsPrime(5, 20) == 6)
{
    printf("GetCountIsPrime 함수 테스트 성공 \n");
}
else
{
    printf("GetCountIsPrime 함수 테스트 실패 \n");
}

d. n 개의 정수의 합계를 구하는 함수
int arr[6]= {1, 3, 10, 8, 5, 2}; 처럼 정수형을 원소로 하는 배열을 선언하여 배열 이름과 원소 개수를 전달하여 반환 값이 합계와 같은지 확인하세요.

int arr[6] = { 1, 3, 10, 8, 5, 2};
if (GetSum (arr,6) == 29 )
{
    printf("GetSum 함수 테스트 성공\n");
}
else
{
    printf("GetSum 함수 테스트 실패 \n");
}

e. 두 수를 바꾸는 함수
int a=2, b=3; 처럼 선언한 후에 Swap(&a,&b);를 호출하여 값이 바뀌었는지 확인하세요.

int a = 2, b = 3;
Swap(&a,&b);
if( (a==3) && (b == 2))
{
    printf("Swap 함수 테스트 성공 \n");
}
else
{
    printf("Swap 함수 테스트 실패 \n");
}

f. n 개의 정수에서 제일 큰 정수가 있는 메모리 주소를 구하는 함수
int arr[5]= {10, 1100,34,134,100}; 처럼 선언하고 GetMaxPos(arr,5)를 호출하여 반환 결과가 제일 큰 값이 있는 arr+1 인지 확인할게요.

int arr[5]= {10, 1100,34,134,100}; 
if( GetMaxPos(arr,5) == arr+1)
{
     printf("TestGetMaxPos 함수 테스트 성공 \n");
}
else
{
     printf("TestGetMaxPos 함수 테스트 실패 \n");
}

g. n 개의 정수를 크기 순으로 정렬하는 함수(내림 차순으로 정렬, 선택 정렬 알고리즘으로 정렬)
int arr[5]= {10, 1100,34,134,100}; 선언하여 SelectionSort 함수를 호출한 후에 arr의 원소들이 크기 순으로 정렬하였는지 확인할 수 있게 테스트 할게요.

int arr[5]= {10, 1100,34,134,100};
int lcnt=0;
SelectionSort(arr,5);
for(lcnt=0; lcnt<5; lcnt++)
{
    printf("%d \n",arr[lcnt]);
}

여러분은 다양한 형태의 테스트가 필요하거나 다른 방법으로 테스트하는 것이 효과적이라면 테스트 코드를 변경하세요.
여기에서 보여준 코드는 하나의 테스트 예제 코드일 뿐입니다.

66. 구현 (함수 만들기 실습)

이제 하나 하나 구현해 보세요.
여러분은 먼저 함수를 구현해 본 후에 책을 보세요.
어렵고 귀찮아도 구현 전에 논리를 의사코드(pseudo code)나 플로우 차트, UML 등을 이용해서 정리해 보세요.
그리고 구체적으로 구현하는 것이 전체 비용을 줄이는 데 도움을 줄 거예요.

a. 범위 내의 정수 합계를 구하는 함수
int GetSumInBoundary(int start, int end)
start에서 end 구간까지의 정수 합계를 구하기 위해 반복문이 필요하겠죠.
여기서는 for 문을 사용할게요.
반복문에서는 현재 어디까지 더했는지 기억하기 위한 루프(반복문) 카운터 변수와 합계를 기억할 변수가 필요해요.
그리고 반복문에서는 루프 카운터를 1씩 증가하면서 합계에 루프 카운터를 더하면 되겠죠.
물론 반복문을 탈출한 후에는 더한 합계를 반환해야죠.

함수 GetSumInBoundary(start:구간의 시작, end: 구간의 끝)
    sum 을 0으로 초기화
    lcnt 를 0으로 초기화
    lcnt를 start로 대입(for문의 초기 구문)
반복: lcnt가 end보다 작거나 같다면
        sum에 sum+lcnt를 대입
        lcnt를 1 증가(for문의 후처리 구문)
    sum 반환

int GetSumInBoundary(int start,int end)
{
    int sum = 0;
    int lcnt = 0;
    for( lcnt = start; lcnt <= end; lcnt++)
    {
        sum += lcnt;
    }
    return sum;
}

b. 특정 수가 소수(Prime Number)인지 판단하는 함수
int IsPrime (int number)
소수는 1과 자기 자신만을 약수인 자연수죠.
따라서 2부터 전달받은 number보다 작은 수들이 약수인지 확인하는 코드를 반복하면 되겠죠.
반복문에서는 피젯수를 2부터 number보다 작을 때까지 1씩 증가해야 하므로 지역 변수(lcnt)가 필요해요.
반복문 내부에서는 number를 lcnt변수로 나누었을 때 나머지가 0면 lcnt가 약수이므로 소수가 아님을 반환하세요.
반복문을 탈출하였다면 약수를 만나지 않았으므로 소수임을 반환하하세요.
여기서는 소수일 때 1, 아닐 때 0을 반환할게요.

함수 IsPrime(number:판별할 정수)
    lcnt 를 2로 초기화(for문의 초기 구문)
반복: lcnt가 number보다 작을동안
조건: number를 lcnt로 나누었을 때 나머지가 0이면
            0 반환
    lcnt를 1 증가(for문의 후처리 구문)
    1 반환

int IsPrime(int number)
{
    int lcnt = 0;
    for( lcnt = 2; lcnt < number; lcnt++)
    {
        if( (number % lcnt) == 0)
        {
            return 0;
        }
    }
    return 1;
} 

c. 범위 내의 정수중에 소수(Prime Number)의 개수를 구하는 함수
int GetCountIsPrime(int start, int end)
여기에서는 start에서 end 사이의 수가 소수인지 확인하여 소수일 때 카운터를 증가시키는 작업을 수행하면 되겠죠.
특히 특정 수가 소수인지 판별하는 함수는 이미 IsPrime 함수로 작성하였으니 이를 호출하여 구현하세요.

함수 GetCountIsPrime(start: 구간의 시작, end: 구간의 끝)
    count를 0으로 초기화
    lcnt를 start로 초기화(for문의 초기 구문)
반복: lcnt가 number보다 작을동안
조건: lcnt가 소수이면
            count를 1 증가
        lcnt를 1 증가(for문의 후처리 구문)
    count 반환

int GetCountIsPrime(int start, int end)
{
    int lcnt = 0;
    int count = 0;
    for(lcnt = start; lcnt < end; lcnt++)
    {
        if(IsPrime(lcnt))
        {
            count++;
        }
    }
    return count;
}  

d. n 개의 정수의 합계를 구하는 함수
int GetSum(int *base, int n)
먼저 합계를 기억할 변수(sum)이 필요하겠죠.
그리고 반복문을 수행하면서 현재 어느 원소까지 더했는지 기억할 변수(lcnt)가 필요해요.
lcnt 변수는 0부터 n보다 작을 때까지 1씩 증가시키면 되겠죠.
그리고 반복문에서는 현재 합계에 base에서 상대적 거리 lcnt에 있는 원소의 값을 더하세요.
반복문을 탈출한 후에 합계를 반환합시다.

함수 GetSum(base: 더할 정수들이 있는 시작 위치 n:원소 개수)
    sum을 0으로 초기화
    lcnt를 0으로 초기화(for문의 초기 구문)
반복: lcnt가 n보다 작을동안
현재 sum에 base에서 상대적 거리 lcnt의 원소를 더함
    lcnt를 1 증가(for문의 후처리 구문)
    sum 반환

int GetSum(int *base, int n)
{
    int sum = 0;
    int lcnt = 0;
    for(lcnt = 0; lcnt < n; lcnt++)
    {
        sum += base[lcnt];
    }
    return sum;
}

e. 두 수를 바꾸는 함수
void Swap(int *p1, int *p2)
C언어는 함수 호출할 때 인자를 값에 의한 전달 방식을 사용하기 때문에 변수의 주소를 전달하여 간접 연산을 이용하여 두 수를 바꿀 수 있다고 얘기했었죠.
여기에서는 별도의 설명을 하지 않을게요.

void Swap(int *p1, int *p2)
{
    int temp = *p1;
    *p1 = *p2;
    *p2 = temp;
}
 

f. n 개의 정수에서 제일 큰 정수가 있는 메모리 주소를 구하는 함수
int *GetMaxPos(int *base,int n)
n개의 정수에서 제일 큰 정수를 구하기 위해서는 모든 원소의 값을 비교해야겠죠.
일단 맨 앞의 원소를 제일 큰 정수라고 설정하세요.
여기에서는 위치를 찾는 함수이므로 제일 큰 정수가 있는 인덱스를 기억할 거예요.
그리고 다음 원소부터 반복해서 기억하고 있는 제일 큰 정수와 비교하세요.
만약 더 큰 수를 발견하면 제일 큰 정수가 있는 인덱스를 변경하세요.
반복문을 탈출하였을 때 인덱스가 제일 큰 수가 있겠죠.
따라서 base에서 제일 큰 값이 있는 인덱스를 더한 메모리 주소를 반환해야겠죠.

함수 GetMaxPosbase: 정수들이 있는 시작 위치 n:원소 개수)
    max_index를 0으로 초기화
    index를 1로 초기화 (for문의 초기 구문)
반복: index가 n보다 작을동안
조건: base[index]가 base[max_index]보다 크다면
    index를 1 증가(for문의 후처리 구문)
    base에서 max_index를 더한 위치를 반환

int *GetMaxPos(int *base,int n)
{
    int max_index = 0;
    int index = 0;
    for(index=1 ;index< n; index++)
    {
        if(base[index] > base[max_index])
        {
            max_index = index;
       }
    }
    return base+max_index;
} 

g. n 개의 정수를 크기 순으로 정렬하는 함수(내림 차순으로 정렬, 선택 정렬 알고리즘으로 정렬)
void SelectionSort(int *base, int n)
선택 정렬은 제일 큰(작은) 값의 위치를 찾아 맨 앞의 요소를 찾아 교환한 후에 맨 앞의 요소를 제외한 나머지 구간의 요소를 같은 방법을 반복하여 정렬하는 알고리즘이예요.

따라서 정렬할 구간이 남아있다면 반복해서 구간 내에서 최대 값이 있는 위치를 찾아 구간 맨 앞의 요소와 교환하세요.
교환한 후에는 구간 내의 요소 개수를 1 감소하고 구간의 시작 위치를 다음 위치로 이동하세요.
제일 큰 값의 위치를 찾는 부분과 두 수를 교환하는 부분은 이미 작성한 함수를 호출하세요.

함수 SelectionSort: 정수들이 있는 시작 위치 n:원소 개수)
반복: n이 0보다 클 동안
        base에서 n 개의 원소 중에 제일 큰 위치를 찾아 max_pos에 대입
        max_pos와 base 위치의 원소를 교환
    n을 1 감소, base를 다음 위치로 이동(for문의 후처리 구문)

void SelectionSort(int *base, int n)
{
    int *max_pos=0;
    for (   ; n>0 ;  n--, base++)
    {
        max_pos = GetMaxPos(base,n);
        Swap(max_pos, base);
    }
}

67. 정리하기 (함수)

1. 피보나치 수열의 n 항을 구하는 함수를 구현하시오.

더보기
//피보나치 수열의 n 항을 구하는 함수를 구현하시오.
#include <stdio.h>
 
int Fibonacci(int n);
int main(void)
{
    int i;
    for (i = 1; i <= 10; i++)
    {
        printf("%d ", Fibonacci(i));
    }
    printf("\n");
    return 0;
}
int Fibonacci(int n)
{
    if (n < 1)
    {
        return 0;
    }
    if ((n == 1) || (n == 2))
    {
        return 1;
    }
    return Fibonacci(n - 1) + Fibonacci(n - 2);
}

2. 특정 구간 내에 n의 배수의 개수를 구하는 함수를 구현하시오.

더보기
//특정 구간 내에 n의 배수의 개수를 구하는 함수
#include <stdio.h>
int CountMultiple(int n, int s, int e);
int main(void)
{
    printf("1~100사이에 6의 배수의 개수:%d\n", CountMultiple(6, 1, 100));
    return 0;
}
int CountMultiple(int n, int s, int e)
{
    int count = 0;
    for (; s <= e; s++)
    {
        if (s%n == 0)
        {
            count++;
        }
    }
    return count;
}

3. 1에서 n 사이의 수 중에서 랜덤한 수를 m개 발급하는 함수를 구현하시오.

더보기
//1에서 n 사이의 수 중에서 랜덤한 수를 m개 발급하는 함수
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
 
#define MAX_RANDS   1000
 
int MakeRandom(int s, int n, int *base, int m);
int main(void)
{
    int arr[6];    
    int i;
    srand((unsigned)time(0));//랜덤 Seed 값 설정
    if (MakeRandom(1, 45, arr, sizeof(arr) / sizeof(arr[0])) == 0)
    {
        printf("생성 실패\n");
    }
    else
    {
        int asize = sizeof(arr) / sizeof(arr[0]);
        for (i = 0; i < asize; i++)
        {
            printf("%d ", arr[i]);
        }
        printf("\n");
    }
    return 0;
}
int MakeRandom(int s, int n, int *base, int m)
{
    int check[32768] = { 0 };//발급 여부    
    int count = 0;
    int rval;
    int boundary;
 
    boundary = (n - s + 1);//s~n 사이의 수의 개수
    if (m > MAX_RANDS)//m이 최대 발급할 수 있는 개수보다 크면
    {
        return 0;//발급 실패 반환
    }
    if (m > boundary)//m인 범위의 수의 개수보다 크면
    {
        return 0;//발급 실패 반환
    }
    for (count = 0; count < m;count++)
    { 
        do  
        {
            rval = rand() % boundary + s;
        } while (check[rval]); //이미 발급한 수이면 반복
        check[rval] = 1;
        base[count] = rval;
    }
    return 1;    
}

4. 두 수의 최대 공약수를 구하는 함수를 구현하시오.

더보기
//최대 공약수를 구하는 함수 작성
#include <stdio.h>
int FindGCD(int a, int b);
 
int main(void)
{
    int a, b;
    int lcm;
 
    printf("두 개의 정수 입력:");
    scanf_s("%d%d", &a, &b);
 
    lcm = FindGCD(a, b);
    if (lcm == -1)
    {
        printf("최대 공약수를 구할 수 없습니다.\n");
    }
    else
    {
        printf("%d와 %d의 최대 공약수는 %d\n", a, b, lcm);
    }
 
    return 0;
}
 
int FindGCD(int a, int b)
{
    int gcd;
    if (a > b)//a가 b보다 크면
    {
        //두 수를 교환
        int temp = a;
        a = b;
        b = temp;
    }
    for (gcd = a; ; gcd--)
    {
        if ((a%gcd==0)&&(b%gcd == 0))
        {
            return gcd;
        }
    }
    return -1;
}

5. 두 수의 최소 공배수를 구하는 함수를 구현하시오.

더보기
//최소 공배수를 구하는 함수 작성
#include <stdio.h>
int FindLCM(int a, int b);
 
int main(void)
{
    int a, b;
    int lcm;
    
    printf("두 개의 정수 입력:");
    scanf_s("%d%d", &a, &b);
 
    lcm = FindLCM(a, b);
    if (lcm == -1)
    {
        printf("int 형식 표현 범위에서 최소 공배수를 구할 수 없습니다.\n");
    }
    else
    {
        printf("%d와 %d의 최소 공배수는 %d\n", a, b, lcm);
    }
 
    return 0;
}
 
int FindLCM(int a, int b)
{
    int lcm;
    if (a > b)//a가 b보다 크면
    {
        //두 수를 교환
        int temp = a;
        a = b;
        b = temp;
    }
    for (lcm = b; ; lcm += b)
    {
        if (lcm%a == 0)
        {
            return lcm;
        }
    }
    return -1;    
}

6. 두 수의 공약수의 개수를 구하는 함수를 구현하시오.

더보기
//두 수의 공약수의 개수를 구하는 함수
#include <stdio.h>
int CountCD(int a, int b);
int main(void)
{
    int a, b;    
    printf("두 개의 정수 입력:");
    scanf_s("%d%d", &a, &b);
 
    if (a > b)//a가 b보다 크면
    {
        //두 수를 교환
        int temp = a;
        a = b;
        b = temp;
    }
    printf("%d와 %d의 공약수 개수:%d\n", a, b, CountCD(a, b));
 
 
    return 0;
}
int CountCD(int a, int b)
{
    int n;
    int count=0;
    for (n = 1; n <= a ; n++)
    {
        if ((a%n == 0) && (b%n == 0))//n이 a와 b의 약수일 때
        {
            count++;            
        }
    }
    return count;
}

7. 1부터 n 사이에 두 수의 공배수의 개수를 구하는 함수를 구현하시오.

더보기
//1에서 n사이에 두 수의 공배수의 개수를 구하는 함수
#include <stdio.h>
int CountCM(int a, int b,int n);
int FindLCM(int a, int b);
int main(void)
{
    int a, b;
    printf("두 개의 정수 입력:");
    scanf_s("%d%d", &a, &b);
 
    if (a > b)//a가 b보다 크면
    {
        //두 수를 교환
        int temp = a;
        a = b;
        b = temp;
    }
    printf("%d와 %d의 공배수 개수:%d\n", a, b, CountCM(a, b,1000));
 
    return 0;
}
int CountCM(int a, int b,int n)
{
    int i;
    int count = 0;
    int lcm;
    lcm = FindLCM(a, b);
    for (i = lcm; i < n; i += lcm)
    {        
        count++;
    }
    return count;
}
int FindLCM(int a, int b)
{
    int lcm;
    if (a > b)//a가 b보다 크면
    {
        //두 수를 교환
        int temp = a;
        a = b;
        b = temp;
    }
    for (lcm = b; ; lcm += b)
    {
        if (lcm%a == 0)
        {
            return lcm;
        }
    }
    return -1;
}

8. 버블 정렬 알고리즘을 학습하여 n 개의 정수를 정렬하는 함수를 구현하시오.

더보기
//버블 정렬
#include <stdio.h>
#define SWAP(x,y) {int temp; temp=x; x=y; y=temp;}
void bubbl_sort(int *base, int n);
int main(void)
{
    int arr[10] = { 34,23,66,89,22,12,90,26,37,68 };
    int i;
 
    bubbl_sort(arr, 10);
    for (i = 0; i < 10; i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
    return 0;
}
void bubbl_sort(int *base, int n)
{
    int i, j;
    for (i = n; i > 1; i--)//정렬 범위를 좁히면서
    {
        for (j = 1; j < i; j++)//1에서 정렬 범위 i까지
        {
            if (base[j - 1]>base[j])//앞에 원소가 더 크면
            {
                SWAP(base[j - 1], base[j]);//교환
            }
        }
    }
}