[C] 형변환(Type Casting)과 연산자 우선순위 (14626 - ISBN)

김태희·2025년 7월 2일
post-thumbnail

14626 - ISBN

BAEKJOON : 14626 - ISBN


#include <stdio.h>

int main() {
  char check;
  int num[13] = {0,}, sum = 0, flag, result;

  for (int i = 0; i < 13; i++) {
    scanf("%c", &check);
    if (check == '*')
      flag = i;
    else
      num[i] = check-48;
  }
  for (int i = 0; i < 13; i++) {
    if(i!=flag){
      if (i % 2 == 1)
        sum += num[i] * 3;
      else
        sum += num[i];
    } 
  }
  if (flag % 2 == 0) { // 1을 곱하는 경우
    for(int i=0; i<10; i++){ 
      if((sum+i)%10==0){
        printf("%d", i);
      }
    }
  } else { // 3을 곱하는 경우
    for(int i=0; i<10; i++){ 
      if((sum+3*i)%10==0){
        printf("%d", i);
      }
    }
  }
  return 0;
}

오랜만에 알고리즘 문제를 풀어봤더니 내가 생각한대로 동작을 안했다.

디버깅 과정에서 배운 내용을 복습겸 정리해보려고 한다.


형변환(Type Casting)

형변환은 데이터의 자료형을 다른 자료형으로 바꾸는 것이다.

예를 들어 정수 int를 문자 char로 바꾸는 식이다.

1. 자동 형변환 (Implicit Type Conversion)

컴파일러가 "알아서" 해주는 형변환을 자동 형변환이라고 한다.

주로 데이터 손실이 없는 방향으로, 즉 더 작은 자료형이 더 큰 자료형으로 바뀔 때 일어난다.

규칙
charintlongfloatdouble
(더 표현 범위가 넓고 정밀한 쪽으로 자동 변환)

언제 일어나는가?
서로 다른 자료형을 가진 변수끼리 연산할 때 발생한다.

    #include <stdio.h>

    int main() {
        int a = 10;
        double b = 3.0;

        // a(int)가 b(double)와 계산되기 위해 
        //컴파일러에 의해 임시로 double형으로 자동 형변환된다
        // 10 -> 10.0 으로 바뀐 뒤에 3.0과 더해진다
        printf("결과: %f\n", a + b); // 결과: 13.000000

        return 0;
    }

이때 큰 자료형을 작은 자료형에 대입하면 데이터 손실이 발생할 수 있다.

    int c = 3.141592; // double형 실수를 int형에 넣으려고 함
    printf("%d\n", c); // 소수점 이하가 모두 잘리고 '3'만 저장된다
    

2. 명시적 형변환 (Explicit Type Casting)

개발자가 강제로 자료형을 바꾸는 것이다.

데이터 손실을 감수하고서라도 형변환이 필요할 때 사용한다.

사용법
(바꿀_자료형)변수_또는_값

언제 사용하는가?
가장 대표적인 예시는 정수 나눗셈의 결과를 실수로 얻고 싶을 때 사용한다.

 
 #include <stdio.h>

 int main() {
     int a = 10;
     int b = 3;

     // (1) 잘못된 경우
     // 정수와 정수의 나눗셈 결과는 무조건 정수(몫)이다.
     printf("잘못된 계산: %f\n", a / b); // 3.000000 같은 이상한 값이 나옴

     // (2) 올바른 경우 (명시적 형변환 사용)
     // 변수 a를 연산 순간에만 잠시 double형으로 강제 변환한다.
     // (double)a / b  ->  10.0 / 3  ->  double과 int의 연산이 됨
     // b는 자동으로 double형으로 '자동 형변환'되어 계산된다.
     printf("올바른 계산: %f\n", (double)a / b); // 결과: 3.333333

     return 0;
 }
 

Int형과 Char형 변수 사이의 형변환

위의 형변환에 대해서는 잘 알고 있었지만 Int와 Char 사이의 형변환을 잘 이해하지 못해서 문제를 틀렸다.

(int)'5'= 53

(int)char 형변환이 잘 안되길래 더 공부해봤다.

알고보니 형변환은 아주 잘 되고 있는 게 맞지만, 우리가 기대하는 방식이 아니었다.

왜 (int)'5'는 5가 아닐까 ?

