본문 바로가기
Tech/Coding

C언어 고급]🚀문자

by redcubes 2024. 3. 29.

목차

A. ASCII 와 문자 입출력 함수

B. Buffer 사용 입력 함수

C. 정리 하기

A. ASCII 와 문자 입출력 함수

1. ASCII

분류문자 상수 아스키 코드 값출력할 때

종류 문자상수 코드값 출력할 때
숫자 문자(10개) '0' ~ '9' 48 ~ 57 문자 출력
대문자(26개) 'A' ~ 'Z' 65 ~ 90 문자 출력
소문자(26개) 'a' ~ 'z' 97 ~ 122 문자 출력
특수 문자(33개) ' ' (공백), '!', '&', ... 32, 36, 38 ... 문자 출력
제어 문자(33개) '\0', '\t', '\n', '\r' ... 0, 9, 10, 13 ... 제어 기능 수행
더보기

제어 문자(control characters)는 컴퓨터 텍스트와 통신에서 특정 동작을 제어하거나 특별한 목적을 가진 문자입니다. 이들은 주로 데이터의 흐름을 제어하거나, 텍스트 형식을 조정하는 데 사용됩니다. 아래는 몇 가지 제어 문자의 활용 사례입니다:

  1. 개행(New Line, \n): 텍스트 내에서 새로운 줄을 시작하고자 할 때 사용됩니다. 예를 들어, 프로그래밍 언어에서는 문자열 내에 \n을 삽입하여 여러 줄의 텍스트를 출력할 수 있습니다.
  2. 탭(Tab, \t): 텍스트 내에서 일정한 공간을 띄우고 싶을 때 사용합니다. 주로 텍스트의 정렬이나 가독성을 높이는 데 도움을 줍니다.
  3. 캐리지 리턴(Carriage Return, \r): 커서를 같은 줄의 시작 지점으로 옮기는 데 사용됩니다. 윈도우 운영 체제에서는 새 줄을 시작할 때 개행 문자와 함께 사용되며 (\r\n), 이는 "줄 바꿈"을 의미합니다.
  4. 벨(Bell, \a): 시스템 벨 소리를 내거나 알림을 주기 위해 사용됩니다. 일부 터미널이나 콘솔 환경에서 사용자에게 알림을 주고 싶을 때 활용할 수 있습니다.
  5. 백스페이스(Backspace, \b): 커서를 한 칸 왼쪽으로 이동시키고 그 위치의 문자를 삭제합니다. 텍스트를 지우거나 수정할 때 유용합니다.
  6. Form Feed (\f): 새 페이지를 시작하는 데 사용됩니다. 주로 프린터 컨트롤에서 페이지를 분리하고자 할 때 사용되며, 텍스트 문서에서 페이지 구분을 명확히 하고자 할 때도 활용됩니다.
  7. Escape (ESC): 키보드의 Escape 키와 같은 역할을 하는 제어 문자로, 다양한 제어 시퀀스의 시작을 알리는 데 사용됩니다. 예를 들어, 터미널이나 콘솔 환경에서 특정 모드로 진입하거나 나올 때 사용됩니다.

제어 문자는 프로그래밍, 텍스트 편집, 통신 프로토콜 등 다양한 분야에서 중요한 역할을 합니다. 데이터의 표현과 처리 방식을 제어함으로써 보다 정교한 통신과 텍스트 처리가 가능해집니다.

 

활용 예시

1. 개행(New Line, \n)

#include <stdio.h>

int main() {
    printf("첫 번째 줄\n두 번째 줄\n");
    return 0;
}

2. 탭(Tab, \t)

#include <stdio.h>

int main() {
    printf("이름\t나이\t직업\n홍길동\t30\t개발자\n");
    return 0;
}

3. 캐리지 리턴(Carriage Return, \r)

C 언어에서 캐리지 리턴을 사용하여 진행률을 표시하는 예시입니다. 이 예제에서는 1초 간격으로 0%에서 100%까지 진행률을 업데이트합니다.

#include <stdio.h>
#include <unistd.h>

int main() {
    for (int i = 0; i <= 100; i++) {
        printf("\r진행률: %d%%", i);
        fflush(stdout); // stdout 버퍼를 강제로 비워 즉시 출력하게 합니다.
        sleep(1); // 1초 대기
    }
    printf("\n"); // 마지막에 개행을 출력하여 다음 명령어 줄로 넘어갑니다.
    return 0;
}

4. 벨(Bell, \a)

#include <stdio.h>

int main() {
    printf("\a");
    return 0;
}

5. 백스페이스(Backspace, \b)

#include <stdio.h>

