본문 바로가기

Coding Tests/백준 온라인

( C )백준 10757(문자열을 사용해 값이 큰 수 더하기)

문제

두 정수 A와 B를 입력받은 다음, A+B를 출력하는 프로그램을 작성하시오.

입력

첫째 줄에 A와 B가 주어진다. (0 < A, B < 10의 만승)

출력

첫째 줄에 A+B를 출력한다.

 

#include<stdio.h>
#include<string.h>

void reverse (char arr[])
{
	int len = strlen(arr);
	for (int i = 0; i < len / 2; i++) { 
		char temp = arr[i];
		arr[i] = arr[len - i - 1];
		arr[len - i - 1] = temp;
	}
}

int main(void) {
	char A[10002] = { 0 }; 
	char B[10002] = { 0 };
	char res[10003] = { 0 }; 
	int carry = 0, i; 

	scanf("%s %s", A, B);
	reverse(A);
	reverse(B);

	int len = strlen(A) > strlen(B) ? strlen(A) : strlen(B); 
    
	for (i = 0; i < len; i++)
	{
		int sum = A[i] - '0' + B[i] - '0' + carry;  
		while (sum < 0) sum += '0';
		
		if (sum > 9) carry = 1;
		else carry = 0;
		res[i] = sum % 10 + '0';
	}
	if (carry == 1) res[len] = '1';
	reverse(res);
	printf("%s", res);
	return 0;
}

#include<string.h> : 문자열 기반함수를 사용할 수 있게끔 헤더선언.

 

void reverse (char arr[ ])  : 배열을 함수의 인자로 전달 받을때 사용 char arr[ ] (매개변수 선언 에서는 char * arr과 동일)   <주의> 문자열을 인자로 받는데, int형을 쓰지 않도록 주의 하자!

 

char A[10002] = { 0 };  : 널문자까지 포함해서 배열의 길이는 10002 ( 왜냐! 10의 1승은 2자리, 10의 3승은 4자리소요, 그래서 10의 만승은 10001자리 수가 나오고, 널문자까지 포함하여서 10002가 배열의 길이)

그리고 널문자(0값으로) 초기화

 

char res[10003] = { 0 };  : 999 더하기 999 하면, 4자리 출력값이 나오고,  9999더하기 9999하면 5자리 출력결과 값이 나옴. 이 res배열은 계산 결과를 저장해줄 배열이므로 10003자리로 길이 설정을 해준다.

 

int carry = 0;   : carry는 자리올림

 

int len = strlen(A) > strlen(B) ? strlen(A) : strlen(B);  : 조건연산자를 사용하였는데,  어느자리 숫자까지 더해야하는지는 큰수의 자릿수 만큼 덧셈이 이루어져야 한다. 예를들어 123 하고 9가 있는데 한자릿수 만큼만 덧셈이 이루어 질수는 없는 노릇이기 때문이다.

 

 A[ i ] - '0' 의 형태는 :문자는 아스키코드로 인해 십진수로 변형될 수 있는데, 각자리(A[ ], B[ ])에 문자 0을 빼주고 그것을 int형 으로 저장해 줌으로써 문자에서 숫자로 저장을 할 수있는것이다.

 

if (sum > 9) carry = 1; : carry는 자리 올림이니 다음 반복문 돌때 1 더해주면 된다...(즉, 자리올림이니까 다음연산에서 1더해주는 것임)

 

res[i] = sum % 10 + '0'; : 예를 들어 9랑 3을 더할때 12란 결과가 나오는데, 이 12를 10으로 나눈 나머지는 2이므로 그자리(그 해당하는 인덱스 넘버)에 들어가야 할 수가 나온다. 

 

reverse(res);  : 뒤집혔던 수를 다시 뒤집어줘 원래 상태로 돌려준다.

 

if (carry == 1) res[len] = '1'; : 다시 문제를 풀던 중 틀린 부분인데, 만약 반복문이 끝날때에 carry의 값이 1이였다면, 자리올림에 의해 가장 앞자리가 1이 되야 한다는 것이다. 그런데 문자열의 앞자리 이므로 숫자 1 이 아닌, '1' 문자 1로 문장을 작성 하여 주는게 옳다.

 

 