컴퓨터는 '문자'를 그대로 저장하지 못하기 때문에 숫자를 사용한다.

이때 어떤 숫자가 어떤 문자를 뜻할지 약속한것이 아스키(ASCII) 코드이다.

C언어에서 char 자료형은 사실 문자가 아니라 '문자에 해당하는 아스키 코드'를 저장하는 8비트 정수형이다.

우리가 char c = '5'; 라고 쓰면,

컴퓨터는 변수 c에 '문자 5'에 해당하는 아스키 코드 값인 53을 저장한다.

'0' 48
'1' 49
'2' 50
'3' 51
'4' 52
'5' 53
... ...
'9' 57

따라서 (int)c 라고 형변환을 하면, c에 저장된 값 53을 그냥 더 큰 정수 자료형인 int로 옮겨 담는 것이다.

이러한 원리 때문에 값이 바뀌지 않고 53이 그대로 유지되는 것이다.

올바른 형변환 방법

1. 한 글자 숫자('0' ~ '9')를 바꿀 때: 아스키 코드 값 빼기

가장 기본적이고 빠른 방법으로 위의 알고리즘 문제에서도 사용되었다.

'5' - '0' → 53 - 48 → 5

'8' - '0' → 56 - 48 → 8
#include <stdio.h>

int main() {
    char c1 = '7';

    // 방법 1: '0' 문자를 빼기 (가장 추천하는 방식, 직관적이다)
    int num1 = c1 - '0';

    // 방법 2: 48 숫자를 빼기 (결과는 같지만, 48이 뭔지 모르면 헷갈림)
    int num2 = c1 - 48;

    printf("문자 '7'은 숫자 %d 입니다.\n", num1); // 결과: 문자 '7'은 숫자 7 입니다.
    printf("문자 '7'은 숫자 %d 입니다.\n", num2); // 결과: 문자 '7'은 숫자 7 입니다.

    return 0;
}

2. 문자열("123")을 숫자로 바꿀 때: atoi() 함수

여러 글자로 이루어진 숫자 문자열을 한 번에 정수로 바꿀 때 사용한다.

atoiASCII to Integer 의 줄임말이다.

stdlib.h 헤더 파일에 포함된 함수로, 숫자 문자열의 시작 주소를 받아서 정수(int)로 변환해 돌려준다.

#include <stdio.h>
#include <stdlib.h> // atoi 함수를 쓰려면 꼭 포함해야 함!

int main() {
    char str[] = "14626"; // 큰따옴표로 묶인 문자열 (내부적으로는 char 배열)

    int num = atoi(str);

    printf("문자열 \"%s\"는 숫자 %d 입니다.\n", str, num); // 결과: 문자열 "14626"는 숫자 14626 입니다.
    printf("계산도 가능: %d * 2 = %d\n", num, num * 2); // 결과: 계산도 가능: 14626 * 2 = 29252

    return 0;
}

atoi는 char c = '5' 같은 단일 문자 변수에는 직접 쓸 수 없다.

항상 char 배열, 즉 문자열을 인자로 넣어줘야 한다.


C언어 연산자 우선순위 (Operator Precedence)

연산자 우선순위를 기존에도 알고 있었지만 연산이 많아지니까 헷갈려서 정리해보겠다.

C언어도 연산자마다 정해진 계산 순서가 있다.

아래 표는 위에서 아래로 갈수록 우선순위가 낮아진다.

같은 줄에 있는 연산자들은 우선순위가 같다.

우선순위연산자 종류연산자결합 방향
1 (최고)후위(postfix), 구조체() [] . -> ++ --L → R
2단항(unary)++ -- + - ! ~ * & (type) sizeofR → L
3곱셈/나눗셈* / %L → R
4덧셈/뺄셈+ -L → R
5비트 시프트<< >>L → R
6관계< > <= >=L → R
7등가== !=L → R
8비트 AND&L → R
9비트 XOR^L → R
10비트 OR``
11논리 AND&&L → R
12논리 OR`
13조건(삼항)?:R → L
14대입= += -= *= /= %= &= ^= `= <<= >>=`
15 (최저)쉼표(순차),L → R

조금이라도 헷갈리면 무조건 괄호 ( )를 사용하는것이 좋다.

괄호를 사용하면 우선순위가 가장 높기에 먼저 실행되고 가독성도 좋아진다.

0개의 댓글