int main() {
    printf("Hello, world!\b\b\b\b\b\bPython\n");
    return 0;
}

6. Form Feed (\f)

C 언어에서는 \f가 종종 문서의 페이지를 분리하기 위해 사용되지만, 콘솔이나 터미널에서는 특별한 효과가 없습니다. 그래도 예시를 드리자면:

#include <stdio.h>

int main() {
    printf("페이지1\f페이지2\n");
    return 0;
}

7. Escape (ESC)

Escape 문자를 직접 사용하는 대신, 특정 터미널 명령(예: 화면 지우기)을 수행하고자 할 때 ESC 시퀀스를 사용할 수 있습니다. 이 예시는 일부 환경에서만 작동할 수 있습니다.

#include <stdio.h>

int main() {
    // ANSI 이스케이프 코드를 사용하여 콘솔 화면을 지웁니다.
    printf("\033[2J"); // 화면 전체를 지우는 ESC 시퀀스
    return 0;
}
 
--- ---

파일 입출력에서 제어 문자의 활용은 파일의 구조를 정의하고, 데이터를 읽거나 쓸 때 형식을 지정하는 데 중요한 역할을 합니다. C 언어를 예로 들어, 파일 작업에서 자주 사용되는 제어 문자의 활용법을 살펴보겠습니다.

1. 개행 (New Line, \n)

파일에 텍스트 데이터를 쓸 때, 개행 문자를 사용하여 여러 줄의 데이터를 구분합니다. 로그 파일을 작성하거나, 텍스트 기반의 데이터 파일을 생성할 때 유용합니다.

2. 탭 (Tab, \t)

CSV(Comma Separated Values) 파일과 같이, 데이터 필드를 구분할 때 탭 문자를 사용할 수 있습니다. 이는 가독성을 높이고, 데이터를 열로 구분하는 데 도움을 줍니다.

예제 코드: 개행과 탭 사용하기

파일에 여러 줄의 텍스트를 쓰고, 각 필드를 탭으로 구분하는 간단한 예제입니다.

#include <stdio.h>

int main() {
    FILE *fp = fopen("example.txt", "w"); // 파일을 쓰기 모드로 엽니다.
    if (fp == NULL) {
        perror("파일을 열 수 없습니다");
        return -1;
    }
    
    // 파일에 데이터 쓰기
    fprintf(fp, "이름\t나이\t직업\n");
    fprintf(fp, "홍길동\t30\t개발자\n");
    fprintf(fp, "김철수\t25\t디자이너\n");

    fclose(fp); // 파일을 닫습니다.
    return 0;
}

3. 파일 포맷 조정

파일의 헤더나 특정 섹션을 구분할 때, Form Feed (\f)나 다른 제어 문자를 사용하여 섹션을 구분하거나 페이지를 나눌 수 있습니다. 그러나 대부분의 텍스트 편집기나 시스템에서는 이러한 제어 문자가 시각적으로 표시되지 않을 수 있습니다.

예제 코드: 파일 읽기

저장된 파일을 읽고, 내용을 콘솔에 출력하는 예제입니다.

#include <stdio.h>

int main() {
    FILE *fp = fopen("example.txt", "r"); // 파일을 읽기 모드로 엽니다.
    if (fp == NULL) {
        perror("파일을 열 수 없습니다");
        return -1;
    }
    
    // 파일에서 데이터 한 줄씩 읽기
    char buffer[100];
    while (fgets(buffer, 100, fp) != NULL) {
        printf("%s", buffer); // 읽은 데이터를 출력합니다.
    }

    fclose(fp); // 파일을 닫습니다.
    return 0;
}

이 예제들은 파일 입출력에서 개행과 탭 같은 제어 문자를 활용하여 데이터를 구조화하고, 가독성 있는 방식으로 정보를 저장하고 읽는 방법을 보여줍니다. 파일 작업을 할 때 제어 문자를 적절히 사용하는 것은 데이터의 형식을 명확하게 정의하고, 필요한 정보를 쉽게 파싱할 수 있게 합니다.

%가 바뀌면서 프로그레스 바가 채워지는 애니메이션을 연출하려면?

#include <stdio.h>
#include <unistd.h>

#define PROGRESS_BAR_WIDTH 50

