수와 진법을 입력받아 진법을 변환해주는 문제
10진법의 숫자를 입력받아 2~16진수로 변환시켜주는 프로그램입니다.
먼저, `pow` 함수를 쓸 것이므로 `math.h`를 include해줍니다.
```C
#include <stdio.h>
#include <math.h>
```
먼저, 핵심로직에 해당하는 진법 변환 함수를 만들어줍니다.
`0123456789ABCDEF`이라는 문자열을 만들어 각 index가 올바른 digit에 대응되도록 합니다.
`convert` 함수는 새로운 수를 의미하는 `newDigits[]` 배열도 함수 내에서 변경시킵니다.
그래서 `convert` 함수가 새로운 수의 자릿수 `newLength`만 리턴하는데도, `main` 함수에서 새로운 수에 접근이 가능합니다.
그 핵심적인 이유는 포인터를 parameter로 넘겼기 때문인데 Pass by reference와 유사한 효과를 가지므로,
실제 배열 요소 값을 변경하기 때문입니다.
* 파라미터 전달 방식
함수로 parameter를 넘기는 방식은 대표적으로 Pass by Value와 Pass by Reference가 있습니다.
주된 차이는 전달값을 복사해서 값의 형태로 함수로 전달하느냐, 그 실제 값이 저장된 주소를 넘기냐의 차이입니다.
Pass by Value는 값을 복사해서 넘기기 때문에 함수 내에서 그 parameter가 변경되어도 호출한 함수(caller)에 있는 값에는 영향을 주지 못합니다(return하면서 변경된 값을 도로 복사해서 넘겨주는 언어도 있긴 함).
반면, Pass by Reference는 주소값 자체를 넘겨주기 때문에 caller 함수가 사용하는 바로 그 메모리에 직접 접근하여 실제 값을 수정할 수 있고, 함수가 종료되고도 caller 함수에 있는 값은 변경된 상태로 남습니다.
일반적으로 정수, 문자, 실수, 불리언 등의 원시타입(primitive type)은 Pass by Value를, 객체, 배열 등 참조타입에는 Pass by Reference가 이용됩니다.
그러나 사실 C에는 Pass by Reference가 없습니다. 여기서는 문자열의 첫 주소를 가리키는 포인터 `convertedNum`를 넘겼으므로 주소값 자체가 복사되어 넘어갔고, 이는 다른 언어의 Pass by Reference와 유사한 효과를 가지게 되는 것입니다.
```C
int convert(unsigned n, unsigned newBase, char newDigits[]) {
unsigned newLength, rem;
char digits[16] = "0123456789ABCDEF";
newLength = 0; // initialize
do {
rem = n % newBase;
newDigits[newLength++] = digits[rem];
n /= newBase; // division between ints works as Quotient(//) function
} while (n > 0);
return newLength;
}
```
후위 연산자 `++`로 index 증가도 한 큐에 해결해줍니다.
return 되는 값은 최대 index보다 1 큰 값이 되는데, 일반적으로 우리가 length라고 부르는 그 값이 됩니다.
(C는 index가 0에서 시작하기 때문)
다음으로 `main` 함수를 작성해줍니다.
진법 변환이 올바르게 이루어졌는지 검산식도 출력해주려고 합니다.
이를 위해서 `realInt`라는 배열을 만들었습니다.
현재 `convertedNum`에는 `char` 타입이 들어있으므로, 0~9는 사실 '0' ~ '9'가 됩니다.
이를 정수로 바꾸려면 48을 빼주면 됩니다. ('0'의 ASCII 값이 48)
문제는 'A' ~ 'F'인데 이 친구들은 48만 빼서는 안 되므로, 삼항연산자로 분기해서 정수로 바꿔줍니다.
`atoi()` 함수나 `sscanf()` 함수를 이용하거나 `int num = ch - '0';`와 같은 세련된 방법을 써도 됩니다.
```C
int main(void) {
unsigned num, base, convertedLength, validBase; // None of these need be negative
char convertedNum[256];
printf("Number to convert : ");
scanf("%u", &num);
do {
printf("New base to convert (2~16) : ");
scanf("%u", &base );
validBase = (base >= 2 && base <= 16) ? 1 : 0; // whether the base is in 2~16
if (!validBase)
puts("Not a valid base. It should be between 2~16.");
} while (!validBase);
convertedLength = convert(num, base, convertedNum);
printf("Converted -> ");
int i, idx;
unsigned realInt[convertedLength];
for (i = 0; i < convertedLength; i++) {
idx = convertedLength - 1 - i;
printf("%c", convertedNum[idx]);
realInt[i] = (convertedNum[idx] < 58) ? (unsigned)convertedNum[idx] - 48 : (unsigned)convertedNum[idx] - 55;
}
printf("\n");
printf("Real Integer : ");
for (i = 0; i < convertedLength; i++) {
printf("%d ", realInt[i]);
}
printf("\n");
for (i = 0; i < convertedLength; i++) {
printf("%u * %.0f", realInt[i], pow(base, convertedLength - 1 - i));
if (i < convertedLength - 1)
printf(" + ");
else
printf("\n= ");
}
for (i = 0; i < convertedLength; i++) {
printf("%.0f", realInt[i] * pow(base, convertedLength - 1 - i));
if (i < convertedLength - 1)
printf(" + ");
else
printf("\n= ");
}
printf("%u", num);
return 0;
}
```
`pow(a, b)` 함수는 엑셀의 `a^b`나 파이썬의 `a ** b`에 해당하는 승수 함수입니다.
`pow` 함수는 `float`를 리턴하므로 `%.0f`를 사용하여 정수와 비슷하게 표현해주어야 합니다.
실행결과는 아래와 같습니다.
'Programming Languages > C' 카테고리의 다른 글
[C] 랜덤으로 생성된 몸무게들 중 최솟값 찾기 (0) | 2024.08.23 |
---|---|
[C] 별표 피라미드 만들기 (0) | 2024.08.20 |
[C] 3개 정수의 중앙값을 구하기 (0) | 2024.08.19 |
[C] 3개 정수 중 최댓값 구하기 (0) | 2024.08.19 |
[C] 내 컴파일러의 C표준 버전 확인하기 (0) | 2024.08.18 |