본문 바로가기
C

입.출력 함수와 연산자

by curious week 2025. 10. 22.

 

 

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. 우선순위(상위 → 하위, 핵심만)

  1. 단항/후위: (), [], ., ->, x++, x--
  2. 단항 연산: ++x, --x, +, -, !, ~, (type), *(역참조), &(주소), sizeof
  3. 곱셈/덧셈: * / % → + -
  4. 시프트: << >>
  5. 관계/동등: < <= > >= → == !=
  6. 비트: & → ^ → |
  7. 논리: && → ||
  8. 삼항: ? :
  9. 대입: =, +=, -=, ...
  10. 쉼표: ,

결합 방향: 대부분 좌→우, 단, 대입/삼항/단항/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) 자주 나오는 함정/체크리스트

  1. 서식자 불일치
long x;   scanf("%ld", &x);  // long은 %ld
double d; scanf("%lf", &d);  // double은 %lf
  1. scanf("%c", &ch) 전에 남은 개행 처리
scanf(" %c", &ch); // 서식 앞 공백으로 공백류 스킵
  1. 문자열 입력 안전
scanf("%63s", s);       // 길이 한정
// 또는
fgets(s, sizeof s, stdin);
  1. 정수 나눗셈 주의
int a=3; printf("%f\n", a/2.0);  // 한쪽을 실수로
  1. 증감 연산자와 같은 피연산자 다중 사용 금지
// 미정의/구현 의존 위험
// printf("%d %d\n", x++, ++x);
  1. 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