C 언어 코딩 도장 2
변수 만들기
변수 = 값을 저장하는 공간 = 뭔가를 담는 그릇
int num1;
//int -> 자료형(타입)
//num1 -> 변수 이름 (세미콜론은 포함되지 않음)
"자료형 변수이름;" 형식으로 만듦
변수를 만든다 = 변수를 선언한다
자료형 | |
정수 | char, short, int, long |
실수 | float, double |
형태가 없는 자료형 (포인터나 함수의 반환값 표현할 때 사용) |
void |
변수의 이름을 짓는 규칙
- 영문 문자와 숫자를 사용할 수 있음
- 대소문자를 구분 (num1 ≠ Num1 ≠ NUM1)
- ★ 문자부터 시작, 숫자부터 시작 X
- _(밑줄 문자)로 시작할 수 있음
- C 언어의 키워드는 사용할 수 없음 (int, short, long, float, void, if, for, while, switch 등)
변수를 만들고 값 저장하기
#include <stdio.h>
int main()
{
int num1; //정수형 변수 선언
int num2;
int num3;
num1 = 10; //변수에 값을 저장하는 과정 = 변수에 값을 할당한다.
num2 = 20;
num3 = 30;
printf("%d %d %d\n", num1, num2, num3);
return 0;
}
변수 = 값;
변수1 = 변수2;
※ %d는 10진수(decimal)를 출력할 때 사용하는 서식 지정자
변수 여러 개를 한 번에 선언하기
자료형 변수1, 변수2, 변수3;
#include <stdio.h>
int main()
{
int num1, num2, num3; // 변수를 콤마로 구분하여 변수 여러 개를 선언
num1 = 10;
num2 = 20;
num3 = 30;
printf("%d %d %d\n", num1, num2, num3);
return 0;
}
※ 만약 자료형이 다르다면, 따로 선언해야함
변수를 선언하면서 초기화하기
자료형 변수 = 값;
자료형 변수1 = 값1, 변수2 = 값2;
변수를 선언하면서 값을 할당(초기화)
#include <stdio.h>
int main()
{
int num1 = 10;
int num2 = 20, num3 = 30;
printf("%d %d %d\n", num1, num2, num3);
return 0;
}
※ 변수를 선언하면서 값을 할당하는 과정 = "변수를 초기화한다"
5.4 Quiz 완료
#include <stdio.h>
int main()
{
int num1 = 10, num2 = 20, num3 = 30;
printf("%d %d %d\n", num1, num2, num3);
return 0;
}
5.6 심사 문제 완료
num1 = 10;
int num2 = 20, num3 = 30;
▲ 정답으로 제출한 코드
디버거 사용하기
버그 = 프로그램이 의도하지 않은 동작을 일으키는 것
디버거 = 버그(bug)를 제거하는(de-) 도구 = Debugger
프로그램의 내부 상황을 손쉽게 파악할 수 있어 버그를 찾는데 큰 도움을 줌
중단점 사용하기
중단점, 브레이크 포인드(Break Point) = 소스 코드의 특정 지점에서 프로그램의 실행을 멈추는데 사용
소스 코드 편집 창에서 main() 함수가 있는 중괄호에서 마우스 오른쪽 -> 중단점 -> 중단점 삽입
그냥 회색부분 클릭만 해도 됨
중단점을 만들 줄에서 f9 키 누르기만 해도 됨
f5 누르면 => 진단 도구는 x 버튼 눌러도 됨
실행하기 위해 대기하고 있다는 뜻
f10 누르면 => 노란색 화살표가 밑으로 이동
변수 num1, num2, num3이 생성됨 => 계속 f10 누르면
변수에 값이 할당된 것을 볼 수 있음
printf 위로 화살표가 올라가면 그제서야 명령 프롬포트에 하나씩 올라오는 걸 볼 수 있음
디버거 종류 => shift + f5
디버거 단축키
중단점 삽입/삭제 | f9 |
디버깅 시작 | f5 |
디버깅 중지 | shift + f5 |
프로시저 단위 실행 (코드 한 줄씩 실행) | f10 |
한 단계씩 코드 실행 (함수 안으로 들어갈 때) | f11 |
정수 자료형 사용하기
C 언어는 다양한 정수 자료형 제공
정수는 부호와 크기에 따라 자료형이 달라짐
부호 + 정수 자료형
signed int 부호 있는 정수 //signed 생략 가능 = int = signed
unsigned int 부호 없는 정수 //unsigned 생략 불가능 = unsigned
부호 + 문자 자료형
signed char = char
unsigned char
부호 + short 자료형
signed short int = short
unsigned short int = unsigned short
부호 + long 자료형
signed long int = long //long만 쓸 수 있지만, long int로도 많이 사용함
unsigned long int = unsigned long
부호 + long long 자료형
signed long long int = long long
unsigned long long int = unsigned long long
자료형 | 크기 | 범위 | 비고 |
char signed char |
1바이트, 8비트 | -128 ~ 127 | |
unsigned char | 1바이트, 8비트 | 0 ~ 255 | |
short short int |
2바이트, 16비트 | -32,768 ~ 32,767 | int 생략 가능 |
unsigned short unsigned short int |
2바이트, 16비트 | 0 ~ 65,535 | int 생략 가능 |
int signed int |
4바이트, 32비트 | -2,147,483,648 ~ 2,147,483,647 | |
unsigned unsigned int |
4바이트, 32비트 | 0 ~ 4,294,967,295 | int 생략 가능 |
long long int signed long signed long int |
4바이트, 32비트 | -2,147,483,648 ~ 2,147,483,647 | int 생략 가능 |
unsigned long unsigned long int |
4바이트, 32비트 | 0 ~ 4,294,967,295 | int 생략 가능 |
long long long long int signed long long signed long long int |
8바이트, 64비트 | -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 |
int 생략 가능 |
unsigned long long unsigned long long int |
8바이트, 64비트 | 0 ~ 18,446,744,073,709,551,615 | int 생략 가능 |
▲ 정수 자료형의 크기 및 범위
※ long은 운영체제와 플랫폼마다 크기가 다름
정수형 변수 선언하기
#include <stdio.h>
int main()
{
char num1 = -10; //1바이트 부호 있는 정수형
short num2 = 30000; //2바이트 부호 있는 정수형
int num3 = -1234567890; //4바이트 부호 있는 정수형
long num4 = 12345467890; //4바이트 부호 있는 정수형
long long num5 = -1234567890123456789; //8바이트 부호 있는 정수형
//char, short, int -> %d, long -> %ld, long long -> %lld
printf("%d %d %d %ld %lld\n", num1, num2, num3, num4, num5);
return 0;
}
#include <stdio.h>
int main()
{
unsigned char num1 = 200; //1바이트 부호 없는 정수형
unsigned short num2 = 60000; //2바이트 부호 없는 정수형
unsigned int num3 = 4123456789; //4바이트 부호 없는 정수형
unsigned long num4 = 4123456789; //4바이트 부호 없는 정수형
unsigned long long num5 = 12345678901234567890; //8바이트 부호 없는 정수형
//char, short, int -> %u, long -> %lu, long long -> %llu
printf("%u %u %u %lu %llu\n", num1, num2, num3, num4, num5);
return 0;
}
※ %u -> unsigned decimal
오버플로우와 언더플로우 알아보기
#include <stdio.h>
int main()
{
char num1 = 128; // 최댓값 127
// 오버플로우 발생
unsigned char num2 = 256; // 최댓값 255
// 오버플로우 발생
printf("%d %u\n", num1, num2); // -128 0: 저장할 수 있는 범위를 넘어서므로
// 최솟값부터 다시 시작
return 0;
}
오버플로우 = 저장할 수 있는 범위를 넘어서면 다시 최솟값부터 시작하게 됨
언더플로우 = 최솟값보다 작아지면 다시 최댓값부터 시작하게 됨
자료형 크기 구하기
sizeof 연산자
자료형(타입)의 크기를 바이트(Byte) 단위로 구하는연산자
sizeof 표현식 //자료형의 크기를 구할 수 있음
sizeof(자료형) //자료형의 크기를 직접 구하려 할 때 사용
sizeof(표현식)
표현식
변수, 상수, 배열 등 프로그래머가 만들어낸 요소
#include <stdio.h>
int main()
{
printf("char: %d, short: %d, int: %d, long: %d, long long: %d\n",
sizeof(char),
sizeof(short),
sizeof(int),
sizeof(long),
sizeof(long long)
);
return 0;
}
최솟값과 최댓값 표현하기
limits.h 헤더 파일
소스 코드에서의 정수의 최솟값을 표현할 때 사용
부호 있는 정수와 부호 없는 정수의 최솟값과 최댓값이 정의되어 있
자료형 | 최솟값 | 최댓값 |
char | CHAR_MIN | CHAR_MAX |
short | SHRT_MIN | SHRT_MAX |
int | INT_MIN | INT_MAX |
long | LONG_MIN | LONG_MAX |
long long | LLONG_MIN | LLONG_MAX |
unsigned char | 0 | UCHAR_MAX |
unsigned short | 0 | USHRT_MAX |
unsigned int | 0 | UINT_MAX |
unsigned long | 0 | ULONG_MAX |
unsigned long long | 0 | ULLONG_MAX |
#include <stdio.h>
#include <limits.h>
int main()
{
char num1 = CHAR_MIN;
short num2 = SHRT_MIN;
int num3 = INT_MIN;
long num4 = LONG_MIN;
long long num5 = LLONG_MIN;
printf("%d %d %d %ld %lld\n", num1, num2, num3, num4, num5);
return 0;
}
limits.h에 정의된 최댓값을 넘었을 때?
= 오버플로우 발생
#include <stdio.h>
#include <limits.h>
int main()
{
char num1 = CHAR_MAX + 1;
short num2 = SHRT_MAX + 1;
int num3 = INT_MAX + 1;
long num4 = LONG_MAX + 1;
long long num5 = LLONG_MAX + 1;
printf("%d %d %d %ld %lld\n", num1, num2, num3, num4, num5);
unsigned char num6 = UCHAR_MAX + 1;
unsigned short num7 = USHRT_MAX + 1;
unsigned int num8 = UINT_MAX + 1;
unsigned long num9 = ULONG_MAX + 1;
unsigned long long num10 = ULLONG_MAX + 1;
printf("%u %u %u %lu %llu\n", num6, num7, num8, num9, num10);
return 0;
}
limits.h에 정의된 최솟값보다 작아졌을 때?
= 언더플로우 발생
#include <stdio.h>
#include <limits.h>
int main()
{
char num1 = CHAR_MIN - 1;
short num2 = SHRT_MIN - 1;
int num3 = INT_MIN - 1;
long num4 = LONG_MIN - 1;
long long num5 = LLONG_MIN - 1;
printf("%d %d %d %ld %lld\n", num1, num2, num3, num4, num5);
unsigned char num6 = 0 - 1;
unsigned short num7 = 0 - 1;
unsigned int num8 = 0 - 1;
unsigned long num9 = 0 - 1;
unsigned long long num10 = 0 - 1;
printf("%u %u %u %lu %llu\n", num6, num7, num8, num9, num10);
return 0;
}
크기가 표시된 정수 자료형 사용하기
stdint.h
크기별로 정수 자료형이 정의된 헤더 파일
- 부호 있는 정수(signed) 최솟값 : INT8_MIN, INT16_MIN, INT32_MIN, INT64_MIN
- 부호 있는 정수 최댓값 : INT8_MAX, INT16_MAX, INT32_MAX, INT64_MAX
- 부호 없는 정수(unsigned) 최솟값 : 0
- 부호 없는 정수 최댓값 : UINT8_MAX, UINT16_MAX, UINT32_MAX, UINT64_MAX
#include <stdio.h>
#include <stdint.h>
int main()
{
int8_t num1 = -128;
int16_t num2 = 32767;
int32_t num3 = 2147483647;
int64_t num4 = 9223372036854775807;
printf("%d %d %d %lld\n", num1, num2, num3, num4);
uint8_t num5 = 255;
uint16_t num6 = 65535;
uint32_t num7 = 4294967295;
uint64_t num8 = 18446744073709551615;
printf("%u %u %u %llu\n", num5, num6, num7, num8);
return 0;
}
7.6 Quiz 완료
#include <stdio.h>
int main()
{
unsigned char num1 = 256;
unsigned short num2 = 65536;
long long num3 = 9223372036854775808;
printf("%u %u %lld\n", num1, num2, num3);
return 0;
}
#include <stdio.h>
int main()
{
short num1;
long long num2;
printf("%d\n", sizeof(num1) + sizeof(num2) + sizeof(int));
return 0;
}
#include <stdio.h>
#include <limits.h>
int main()
{
char num1 = CHAR_MAX;
short num2 = SHRT_MAX;
int num3 = INT_MAX;
long num4 = LONG_MAX;
long long num5 = LLONG_MAX;
printf("%d %d %d %ld %lld\n", num1, num2, num3, num4, num5);
return 0;
}
#include <stdio.h>
#include <stdint.h>
int main()
{
int8_t num1 = INT8_MIN;
uint16_t num2 = UINT16_MAX;
int32_t num3 = INT32_MAX;
uint64_t num4 = UINT64_MAX;
printf("%d %u %d %llu\n", num1, num2, num3, num4);
return 0;
}
7.11 심사 문제 완료
unsigned short num1;
unsigned long num2;
char num3;
▲ 정답으로 제출한 코드
7.12 심사 문제 완료
char num1;
short num2;
▲ 정답으로 제출한 코드
7.13 심사 문제 완료
#include <limits.h>
▲ 정답으로 제출한 코드
7.14 심사 문제 완료
#include <stdint.h>
▲ 정답으로 제출한 코드
실수 자료형 사용하기
자료형 | 크기 | 범위 | 유효자릿수 | 비고 |
float | 4바이트, 32비트 |
1.175494e-38~3.402823e+38 | 7 | IEEE 754 단정밀도 부동소수점 |
double | 8바이트, 64비트 |
2.225074e-308~1.797693e+308 | 16 | IEEE 754 배정밀도 부동소수점 |
long double | 8바이트, 64비트 |
2.225074e-308~1.797693e+308 | 16 | IEEE 754 배정밀도 부동소수점 |
▲실수 자료형의 크기 및 범위
※ 지수 표기법(exponential notation| 과학 표기법 scientific notation)
- 실수e+지수 : 실수 * 10의 거듭제곱
- 실수e-지수 : 실수 * 1/10의 거듭제곱
※ long double
운영체제 및 플랫폼별 long double의 크기
운영체제 | CPU(플랫폼) | 바이트 크기 | 비트 크기 |
Windows | x86(32비트) | 8 | 64 |
x86-64(64비트) | 8 | 64 | |
리눅스 | x86(32비트) | 12 | 96 |
x86-64(64비트) | 16 | 128 | |
OS X | x86(32비트) | 16 | 128 |
x86-64(64비트) | 16 | 128 |
64비트 리눅스, OS X에서는 IEEE 754 4배 정도 부동 소수점을 저장할 수 있음(3.352103e-4932~1.189731e+4932)
부동소수점 표현 방식
컴퓨터에서는 값을 0과 1로 저장하기 때문에, 실수도 0과 1로 저장해야 하는데, 실수와 소수점을 2진수로 표현하는 방식
자료형의 일정 부분을 비트 단위로 나누어 부호, 가수(significand), 기수(base), 지수(exponent)를 저장하여 실수를 표현
기수(n)를 지수(p)만큼 거듭제곱한 값을 가수(m)와 곱하는 방식
컴퓨터는 값을 저장할 때 2진수로 저장하기 때문에 기수(밑수)는 2로 고정되어 있음
자료형 | 크기 | 부호 | 지수 | 가수 |
float | 32비트 | 1비트 | 8비트 | 23비트 |
double | 64비트 | 1비트 | 11비트 | 52비트 |
▲IEEE 754 32비트 단정밀도, 64비트 배정밀도 부동소수점 저장 방식
유효자릿수 = 실수를 일정 자릿수만큼만 표현할 수 있음
만약, 유효자릿수 = 7 → 0.123456789 ▶ 0.123457(반올림)
실수형 변수 선언하기
#include <stdio.h>
int main()
{
float num1 = 0.1f; //단정밀도 부동소수점 변수를 선언하고 값 할당
//float는 숫자 뒤에 f를 붙임
double num2 = 3867.215820; //배정밀도 부동소수점 변수를 선언하고 값을 할당
//double은 숫자 뒤에 아무것도 붙이지 않음
long double num3 = 9.327516l; //배정밀도 부동소수점 변수를 선언하고 값을 할당
//long double은 숫자 뒤에 l을 붙임
printf("%f %f %Lf\n", num1, num2, num3);
return 0;
}
- %f : 부동소수점(floating point)의 약어로 f를 사용
- %Lf : long floating point에서 point를 제외한 첫 글자를 따서 Lf를 사용
지수 표기법으로 실수 저장
#include <stdio.h>
int main()
{
float num1 = 3.e5f; //지수 표기법으로 300000을 표기
double num2 = -1.3827e-2; //지수 표기법으로 -0.013827을 표기
long double num3 = 5.21e+9l; //지수 표기법으로 5210000000을 표기
printf("%f %f %Lf\n", num1, num2, num3);
printf("%e %e %Le\n", num1, num2, num3);
return 0;
}
- %e : 지수 표기법(exponential notation)의 약어로 e를 사용
- %Le : long exponential notation에서 notaion을 제외한 첫 글자를 따서 Le를 사용
자료형 크기 구하기
#include <stdio.h>
int main()
{
float num1 = 0.0f;
double num2 = 0.0;
long double num3 = 0.0l;
printf("float : %d, double : %d, long double : %d",
sizeof(num1),
sizeof(num2),
sizeof(num3)
);
return 0;
}
※ float는 4바이트, double과 long double은 8바이트 | 64비트 리눅스, OS X에서는 long double이 16바이트
최솟값과 최댓값 표현하기
float.h
실수 자료형의 양수 최솟값, 최댓값이 정의된 헤더 파일
각 자료형 별로 양수 최솟값과 최댓값이 정의되어 있음
#include <stdio.h>
#include <float.h>
int main()
{
float num1 = FLT_MIN;
float num2 = FLT_MAX;
double num3 = DBL_MIN;
double num4 = DBL_MAX;
long double num5 = LDBL_MIN;
long double num6 = LDBL_MAX;
printf("%.40f %.2f\n", num1, num2);
printf("%e %e\n", num3, num4);
printf("%Le %LE\n", num5, num6);
return 0;
}
printf 함수에서 서식 지정자를 %.40f, %.2f처럼 소수점 뒤에 숫자를 지정하면 해당 숫자 만큼 소수점 이하 자릿수를 출력
https://dojang.io/mod/page/view.php?id=736#google_vignette
C 언어 코딩 도장: 85.2 서식 지정자
printf, sprintf, fprintf에서 사용하는 서식 지정자(format specifier)는 다양한 활용법이 있습니다. 다음은 기본 서식 지정자이며 정수, 실수, 문자, 문자열, 포인터의 메모리 주소를 출력하는 기본 서식
dojang.io
▲서식 지정자 자릿수 설정 방법 참조
오버플로우와 언더플로우 알아보기
#include <stdio.h>
#include <float.h>
int main()
{
float num1 = FLT_MIN;
float num2 = FLT_MAX;
num1 = num1 / 100000000.0f;
//float의 양수 최솟값을 100000000.0으로 나누면 아주 작은 수가 되면서 언더플로우 발생
num2 = num2 * 1000.0f;
//float의 양수 최댓값에 1000.0을 곱하면 저장할 수 있는 범위를 넘어서므로 오버플로우 발생
printf("%e %e\n", num1, num2);
//실수의 언더플로우는 0, 오버플로우는 무한대가 됨
return 0;
}
정수와는 달리 실수는 오버플로우가 발생했을 때 최솟값으로 돌아가지 않고 무한대(infinity)가 되므로 inf가 출력
8.5 Quiz 완료
#include <stdio.h>
int main()
{
float num1 = 1.97f;
long double num2 = 5.524218l;
double num3 = 3792.8e+4;
printf("%f %Lf %f\n", num1, num2, num3);
return 0;
}
#include <stdio.h>
int main()
{
double num1 = 0.4284;
float num2 = 2.7f;
printf("num1의 크기 : %d, num2의 크기 : %d\n", sizeof(num1), sizeof(num2));
return 0;
}
#include <stdio.h>
#include <float.h>
int main()
{
float num1 = FLT_MAX;
double num2 = DBL_MIN;
long double num3 = LDBL_MAX;
printf("%.2f\n", num1);
printf("%e\n", num2);
printf("%Le\n", num3);
return 0;
}
#include <stdio.h>
#include <float.h>
int main()
{
float num1 = FLT_MIN;
num1 = num1 / 100000000.0f;
printf("%e\n", num1);
return 0;
}
8.10 심사 문제 완료
8.11 심사 문제 완료
8.12 심사 문제 완료