백준으로 공부하는 C언어 | 자료형, 데이터 입출력, 연산자

설탕·2024년 3월 12일
0
post-thumbnail

혼자 공부하는 C언어 책의 2장(상수와 데이터 출력), 3장(변수와 데이터 입력), 4장(연산자)을 읽고 간단한 백준 문제들을 풀면서 정리해보았다.

문제 11654. 아스키 코드

풀이

#include <stdio.h>

int main(void)
{
  char ch;

  scanf("%c", &ch); // 주소 연산자 & 붙이기
  printf("%d\n", ch); // 문자를 정수로 출력

  return 0;
}

scanf 함수에서 변수명 지정할 때는 주소 연산자(&) 붙이기

  • &(앰퍼샌드)는 변수의 주소를 구하는 연산자이다.
  • 변수 값을 출력할 때는 변수명만 사용하지만, 입력할 때는 변수명 앞에 &를 붙여야 한다.

아스키 코드

  • 아스키 코드는 컴퓨터에서 필요한 128개의 문자(영문 대소문자, 아라비아 숫자, 특수 문자, 제어 문자 등)를 코드화한 것이다.
    • 예를 들어 소스 코드에 A라는 문자를 사용하면 컴퓨터는 8개의 비트를 01000001과 같은 상태로 저장한다.
  • 문자 상수를 컴파일하면 2진수 형태의 아스키 코드 값으로 번역되어 정수 상수와 같은 방식으로 처리된다.
    • 예를 들어 문자 'A'의 아스키 코드 값은 65이므로 정수 상수 65와 같은 형태로 번역된다.

문제 11382. 꼬마 정민

풀이

#include <stdio.h>

int main(void)
{
  unsigned long a, b, c;
  
  scanf("%lu%lu%lu", &a, &b, &c);
  printf("%lu\n", a + b + c);

  return 0;
}
  • 입력값이 항상 양수로 주어지기 때문에 unsigned 정수 자료형을 사용했다.
  • unsigned int형으로 했더니 통과가 안 되어서 더 큰 값을 저장할 수 있는 unsigned long형으로 바꾸었더니 통과되었다.

자료형(Data Types)과 변환 문자(Format Specifiers)

문자 자료형

자료형크기값의 저장 범위출력 변환 문자
char1 Byte-128 ~ 127%c

정수 자료형

  • int형을 기본적으로 사용한다.
  • 정수 자료형의 크기는 컴파일러에 따라 달라지기도 하며, sizeof 연산자로 확인할 수 있다.
자료형크기값의 저장 범위출력 변환 문자
char1 Byte-128 ~ 127%d
short2 Byte-32,768 ~ 32,767%hd
int4 Byte-2,147,483,648 ~ 2,147,483,647%d
long4 Byte-2,147,483,648 ~ 2,147,483,647%ld
long long8 Byte-(2^63) ~ (2^63)-1%lld

unsigned 정수 자료형

  • 기본값은 signed로 선언되어 양수와 음수를 모두 저장한다.
  • unsigned를 사용해서 양수만 저장하면 두 배 더 넓은 범위의 값을 저장할 수 있다.
자료형크기값의 저장 범위출력 변환 문자
unsigned char1 Byte0 ~ 255%u
unsigned short2 Byte0 ~ 65,535%hu
unsigned int4 Byte0 ~ 4,294,967,295%u
unsigned long4 Byte0 ~ 4,294,967,295%lu
unsigned long long8 Byte0 ~ (2^64)-1%llu

실수 자료형

  • 유효 숫자가 많은 double형을 기본적으로 사용한다.
자료형크기값의 저장 범위출력 변환 문자
float4 Byte-3.4e-38 ~ 3.4e+38%f
double8 Byte-1.7e-308 ~ 1.7e+308%lf
long double8 Byte 이상double형과 같거나 큰 범위%Lf

문제 10869. 사칙연산

풀이

#include <stdio.h>

int main(void)
{
  unsigned int a, b, sum, product, quotient, remainder;
  int difference;

  scanf("%u%u", &a, &b);
  
  sum = a + b;
  difference = a - b;
  product = a * b;
  quotient = a / b;
  remainder = a % b;

  printf("%u\n%d\n%u\n%u\n%u\n", sum, difference, product, quotient, remainder);

  return 0;
}
  • 문제에서 주어진 입력값 조건이 자연수이기 때문에 위의 꼬마 정민 문제와 마찬가지로 unsigned int 자료형을 사용했다.
  • 정수 자료형이기 때문에 나누기(/) 연산자로 몫을 구하고, 나머지(%) 연산자로 나머지를 구할 수 있다. (실수 자료형을 나머지 연산자로 연산하려고 하면 에러가 발생한다.)
  • 두 수의 차는 음수가 될 수 있기 때문에 signed int 자료형으로 선언했다.

unsigned로 저장할 때는 항상 양수만 저장하고 %u로 출력하세요!

그 이유는?

  • 음수는 절댓값을 2의 보수로 저장한다.
    • -1은 4294967295와 똑같이 메모리에 32비트 형태의 11111111 11111111 11111111 11111111로 저장된다.
  • 데이터를 변환할 때 %d는 가장 왼쪽 비트를 부호 비트로 간주하여 10진수로 출력하고, %u는 부호 비트를 고려하지 않고 모든 비트를 10진수로 바꿔 출력한다.
    • %d 변환 문자는 -1을 출력하고, %u 변환 문자는 4294967295를 출력한다.

따라서 변환 문자 unsigned형 변수에 음수를 저장하거나, 큰 양수를 저장하고 %u가 아니라 %d로 출력할 경우 결과값이 예상과 달라질 수 있다.

문제 2743. 단어 길이 재기

풀이

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

int main(void)
{
  char word[101];

  scanf("%s", word); // 배열명에 주소 연산자(&) 붙이지 않음
  printf("%ld\n", strlen(word));

  return 0;
}

char 배열명은 주소 상수

  • 문자열 배열명은 주소 상수이기 때문에 주소 연산자(&)를 붙이지 않는다.
    • cf. 같은 이유로 배열은 선언된 이후에 대입 연산자(=)로 문자열을 입력할 수 없다!
      (word = "apple"; ← 이런 식으로 대입 불가능)

char 배열 크기 = 문자열 길이 + 1

  • 컴파일러가 문자열 끝에 널 문자(\0)를 자동으로 추가한다.
  • 널 문자는 문자열의 끝을 표시하는 문자로, 1바이트를 차지한다.
  • 따라서 문제에서 주어지는 단어의 길이가 최대 100이므로 char 배열 크기는 101로 만들었다.

sizeof vs strlen

처음에는 sizeof 연산자로 단어 길이를 구하려고 했다. 그런데...

  printf("%ld\n", sizeof(word)); // word 변수의 메모리 할당 크기인 101 출력

뭘 입력하든 항상 101이 출력되는 것이었다! 입력받은 문자열 끝에 있는 널 문자와는 상관 없이 sizeof 연산자는 항상 char 배열을 초기화할 때 할당한 크기인 101을 반환했다.

찾아봤더니 strlen 함수를 사용하면 널 문자 전까지 문자열의 길이를 구할 수 있었다. strlen 함수를 사용하기 위해서는 소스 코드에 string.h 헤더 파일을 포함시켜야 한다.

정리:

  • sizeof 연산자는 메모리 할당 크기로, 피연산자의 크기를 바이트 단위로 계산한다.
  • strlen 함수는 문자열의 끝 널 문자(\0)를 만나기 전까지 문자의 개수를 센다.
profile
공부 기록

0개의 댓글