- 자료형(data type)
- 자료형 : 변수가 가질 수 있는 값들의 종류. 데이터의 종류. 데이터 타입.
* C언어는 자료형이 엄격하기로 유명하다고 한다.
- 자료형 구별은 귀찮을 수 있지만, 이러한 특징 때문에 C언어로 작성된 프로그램의 실행 속도가 빠르다.
- C언어에서는 변수 선언시 반드시 자료형을 명확히 적어줘야 함(반면, 파이썬은 변수의 자료형을 적지 않아도 됨).
- 정수형으로 선언된 변수는 정수만을 저장 가능, 부동소수점형은 실수만을 저장 가능, 문자형은 하나의 문자만을 저장 가능.
- 각 자료형은 정해진 비트 개수를 갖고 있다. 비트 개수에 따라 나타낼 수 있는 수의 범위가 달라짐.
- 자료형의 크기
- sizeof 연산자를 사용하며 자료형의 크기를 알 수 있다. sizeof는 변수나 자료형의 크기를 바이트 단위로 변환한다.
ex) int x; printf("변수 x의 크기: %d\n", sizeof(x)); //변수 x의 크기: 4라고 출력됨.
참고) 문자는 'a'와 같이 작은따옴표로 나타냄. 문자형 저장시 그냥 a라고 하면 컴파일러는 a를 변수 이름으로 생각함.
- 다양한 자료형 사용 이유
- 물건이 상자보다 크면 들어가지 않을 것이고, 물건이 상자보다 너무 작으면 공간 낭비.
- 예를 들어, 자료가 1~10까지의 정수로만 변경되고 음수 값을 갖지 않을 것이라면 unsigned 자료형을 선택하는 것이 좋음.
- 자료형 선택은 귀찮을 수 있지만, 이것 덕분에 C는 매우 가볍고 효율적인 코드를 생성 가능하다.
참고) 일부 프로그래밍 언어(파이썬, 자바스크립트)에서는 하나의 변수에 모든 타입의 값을 저장할 수도 있다. 하나의 변수에 모든 종류의 값을 저장하려면 필수적으로 객체 개념을 사용하여야 한다. 입문자들에게는 친절하고 편리한 방법이지만 오류 발생 쉽고 비효율적인 방법이다.
- 상수(constant) :3.14와 같이 실행 중에 변경되지 않는 값.
- 프로그램에서 값을 저장하는 공간은 변수와 상수로 나눌 수 있다.
- 변수(variable)는 한 번 값이 저장되었어도 언제든지 다시 다른 값으로 변경 가능. 상수는 한 번 정해지면 변경할 필요가 없다. 상수도 자료형을 가지고 있다.
- 정수형 : 가장 기본적인 자료형으로, 정수를 저장할 수 있다.
- 정수형에는 다음과 같은 자료형이 있다.
- short : 16비트(2바이트)
- int : 32비트(4바이트)
- long : 32비트(4바이트)
- long long : 64비트(8바이트)
- 위 자료형이 표현할 수 있는 정수의 범위 계산 방법 : short는 총 16비트로 값을 표현하는데, 각 비트마다 0 또는 1이 올 수 있으므로 2의 16제곱가지의 숫자를 표현 가능. 첫 비트는 부호를 나타냄. 따라서 한 비트는 제외되어야 하고, -32,768에서 +32,767까지의 정수 표현 가능(2의 15제곱은 32,768이고, 0때문에 +32,768없음).
참고) 비트(bit)와 바이트(byte) : 컴퓨터에서 사용하는 정보의 최소단위를 비트라고 함. 컴퓨터에서는 이진수를 사용하며, 비트는 이진수의 하나의 자릿수가 되어 0이 되거나 1일 수 있다. 8개의 비트가 모인 것을 바이트라고 한다.
참고) limit.h 헤더 파일을 이용하면 자료형이 나타낼 수 있는 범위를 알 수 있다. 여기에는 각 자료형은 최댓값과 최소값을 기호 상수로 정의해 놓았다. 예를 들어서 int형의 최댓값은 INT_MAX로, 최소값은 INT_MIN으로 알 수 있다.
참고) 상황별 사용하면 좋은 정수 타입 : 32,767 이상 또는 -32,767 이하 값들을 필요로 한다면 long형, 메모리 공간을 줄여야 한다면 short형, 일반적인 경우 int형, 음수 사용하지 않는 경우 unsigned형
- unsigned 수식자 : unsigned는 변수가 음수가 아닌 값만을 나타낸다는 것을 의미한다. 음수가 제외되면 같은 비트로 더 넓은 범위의 양수를 나타낼 수 있다는 장점이 있다. 예를 들어, 원래의 short형은 -32,768에서 +32,767까지 정수 표현 가능이라면, unsigned short형은 0에서 65,535까지의 정수를 표현 가능.
참고) unsigned int = unsigned, short int = short, long int = long
- 오버플로우 : 변수가 나타낼 수 있는 범위를 넘는 숫자를 저장하려고 할 때 발생한다.
- 오버플로우가 발생하면 다시 처음으로 돌아간다.
ex) short형 변수 32,767에 1을 더하면 -32,768이 된다.
- 오버플로우가 발생하더라도 컴파일러는 아무런 경고를 하지 않는다.
- 음수의 표현 방법 : 컴퓨터에서 숫자는 2진수로 표현, 양의 정수는 10진수를 2진수로 변환하여 표시하면 된다. 음수는 2의 보수로 나타낸다.
- 2의 보수 : 해당 정수의 1의 보수에 1을 더한 값으로 구하기 가능.
* 1의 보수는 이진수의 각 비트를 반전시키는 것임.
ex) -7의 절댓값인 7을 이진수로 표현(00000111), 1의 보수 구하기(11111000), 1의 보수에 1을 더하기(11111001).
- 음수를 2의 보수로 나타내면, 뺄셈 연산 (7-7)을 덧셈 연산 (7+(-7))로 대체할 수 있기 때문에, 하드웨어 회로 단순화 가능.
- 00000111(7)과 11111001(-7)을 더하면 1 00000000(0). 최상위 비트에서 올라오는 캐리 비트만 무시하면 됨,
- 또, 1의 보수에서 문제였던 양의 0(00000000)과 음의 0(10000000)이 발생하지 않는다.
- 정수형 상수 : 정수 상수는 12나 100과 같이 프로그램 안에 직접 입력하면 된다.
ex) int x; x = 3; 에서 3, int x; x = 2L; 에서 2L이 정수 상수
- 정수 상수는 기본적으로 int형으로 간주됨.
- 만약 상수의 자료형을 프로그래머가 지정하고 싶은 경우는 접미사를 붙인다.
ex) 123L (123이라는 상수를 long형으로 간주)
ex) 123U (unsigned형)
- 접미사
- u 또는 U : unsigned int형
- l 또는 L : long형
- ul 또는 UL : unsigned long형
- 정수 상수는 10진법뿐만 아니라 8진법이나 16진법으로도 표기가 가능함.
- 8진법으로 표기하려면 앞에 0을 붙이면 된다.
- 16진법으로 표기하려면 앞에 0x를 붙이면 된다.
* 16진법은 0~9까지의 10개의 숫자, A~F까지의 6개의 문자를 추가하여 표현하는 방법.
ex) 41719(10진수) > 0xA2F7(16진수). 0xA2F7(16진수) = 10*16의 3제곱 + 2*16의 2제곱 + 15*16의 1제곱 + 7*16의 0제곱 = 41719(10진수)
* 16진수에서 하나의 자릿수는 4비트에 해당함.
ex) 0x0f(16진수) > 0000 1111(2진수)
- 정수형 값을 10진수로 출력시 형식 지정자로 "%d" 사용, 8진수로 출력시 "%#o", 16진수로 출력시 "%#x" 사용.
- 기호 상수(#define 이용) :
- 보통 상수는 변수와 달리 이름이 없음. 이름 없는 상수는 리터럴 상수(literal)라고 함. 상수에 이름을 붙일 수 있다. 기호 상수(symbolic constant)는 상수를 기호로 표현한 것.
ex) #define EXCHANGE_RATE 1120
- 보통 #define 문장은 프로그램의 맨 첫 부분에 모여 있다. #define이 들어가는 문장은 전처리기(preprocessor)가 처리한다. 전처리기는 코드에서 기호 상수의 이름을 전부 찾아서 상수를 1120으로 바꾼다.
- 리터럴 상수에 비해, 기호 상수는 프로그램을 읽기 쉬워진다는 장점이 있다.
ex) won = EXCHANGE_RATE * dollar; 가 won = 1120 * dollar; 보다 이해가 쉬움.
- 리터럴 상수에 비해, 기호 상수는 동일한 상수를 여러 곳에서 사용하는 경우, 값을 쉽게 변경할 수 있다는 장점이 있다.
ex) 위 예시에서 환율이 1050으로 변경된 경우, 리터럴 상수 사용시에는 일일이 바꿔줘야한다. 그러나 기호 상수 사용시 기호 상수의 정의만 변경하면 된다.
- 기호상수(const 이용) :
- 변수 선언 앞에 const를 붙이면 상수가 됨.
ex) const int EXCAHNGE_RATE = 1120;
- const는 constant의 약자로서, 변수의 값이 변경되지 않는다는 의미.
- const로 선언된 변수는 딱 한 번만 값을 지정 가능.
- 입출력 형식 지정자 : printf()나 scanf() 함수에서 정수형을 입출력하는 형식 지정자는 다음과 같음.
- short : %hi (출력 시에는 %d도 가능)
- int : %d
- long : %d
- long long : %lld (입력시 특히 반드시 %lld 사용)
참고) size_t 형식 출력시 %zu 사용, sizeof 연산자가 반환하는 값의 자료형이 size_t. 형식 지정자 앞에 #이 붙으면 8진수인 경우에는 앞에 0을 출력하고 16진수인 경우에는 앞에 0x를 출력함.
- 부동소수점형 : C에서는 부동소수점형 방식으로 실수를 표현한다. 부동소수점은 소수점의 위치가 고정되어 읺지 않으며, 가수와 지수를 사용하여 실수를 표현한다. 가수는 유효숫자, 지수는 소수점의 위치를 나타낸다.
ex) 12345(10진수) = 1.23450*10의 4제곱(가수*(밑수의 4제곱, 4는 지수))
- C에서는 float, double, long double의 3가지 부동소수점 자료형이 있다. PC에서 double과 long double은 같다.
- float은 약 6개, double은 약 16개의 유효 숫자를 가질 수 있다. 부동소수점형은 비트의 개수가 제한되어 있으므로 정확하게 값을 저장하기가 어려운 경우가 있다.
* 유효 숫자 : 믿을 수 있는 의미 있는 숫자.
ex) 2,696을 십의 자리에서 반올림하면 2,700이다. 여기서 2와 7은 의미 있는 숫자이다. 반면 뒤에 붙은 00은 단순히 자릿수를 나타내는 데 사용된다. 유효 숫자의 개수는 소수점의 위치와는 상관이 없다. 2700을 2.7e3이라고 표현해도 유효 숫자는 역시 2개이다.
- 부동소수점형은 소수점의 위치가 떠서 움직인다는 의미에서 부동소수점수라고 한다.
- 부동소수점형 상수 : 표기 방법에는 다음과 같이 두 가지가 있다.
- 하나는 소수점 표기법으로 12345.6과 같이 우리에게 친근한 소수점을 이용하여 표현하는 방법이다.
- 두 번째 방법은 지수 표기법으로 지수를 이용하여 표기하는 방법이다. 즉 12345.6은 1.23456*10의 4제곱으로 표기가 가능하고 이것을 C에서는 1.23456e4로 표기한다. 지수 부분은 E나 e를 사용하여 표기한다.
- 정수여도 2.0처럼 뒤에 소수점 붙이면 부동소수점형 상수로서 간주되어 double형이 된다.
- 지수 표기법슨 주로 매우 큰 수나 작은 수 표기에 유용.
- 부동소수점형 상수는 기본적으로 double형으로 간주됨. float형 상수를 만들려면 상수 끝에 f나 F를 붙여주면 된다.
ex) 3.141592F
ex) 유효한 부동소수점형 상수 : 1. .28 9.26E3 0.62e-7
- 부동소수점형의 한계를 알려주는 헤더 파일 존재 : float.h 헤더 파일에 있는 FLT_MIN과 FLT_MAX는 float로 나타낼 수 있는 가장 작은 값과 가장 큰 값을 의미함. 비슷하게 double형에 대해서도 DBL_MIN과 DBL_MAX가 정의되어 있음.
- 형식 지정자 :
- float형의 값을 출력 또는 입력하려면 형식 지정자로 "%f"를 사용.
- double형의 값을 입출력하려면 "%lf"를 사용. double형의 값을 입력받을 때 "%lf"를 사용하지 않으면 값이 이상하게 저장됨.
- 출력할 때 소수점 이하 자릿수 지정 가능.
ex) 소수점 2자리까지만 출력하려는 경우 : printf("%.2lf", result); 와 같이 사용하면 됨.
참고) float과 같은 실수를 int 같은 정수에 넣을 경우, 컴파일러는 경고를 한다. 실수 중에서 소수점 이하는 없어지고 정수 부분만 정수 변수에 대입된다.
- 오버플로우(overflow) : 변수에 대입된 수가 너무 커서 변수가 저장할 수 없는 상황.
- 언더플로우(underflow) : 수가 너무 작아서 표현하기가 힘든 상황. 오버플로우와 반대의 상황.
* 실수의 경우, 오버플로우 발생시 컴파일러는 해당 변수에 무한대를 의미하는 특별한 값을 대입하고 printf()는 이 값을 inf라고 출력한다.
- 부동소수점형은 부정확할 수도 있다.
- 0.1을 float형으로 소수점 이하를 20자리로 출력하면, 0.1의 값이 정확하게 출력되지 않는다.(0.10000000149011611938) 이진법으로는 정확하게 나타낼 수 없는 값들이 있기 때문이다. 0.1도 그 중 하나이다.
- 십진법에서 1/3을 정확하게 나타낼 수 없는 것과 같다.(0.3333...이 무한 반복됨)
- 이진법에서 어떻게 해도 0.1 정확하게 표현 불가. 반올림 하면 실용적으로 사용은 가능하다.
참고) 헤더파일 math.h에는 pow()함수와 sqrt()함수가 있다. pow는 원하는 수만큼 제곱해주는 함수로, pow(제곱할 수, 제곱 수)와 같이 쓴다. sqrt는 제곱근을 구해주는 함수로, sqrt(제곱근을 구할 수)와 같이 쓴다.
참고) 위 헤더파일에는 fabs()라는 함수도 있는데, 부동소수점형의 절댓값을 계산한다.
- 문자형 : 문자(character)는 한글이나 영어에서 하나의 글자를 의미.
- 컴퓨터는 모든 것을 숫자로 표현하므로, 문자도 숫자로 표현한다.
- 'A'는 65로, 'a'는 97로 표현한다. 이것을 문자 코드라고 한다.
참고) B는 66, b는 98이며 알파벳 순으로 1씩 증가하므로 A와 a의 아스키 코드를 잘 기억하자.
- 널리 사용하는 표준적인 문자 코드는 아스키 코드(ASCII code)이다. 이는 영어의 대소문자, 숫자, 기호들에 대하여 0에서 127 사이의 값들을 부여한다. 영문자의 경우, 글자들의 개수가 128개 이하이기 때문에 하나의 글자에 대하여 8비트면 충분하다. 아스키 코드에서 인쇄 가능한 코드는 스페이스 문자부터 시작한다. 스페이스(space) 문자는 32로 표현된다. 느낌표 문자(!)의 코드는 33이다. 이런 식으로 1씩 증가하면서 알파벳 문자들을 차례대로 표현한다.
- 문자 변수와 문자 상수
- 문자가 정수로 표현되므로 정수를 저장할 수 있는 자료형은 문자도 저장할 수 있다.
- char형 : 문자를 저장하는 데 주로 사용됨. 8비트 정수를 저장할 수 있다(1바이트).
- char code; code = 'A'; 에서 'A'와 같이 작은따옴표로 감싸진 문자를 문자 상수(character constant)라고 한다.
- 컴파일러는 작은따옴표로 감싸진 문자 상수를 만나면 이것을 아스키 코드로 변환하여 저장된다. 실제로 위의 code를 십진수 형식으로 출력하면 65가 출력된다.
참고) 파이썬에서 작은따옴표와 큰따옴표는 모두 문자열을 나타내지만, C언어에서 작은따옴표는 하나의 문자를 나타내며, 큰따옴표가 문자열을 나타낸다.
- char의 형식지정자는 "%c"이다.
참고) 문자 'A'부터 'Z'까지를 0에서 25까지로 바꾸고자 한다면, 문자를 저장하고 있는 변수(c라 하자)에 'A'를 뺀 (c - 'A')수식으로 문자를 정수로 바꿀 수 있다.
- 문자를 입출력하기 위해서는, scanf()를 형식 지정자 %c로 호출해도 되고 getchar()라는 전용함수를 사용해도 된다. (둘 다 stdio.h 헤더파일에 존재)
참고) char code = A;와 같이 문자 상수에 작은따옴표를 쓰지 않게 되면, 컴파일러는 A를 변수 이름으로 생각한다.
- 제어 문자 : 제어 문자들은 인쇄될 수가 없고 주로 콘솔이나 프린터를 제어할 목적으로 이용되는 문자들이다.
ex) 줄바꿈 문자, 화면에 탭을 나타내는 문자, 벨소리를 나타내는 문자, 백스페이스 문자
- 제어 문자 프로그램 안에서 표현 방법
1) 아스키 코드 값을 직접 사용
ex) printf("%c", 7);
* 벨소리 발생 제어 문자 아스키 코드값 7
2) 이스케이프 시퀀스(escape sequence) 이용 (권장)
- 역슬래시(\)와 의미를 나타내는 한 글자를 붙여서 만들어짐.
- 이스케이프 시퀀스 정리
- 널문자 : \0 (값 0)
- 경고(bell) : \a(값 7, "삐" 하는 경고 벨소리 발생)
- 백스페이스(backspace) : \b (값 8, 커서를 현재의 위치에서 한 글자 뒤로 옮김)
- 수평탭(horizontal tab) : \t (값 9, 커서의 위치를 다음 탭 위치로 옮김)
- 줄바꿈(newline) : \n (값 10, 커서를 다음 라인의 시작 위치로 옮김)
- 수직탭(vertical tab) : \v (값 11, 다음 수직 탭 위치로 커서를 이동)
- 폼피드(form feed) : \f (값 12, 주로 프린터에서 강제적으로 다음 페이지로 넘길 때 사용됨)
- 캐리지 리턴(carriage return) : \r (값 13, 커서를 현재 라인의 시작 위치로 옮김)
- 큰따옴표 : \" (값 34, 원래의 큰따옴표 자체)
- 작은따옴표 : \' (값 39, 원래의 작은따옴표 자체)
- 역슬래시(back slash) : \\ (값 92, 원래의 역슬래시 자체)
ex) 프로그램에서 경고음 내기 : printf("\a");
참고) 특수 문자 표기 방법을 이스케이프 시퀀스라고 부르는 이유는 역슬래시(\)가 다음에 오는 문자의 의미를 본래의 의미에서 탈출하도록 하기 때문이다. \ 다음에 오는 문자는 원래의 의미인 글자가 아닌 특별한 명령을 의미한다.
참고) 정수를 입력받은 후 문자나 문자열을 입력받으면 이상하게 동작하는 것처럼 보인다.
ex) scanf("%d", &i); // 정수 입력
c = getchar(); // 문자 입력
위 코드를 실행하면 우리가 문자를 입력하기도 전에 실행이 끝나버린다. 그 이유는 정수를 입력할 때 엔터키를 눌러야 하는데 이것이 줄바꿈 문자로 바뀌어서 입력 버퍼에 있어서이다.
예를 들어서 우리가 키보드로 "10엔터"를 치면 입력 버퍼에는 '1' '0' '\n' 위와 같이 저장된다. "10"은 정수 10으로 변환되어서 입력 버퍼에서 없어지지만, '\n'은 남아있게 되고, 이어서 getchar()를 호출하면 이것이 우리에게 반환된다. 남아 있는 줄바꿈 문자를 없애려면 getchar(0를 한 번 호출해주면 된다.
ex) scanf("%d", &i); // 정수 입력
getchar(); // 줄바꿈 문자를 없앰
c = getchar(); // 문자 입력
'프로그래밍 언어 > C언어_기초 프로그래밍' 카테고리의 다른 글
[ C언어 기초 ] 6. 반복문 (2) | 2024.09.16 |
---|---|
[ C언어 기초 ] 5. 조건문 (7) | 2024.09.16 |
[ C언어 기초 ] 4. 수식과 연산자 (0) | 2024.09.04 |
[ C언어 기초 ] 2. 변수와 입출력 (1) | 2024.08.07 |
[C언어 기초] 1. 기초사항 (0) | 2024.07.09 |