Notice
Recent Posts
Recent Comments
Link
«   2026/01   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

우당탕탕 개발일지

[C언어] 기본 입출력 및 비트 연산자 본문

Server/Linux, C

[C언어] 기본 입출력 및 비트 연산자

YUDENG 2025. 5. 11. 14:35

Linux man 사용법

$ man [options] [section] command
[SPACE] :  한 페이지 밑으로 내려간다
[ENTER] : 한 줄 밑으로 내려간다. 
[b] : 전 페이지로 올라간다. 
[q] : man 명령을 종료한다.

 

 


1. printf(), sprintf(), snprintf()

 

✅ printf 형식

int printf(const char *format, …)
 

 

printf 출력 형식

%d %i %u %X %x %o %p %s %c %C %f %e %E %g %G
 
출력 형식 인수의 형을 지정
%d int값을 10진수로 출력
%c 문자열 하나 출력
%p 포인터값을 16진수로 출력
%x int값을 부호없는 16진수로 출력, 10~15은  'a'~'f'로 표시
%u int 값을 부호없는 10진수로 출력
%o int 값을 부호없는 8진수로 출력
%s 문자열 출력, ‘\0’인 문자를 만날때까지 출력
%ld 부호있는 long 형 정수 출력
%lu 부호없는 long 형 정수 출력
%e double 값을 지수로 출력
 
 

  sprintf 형식

#include <stdio.h>
int sprintf(char *buffer, const char *format, argument-list);
  • 콘솔에 출력하는 대신 일반 문자열에 저장하는 함수
  • 첫 인수는 저장할 문자 버퍼, 두번째는 포맷 문자열, 세번째는 형식에 대응되는 데이터들이다.

 

  snprint 형식

#include <stdio.h>
int sprintf(char *buffer, const char *format, argument-list);
  • snprintf 함수의 취약점을 보완하고자 나온 함수로 지정한 크기만큼만 데이터를 버퍼에 저장하고 초과되는 데이터는 무시하는 함수
  • 첫 인수는 문자열을 저장할 배열, 두번째는 배열 크기, 세번째는 포맷 문자열, 네번째는 형식에 대응되는 데이터들이다.

2. scanf(), sscanf()

 

  scanf 형식

int scanf(const char *format, ...)
  • 사용자의 키보드 입력에서 받은 데이터를 포맷 스트링대로 분리해서 각 변수에 저장해주는 함수
  • %s는 스페이스를 끝으로 인식해 그 다음 0을 넣어 문자열을 종결시킨다.

 

  sscanf 형식

#include <stdio.h>
int sscanf(const char *buffer, const char *format, argument-list);
  • scanf( )와 동일하지만 입력 대상이 표준 입력이 아닌 매개변수로 전달되는 문자열 버퍼라는 차이가 있다.

 

  scanf, sscanf 특징

  1. %c를 제외하고 모든 데이터는 한단어씩 읽는다. 기본적으로 공백 문자(스페이스, 탭, 개행 문자 등)도 포함하여 처리한다.
  2. %d, %f, %s 와 같은 다른 형식 지정자들은 공백 문자를 무시한다.
  3. 배열의 크기보다 큰 문자열이 들어오면 버퍼오버플로우가 일어난다.
  4. 서식자에 맞지않는 데이터가 들어오면 오류가 발생한다.
  5. scanf함수의 경우 stdin(입력스트림)의 형식으로 입력을 받는다.
 
  성공 실패
scanf 읽어들인 것의 개수 0(아무것도 못읽었을 경우)
sscanf 읽어들인 것의 개수 0(아무것도 못읽었을 경우)

3. getchar(), gets()

 

  getchar 형식

#include <stdio.h>
int getchar(void);
 
  • 표준 입력으로 들어온 문자열을 한 문자씩 읽어오는 함수
  • 반환값이 int인 이유 → EOF(-1)를 처리하기 위함.

 

  gets 형식

#include <stdio.h>
int *gets(char *s);
  • 표준 입력으로 들어온 문자열을 char*, char[ ] 타입으로 저장해주는 함수
  • 문자열이라고 감지하는 기준은 개행(\n)이다. 즉, 표준 입력으로 들어온 문자열을 개행한 부분 앞까지 잘라서 char* 타입의 문자열로 저장해주고, 자동으로 문자열 맨 끝에 ‘\n’을 넣어서 문자열을 완성해준다.

 

  gets 사용 예제

#define BUFFER 256

int main(void)
{
	char string[BUFFER];
	char *result;

	result = gets(string);
	printf("%s\n", result);
}

 

  getchar, gets특징

  1. gets 함수는 자동으로 끝에 (\0)을 넣어준다.
  2. gets는 버퍼 오버플로우가 날 수 있다.
 
  성공 실패
getchar 읽어들인 문자 EOF(-1)
gets 읽어들인 문자열 NULL 포인터

 

🔷 사용자가 개행 문자를 입력할 때까지 입력받는 my_getline() 함수

