C언어 이론 정리 - 01

Lee Pil Ung·2021년 12월 3일
2

C

목록 보기
1/6
post-thumbnail

📖 공부를 시작함에 앞서

C언어를 크게 20개 가량의 챕터로 나눠서 공부한 개념을 별도로 정리할 계획이다. 
각 게시글마다의 길이는 천차 만별일 수도 있다.
연관되는 개념, 지식등도 별도로 작성헀다.
일단은 글쓴 본인에 맞춰 알아보기 쉽게 별도로 정리하였다. 
자료 참조 : TCP School.com

C언어

C언어는 현재 사용하고 있는 거의 모든 컴퓨터 시스템에서 사용할 수 있는 프로그래밍 언어이다.

프로그래밍 언어는 크게 저급 언어(low-level language)고급 언어(high-level language) 나뉜다.

저급 언어와 고급 언어는 좋고 나쁜 언어가 아니라, 기계가 이해하기 쉬운가(저급 언어), 사람이 이해하기 쉬운가(고급 언어)를 상대 적으로 나눈 개념이다.

❓ 저급 언어(low-level language)란?

저급 언어는 컴퓨터가 이해하기 쉽게 작성된 프로그래밍 언어로, 대표적인 언어로는 기계어(machine language)어셈블리어(assembly language) 등이 있다.

이 언어는 실행 속도가 매우 빠르지만, 사람이 배우기에는 매우 어려워 프로그램의 유지보수가 힘들다.

❓ 고급 언어(high-level language)란?

고급 언어는 컴퓨터보다는 사람이 알기 쉽도록 작성된 프로그래밍 언어이다.

고급 언어는 컴파일러나 인터프리터에 의해 기계가 이해 할 수 있는 언어로 번역되어 실행된다.

저급 언어보다는 상대적으로 실행 속도가 느리다. 대표적으로 자바, 파이썬 등이 있다. 저급 언어에 비해 가독성이 높고 다루기가 쉽다.

C언어는 저급 언어와 고급 언어의 특징을 모두 가지고 있는 절차 지향 프로그래밍 언어(procedure-oriented programming language)에 해당한다.

C 언어의 특징

C언어가 가지는 장, 단점은 다음과 같다.

👍 장점

  1. C언어로 작성된 프로그램은 다양한 하드웨어로의 이식성이 좋다.
  2. C언어는 절차 지향 프로그래밍 언어로, 코드가 복잡하지 않아 유지보수가 상대적으로 쉽다.
  3. C언어는 저급 언어의 특징을 가지고 있으므로, 어셈블리어 수준으로 하드웨어를 제어할 수 있다.
  4. C언어는 코드가 간결하여, 완성된 프로그램의 크기가 작고 실행 속도가 빠르다.

👎 단점

  1. C언어는 저급 언어의 특징을 지니고 있어, 자바와 같은 다른 고급 언어보다 배우기가 쉽지 않다.
  2. C언어는 다른 언어와는 달리 시스템 자원을 직접 제어할 수 있어 프로그래밍하는데 세심한 주의를 기울여야 한다.

C 프로그래밍(C Programming)

프로그래밍(Programming)이란 목적에 맞는 알고리즘으로부터 프로그래밍 언어를 사용하여 구체적인 프로그램을 작성하는 과정을 의미한다.

C언어에서는 작성된 프로그램이 실행파일로 변환되어야 실행할 수 있다.

C언어에서 실행 파일을 생성하는 순서이다.

  1. 소스 파일(source file)의 작성

  2. 선행처리기(preprocessor)에 의한 선행처리

  3. 컴파일러(compiler)에 의한 컴파일

  4. 링커(linker)에 의한 링크

  5. 실행 파일(executable file)의 생성

1. 소스 파일(source file)의 작성

C언어를 사용하여 문법에 맞게 논리적으로 작성된 프로그램을 원시 파일 또는 소스 파일이라고 부른다.

C언어를 통해 작성된 소스 파일의 확장자는 .c 가 된다.