void reverse (char arr[ ]) 이 함수를 만들어준 이유는 

   

예를 들어                 

                      1, 2, 3, 4...........번째의 배열 자리라 하고,

              arr1[5]:7 5 3,

              arr2[5]:7 3 4 을 더한다 했을 때,

            결과값:  1 4 8 7  처럼, 자릿수가 증가 하면 배열의 인덱스들이 뒤로 한칸씩 밀려나는 걸 볼 수있다.

 

이러한 이유때문에, 배열요소의 앞과 뒤를 뒤집어줘 이런 불편함 없이 조금 더 편하게 연산과정을 진행 해주려 하고있다.

(거꾸로 뒤집어 연산을 해주면 자리 올림을 통해 조금더 자연스러운 연산을 진행할 수있다.)

 

 

<오래 생각했던 것>

 

res[i] = sum % 10 + '0'; 의 문장에서 '0'을 왜 더해 줄까를 예상보다 조금 오래 생각하였다. 아무렇지 않게 넘어가듯 이해하면 자연스럽게 이해되는듯 했지만, 뭔가 좀 아쉬워 생각을 조금 더 해보았다.

 

우선, 예를 들어서 sum % 10의 값이 4라고 해보자.  그럼 이 4라는 숫자는 문자가 아닌 십진수라는것을 위 코드들을 보면 알 수 있을 것이다.

 

그럼, res[i] = 4+'0'인데 이값은 십진수 상으로는 52이고 문자상으로는 4라고  표현이된다.

처음에는 왜 52라는 십진수를 왜 넣어줄까? 라는 생각을 좀 하였었는데, 우리가  처음 A[i] - '0' 을 통해 숫자형태의 문자에 문자0을 빼줌으로써 그 형태에 해당하는 숫자를 십진수로 얻을 수 있었다.

 

지금은 그와 반대로 십진수 형태의 숫자를 숫자형태의 문자로 변환해주어야 한다. 그러므로 48('0')을 더해줌으로써 다시 십진수에서 숫자형태의 문자로 돌아간것이라 생각할 수있다. '0'을 더해줌으로써 이 문자열안에서 문자 4로 존재할 수 있는것이다. 만약 십진수 4가 그대로 문자로 변환되게 된다면 ^D(EOT)와 같은 표식의 문자가 출력시 나오게 될것이다.

 

<참고>

#include<stdio.h>
#include<string.h>

int main(void)
{
	int arr[6] = { 0 };
	printf("%d\n", sizeof(arr) / sizeof(int));
	char arr2[7] = { 'G','H'};
	printf("%d\n", sizeof(arr2) / sizeof(char));
	char arr3[7] ={'a','ppe'};   
	printf("%d", strlen(arr3));  
	return 0;
}

char arr2[7] = { 'G','H'};
printf("%d\n", sizeof(arr2) / sizeof(char));  의 출력값은? 7이다. 이는 그냥 단순! 배열의 길이를 나타내는것이고,

 

char arr3[7] ={'a','ppe'};  

printf("%d", strlen(arr3));  의 코드는 문자열의 길이를 나타내는것!

즉 apple영단어(알파벳 하나하나 구분되어있는)가있다면 5가 문자열의 길이로 나올것이다. 

 

책으로 공부를 하던도중 함수내에서는 인자로 전달된 배열의 길이를 계산할 수 없다. 라는 사실을 알게되었고, 첫번째 코드블록에서 문자열을 인자로 받고 그에 해당하는 문자열의 길이를 계산하는 것을 볼 수 있는데, 바로 여기서 책과는 조금 다르다 라는 생각을 하였고, 스스로 정리를 조금 해보고자 바로위의 코드를 작성해 보았다.

그 결과 배열의 길이와 문자열의 길이는 다른 개념이다라는 것을 다시 확립하였고,

 정답코드가 이상이 없다는것을 알 수있었다.