능동적인 생각은 프로그래밍 공부에 큰 도움 3장 근의 공식은 어떻게 표현하나? 왜 정수와 실수를 구별하나? 실수와 정수를 더하면 오류가 날까? 문자열은 메모리 내부에 어떻게 표현할까? … 3장 기본형과 그들의 변형 연산자 그리고 그들의 우선순위와 결합 법칙 3.7절은 π를 추정하는 프로그램
3.1 데이터 형 C에서 모든 변수는 형을 가짐 프로그래머는 목적에 따라 적절한 형을 사용해야 함 형type C 제공형: char, int, float 그리고 그들의 여러 변형 (3장) 사용자 정의형: struct, typedef, enum (7장)
3.1.1 기본 형과 그들의 변형 프로그래머는 이들을 충분히 이해해야 하며 적절한 형을 선택하여 사용해야 한다.
int의 변형 부호가 있느냐에 따라 signed int unsigned int 할당되는 바이트 수에 따라 (즉 표현 가능한 값의 범위에 따라) short int (short) // int 보다 적거나 같음 int long int (long) // int 보다 많거나 같음 long long // C99 표준에서 제공 int 사용 예 정수 상수의 진법 표현 십진수 (예, 182) 8진수 (예, 0266) 16진수 (예, 0xB6)
char의 변형 float의 변형 부호가 있느냐에 따라 signed char unsigned char 할당되는 바이트 수에 따라 (즉 표현 가능한 유효 숫자와 값의 범위에 따라) float의 유효 숫자는 7 자리 double의 유효 숫자는 15 자리 long double은 double보다 많거나 같음 실수 상수의 표현 예
오버플로우와 언더플로우 표현 가능한 최소값보다 작은 값이 발생하면 언더플로우 표현 가능한 최대값보다 큰 값이 발생하면 오버플로우 이들 오류가 발생하지 않도록 하는 일은 프로그래머의 몫 자동으로 검사해 주지 않는다. sizeof 연산자를 사용하면 도움이 된다. 형 또는 변수에 할당되는 바이트 수를 알 수 있음 사용 예 최대값과 최소값을 나타내는 기호 상수를 사용하면 도움이 된다. 예를 들어 INT_MAX는 int 형의 최대값
오버플로우 예 (factorial 계산)
연습 문제
3.1.3 형 변환 C는 혼합 연산에 너그럽다. 형 변환 규칙 낮은 표현을 높은 표현으로 변환 (즉 정보 손실이 적은 방향으로) 예를 들어, 정수와 실수가 혼합된 경우 정수를 실수로 변환. 왜? 예제 3.1
int와 char의 형 변환 C는 int를 char로 간주하기도 하고 int를 char로 간주하기도 한다. 처음에는 약간 혼란스러울 수 있으나 알고 보면 여러 장점 (3.2.1절) 캐스트 (형 변환) 연산자 강제로 (명시적으로) 형을 변화시킴
3.2 문자와 문자열 프로그램은 숫자 뿐 아니라 문자도 많이 다룬다. 웹 검색 엔진의 검색어 보고서 작성 등
3.2.1 문자 char 형 상수 예, ‘a’ // 작은 따옴표로 묶음 1바이트를 사용 ASCII 코드 표: 부록 B
char를 int로, int를 char로 사용할 수 있음은 장점이다. 첫째 예, RGB 컬러 영상 표현 한 화소는 r, g, b 요소를 가지며 각 요소는 0~255 사이 값을 갖는다. 따라서 r, g, b 각각을 unsigned char로 표현하면 된다. int를 사용하면 4배의 메모리가 필요하다.
문자를 정수로, 정수를 문자로 사용할 수 있음은 장점이다. (앞에서 계속) 둘째 예, 문자열에서 소문자 알파벳의 빈도 수 세기 라인 13: histogram[]의 0번 요소는 ‘a’, 1번 요소는 ‘b’, …
프로그램[3.2] 함수 버전 … …
연습 문제
3.2.2 문자열 0개 이상의 문자가 이어져 있는 것을 문자열이라 한다. 예, ”Hi, C.” // 큰 따옴표로 묶음 char 형 배열 사용 문자열 끝은 ‘\0’로 채움
문자열 길이 구하기 배열의 첫 요소부터 조사를 시작하여 ‘\0’가 나타날 때까지 센다.
문자열 길이 구하기의 함수 버전 라인 13-14를 한 줄로 줄여 쓸 수 있다. …
문자열 뒤집기 예, “Hi, C.” “.C ,iH”
연습 문제
3.2.3 문자 입출력 표준 라이브러리 함수 getchar()와 putchar() 문자 입출력에 혼란스런 상황이 있다. 아래 예제 코드에서 “20 A<ENTER>”를 입력했다면, 사용자 의도는 i에 20, a에 ‘A’ 하지만 i에 20, a에 ‘ ’이 입력됨. 왜? 이유는 버퍼 입출력에 있다. i에 20, a에 ‘ ’이 입력되고 버퍼에 “A\n”이 남음
버퍼 입출력 C 언어는 몇 가지 예외를 제외하고 입출력을 버퍼를 통해 한다. 프로그램 수행 속도 (매우 빠름)와 입출력 속도 (느림)의 차이를 완충시키기 위함
해결 방법 사용자가 “20A”를 입력함 사용자에게 이상한 걸 강요하는 꼴 또는, 아래 scanf()로 읽어 들임 (%d와 %c 사이에 공백이 있어야 함) 또는, getchar()대신 비 버퍼 입력 함수 getch()를 사용
한 줄의 문자열을 입출력 하는 gets()와 puts() 입출력의 추가 사항: 부록 A 정확한 입출력은 매우 중요하다.
3.3 사칙, 관계, 그리고 논리 연산자 사칙 +, -, … 관계 <, <=, ==, … 논리 &&, ||, … 그리고 재미있고 유용한 연산자 들 … 이들의 우선 순위와 결합 법칙 참/거짓 판정 규칙
3.3.1 연산자와 우선 순위
몇 가지 예 첫 번째 식은 항상 참이다. 왜?
3.3.2 프로그래밍 연습: 이차 방정식 풀기
라인 1-3을 코딩하면, 아래처럼 쓰면 안 된다. 왜?
C 코딩 하면
연습 문제
3.3.3 참/거짓 판정 C는 참/거짓 판정에 독특한 점이 있다. 첫째, 관계식과 논리식의 결과에 정수 값을 부여한다. 참은 1, 거짓은 0 그 값이 사칙 연산에 참여할 수도 있다. 둘째, 수치 값을 가지는 어떤 명령문이라도 참 거짓 판정에 참여할 수 있다. 0은 거짓, 0이 아닌 모든 수는 참
주어진 조건을 정확히 코딩하는 것이 매우 중요하다. 예, 윤년 판정 조건 4의 배수인 해가 윤년이다. 하지만 100의 배수는 윤년이 아니다. 예외로 400의 배수는 윤년이다. 아래 코드가 맞나? 아래 코드가 맞나?
3.4 유용한 연산자들 C 언어는 연산자가 풍부하다는 특성이 있다. 독특한 연산자들 증감 연산자 비트 연산자 대입 연산자 조건 연산자
3.4.1 증감 연산자 ++는 1만큼 증가, --은 1만큼 감소 앞 증감은 ‘증감을 한 뒤에 값을 사용’ 뒤 증감은 ‘값을 사용한 후에 증감을 함’
증감 연산자는 프로그램을 간결하게 작성하는데 유용함 예, 문자열 뒤집기 함수
3.4.2 비트 연산자 비트 단위로 연산이 가능함
비트 연산자 연습을 위해, 1인 비트를 세는 함수 변수의 비트 수는 sizeof()로 알아냄 (라인 3) 이식성을 위해 라인 7의 x&01은 x의 가장 오른쪽 비트가 1이면 1, 그렇지 않으면 0 라인 7에서 no+(x&01)을 no+x&01로 쓰면 어떻게 될까?
연습 문제
3.4.3 대입 연산자 자신에 어떤 값을 더하고 그것을 자신이 대입 받을 때, 이러한 형태를 취할 수 있는 연산자들
3.4.4 조건 연산자 피연산자가 세 개인 삼항 연산자 예, 일반적인 형태 유용한 경우 (둘 중 어느 것을 쓸 지는 프로그래머의 취향)
3.5 연산자 우선 순위와 결합 법칙
3.6 프로그래밍 스타일 플랫폼 프로그램 (소프트웨어) 실행을 지원하는 제반 환경 환경은 컴퓨터 기종, 운영 체제, 미들웨어 등을 포함 현대 컴퓨터 기술의 특성 중의 하나는 플랫폼의 다양성 이식성이 중요 . 이식성을 높이려면, 표준을 잘 따를 것 컴파일러에 따라 다름이 발생할 가능성이 있는 곳은 표시해 둠 sizeof() 연산자 사용 (예, 프로그램 [3.9]) 컴파일러에 따라 다르게 계산할 소지 있는 명령문 피함 (아래 예)
3.7 프로그래밍 연습: π 추정 원주율 π 추정은 고대에도 연구 대상 현재는 컴퓨터 기술의 도움의 1조 자리까지 알려짐 50자리까지 보여 주면,
3.7.1 면적을 이용한 방법 [-1,1]사이에 놓인 점을 충분히 많이 생성 시킴 원의 내부 (no_inside)와 외부 점 (no_outside)의 수를 셈 아래 예는 no_inside=27, no_outside=8
알고리즘으로 정리하면, 이 알고리즘은 수행 시간을 설정하여 점의 개수를 조절함
프로그램 설계 no_inside와 no_outside는 unsigned long int를 사용하자. 실수 변수는 double 형을 쓰자. (double은 유효 숫자가 15 자리)
시간 측정은 time()과 difftime() 함수로
오버플로우 발생 위험은? 라인 24-27에서 자체 점검 (ULONG_MAX를 넘지 않도록 함) 라인 33을 아래와 같이 바꾸면 위험하다. 왜? pi=(4.0*(double)no_inside)/(no_inside+no_outside); unit_rand()함수도 살펴 보자. 라인 40을 아래와 같이 하면 오동작한다. 왜? { return rand()/RAND_MAX;}
연습 문제
3.7.2 Plouffe 알고리즘 1995년 Simon Plouffe가 제안 예를 들어, n=2라면
아래 프로그램의 오버플로우 또는 언더플로우 위험은?
연습 문제