C언어- AtoI함수 없이 문자를 숫자로 바꿔보자!! (String->Positive or Negative Number)

우리는 c언어를 통해 생각보다 많이 문자를 숫자로 바꿉니다.

오늘은 Atoi함수없이, 문자열를 정수로 바꾸는 방법을 알아 봅시다!

‘/’ 문자를 이용해서 쉽게 해결할 수가 있습니다.

글이 길더라도 이해만 하면 짧은 소스로 문제를 쉽게 해결할 수 있을 것입니다!!!

int main(void) {
	char s[10] = "";
	int num = 0;
	int tmp = 0;

	gets(s);

	// 문자 끝에 오는 널 문자 -> '/'로 바꾸기 
        s[strlen(s)] = '/';

	while ((tmp = get_symbol(s)) != '/')
		num = 10 * num + tmp;
	printf("처리 결과: %d", num);
}

main함수부터 살펴 봅시다!

s문자형 배열은 앞으로 사용자로부터 입력받을 문자들이 저장될 배열입니다!

num변수는 계속 더해질 변수입니다. 계속 더해서 최종적으로 우리가 원하는 정수를 나오게 할 것입니다!

tmp변수는 문자 하나를 숫자로 바꿨을 때 해당되는 정수입니다!

먼저 gets()함수를 통해 s배열에 정수 형태의 문자열을 넣습니다.

그런데 // 문자 끝에 오는 널 문자 -> ‘/’로 바꾸기 <- 이 부분은 왜 필요한 것일까요?

우리는 보통 문자 끝에 널 문자가 오니까 ‘널 문자가 오기 전까지 s배열을 처리하면 되겠지’ 라고 생각합니다. 하지만 널 문자는 (int)0과 같습니다. 즉 널 문자로 처리하면 컴퓨터는 “7530”을 “753”까지만 인식합니다.

하지만 문자형 배열을 이해하면 다음과 같이 해결할 수 있습니다. ->

문자의 개수를 인덱스로 가지는 원소를 ‘/’으로 대치하자!!

예를 들어 사용자가 “123”을 입력했다고 가정합시다.

그러면 문자가 ‘1’ ‘2’ ‘3’ 이렇게 3개라고 strlen()함수는 반환합니다.

이 때, ‘1’ ‘2’ ‘3’ ‘/’ <- 인덱스 3에 해당하는 것(‘\0’) ‘/’로 바꾸고 문자의 끝이 ‘/’이다! 라고 생각하면 기존의 수에 전혀 영향을 끼치지 않습니다!!

s[strlen(s)] = ‘/’; 이 위에서 설명한 소스입니다!!

이후 배열의 요소를 반환하는 함수( get_symbol )를 이용합시다! 이 함수는 첫 번째 호출하면 s[0]을 반환하고 두 번째 호출하면 s[1]을 반환하는 유용한 함수입니다. 필자는 이 함수가 정수를 반환하도록 작성하였습니다.

문자형 배열의 끝에는 ‘/’문자가 오는 것을 생각해서 tmp가 ‘/’문자가 오기 전까지 while조건은 만족됩니다.

( num=10*num+tmp ) <- ‘=’앞에 있는 num은 다음의 num이고 ‘=’뒤에 있는 num은 현재의 num입니다.

s데이터가 “123”이라고 했을 때, 처음 tmp값은 1이 될 것이고 num=10*num+tmp 에 대입하면 ->

1=10*0+1 (1)

12=10*1+2 (2)

123=10*12+3 (3)

이 되서 최종적으로 num은 s데이터의 정수 형태인 123과 같아 지는군여!!

int get_symbol(char *s) {
	static int idx = 0;

	// 음수가 올 때 처리 
	if (s[0] == '-') {
		if (s[idx+1] == '/') // 음수 처리 중 마지막 '/'문자가 올 때!
			return '/';
		return -(s[++idx] - '0');
	}

	// 양수나 0이 올 때 처리 
	else {
		if (s[idx] == '/') // 양수,0 처리 중 마지막 '/'문자가 올 때! 
			return '/';
		return s[idx++] - '0';
	}
}

이제 get_symbol함수를 살펴 봅시다!

idx변수는 static처리가 되서 함수가 2번 이상 호출되면 초기화(초깃값 설정)가 되지 않습니다. 즉 처음에 0으로 초기화되고 idx++이 됐다면 다음에는 1이 되겠죠? 이 변수는 s배열의 인덱스로 사용할 것입니다!

좀 더 쉬운 else문을 먼저 살펴 봅시다!