2. 선행처리기(preprocessor)에 의한 선행처리

선행처리(preprocess)란 소스 파일 중에서도 선행처리 문자(#)로 시작하는 선행처리 지시문의 처리 작업을 의미한다.

이러한 선행처리 작업은 선행처리기(preprocessor)가 수행한다.

선행처리기는 코드를 생성하는 것이 아닌, 컴파일하기 전 컴파일러가 작업하기 좋도록 소스를 재구성해주는 역할만을 한다.

3. 컴파일러(compiler)에 의한 컴파일

컴퓨터는 0과 1로 이루어진 이진수로 작성된 기계어만을 이해할 수 있다.

그러나 소스 파일은 개발자에 의해 C언어로 작성되므로, 컴퓨터는 그것을 바로 이해할 수 없다.

따라서 소스 파일을 컴퓨터가 알아볼 수 있는 기계어로 변환시켜야 하는데, 그 작업을 컴파일(compile)이라고 부른다.

컴파일은 컴파일러에 의해 수행되며, 컴파일이 끝나 기계어로 변환된 파일을 오브젝트 파일(object file)이라고 부른다.

이러한 오브젝트 파일의 확장자는 .o.obj 가 된다.

4. 링커(linker)에 의한 링크

컴파일러에 의해 생성된 오브젝트 파일(.o.obj)은 운영체제와의 인터페이스를 담당하는 시동 코드(start-up code)를 가지고 있지 않는다.

또한, 대부분의 C 프로그램에서 사용하는 C 표준 라이브러리 파일도 포함되어 있지 않다.

이때 하나 이상의 오브젝트 파일과 라이브러리 파일, 시동 코드 등을 합쳐 하나의 파일로 만드는 작업을 링크(link)라고 한다.

링크링커(linker)에 의해 수행되며, 링크가 끝나면 하나의 새로운 실행 파일이나 라이브러리 파일이 생성된다.

이처럼 여러 개의 소스 파일을 작성하여 최종적으로 링크를 통해 하나의 실행 파일로 만드는 것을 분할 컴파일이라고 부른다.

5. 실행 파일(executable file)의 생성

소스 파일은 선행처리기, 컴파일러 그리고 링커에 의해 위와 같은 과정을 거쳐 실행 파일로 변환된다.

최근 사용되는 개발 툴은 대부분 위에서 소개한 선행처리기, 컴파일러, 링커를 모두 내장하고 있기 때문에 소스 파일에서 한 번에 실행 파일을 생성해 준다.

이렇게 생성된 실행 파일의 확장자는 .exe 가 된다.

C 프로그램의 구조

간단한 C 프로그램의 기본 구조는 다음 예제와 같습니다.

📝 예제

#include
#define

int main(void)

{
    명령문;
    ...
    return;
}

📝 예제

#include <stdio.h>
#define TEXT "Welcome to C Programming!!"

int main()

{
    printf(TEXT);
    return 0;
}
// 실행결과 = Welcome to C Programming!!

C 프로그램의 특징

C언어로 작성된 프로그램이 가지는 일반적인 특징은 다음과 같다.

  1. C 프로그램의 기본 단위는 함수이다.

  2. 함수 내의 각 명령문은 세미콜론(;)으로 끝나야 한다.

  3. C언어는 대소문자를 구분한다.

  4. C언어는 자유 형식(free-format)을 허용한다.

또한 C프로그램의 기본 단위는 함수이다.

C프로그램은 하나 또는 그 이상의 함수(function)으로 이뤄진다.

또한, C언어로 구현되는 모든 프로그램은 반드시 main()함수를 가지고 있어야 한다. 왜냐하면 C 프로그램이 실행되면 컴퓨터는 제일 먼저 main()함수를 찾아서 호출하기 때문이다.

#include <stdio.h>
#define TEXT "Welcome to C Programming!!"

int main()
{
    return 0;     // main() 함수의 모든 명령문을 수행한 후에는 0을 반환함.
}

또한 함수 내의 각 명령문은 세미콜론(;)으로 끝나야 한다.

함수는 언제나 기능을 가지고 있어야 한다. C언어에서 이러한 기능을 정의하기 위해 사용되는 문장을 명령문(statement)라고 한다.

함수 내의 명령문은 언제나 위에서부터 아래로 순차적으로 실행되며, 언제나 세미콜론(;)으로 끝나야 한다.

📝 예제

printf("C언어"); // 정상적으로 출력됨.
printf("C언어") // 오류가 발생함.

C언어는 대소문자를 구분한다.

C언어에서 변수나 함수의 이름을 작성할 때나 키워드나 예약 등을 사용할 때는 대소문자를 정확히 구분하여 사용해야 한다.

📝 예제

printf("C언어"); // 정상적으로 출력됨.
Printf("C언어")  // 오류가 발생함.

C언어는 자유 형식(free-format)을 허용한다.

C언어에서는 문법만 맞으면 여러 개의 명령문을 한 줄에 쓸 수도 있고, 하나의 명령문을 여러 줄에 나누어 쓸 수도 있다.

하지만 프로그램의 구조를 한눈에 파악할 수 있도록, 될 수 있으면 들여쓰기 등을 잘 활용해 보기 좋게 작성하는 것이 좋다.

다음 두 예제는 동일한 동작을 한다.

📝 예제

int func() { printf("C언어는 재밌어요!"); }
int func()
{
    printf("C언어는 재밌어요!");
}
// 그러나 코드의 가독성을 위해 들여쓰기를 사용하여 코들들 작성하는 것이 좋다.

주석(comments)

주석은 코드에 대한 이해를 돕는 설명을 적거나 디버깅을 위해 작성한다.

C언어의 한 줄 주석은 시작위치에 //을 사용하고, 여러 줄 주석은 /로 시작해서 반드시 /로 끝나야 한다.

✅ 문법(Grammar)

// 한 줄 주석

/* 여러
   줄
   주석 */

📝 예제

/* 여러 줄
    // 이렇게 두 줄 주석 안에 또 다른 한 줄 주석을 삽입할 수 있습니다.
주석입니다. */

C언어에서는 여러 줄 주석 안에 또 다른 한 줄 주석은 삽입할 수 있다.

하지만 다음 예제처럼 여러 줄 주석 안에 또 다른 여러 줄 주석은 중첩해서 삽입할 수 없다.

📝 예제

/* 여러 줄
②    /* 또 다른 여러 줄 주석입니다. */
③ 주석입니다. */

위의 예제처럼 여러 줄 주석 안에 또 다른 여러 줄 주석을 삽입하면, 2번 라인에서 삽입한 주석의 종료 기호(*/)를 1번 라인에서 시작한 첫 번째 주석이 자신의 종료 기호(*/)로 잘못 인식하게 된다.

따라서 위 예제의 3번 라인은 주석으로 인식되지 못하고, 컴파일 시 오류가 발생한다.

그렇기 때문에 C언어에서 여러 줄 주석은 절대로 중첩해서 사용하면 안 된다.

#include <stdio.h>
#define TEXT "Welcome to C Programming!!"

/* 여기서부터 main() 함수 시작 부분임.
    작성자 : 이필웅(Lenol) */

int main()
{
    printf(TEXT); // printf() 함수는 인자로 전달받은 데이터를 출력해주는 함수이다.
    return 0;   // main()함수의 모든 명령문을 수행한 후에 반환하는 부분. (여기선 0을 반환)
}

printf() 함수

printf() 함수란 C 언어 표준 입출력 함수이다.

  • 입출력 함수란?
    사용자가 프로그램과 대화하기 위해 사용하는 함수를 입출력 함수 or I/O(= In/Out) 함수라고 한다.

printf() 함수와 scanf() 함수는 C언어 표준 입출력 함수중에서도 가장 많이 사용되는 대표적인 입출력 함수이다.

printf()함수는 여러 종류의 데이터(data)를 다양한 서식에 맞춰 출력할 수 있게 해준다.

✅ 함수 원형

#include <stdio.h>
int printf(const char * restrict format, ...);

printf 에서 f는 formatted의 약자이며, 서식화된 출력을 지원한다는 의미이다.

이 함수는 출력할 데이터를 어떤 서식에 맞춰 출력할지 서식 지정자(format specifier)를 통해 직접 지정할 수 있다.

📝 예제

printf("printf() 함수는 서식 지정자를 통해 출력할 데이터의 서식을 지정할 수 있어요!\n");
// printf() 함수는 서식 지정자를 통해 출력할 데이터의 서식을 지정할 수 있어요!  -> 출력됨

printf("변수에 저장된 숫자는 %d입니다.", 10);
// 변수에 저장된 숫자는 10입니다. -> 출력됨

위의 예제에서 int형 데이터를 나타내기 위해 %d와 같은 서식 지정자를 사용했다.

또한 줄 바꿈은 흔히 아는 \n이라는 이스케이프 시퀀스를 사용하여 표현하고 있다.

이스케이프 시퀀스(escape sequence)

\n과 같은 문자를 이스케이프 시퀀스(escape sequence)라고 한다.

서식지정자출력데이터 형태
\'작은따옴표
\"큰따옴표
\?물음표
\\백슬래시(\)
\a경고음 발생
\b백스페이스(backspace)
\n줄 바꿈(new line)
\r캐리지 리턴(carriage return)
\t수평 탭(tab)
\v수직 탭(tab)
\f폼 피드(form feed)

📝 예제

#include <stdio.h>
#define TEXT "C언어에서 사용하는 \'특수 문자\'에는 여러가지가 있습니다. \n"
#define TEXT2 "\t특수 문자의 바로 앞에는 언제나 \\가 와야 합니다."

int main()
{
  printf(TEXT);
  return 0;
}
// C언어에서 사용하는 '특수 문자'에는 여러가지가 있습니다. -> 출력됨

// 	특수 문자의 바로 앞에는 언제나 \가 와야 합니다. -> 출력됨

서식 지정자(format specifier)

앞선 예제에서 두 번째 printf() 함수에 나온 %d와 같은 문자를 서식 지정자(format specifier)라고 한다.

printf() 함수에서는 이러한 서식 지정자를 통해 출력할 데이터의 서식을 사용자가 직접 지정할 수 있다.

C언어에서 사용되는 대표적인 서식 지정자는 다음과 같다.

서식 지정자출력 데이터 형태
%c하나의 문자
%s문자열
%d부호 있는 10진 정수
%i부호 있는 10진 정수 (%d와 동일)
%f고정 소수점으로 표현한 실수 (소수점 이하 6자리까지 표현)
%o부호 없는 8진 정수
%u부호 없는 10진 정수
%x부호 없는 16진 정수 (소문자 사용)
%X부호 없는 16진 정수 (대문자 사용)
%e부동 소수점으로 표현한 실수 (e-표기법)
%E부동 소수점으로 표현한 실수 (E-표기법)
%g값에 따라 %f나 %e를 사용함.
%G값에 따라 %f나 %E를 사용함.
%%퍼센트(%) 기호 출력

📝 예제

#include <stdio.h>

int main()
{
  printf("%%c를 사용한 결과 : %c\n", 'a');            // 문자, 출력값 : %c를 사용한 결과 : a
  printf("%%s를 사용한 결과 : %s\n", "즐거운 C언어"); // 문자열, 출력값 : %s를 사용한 결과 : 즐거운 C언어

  printf("%%f를 사용한 결과 : %f\n", 0.123456); // 출력값 : %f를 사용한 결과 : 0.123456
  printf("%%f를 사용한 결과 : %f\n", 0.123456789);    // 소수점 6자리까지만 표현, 출력값 : %f를 사용한 결과 : 0.123457

  printf("%%o를 사용한 결과 : %o\n", 123);            // 8진 정수, 출력값 : %o를 사용한 결과 : 173
  printf("%%x를 사용한 결과 : %x\n", 123);            // 16진 정수, 출력값 : %x를 사용한 결과 : 7b

  printf("%%g를 사용한 결과 : %g\n", 0.001234);       // 값에 따라 %f나 %e, 출력값 : %g를 사용한 결과 : 0.001234
  printf("%%g를 사용한 결과 : %g\n", 0.00001234);     // 값에 따라 %f나 %e, 출력값 : %g를 사용한 결과 : 1.234e-05
  printf("%%G를 사용한 결과 : %G\n", 0.000001234);    // 값에 따라 %f나 %E, 출력값 : %G를 사용한 결과 : 1.234E-06
}

서식 지정자의 동시 사용

여러 개의 서식 지정자를 동시에 사용하여 다른 데이터값을 한번에 출력할 수 있다.

이때 서식 지정자의 순서와 타입은 출력할 데이터의 순서나 타입과 일치해야 한다.

📝 예제

#include <stdio.h>

int main()
{
  printf("저장된 정수는 %d이며, 저장된 문자열은 %s입니다.\n", 123, "C언어");
    // 출력값 : 저장된 정수는 123이며, 저장된 문자열은 C언어입니다.
}

출력 필드의 폭 설정

서식 지정자의 %기호와 타입을 나타내는 영문자 사이에 숫자를 추가하여 출력되는 필드의 폭을 직접 설정할 수 있다.

내부의 숫자는 오른쪽 정렬이 기본값이며, 숫자 앞에 '-' 기호를 붙이면 왼쪽 정렬로 바뀐다.

또한, 숫자 앞에 '+'기호를 붙이면 숫자를 오른쪽 정렬한 상태에서 양수에는 '+' 기호를, 음수에는 '-' 기호를 붙여서 출력한다.

이때 소수 부분의 숫자는 출력되는 소수의 자릿수를 명시해야 한다.

📝 예제

#include <stdio.h>

int main()
{
  printf(" %%d를 사용한 결과 : |%d|\n", 123); // 출력값 : %d를 사용한 결과 : |123|

  printf(" %%7d를 사용한 결과 : |%7d|\n", 123);  // 출력값 : %7d를 사용한 결과 : |    123|

  printf(" %%+7d를 사용한 결과 : |%+7d|\n", 123);  // 출력값 : %+7d를 사용한 결과 : |   +123|

  printf(" %%-7d를 사용한 결과 : |%-7d|\n\n", 123);  // 출력값 : %-7d를 사용한 결과 : |123    |

  printf(" %%f를 사용한 결과 : |%f|\n", 1.23);  // 출력값 : %f를 사용한 결과 : |1.230000|

  printf(" %%.1f를 사용한 결과 : |%.1f|\n", 1.23);  // 출력값 : %.1f를 사용한 결과 : |1.2|

  printf(" %%7.2f를 사용한 결과 : |%7.2f|\n", 1.23);  // 출력값 : %7.2f를 사용한 결과 : |   1.23|

  printf("%%+7.2f를 사용한 결과 : |%+7.2f|\n", 1.23);  // 출력값 : %+7.2f를 사용한 결과 : |  +1.23|

  printf("%%-7.2f를 사용한 결과 : |%-7.2f|\n\n", 1.23);  // 출력값 : %-7.2f를 사용한 결과 : |1.23   |
}

scanf() 함수

scanf() 함수 또한 C언어의 대표적인 표준 입력 함수로, 사용자로부터 다양한 데이터를 다양한 서식에 맞춰 입력받을 수 있게 한다.

scanf() 함수의 원형은 다음과 같다.

✅ 함수 원형

#include <stdio.h>

int scanf(const char * restrict format, ...);

여기서 f는 printf()의 경우와 동일하다.

📝 예제

#include <stdio.h>

int main()
{
    int num01, num02;

    printf("첫 번째 정수를 입력하세요 : ");
    scanf("%d", &num01);

    printf("두 번째 정수를 입력하세요 : ");
    scanf("%d", &num02);

    printf("입력하신 두 정수의 합은 %d입니다.\n", num01 + num02);
    return 0;
}
// 실행 결과
첫 번째 정수를 입력하세요 : 10
두 번째 정수를 입력하세요 : 20
입력하신 두 정수의 합은 30입니다.

C언어에서 데이터를 입력받으려면 입력받고자 하는 데이터의 타입에 해당하는 크기의 메모리를 우선 할당받아야 한다.

이처럼 데이터를 저장하기 위해 프로그램에 의해 이름을 할당받은 메모리 공간을 변수(variable)라고 한다.

앞선 예제에서 scanf() 함수에 포함된 &기호는 주소 연산자(&)라고 한다.

이 주소 연산자는 입력받은 데이터를 뒤에 나오는 변수에 저장하라는 의미이다.

서식 지정자의 동시 사용

여러 개의 서식 지정자를 동시에 사용하여, 여러 데이터를 서로 다른 서식으로 한 번에 입력받을 수 있다.

입력받는 데이터의 구분은 공백(줄 바꿈, 탭, 띄어쓰기 등)을 기준으로 삼는다. 또한 이때에도 서식 지정자의 순서, 변수의 순서등이 같아야 한다.

📝 예제

#include <stdio.h>

int main(void)
{
    int num01, num02;

    printf("두 개의 정수를 입력하세요 : ");
    scanf("%d %d", &num01, &num02);

    printf("입력하신 두 정수를 8진수로 나타내면 %o와 %o가 되고,\n", num01, num02);
    printf("입력하신 두 정수를 16진수로 나타내면 %x와 %x가 됩니다.\n", num01, num02);

    return 0;
}
// 실행 결과
두 개의 정수를 입력하세요 : 10 20
입력하신 두 정수를 8진수로 나타내면 1224가 되고,
입력하신 두 정수를 16진수로 나타내면 a와 14가 됩니다.

double형 실수의 입력

scanf() 함수로 float형 실수를 입력받을 때는 서식 지정자로 '%f'를 사용하면 뙨다.

하지만 double형 실수를 입력받을 때는 printf() 함수에서처럼 '%f'를 사용하면 안 된다.

-❓ 여기서 double형 이란??

    double형 실수란 실수형 변수 선언의 한 종류로써 float형과 더불어 사용된은 표현이다.
    float형보다 크기가 더 크며 소수점 이하 표현 자리수도 더 길다.
  • float형(4바이트, 32비트, 소수점 이하 7자리까지 표현)

  • double형(8바이트, 64비트, 소수점 이하 15자리까지 표현)

scanf() 함수로 double형 실수를 입력받을 때는 반드시 %lf 서식 지정자를 사용해야 정확한 값으로 입력받을 수 있다.

📝 예제

#include <stdio.h>

int main(void)

{
    float num01;
    double num02;

    printf("두 개의 실수를 입력하세요 : ");
    scanf("%f %f", &num01, &num02);
    printf("입력하신 두 실수는 %f와 %f입니다.\n", num01, num02);
    printf("입력받은 두 실수 중 두 번째 double형 변수에는 전혀 다른 값이 저장되었습니다.\n\n");

    printf("다시 한 번 두 개의 실수를 입력하세요 : ");
    scanf("%f %lf", &num01, &num02);
    printf("입력하신 두 실수는 %f와 %f입니다.\n", num01, num02);
    printf("이번에는 두 실수 모두 제대로 저장되었습니다.\n");
    return 0;
}
// 실행 결과
두 개의 실수를 입력하세요 : 1.2 3.4
입력하신 두 실수는 1.200000와 0.000000입니다.
입력받은 두 실수 중 두 번째 double형 변수에는 전혀 다른 값이 저장되었습니다.

다시 한 번 두 개의 실수를 입력하세요 : 1.2 3.4
입력하신 두 실수는 1.200000와 3.400000입니다.
이번에는 두 실수 모두 제대로 저장되었습니다.
profile
Frontend SoftWare Engineer(2022.06.27 ~)

0개의 댓글