함수 프로토타입: int my_getline(char *buf, int buf_len)

  • getline 함수는 터미널에서 사용자가 개행문자를 입력할 때까지 입력한 문자열을 buf에 저장하는 함수이다.
  • 사용자가 입력한 문자열이 buf의 길이보다 작을 때는 buf에 사용자가 입력한 문자열을 저장하고 개행문자를 널문자로 치환한다.
  • 사용자가 입력한 문자열이 buf의 길이보다 큰 경우에는 buf_len-1 만큼만 buf에 저장하고 마지막에 널문자를 저장하고 이후 사용자가 개행문자를 입력할 때까지 입력한 문자열은 저장하지 않고 버린다.
  • buf는 입력받은 문자열을 저장할 인자이고 buf_len은 buf의 길이이다.
  • 리턴값은 실패인 경우에 -1, 성공한 경우에는 사용자가 입력한 문자열의 길이를 리턴한다.
#include <stdio.h>
#include <string.h>

int my_getline(char *buf, int buf_len) {
	
	char ch;
	int len = 0;

	if(buf == NULL) {
		puts("buf is NULL");
		return -1;
	}

	if(buf_len <= len) {
		puts("buf_len is too small");
		return -1;
	}

	while(1) {
	
		ch = getchar();

		if(ch == EOF) {
			return -1;
		}

		if(ch == '\n') {
			buf[len++] = '\0';
			break;
		}

		if(len >= buf_len - 1) {
			buf[buf_len - 1] = '\0';
			break;
		}
		
		buf[len++] = ch;
	}

	return len;
}

4. putchar(), puts()

 

  putchar 형식

#include <stdio.h>
int putchar(int c);
 
  • char*, char[ ] 타입을 표준 출력(stdout)으로 보내는 함수

 

  puts 형식

#include <stdio.h>
int puts(const char *s);
  • putchar 함수는 문자 한개를 출력할 때 유용한 함수

 

  putchar, puts 특징

  1. puts 함수는 자동으로 마지막에 개행 문자를 넣어준다.
  2. putchar 함수는 한 문자만 출력하며, 개행 문자를 자동으로 추가하지 않는다.
 
  성공 실패
puts 음이아닌값 EOF(-1)
putchar 출력된문자 EOF(-1)
 

 

  EOF

EOF = End Of File 이며, 파일의 끝을 표현하기 위해 정의해 놓은 상수이다.

 

EOF를 반환하는 경우

  1. 함수 호출의 실패
  2. 윈도우에서 ctrl + z, 리눅스에서 ctrl + d를 입력 했을 경우

5. 비트 연산자

 

 
연산자 연산자의 기능
& 비트단위로 AND 연산을 한다.
| 비트단위로 OR 연산을 한다.
^ 비트단위로 XOR 연산을 한다.
~ 단항 연산자로서 피연자의 모든 비트를 반전시킨다.
<< 피연산자의 비트 열을 왼쪽으로 이동시킨다.
>> 피연산자의 비트 열을 오른쪽으로 이동시킨다.

 

NOT(~) 연산자

비트를 0에서 1로, 1에서 0으로 발전시키는 NOT 연산을 하며, 보수연산이라고도 불린다.

연산 결과
~ 0 1
~ 1 0
 

AND(&) 연산자

두 개의 비트가 모두 1일때 1을 반환하는 AND 연산을 한다.

연산 결과
0 & 0 0
0 & 1 0
1 & 0 0
1 & 1 1
 

OR(|) 연산자

두 개의 비트 중 하나라도 1이면 1을 반환하는 OR 연산을 한다.

연산 결과
0 | 0 0
0 | 1 1
1 | 0 1
1 | 1 1
 

XOR(^) 연산자

두 개의 비트가 서로 다른 경우에 1을 반환하는 XOR 연산을 한다.

연산 결과
0 ^ 0 0
0 ^ 1 1
1 ^ 0 1
1 ^ 1 0
 

Shift(<<, >>) 연산자

<< 연산자는 비트를 왼쪽으로, >> 연산자는 비트를 오른쪽으로 이동하는 shift 연산이다.

 

🔷 수강 신청 정보를 입력받아 관리하는 수강 신청 프로그램 (비트연산 응용)

  • 수강 신청 정보는 최대로 5개까지 저장해야 하며, 5개 초과되는 정보를 입력한 경우에는 에러를 출력한다.
  • 입력된 수강 신청 정보는 메모리에 보관하고 프로그램 재기동시에 리셋된다.
  • 프로그램은 수강 신청 입력, 수강 신청 출력, 종료 3개 메뉴를 출력하고 사용자가 종료를 선택하기 전까지 반복해서 수강 신청 입력/출력/종료를 반복한다.
  • 수강 신청 정보 입력은 my_getline() 함수를 사용한다.

🔹 입력

 

1. 사용자가 메뉴에 해당하는 번호를 입력한다.

  • 1은 수강 신청 정보 입력, 2는 수강 신청 정보 출력, 3은 종료
  • 메뉴에 없는 번호를 입력한 경우, 다시 메뉴를 출력한다.