만약 s배열 idx인덱스에 해당하는 값이 ‘/’ 문자이면 문자열이 끝났다는 것을 의미합니다. 이 때는 ‘/’을 반환해서 while조건을 벗어 납시다!!

그렇지 않다면 밑에 있는 반환문이 성립하는군여

=> s배열 idx인덱스에 해당하는 값을 정수로 바꿔서 리턴 후 idx를 1 올린다

s배열 데이터가 “123”일 때를 기준으로 반환하는 것을 따져 봅시다!

idx=0 -> s[0]-‘0’=1 반환 -> idx=idx+1

idx=1 -> s[1]-‘0’=2 반환 -> idx=idx+1

idx=2 -> s[2]-‘0’=3 반환 -> idx=idx+1

idx=3 -> s[3]=’/’ -> ‘/’ 반환

위와 같이 1,2,3,’/’이 차례차례 tmp로 가게 됩니다!

마지막으로 if문을 살펴 봅시다!

	// 음수가 올 때 처리 
	if (s[0] == '-') {
		if (s[idx+1] == '/') // 음수 처리 중 마지막 '/'문자가 올 때!
			return '/';
		return -(s[++idx] - '0');
	}

음수가 온다면 s배열 인덱스 0에 해당하는 값은 ‘-‘가 될 것입니다. 이런 조건을 세우면 두 번째 get_symbol()이 호출되서 다음 인덱스로 넘어가도 컴퓨터가 음수인 것을 확인하고 일을 진행합니다!

-(s[++idx] – ‘0’) <- 이 소스를 살펴 보면 else문과는 달리 전위 연산자가 쓰입니다. 양수 처리할 때는 idx가 0일 때부터 값을 넘겨 줘야 하지만 음수 처리는 idx가 1일 때부터 값을 넘겨 줍니다. 따라서 먼저 idx값에 1을 더합니다.

음수 처리를 하다가 ‘/’ 문자가 오면 모두 처리했다는 것을 의미합니다. 이전에 전위 연산자를 이용했으니, idx+1에 해당하는 값이 ‘/’ 문자인지 확인하면 됩니다!

s배열 데이터가 “-123″일 때를 기준으로 반환하는 것을 따져 봅시다!

idx=0 -> s[0]=’-‘ 확인

idx=idx+1 -> idx=1 -> -(s[1]-‘0’)=-1반환

idx=idx+1 -> idx=2 -> -(s[2]-‘0’) =-2 반환

idx=idx+1 -> idx=3 -> -(s[3]-‘0’)=-3반환

idx+1=4 -> s[4]=’/’ -> ‘/’ 반환

위와 같이 -1,-2,-3,’/’이 차례차례 tmp로 가게 됩니다!

#include <stdio.h>
int get_symbol(char *s);

int main(void) {
	char s[10] = "";
	int num = 0;
	int tmp = 0;

	gets(s);

	// 문자 끝에 오는 널 문자 -> '/'로 바꾸기 
	s[strlen(s)] = '/';

	while ((tmp = get_symbol(s)) != '/')
		num = 10 * num + tmp;
	printf("처리 결과: %d", num);

}

int get_symbol(char *s) {
	static int idx = 0;

	// 음수가 올 때 처리 
	if (s[0] == '-') {
		if (s[idx+1] == '/') // 음수 처리 중 마지막 /문자가 올 때!
			return '/';
		return -(s[++idx] - '0');
	}

	// 양수나 0이 올 때 처리 
	else {
		if (s[idx] == '/') // 양수,0 처리 중 마지막 /문자가 올 때! 
			return '/';
		return s[idx++] - '0';
	}
}

전체 소스입니다.

아래는 실행결과입니다!

참고로 출력 소스는 printf(“처리 결과: %d”, num); 가 됩니다!!

< 양수로 처리를 하였을 때 >
<음수로 처리를 하였을 때>
< 0으로 처리를 하였을 때 >

s배열 크기가 10이면 양수는 최대 10^8자리까지, 음수는최소 -10^7자리까지 처리가 가능하겠군요!

< 본 강좌를 응용 제작한 함수 링크: https://shacoding.com/2019/08/01/c%ec%96%b8%ec%96%b4-%eb%ac%b8%ec%9e%90%ec%97%b4%ec%97%90%ec%84%9c-%ec%88%98%eb%a7%8c-%eb%b9%bc%ea%b8%b0-%ed%95%a8%ec%88%98-%ec%a0%9c%ea%b3%b5/ >

< I use Korean to save time on lecture or explanation. If you need an explanation, please send an email or comments!! >

Leave a Reply

Your email address will not be published. Required fields are marked *