int main() {
    int progress;
    printf("진행 중: [");
    for (int i = 1; i <= PROGRESS_BAR_WIDTH; ++i) printf(" "); // 빈 프로그레스 바 공간 확보
    printf("]");

    for (progress = 0; progress <= 100; progress += 2) { // 2%씩 증가
        printf("\r진행 중: ["); // 캐리지 리턴으로 커서를 줄의 시작으로 이동
        int pos = (progress * PROGRESS_BAR_WIDTH) / 100;
        for (int i = 0; i < PROGRESS_BAR_WIDTH; ++i) {
            if (i < pos) printf("=");
            else if (i == pos) printf(">");
            else printf(" ");
        }
        printf("] %d%%", progress); // 현재 진행률 출력
        fflush(stdout); // 출력 버퍼를 즉시 비워 화면에 출력
        sleep(1); // 1초 대기
    }

    printf("\n완료!\n");
    return 0;
}


2. scanf

%c 로 문자 입력. 공백, 탭, 개행 등 제어 문자도 입력함.
공백, 탭, 개행  숫자를 입력할 때는 구분자가 되지만 문자에서는 하나의 데이터가 됨.

int a, b;
scanf("%d %d", &a, &b); //이렇게 하면 공백문자가 구분자가 됨.(공백은 숫자가 될 수 없음.)
scanf("%d%d", &a, &b); //이렇게 해도 공백문자가 구분자가 됨.(공백은 숫자가 될 수 없음.)
char ch1, ch2;
scanf(" %c %c", &ch1, &ch2); 
//%c앞에 화이트 스페이스 중 아무거나 추가하면 화이트 스페이스는 무시하고 
// 그 외 문자만 입력하는 기능이 있음.

scanf는 문자를 메모리 1바이트에만 저장하게 만들어져서 int변수를 쓰면 가비지값이 끼어서 입력한 문자의 아스키 코드 값을 바로 사용할 수 없게 됨. = 가능한 한 char형을 써라.

3. getchar, putchar

scanf, printf는 다목적(문자, 숫자 입력) = 덩치가 큼.

getchar(void), putchar(int)는 문자 전용.

getchar(); 는 공백 탭 개행 제외 못 함.

putchar("a"); 는 아스키 값이나 문자 상수를 주면 홤녀에 출력. 리턴으로 출력 문자를 반환하고 출력 과정에서 에러가 나면 -1 리턴.

char 형이 아니라 int로 반환하는 이유: 컨트롤z같이 입력을 끝내는 데 쓰는 문자가 입력되면 반환되는,
0~127이외의 값인 -1 반환값을 문자와 구분하기 위해(-1 값을 다루기 위해.)

키보드 입출력의 경우는 0~127 과 -1이 겹치지 않아서 구분이 가능하지만
파일 입출력의 경우 1바이트만 불러오면 255와 구분이 불가능해서 int로 -1인지 검사 후 char변수에 옮기는 게 좋음.

 

B. Buffer 사용 입력 함수

버퍼: 운영체제가 할당하는 메모리 저장 공간. 데이터 보관.

1. scanf 문자입력 과정

scanf로 한 문자씩 입력받을 때, 콘솔에서 여러 글자를 입력하고 한 번 리턴하면 버퍼에서 한 글자씩 읽어 옴.(세 번 입력받지 않음. 버퍼에 문자가 남아있지 않아야 다시 입력을 요구함.)
엔터를 누르는 순간 입력 데이터가 버퍼에 저장. 개행문자 포함 저장.

버퍼를 사용하면,

  • 데이터를 안정적으로 입력받음.(프로그램이 다른 일을 하느라 지금 입력을 못 받아도 데이터가 사라지지 않음. 예전 한글에서 빠르게 타자를 치면 아무 것도 안 나오다가 고스트 타이핑이 되는 현상.)
  • 입력 장치와 독립적으로 사용 가능. 키보드 말고 다른 장치로 바뀌어도 버퍼에만 넣는다면 (버퍼와 입력장치 연결은 운영체제의 몫임.)

2. scanf 함수 리턴값 활용

개행 문자도 입력 값으로 쓴다면 별도의 신호가 필요함. 반환값 이용.

ctrl + z 쓰면 -1 반환 운영체제에 따라 ctrl + z 엔터 ctrl + z를 써야 할 수도 있음(윈도10). 리눅스 계열은 ctrl + D
scanf가 -1리턴하기 전까지 입력을 반복하면 개행 문자를 포함한 모든 문자를 데이터로 사용할 수 있음.

그 이외에는 입력한 값의 개수 반환.(문자라면 1)

키보드로 숫자를 입력해도 일단 문자열로 버퍼에 자장. 변환문자로 변환해 저장.

EOF는 stdio.h에서 전처리 지시자가 1로 정의(사용하면 의미 파악이 쉬워 가독성에 도움이 됨)

#include <stdio.h>