2. 수강 신청 정보 입력을 선택하면 다음과 같이 출력하고 ID와 수강 신청 과목 정보를 입력받는다.

  ID:
  수강 신청 과목:

  • ID는 정수로 1 <= ID <= 100 의 범위 값을 가진다. 범위에 벗어나는 값을 입력한 경우 에러 문구 출력하고 메뉴를 출력한다.
  • 수강 신청 과목은 컴퓨터개론, 이산수학, C언어, JAVA초급, 리눅스구조, 자료구조, 컴파일러, 네트워크개론이다.
  • 수강 신청 과목은 컴퓨터개론, 이산수학, C언어, JAVA초급, 리눅스구조, 자료구조, 컴파일러, 네트워크개론으로 각 과목을 신청할지 말지를 O, X로 입력받는다(각 과목당 한줄). O은 신청, X는 미신청

    컴퓨터개론: O
    이산수학: X
    C언어: O
    JAVA초급: X
    리눅스구조:O
    자료구조: X
    컴파일러: O
    네트워크개론:O

  • 수강 신청 과목 정보 입력시 O 또는 X 이외의 문자를 입력하면 에러를 출력하고 메뉴를 출력한다.

3. 수강 신청 출력을 선택하면, 저장된 모든 수강 신청 정보를 출력한다.

4. 종료를 선택하면 프로그램을 종료한다.

 

#include <stdio.h>
#include <stdlib.h>
#include "my_getline.h"

#define MIN_ID 1
#define MAX_ID 100
#define MAX_SUBJECTS 8
#define MAX_SUBJECTS_NUM 5
#define MAX_STORE 100

typedef struct _subjects_info_s {
	int id;
	unsigned char subjects; 
} subjects_info_t;

typedef struct _subjects_data_s {
	subjects_info_t subjects_info[MAX_STORE];
	size_t subjects_info_size;
} subjects_data_t;

const char *subjects[] = {
    "컴퓨터개론", "이산수학", "C언어", "JAVA초급", 
    "리눅스구조", "자료구조", "컴파일러", "네트워크개론"
};

int subjects_input(int n, subjects_info_t *subjects_data) {

	if (subjects_data == NULL) {
		printf("subjects_input : subjects_data is null\n");
		return -1;
	}
	
	if (subjects_data->subjects_info_size >= MAX_STORE) {
		printf("subjects_input : subjects_data is full\n");
		return -1;
	}

	int i, id;
	char buf[4];

	printf("ID: ");
	if(my_getline(buf, 4) == -1) return -1;

	id = atoi(buf);
	if(id < MIN_ID || id > MAX_ID) {
		printf("wrong id input\n");
		return -1;
	}
	
	subjects_data[n].id = id;
	subjects_data[n].subjects = 0;

	for(i = 0; i < MAX_SUBJECTS; i++) {
		printf("%s: ", subjects[i]);
		
		if(my_getline(buf, 2) == -1) {
			return -1;
		}

		// O -> 원소 추가
		if(buf[0] == 'O'){
			subjects_data[n].subjects |= (1 << i);
		} else if(buf[0] != 'X'){
			printf("O 또는 X 이외의 문자");
			return -1;
		}
	}
    
    subjects_data->subjects_info_size++;
    return 0;
}

void subjects_output(int n, subjects_info_t *subjects_data) {
	
	if(n <= 0) {
		printf("신청 내역이 없습니다.\n");
		return;
	}

	int i, j;

	for(i = 0; i < n; i++) {
		printf("ID: %d // 수강신청 과목: ", subjects_data[i].id);
		
		int first_flag = 1;
		for(j = 0; j < MAX_SUBJECTS; j++) {
			if((subjects_data[i].subjects & (1 << j)) != 0) {
				if(!first_flag) printf(", ");
				
				printf("%s", subjects[j]);
				first_flag = 0;
			}
		}
		printf("\n");
	}
}

int main(void) {

	int num = 0;
	char buf[2];

	subjects_data_t subjects_data;
	memset(&subjects_data, 0x00, sizeof(subjects_data));

	while(1) {

		printf("--------------------------------------------------------- \n");
		printf("1. 수강 신청 정보 입력\n2. 수강 신청 정보 출력\n3. 종료\n");
    	printf("select num: ");
        
        if (my_getline(buf, 2) < 0) {
			printf("get line fail\n");
			continue;
		}

		int ans = 0;
		switch(buf[0]) {
			case '1':
				if (subjects_input(&subjects_data) < 0) {
					printf("subject information input error\n");
				}
				break;

			case '2':
				subjects_output(num, subjects_data);
				break;

			case '3':
				exit(0);

			default:
				break;

		}
	}

	return 0;
}
728x90

'Server > Linux, C' 카테고리의 다른 글

[C언어] Thread  (4) 2025.06.25
[C언어] Makefile / GDB  (0) 2025.05.25
[C언어] 전처리기  (0) 2025.05.25
[Linux] 리눅스 파일과 파일 시스템  (1) 2025.05.11
[C언어] 문자열 (feat. strcpy, strtok_r 활용 예제)  (0) 2025.05.11