C 프로그래밍: 표준 입출력과 연산자(1)
0) 학습 개요
- C는 다양한 연산자(산술·관계·논리·대입·비트 등)를 제공합니다.
- 또한, 표준 입출력(stdin/stdout) 을 통해 콘솔과 상호작용합니다.
- 본 정리에서는 입출력 함수 사용법, 연산자 우선순위/결합 방향, 형 변환의 실무 포인트를 요약합니다.
1) 표준 입출력(Standard I/O)
1-1. 개념
stdin // 표준 입력(키보드 등)
stdout // 표준 출력(콘솔)
stderr // 표준 에러(오류 메시지 전용)
1-2. printf(형식화된 출력)
#include <stdio.h>
int main(void) {
char c = 'A';
int i = 10, j = 20;
long long big = 1234567890123LL;
double d = 3.1415926535;
const char *s = "KNOU";
printf("char: %c\n", c); // 문자
printf("int : %d\n", i); // 정수
printf("hex : 0x%X\n", j); // 16진수(대문자)
printf("long long: %lld\n", big);
printf("double: %.3f\n", d); // 소수점 자릿수
printf("str : %s\n", s); // 문자열
}
- 팁: float는 가변인자 전달 시 자동으로 double로 승격되므로 %f 사용.
서식 편집(폭/정렬/채움/부호)
printf("|%6d|\n", 123); // 폭 6, 우측 정렬: | 123|
printf("|%-6d|\n", 123); // 좌측 정렬 : |123 |
printf("|%+6d|\n", 123); // 부호 표시 : | +123|
printf("|%06d|\n", 123); // 0 채움 : |000123|
printf("|%10.2f|\n", 123.456); // 총 폭 10, 소수 2자리
printf("|% .2f|\n", 123.456); // 양수 앞 공백(부호 자리 확보)
1-3. scanf(형식화된 입력)
#include <stdio.h>
int main(void) {
int a; double b; char ch; char s[64];
scanf("%d", &a); // int
scanf("%lf", &b); // double(반드시 %lf)
scanf(" %c", &ch); // 앞 공백으로 개행/공백 스킵
scanf("%63s", s); // 버퍼 크기-1 지정 (오버플로 방지)
printf("%d %.3f %c %s\n", a, b, ch, s);
}
- 문자열/한 줄 입력은 fgets + sscanf 패턴이 가장 안전:
char line[128], name[64]; int age;
if (fgets(line, sizeof line, stdin) && sscanf(line, "%63s %d", name, &age) == 2) { /* ... */ }
1-4. 문자/문자열 I/O
int ch = getchar(); // 문자 하나 입력(EOF는 -1)
putchar('A'); // 문자 하나 출력
// gets는 보안상 폐기됨 → fgets 사용
char buf[100];
fgets(buf, sizeof buf, stdin); // 개행 포함; 필요시 제거
2) 연산자(Operators) 한눈 정리
2-1. 분류와 예시
- 산술: + - * / %
- 관계: == != < <= > >=
- 논리: && || !
- 대입/복합 대입: =, +=, -=, *=, /=, %=, <<=, >>=, &=, ^=, |=
- 증감: ++ -- (전위/후위)
- 비트: & | ^ ~ << >>
- 삼항 조건: ? :
- 형 변환: (type) expr
- 쉼표: , (왼쪽 평가 후 오른쪽 결과 반환)
- sizeof: sizeof expr / sizeof(type)
2-2. 우선순위(상위 → 하위, 핵심만)
- 단항/후위: (), [], ., ->, x++, x--
- 단항 연산: ++x, --x, +, -, !, ~, (type), *(역참조), &(주소), sizeof
- 곱셈/덧셈: * / % → + -
- 시프트: << >>
- 관계/동등: < <= > >= → == !=
- 비트: & → ^ → |
- 논리: && → ||
- 삼항: ? :
- 대입: =, +=, -=, ...
- 쉼표: ,
결합 방향: 대부분 좌→우, 단, 대입/삼항/단항/cast 는 우→좌.
함정 예시
int a = 2, b = 3, c = 4;
int r = a + b << 1; // (+)가 <<보다 먼저 → (a+b) << 1
int x = 1; printf("%d %d\n", x++, ++x); // 미정의 동작(한 표현식 내 중복 변경 지양)
3) 형 변환(Type Conversion)
3-1. 암시적(자동) 승격/변환
- 산술 연산 시 정수 승격(예: char/short → int) 후 공통 타입으로 맞춤.
- 혼합형 연산: 더 넓은 범위의 타입으로 승격(예: int + double → double).
int a = 3; double b = 2.5;
printf("%.1f\n", a / 2); // 1.0 (정수/정수 연산이 끝난 뒤 double로 변환)
printf("%.1f\n", a / 2.0); // 1.5 (하나가 double이면 실수 연산)
printf("%.1f\n", a / (double)2); // 1.5 (명시적 캐스트)
3-2. 명시적 캐스트
double d = 3.9;
int i = (int)d; // 3 (버림)
unsigned u = (unsigned)-1; // 구현에서 최대값으로 래핑됨(주의)
4) 비트 연산(Bitwise) 실전 포인트
unsigned x = 0b1010u; // C 표준은 0b 리터럴 비권장(컴파일러 확장). 10진/16진 권장.
unsigned y = 0x0F;
printf("%u\n", x & y); // AND
printf("%u\n", x | y); // OR
printf("%u\n", x ^ y); // XOR
printf("%u\n", ~x); // NOT
printf("%u\n", x << 1); // 좌시프트(곱하기 2와 유사, 오버플로 주의)
printf("%u\n", y >> 1); // 우시프트(부호 없는 정수 권장)
- 부호 있는 우시프트는 구현 정의가 될 수 있어 부호 없는 정수로 작업 권장.
5) 미니 실습
실습 A: 안전 입력 + 산술/형변환
#include <stdio.h>
#include <string.h>
int main(void) {
char line[128]; int a; double b;
puts("정수와 실수를 입력하세요 (예: 3 2.5):");
if (fgets(line, sizeof line, stdin) && sscanf(line, "%d %lf", &a, &b) == 2) {
double sum = a + b; // int → double 승격
double avg = (a + b) / 2.0;
printf("sum=%.2f, avg=%.2f\n", sum, avg);
} else {
puts("입력 형식 오류");
}
}
실습 B: 연산자 우선순위 확인
#include <stdio.h>
int main(void) {
int a = 2, b = 3, c = 4;
int r1 = a + b << 1; // (a+b) << 1 = 10
int r2 = a + (b << 1); // a + 6 = 8
printf("%d %d\n", r1, r2);
}
6) 자주 나오는 함정/체크리스트
- 서식자 불일치
long x; scanf("%ld", &x); // long은 %ld
double d; scanf("%lf", &d); // double은 %lf
- scanf("%c", &ch) 전에 남은 개행 처리
scanf(" %c", &ch); // 서식 앞 공백으로 공백류 스킵
- 문자열 입력 안전
scanf("%63s", s); // 길이 한정
// 또는
fgets(s, sizeof s, stdin);
- 정수 나눗셈 주의
int a=3; printf("%f\n", a/2.0); // 한쪽을 실수로
- 증감 연산자와 같은 피연산자 다중 사용 금지
// 미정의/구현 의존 위험
// printf("%d %d\n", x++, ++x);
- gets 사용 금지 → fgets
// gets(str); // 금지
fgets(str, sizeof str, stdin);
7) 요약
- 입출력: printf/scanf 기본과 안전한 fgets+sscanf 패턴 숙지.
- 연산자: 우선순위/결합 방향을 이해하고 괄호로 의도 명확화.
- 형 변환: 정수 승격·혼합형 승격 규칙 이해, 필요 시 명시적 캐스트.
- 비트 연산: 부호 없는 정수로 안전하게 다루기.
용어 간단 확장(약어 풀이)
- stdin: standard input(표준 입력)
- stdout: standard output(표준 출력)
- ASCII: American Standard Code for Information Interchange(문자 인코딩 표준)
C 프로그래밍: 연산자 정리(2)
0) 학습 개요 · 목표
- C 언어에서 쓰이는 연산자 종류/의미를 이해하고 쓸 수 있다.
- 우선순위와 결합 방향을 설명하고, 필요한 곳에 형변환을 적용할 수 있다.
1) 연산자의 개념
- 연산자(operator): 피연산자(값, 변수, 식)에 연산을 지시하는 기호.
분류: 산술 관계 논리 대입/복합대입 조건(?:) 비트 기타(sizeof, 형변환, &, *)
기호: + - * / % ++ -- > < >= <= == != && || ! = += -= ... ?:
& | ^ ~ << >> sizeof (type) & *
2) 산술 연산자
2-1. 이항 산술: + - * / %
printf("%d\n", 5 + 3); // 8 (정수 덧셈)
printf("%.1f\n", 3.0/2.0); // 1.5 (실수 나눗셈)
printf("%d\n", 3/2); // 1 (정수 나눗셈 → 소수부 버림)
- 주의: 정수 나눗셈을 피하려면 한쪽을 실수로 만드세요.
int a=3; printf("%.1f\n", a/2.0); // 1.5
2-2. 나머지 % (정수 전용)
printf("%d\n", 5%3); // 2
printf("%d\n", -5%3); // -2
- 정의: 피제수 - (피제수/제수)*제수 (정수 나눗셈)
2-3. 단항 증감: ++ --
int a=10,b;
b = ++a; // a=11, b=11 (전위: 먼저 변경)
b = a++; // a=12, b=11 (후위: 값 사용 후 변경)
증감 혼용 주의(한 표현식에서 같은 변수를 중복 변경 금지)
int x=5;
// printf("%d %d\n", x++, ++x); // 미정의 동작 → 피하세요
예제
int x=5, a, b;
a = ++x * x--; // 평가 순서에 의존 → 피하는 게 좋음 (괄호로 의도 명확화 권장)
b = x * 10;
printf("a=%d, b=%d, x=%d\n", a, b, x);
3) 관계/논리/조건 연산자
3-1. 불 값
C의 '거짓' = 0, '참' = 0이 아닌 값(대개 1 출력)
3-2. 관계: == != < <= > >=
int a=4;
printf("%d\n", a>2); // 1
printf("%d\n", a==4); // 1
printf("%d\n", a<2); // 0
3-3. 논리: && || ! (단락 평가: short-circuit)
int a=4, b=7, c=10;
int d = (a>0) && (b++<=5) && (--c>0);
printf("d=%d, b=%d, c=%d\n", d, b, c);
// a>0 은 참, b++<=5 는 거짓이므로 뒤의 --c>0 은 평가 안 됨 → 단락
3-4. 조건(?:)
int a=25, b=13;
int m = (a>=b) ? a : b; // 최댓값
printf("max=%d\n", m);
4) 대입/복합 대입
4-1. 대입 =
int a, b;
float c;
b = 5;
c = b + 10; // 우변 평가 후 좌변 타입에 맞게 저장
4-2. 대입식의 값 = 저장된 값
float a=1.5f, c;
int b;
c = b = a; // a(1.5) → b(1) 저장 → c=1.0 저장
printf("b=%d, c=%f\n", b, c); // b=1, c=1.000000
4-3. 복합 대입 op=
int a=10, b=3, c=1;
a *= (b-1); // a = a * (b-1) → 20
b /= 2+3; // b = b / 5 → 0
c += 2; // c = c + 2 → 3
5) 비트 연산자 (정수 전용)
5-1. 기본
unsigned x=0xAB; // 1010 1011
unsigned y=0x3C; // 0011 1100
printf("%X\n", x & y); // AND
printf("%X\n", x | y); // OR
printf("%X\n", x ^ y); // XOR
printf("%X\n", ~x); // NOT
printf("%X\n", x<<2); // 좌시프트(×4 비슷, 오버플로 주의)
printf("%X\n", y>>1); // 우시프트(부호 없는 정수 권장)
5-2. 마스크 활용
unsigned x = 0b10101111u; // 컴파일러 확장. 이식성 위해 16진 권장.
unsigned mask_clear = 0xF0; // 상위 4비트만 남기고 하위 4비트 0으로
unsigned mask_set = 0x0F; // 하위 4비트 1로
unsigned mask_flip = 0x0F; // 하위 4비트 토글
unsigned a = x & mask_clear; // 특정 비트만 0으로
unsigned b = x | mask_set; // 특정 비트만 1로
unsigned c = x ^ mask_flip; // 특정 비트만 반전
5-3. 시프트로 2ⁿ 곱/나눗셈
int x = 40;
int y = x << 3; // 40*8 = 320 (오버플로 주의)
int z = x >> 2; // 40/4 = 10 (음수의 >>는 구현에 따라 부호 유지)
6) 기타 연산자
6-1. sizeof
int a=0;
printf("%zu\n", sizeof a); // 피연산자: 식/변수
printf("%zu\n", sizeof(double)); // 피연산자: 형식명
6-2. 형변환(cast)
int a=3, b=4;
double c = (double)a / b; // 0.75
6-3. 쉼표 , (순차 평가, 마지막 값 반환)
for (int i=0, j=4; i<5; i++, j--) {
printf("[%d, %d]\n", i, j);
}
6-4. 주소/역참조 &, *
int v=10, *p=&v;
printf("%d\n", *p); // 10 (포인터가 가리키는 값)
7) 우선순위·결합 방향(핵심만 압축)
1) () [] . -> x++ x-- (좌→우)
2) ++x --x + - ! ~ (type) * & sizeof (우→좌)
3) * / % (좌→우)
4) + - (좌→우)
5) << >> (좌→우)
6) < <= > >= (좌→우)
7) == != (좌→우)
8) & ^ | && || (모두 좌→우, 순서대로 낮아짐)
9) ?: (우→좌)
10) = += -= ... (우→좌)
11) , (좌→우)
안전한 코드를 위해 괄호로 의도를 명확히 하는 습관을 들이세요.
8) 형변환 규칙(요점)
- 정수 승격: char/short → int (또는 unsigned int)
- 서로 다른 타입이 섞이면 더 넓은 표현 범위의 타입으로 승격
- 정수 나눗셈을 피하려면 한쪽을 (double)로 캐스팅
int a=3; double b=2.5;
printf("%.1f\n", a/2); // 1.0 (정수/정수 → 1 → double 출력)
printf("%.1f\n", a/2.0); // 1.5
printf("%.1f\n", a/(double)2);// 1.5
'C' 카테고리의 다른 글
| 함수와 기억 클래스 (0) | 2025.11.11 |
|---|---|
| 선택 제어문과 반복 제어문 (0) | 2025.11.11 |
| 자료형과 선행처리기 (0) | 2025.10.13 |
| C 언어의 개요 (1) | 2025.08.27 |
| 모두를 위한 컴퓨터 과학(하버드CS50 2019)(4) (0) | 2025.04.29 |