int main(void)
{
	int res;             // scanf 함수의 반환값을 저장할 변수
	char ch;             // 문자를 입력할 변수

	while (1)
	{
		res = scanf("%c", &ch);  // 문자 입력, <Ctrl> + <Z>를 누르면 -1 반환
		if (res == EOF) break;    // 반환값이 -1이면 반복 종료
		printf("%d ", ch);       // 입력된 문자의 아스키 코드 값 출력
	}

	return 0;
}

3. getchar 사용 문자열 입력

얘도 버퍼를 사용함. 반복 사용하면 한줄의 문자열을 char배열에 입력 가능.

#include <stdio.h>

void my_gets(char* str, int size);

int main(void)
{
	char str[7];                             // 문자열을 저장할 배열

	my_gets(str, sizeof(str));               // 한 줄의 문자열을 입력하는 함수
	printf("입력한 문자열 : %s\n", str);     // 입력한 문자열 출력

	return 0;
}

void my_gets(char* str, int size)            // str은 char 배열, size는 배열의 크기
{
	int ch;                                  // getchar 함수의 반환값을 저장할 변수
	int i = 0;                               // str 배열의 첨자

	ch = getchar();                          // 첫 번째 문자 입력
	while ((ch != '\n') && (i < size - 1))   // 배열의 크기만큼 입력
	{
		str[i] = ch;             // 입력한 문자를 배열에 저장
		i++;                     // 첨자 증가
		ch = getchar();          // 새로운 문자 입력
	}
	str[i] = '\0';               // 입력된 문자열의 끝에 널 문자를 저장
}

4. 입력 버퍼 지우기

남은 문자를 모두 입력해서 사용하지(메모리에 저장하지) 않으면 됨.
버퍼에 남는 개행 문자 등을 지우기 위해 getchar();사용.

fgetc와 fputc는 stdin stdout을 인수로 지정해줌.(인수를 바꿀 수 있다는 이야기.)

C. 정리하기

1. 요약

2. 활용

3. 궁금한 점

색깔 있는 막대 프로그래스 바는 어떻게 만드나?

콘솔에서 색상 있는 막대 프로그래스 바를 구현하기 위해서는 ANSI 이스케이프 코드를 사용할 수 있습니다. ANSI 이스케이프 코드는 텍스트 색상 변경, 배경 색상 변경, 굵은 글씨나 이탤릭체 등 다양한 텍스트 스타일링을 가능하게 합니다. 여기서는 프로그래스 바의 색상을 변경하는 간단한 예제를 제공하겠습니다.

C 언어를 사용한 아래 예제에서는 프로그래스 바가 진행됨에 따라 초록색으로 채워지는 효과를 구현합니다. 이 예제는 대부분의 유닉스 기반 시스템(리눅스, macOS)의 터미널에서 잘 동작합니다. 윈도우의 명령 프롬프트나 파워셸에서는 ANSI 이스케이프 코드가 기본적으로 지원되지 않을 수 있으므로, 이를 활성화해야 할 수도 있습니다.

#include <stdio.h>
#include <unistd.h>

#define PROGRESS_BAR_WIDTH 50

int main() {
    int progress;
    for (progress = 0; progress <= 100; progress += 5) {
        int pos = (progress * PROGRESS_BAR_WIDTH) / 100;

        printf("\r["); // 캐리지 리턴으로 커서를 줄의 시작으로 이동
        // 프로그레스 바의 색상을 초록색으로 설정
        for (int i = 0; i < PROGRESS_BAR_WIDTH; ++i) {
            if (i < pos) printf("\033[42m \033[0m"); // 초록색 배경
            else printf(" ");
        }
        printf("] %d%%", progress); // 현재 진행률 출력
        fflush(stdout); // 출력 버퍼를 즉시 비워 화면에 출력

        sleep(1); // 1초 대기
    }

    printf("\n완료!\n");
    return 0;
}

이 코드에서 사용한 주요 개념은 다음과 같습니다:

  • ANSI 이스케이프 코드를 사용하여 텍스트 및 배경 색상을 변경합니다.
    • \033[42m는 배경을 초록색으로 설정하는 코드입니다.
    • \033[0m는 모든 스타일링을 초기화하는 코드입니다.
  • 프로그래스 바가 진행됨에 따라, 해당 비율에 맞게 초록색 배경의 공백 문자()를 출력하여 채워진 부분을 나타냅니다. 아직 채워지지 않은 부분은 기본 배경색의 공백 문자로 표시됩니다.

ANSI 이스케이프 코드는 텍스트 기반 인터페이스에서 시각적 요소를 풍부하게 표현할 수 있는 강력한 수단을 제공합니다. 다양한 색상과 스타일을 조합하여 사용자의 주의를 끌거나, 정보의 가독성을 높이는 데 유용하게 사용될 수 있습니다.