Booil Jung

C 언어 마스터 클래스

C 언어는 단순한 프로그래밍 도구가 아니라, 특정 문제 해결을 위해 탄생한 철학적 산물이다. C의 역사와 특징을 통해 왜 이 언어가 반세기 동안 컴퓨팅 세계의 근간을 이루어왔는지 탐구한다.

C 언어의 역사는 1972년, 미국 AT&T 벨 연구소(Bell Laboratories)의 데니스 리치(Dennis Ritchie)와 켄 톰슨(Ken Thompson)에 의해 시작되었다.1 그 기원은 지극히 실용적인 필요에서 비롯되었다. 당시 벨 연구소의 핵심 프로젝트는 UNIX 운영체제 개발이었는데, 초기의 UNIX는 어셈블리어로 작성되었다. 어셈블리어는 하드웨어의 성능을 최대한 활용할 수 있었지만, 특정 기계에 완전히 종속된다는 치명적인 단점을 안고 있었다. 이는 다른 종류의 컴퓨터로 UNIX를 이식(porting)하는 작업을 거의 불가능하게 만들었다.

이러한 이식성의 문제를 해결하기 위해, 하드웨어를 직접 제어할 수 있는 저수준 언어의 효율성과 여러 시스템에서 동작할 수 있는 고수준 언어의 이식성을 동시에 갖춘 새로운 언어의 필요성이 대두되었다.1 C 언어는 바로 이 간극을 메우기 위해 탄생한 결과물이다. C 언어의 이름은 그것이 B 언어를 계승하여 개발되었기 때문에 붙여졌으며, B 언어는 BCPL(Basic Combined Programming Language)에서, BCPL은 CPL(Combined Programming Language)에서, 그리고 CPL은 ALGOL 60에서 파생된 계보를 따른다.2

C의 탄생 배경은 이 언어의 근본적인 설계 철학을 결정지었다. C는 추상적인 이론이나 학문적 탐구에서 출발한 것이 아니라, “다양한 컴퓨터에서 효율적으로 동작하는 운영체제를 만들고 싶다”는 명확하고 실용적인 목표를 달성하기 위한 도구로서 설계되었다. 이 실용주의 철학은 C가 오늘날까지도 운영체제 커널, 임베디드 시스템 등 시스템 프로그래밍의 핵심 언어로 사용되는 근본적인 이유가 된다. 1973년, struct 자료형이 추가되면서 C 언어는 유닉스 커널의 대부분을 다시 작성할 수 있을 만큼 강력해졌고, 이로써 유닉스는 고급 프로그래밍 언어로 작성된 최초의 운영체제 중 하나가 되었다.

C 언어가 UNIX와 함께 널리 보급되면서, 다양한 기관과 회사에서 자신들의 시스템에 맞는 C 컴파일러를 개발하기 시작했다. 이는 자연스럽게 여러 버전의 C 언어가 난립하는 결과를 낳았고, 코드의 호환성 문제가 중요한 과제로 떠올랐다.1 이러한 혼란 속에서 사실상의 비공식 표준 역할을 한 것은 1978년 브라이언 커니핸(Brian Kernighan)과 데니스 리치가 출간한 저서 “The C Programming Language”였다. 이 책은 저자들의 이름을 따 ‘K&R C’라 불리며 오랫동안 C 언어의 규격과 같은 역할을 수행했다.

언어의 안정성과 이식성을 공식적으로 보장하기 위한 노력은 1983년 미국 국립 표준 연구소(ANSI)가 C 언어 표준 위원회를 결성하면서 본격화되었다. 이 위원회의 작업은 1989년 ANSI 표준 X3.159-1989, 통칭 ‘ANSI C’ 또는 ‘C89’의 제정으로 결실을 보았다. 이 표준은 이듬해 국제 표준화 기구(ISO)에 의해 ISO/IEC 9899:1990, 즉 ‘C90’으로 채택되면서 C를 개인의 프로젝트에서 국제 산업 표준으로 격상시켰다.1

C의 표준화 과정은 ‘안정성’과 ‘진화’ 사이의 신중한 균형을 추구하는 특징을 보여준다. C++가 객체 지향과 같은 새로운 패러다임을 적극적으로 도입하며 빠르게 변화한 반면, C 표준은 비교적 보수적인 태도를 유지했다.1 이는 C가 이미 수많은 운영체제 커널과 임베디드 시스템의 기반으로 깊숙이 자리 잡고 있었기 때문이다. 급진적인 변화는 기존 시스템과의 하위 호환성을 깨뜨릴 위험이 컸다.

따라서 이후의 개정 표준들, 예를 들어 1999년의 ‘C99’, 2011년의 ‘C11’, 그리고 2018년의 ‘C17’ 등은 언어의 근본 철학을 유지하는 선에서 국제 문자 세트 지원 강화, 새로운 자료형 추가, 편의 기능 도입 등 점진적인 개선에 초점을 맞추었다.3 이처럼 C의 표준화는 신뢰성이 중요한 시스템 프로그래밍 언어로서의 정체성을 지키기 위해 하위 호환성과 안정성을 최우선으로 고려하는 전략을 채택해왔다.

C 언어의 핵심 철학은 한 문장으로 요약될 수 있다: “프로그래머는 자신이 무엇을 하는지 알고 있다.” 이 철학은 C의 문법과 기능 전반에 깊이 스며들어 있다. C는 언어 차원에서 프로그래머의 실수를 막기 위한 복잡한 안전장치를 제공하기보다는, 프로그래머에게 최대한의 자유와 제어권을 부여하여 시스템의 성능을 극한까지 끌어올릴 수 있도록 설계되었다.1

이러한 철학은 다음과 같은 특징으로 구체화된다.

그러나 C가 부여하는 ‘자유’는 ‘책임’을 동반하는 양날의 검이다. 포인터를 잘못 사용하면 메모리 누수(memory leak)나 허가되지 않은 메모리 영역을 침범하는 등의 심각한 오류를 유발하여 프로그램 전체를 불안정하게 만들 수 있다.4 C에는 자동 메모리 관리 기능인 가비지 컬렉터(Garbage Collector)가 없으므로, 프로그래머가 할당한 메모리는 반드시 직접 해제해야 한다.8 또한, 배열의 경계를 자동으로 검사해주지 않기 때문에 버퍼 오버플로우(buffer overflow)와 같은 보안 취약점에 노출되기 쉽다.

결론적으로, C의 강력함은 프로그래머의 역량에 정비례한다. C를 마스터한다는 것은 단순히 문법을 아는 것을 넘어, 컴퓨터의 메모리 구조를 깊이 이해하고 자신이 작성한 코드의 모든 동작에 대해 완전한 책임을 지는 능력을 갖추는 것을 의미한다.

C 언어의 설계 철학은 다음과 같은 핵심적인 특징들로 발현된다.

C 언어의 활용 분야는 공통적으로 ‘하드웨어와 가깝고’, ‘최고 수준의 성능이 요구되는’ 영역에 집중되어 있다. 이는 C의 설계 철학이 반세기가 지난 현대 컴퓨팅 환경에서도 여전히 유효함을 증명한다.

C는 최종 사용자에게 직접 노출되는 화려한 애플리케이션보다는, 보이지 않는 곳에서 현대 기술 문명을 지탱하는 기반 기술로서의 성격이 강하다. 우리가 일상적으로 사용하는 스마트폰, 웹 브라우저, 클라우드 서비스 등 모든 기술의 가장 낮은 계층에는 C 언어로 작성된 견고한 기반이 자리 잡고 있다. 따라서 C를 학습하는 것은 단순히 프로그래밍 기술 하나를 익히는 것을 넘어, 컴퓨터 시스템이 근본적으로 어떻게 동작하는지를 이해하는 열쇠를 얻는 과정이며, 이는 다른 고수준 언어를 배울 때에도 깊이 있는 이해의 바탕이 된다.2

C 코드를 실제 실행 가능한 프로그램으로 만드는 데 필요한 도구와 그 설정 방법을 다룬다. 컴파일 과정에 대한 이론적 이해를 바탕으로, Windows, macOS, Linux 각 운영체제에 맞는 최적의 개발 환경을 구축하는 구체적인 절차를 제시한다.

C는 컴파일 언어(Compiled Language)이다. 이는 프로그래머가 작성한 소스 코드(.c 파일)가 컴퓨터가 직접 이해할 수 있는 기계어 코드(실행 파일)로 번역되는 과정을 거쳐야 함을 의미한다. 이 번역 과정을 ‘컴파일’이라 하며, 이 역할을 수행하는 프로그램을 ‘컴파일러(Compiler)’라고 부른다.

C 프로그램의 빌드(build) 과정은 크게 네 단계로 나눌 수 있다.16

  1. 전처리 (Preprocessing): 전처리기(preprocessor)가 소스 코드를 스캔하여 #include, #define과 같이 #으로 시작하는 전처리기 지시문을 먼저 처리한다. 예를 들어, #include <stdio.h>stdio.h 헤더 파일의 내용을 소스 코드에 그대로 삽입하고, #define PI 3.14는 코드 내의 모든 PI3.14로 치환한다. 이 단계의 결과로 확장된 소스 코드 파일(보통 .i 확장자)이 생성된다.
  2. 컴파일 (Compilation): 컴파일러가 전처리된 소스 코드를 어셈블리어로 번역한다. 어셈블리어는 기계어와 일대일로 대응되는 저수준 언어다. 이 단계의 결과로 어셈블리 코드 파일(보통 .s 확장자)이 생성된다.
  3. 어셈블 (Assembly): 어셈블러(assembler)가 어셈블리 코드를 실제 컴퓨터가 실행할 수 있는 기계어 코드로 변환한다. 하지만 이 단계의 결과물인 목적 파일(object file, 보통 .o 또는 .obj 확장자)은 아직 완전한 실행 파일이 아니다. printf와 같은 라이브러리 함수의 코드가 연결되지 않은 상태다.
  4. 링크 (Linking): 링커(linker)가 하나 이상의 목적 파일들과 프로그램에 필요한 표준 라이브러리 파일들을 결합하여 최종적으로 하나의 실행 가능한 파일을 생성한다.

이 복잡한 과정을 이해하는 것은 단순히 ‘빌드’ 버튼을 누르는 것 이상의 의미를 가진다. 개발 과정에서 마주치는 ‘undefined reference’와 같은 링크 에러나 헤더 파일 관련 문제의 원인을 정확히 진단하고 해결하기 위한 필수적인 기초 지식이다.

C 코드를 컴파일하기 위한 여러 컴파일러가 존재하며, 대표적인 것은 다음과 같다.

어떤 컴파일러를 선택하든 C 표준을 준수한다면 대부분의 코드는 동일하게 동작한다. 이 자습서에서는 가장 범용적이고 무료로 사용할 수 있는 GCC와 Clang을 중심으로 설명한다. Windows 환경에서는 GCC를 Windows에서 사용할 수 있도록 이식한 MinGW-w64를 사용한다.23

현대의 C 개발 환경은 크게 두 가지 접근 방식으로 나뉜다. 첫 번째는 Visual Studio나 Xcode와 같이 컴파일러, 디버거, 코드 에디터 등 모든 기능이 통합된 IDE(Integrated Development Environment)를 사용하는 방식이다. 이 방식은 초기 설정이 간편하고 강력한 디버깅 기능을 제공하여 초보자에게 유리하다.25

두 번째는 Visual Studio Code(VS Code)와 같은 경량 코드 에디터터미널(명령줄 인터페이스)을 조합하는 방식이다. 에디터 자체는 단순한 텍스트 편집 기능만 제공하지만, C/C++ 확장 프로그램과 외부 컴파일러(GCC, Clang)를 연동하여 자신에게 맞는 유연하고 가벼운 개발 환경을 구축할 수 있다. 이 방식은 여러 운영체제에서 일관된 개발 경험을 제공한다는 장점이 있다.23

이 자습서에서는 개발자의 선호와 프로젝트 성격에 따라 선택할 수 있도록 두 가지 방식을 모두 안내한다.

이 방식은 가볍고 유연하며, 다른 운영체제에서의 개발 방식과 유사한 경험을 제공한다.

  1. Visual Studio Code 설치: 공식 웹사이트(https://code.visualstudio.com/)에서 설치 파일을 다운로드하여 설치한다.28

  2. MinGW-w64 설치:

    • MSYS2 프로젝트(https://www.msys2.org/)를 통해 최신 GCC를 설치하는 것이 가장 안정적이다. MSYS2 설치 후, MSYS2 터미널에서 다음 명령을 실행한다.

      pacman -Syu
      pacman -S --needed base-devel mingw-w64-x86_64-toolchain
      
    • 또는 SourceForge에서 MinGW-w64 빌드를 직접 다운로드할 수 있다.23

      x86_64-posix-seh 스레드 모델을 선택하는 것이 일반적이다. 다운로드 후 원하는 위치(예: C:\mingw64)에 압축을 푼다.

  3. 환경 변수 설정: 컴파일러를 명령줄 어디에서든 실행할 수 있도록 경로를 설정해야 한다.

    • 시스템 환경 변수 편집을 열고 환경 변수 버튼을 클릭한다.
    • 시스템 변수 목록에서 Path를 선택하고 편집을 누른다.
    • 새로 만들기를 클릭하고 MinGW-w64의 bin 폴더 경로(예: C:\msys64\mingw64\bin 또는 C:\mingw64\bin)를 추가한다.23
  4. 설치 확인: 명령 프롬프트(cmd)를 새로 열고 gcc --version을 입력한다. GCC 버전 정보가 출력되면 성공적으로 설치된 것이다.23

  5. VS Code 확장 프로그램 설치: VS Code를 실행하고 확장(Extensions) 탭에서 C/C++ Extension Pack을 검색하여 설치한다. 이 패키지는 코드 자동 완성, 디버깅 등 필수 기능을 제공한다.23

  6. 프로젝트 설정: 작업할 폴더를 열고, 첫 C 파일(.c)을 생성한다. VS Code는 컴파일 및 디버깅을 위해 .vscode 폴더 내에 tasks.json(빌드 작업 정의)과 launch.json(디버거 설정) 파일 생성을 안내한다. 이 파일들을 통해 GCC 컴파일러를 사용하여 코드를 빌드하고 디버깅하도록 설정할 수 있다.23

Microsoft가 제공하는 강력한 무료 IDE로, Windows 환경에 최적화되어 있다.

  1. Visual Studio 설치: 공식 웹사이트(https://visualstudio.microsoft.com/ko/)에서 ‘Visual Studio Community’ 버전을 다운로드한다.
  2. 워크로드 선택: Visual Studio Installer를 실행하고 ‘워크로드’ 탭에서 ‘C++를 사용한 데스크톱 개발’을 선택하여 설치한다.30
  3. 프로젝트 생성:
    • Visual Studio를 실행하고 ‘새 프로젝트 만들기’를 선택한다.
    • 템플릿 목록에서 ‘빈 프로젝트(Empty Project)’ 또는 ‘콘솔 앱(Console App)’을 선택한다.32
    • 프로젝트 이름과 위치를 지정하고 ‘만들기’를 클릭한다.
  4. 소스 파일 추가:
    • 오른쪽 ‘솔루션 탐색기’에서 ‘소스 파일’ 폴더를 마우스 오른쪽 버튼으로 클릭하고 추가 > 새 항목을 선택한다.
    • ‘C++ 파일(.cpp)’을 선택하되, 파일 이름의 확장자를 반드시 .c로 지정한다. 확장자가 .cpp이면 C++ 컴파일러가 동작하여 일부 C 코드가 다르게 해석될 수 있다.31
  5. 컴파일 및 실행: 코드를 작성한 후, Ctrl+F5 키를 누르거나 메뉴에서 디버그 > 디버그하지 않고 시작을 선택하여 프로그램을 컴파일하고 실행한다.31

macOS는 UNIX 기반이므로 C 개발 환경이 잘 갖추어져 있다.

  1. Command Line Tools 설치: macOS에는 C 컴파일러인 Clang이 기본적으로 포함되어 있다. 터미널을 열고 다음 명령을 입력하여 개발 도구를 설치한다.34

    xcode-select --install
    
  2. Visual Studio Code 설치: Homebrew 패키지 관리자를 사용하는 것이 편리하다. 터미널에서 다음 명령으로 Homebrew를 설치하고, 이어서 VS Code를 설치한다.27

    # Homebrew 설치 (공식 사이트에서 최신 명령어 확인)
    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
    # VS Code 설치
    brew install --cask visual-studio-code
    
  3. VS Code 확장 프로그램 설치: Windows와 마찬가지로 C/C++ Extension Pack을 설치한다. Code Runner 확장을 함께 설치하면 단축키로 간단한 코드 실행이 가능해 편리하다.27

  4. 프로젝트 설정: Windows 환경과 유사하게, 작업 폴더 내에 .vscode 디렉터리를 생성하고 tasks.jsonlaunch.json 파일을 설정하여 Clang 컴파일러와 LLDB 디버거를 사용하도록 구성한다.34

Apple이 공식적으로 제공하는 macOS 및 iOS 개발용 IDE다.

  1. Xcode 설치: App Store에서 ‘Xcode’를 검색하여 설치한다. 용량이 매우 크므로 설치에 시간이 소요될 수 있다.26
  2. 프로젝트 생성:
    • Xcode를 실행하고 ‘Create a new Xcode project’를 선택한다.
    • 플랫폼으로 ‘macOS’를 선택하고, 템플릿으로 ‘Command Line Tool’을 선택한다.26
    • Product Name 등 프로젝트 정보를 입력하고, 가장 중요한 Language 항목을 ‘C’로 선택한다.26
  3. 컴파일 및 실행: 프로젝트가 생성되면 main.c 파일이 자동으로 만들어진다. 코드를 작성한 후, Xcode 창 상단의 실행(▶) 버튼을 클릭하면 컴파일과 실행이 동시에 이루어지고 결과는 하단 콘솔 창에 출력된다.26

Linux는 C 개발에 가장 이상적인 환경 중 하나로, 대부분의 배포판에 GCC가 기본적으로 포함되어 있거나 쉽게 설치할 수 있다.

가장 전통적이고 강력한 방식이다.

  1. 빌드 도구 설치: 터미널을 열고 다음 명령을 실행하여 GCC, make 등 개발에 필요한 필수 패키지들을 한 번에 설치한다.19

    sudo apt update
    sudo apt install build-essential
    
  2. 설치 확인: gcc --version 명령으로 GCC가 올바르게 설치되었는지 확인한다.

  3. 코드 작성: vim, nano, gedit 등 원하는 텍스트 에디터를 사용하여 소스 파일(예: hello.c)을 작성한다.19

  4. 컴파일: 터미널에서 다음 명령을 사용하여 컴파일한다.39

    gcc hello.c -o hello
    
    • -o hello 옵션은 출력될 실행 파일의 이름을 hello로 지정하는 것이다. 이 옵션을 생략하면 기본적으로 a.out이라는 이름의 파일이 생성된다.
  5. 실행: 생성된 실행 파일을 다음 명령으로 실행한다.39

    ./hello
    

Linux에서도 VS Code를 사용하여 그래픽 기반의 편리한 개발 환경을 구축할 수 있다.

  1. 빌드 도구 설치: 방법 1과 동일하게 build-essential 패키지를 먼저 설치한다.

  2. Visual Studio Code 설치: Ubuntu Software Center를 이용하거나, 터미널에서 snap을 통해 설치할 수 있다.40

    sudo snap install code --classic
    
  3. VS Code 확장 프로그램 및 설정: Windows나 macOS에서와 동일하게 C/C++ Extension Pack을 설치하고, .vscode 폴더의 설정 파일들을 통해 GCC 컴파일러와 GDB 디버거를 연동한다.38

이 파트에서는 C 프로그램을 구성하는 가장 기본적인 요소인 변수, 데이터 타입, 연산자, 입출력 함수를 학습한다. 컴퓨터가 데이터를 어떻게 표현하고 처리하는지에 대한 근본적인 이해를 목표로 한다.

모든 프로그래밍 언어 학습의 첫 관문은 화면에 “Hello, World!”를 출력하는 프로그램을 작성하는 것이다. 이 간단한 코드는 C 프로그램의 기본 구조를 담고 있다.

#include <stdio.h>

int main(void)
{
    printf("Hello, World!\n");
    return 0;
}

이 코드의 각 구성 요소를 분석해 보자.

프로그램은 데이터를 다루기 위해 존재한다. C에서는 데이터를 변수와 상수의 형태로 다룬다.

변수는 프로그램이 실행되는 동안 값이 변할 수 있는 데이터를 저장하기 위한 메모리 공간에 붙여진 이름이다.45 변수를 사용하기 위해서는 반드시 먼저 선언(declaration)해야 한다. 선언은 컴파일러에게 어떤 종류의 데이터를 저장할 것인지(자료형), 그리고 그 공간을 무엇이라 부를 것인지(변수명)를 알려주는 과정이다.47

int age;       // 정수(int)를 저장할 수 있는 'age'라는 이름의 변수 선언
age = 25;      // 변수 age에 값 25를 할당(assignment)
double height = 175.8; // 실수(double) 변수 height를 선언과 동시에 175.8로 초기화(initialization)

변수 이름을 짓는 데에는 몇 가지 규칙이 있다.47

상수는 프로그램 실행 중에 값이 변하지 않는 고정된 데이터다.45 상수에는 두 가지 종류가 있다.

데이터 타입(자료형)은 변수가 저장할 데이터의 종류와 그에 따라 할당될 메모리의 크기를 결정하는 핵심적인 개념이다.48 C가 다양한 데이터 타입을 제공하는 이유는 메모리 공간을 낭비 없이 효율적으로 사용하기 위함이다.51 예를 들어, 0부터 100까지의 값만 필요한데 8바이트 크기의 자료형을 쓰는 것은 낭비다.

C의 데이터 타입 시스템은 추상적인 개념이 아니라, 실제 컴퓨터 하드웨어의 아키텍처를 직접적으로 반영한다. char, short, int, long 등 다양한 크기의 정수형이 존재하는 이유는 CPU가 데이터를 처리하는 기본 단위인 워드(word) 크기에 맞춰 가장 효율적인 연산을 수행하기 위함이다.52 특히 int의 크기는 표준에 고정되어 있지 않고, 해당 시스템에서 가장 효율적으로 처리할 수 있는 크기로 정의되는 경우가 많다.

sizeof 연산자를 사용하면 특정 자료형이나 변수가 차지하는 메모리 크기를 바이트 단위로 확인할 수 있다.54

분류 자료형 (Keyword) 크기 (Bytes) 값의 범위 서식 지정자
문자형 char 1 -128 ~ 127 %c
  unsigned char 1 0 ~ 255 %c
정수형 short 2 -32,768 ~ 32,767 %hd
  unsigned short 2 0 ~ 65,535 %hu
  int 4 -2,147,483,648 ~ 2,147,483,647 %d
  unsigned int 4 0 ~ 4,294,967,295 %u
  long 4 -2,147,483,648 ~ 2,147,483,647 %ld
  unsigned long 4 0 ~ 4,294,967,295 %lu
  long long 8 $-9.2 \times 10^{18}$ ~ $9.2 \times 10^{18}$ %lld
  unsigned long long 8 0 ~ 약 $1.8 \times 10^{19}$ %llu
실수형 float 4 $\pm 3.4 \times 10^{\pm 38}$ %f
  double 8 $\pm 1.7 \times 10^{\pm 308}$ %lf (scanf), %f (printf)
  long double 8 이상 double 이상 %Lf

참고: 위 표의 크기와 범위는 일반적인 32/64비트 시스템 기준이며, 컴파일러나 시스템 환경에 따라 다를 수 있다.50

C는 데이터를 가공하고 처리하기 위한 풍부하고 강력한 연산자들을 제공한다.55

하나의 수식에 여러 연산자가 함께 사용될 때, 계산 순서는 우선순위(precedence)결합 방향(associativity)에 따라 결정된다. 우선순위가 높은 연산자가 먼저 실행되며, 우선순위가 같을 경우 결합 방향(왼쪽에서 오른쪽으로 또는 그 반대)에 따라 실행 순서가 정해진다. 복잡한 수식에서는 괄호 ()를 사용하여 실행 순서를 명확히 지정하는 것이 바람직하다.57

우선순위 연산자 설명 결합 방향
1 (높음) () `` . -> x++ x-- 함수 호출, 배열 첨자, 멤버 접근 –»
2 ++x --x ! ~ (type) * & sizeof 전위 증감, 논리/비트 NOT, 형 변환, 포인터 참조
3 * / % 곱셈, 나눗셈, 나머지 –»
4 + - 덧셈, 뺄셈 –»
5 << >> 비트 시프트 –»
6 < <= > >= 관계 연산 –»
7 == != 등가 연산 –»
8 & 비트 AND –»
9 ^ 비트 XOR –»
10 $\rvert$ 비트 OR –»
11 && 논리 AND –»
12 $\rvert\rvert$ 논리 OR –»
13 ? : 조건(삼항) 연산자
14 = += -= *= /= %= 대입 연산자
15 (낮음) , 쉼표 연산자 –»

출처: 55

프로그램은 사용자와 상호작용하기 위해 데이터를 입력받고 결과를 출력해야 한다. C에서는 <stdio.h> 헤더 파일에 정의된 표준 입출력 함수를 통해 이 기능을 수행한다.

printf 함수는 서식 문자열(format string)을 사용하여 다양한 종류의 데이터를 정해진 형식에 맞춰 화면(표준 출력)에 출력한다.44

int age = 25;
double pi = 3.141592;
printf("나이: %d, 원주율: %f\n", age, pi);

서식 문자열 안의 %d, %f와 같은 서식 지정자(format specifier)는 뒤따라오는 인자(age, pi)의 값을 어떤 형태로 출력할지 지정하는 역할을 한다. 서식 지정자는 출력할 데이터의 타입과 일치해야 한다.61

printf는 출력 형식을 세밀하게 제어하는 다양한 옵션을 제공한다.63

scanf 함수는 키보드(표준 입력)로부터 데이터를 입력받아 변수에 저장하는 역할을 한다. printf와 유사한 서식 지정자를 사용한다.65

int age;
printf("나이를 입력하세요: ");
scanf("%d", &age);

scanf를 사용할 때 가장 중요한 규칙은 값을 저장할 변수 앞에 반드시 주소 연산자 &를 붙여야 한다는 것이다.44

scanf는 값을 저장하기 위해 변수의 값이 아닌 변수의 메모리 주소를 필요로 하기 때문이다. (단, 문자열을 배열에 저장할 때는 예외적으로 &를 붙이지 않는다.)

scanf의 동작 원리를 이해하려면 ‘입력 버퍼’의 개념을 알아야 한다. 사용자가 키보드로 입력한 데이터는 프로그램에 직접 전달되지 않고, 운영체제가 관리하는 임시 공간인 입력 버퍼에 먼저 저장된다. scanf는 이 버퍼에서 형식에 맞는 데이터를 읽어간다. 이때, scanf는 기본적으로 공백 문자(스페이스, 탭, 개행)를 데이터의 구분자로 취급한다.68 이로 인해 개행 문자(\n)가 버퍼에 남아 다음 입력 함수에 영향을 주는 등 예기치 않은 동작이 발생할 수 있다. 이는 C 입문자들이 흔히 겪는 문제로, 입력 처리 시 세심한 주의가 필요하다.

서식 지정자 대응 자료형 설명
%d, %i int 부호 있는 10진 정수
%u unsigned int 부호 없는 10진 정수
%o unsigned int 부호 없는 8진 정수
%x, %X unsigned int 부호 없는 16진 정수 (소문자/대문자)
%c char 단일 문자
%s char* (문자열) 문자열 (널 문자 \0까지)
%f float, double 10진 표기법 실수 (printf)
%lf double 10진 표기법 실수 (scanf)
%e, %E float, double 지수 표기법 실수 (소문자/대문자)
%p void* (포인터) 포인터의 메모리 주소 (16진수)
%% 해당 없음 % 문자 자체를 출력

출처: 61

이 파트에서는 프로그램의 실행 순서를 제어하는 방법을 배운다. 조건에 따라 다른 코드를 실행하거나, 특정 코드를 반복적으로 실행하는 제어문을 통해 논리적인 프로그램을 작성하는 능력을 기른다.

조건문은 특정 조건의 참(true) 또는 거짓(false) 여부에 따라 프로그램의 실행 흐름을 분기시키는 구문이다. C에서 참은 0이 아닌 모든 값으로, 거짓은 0으로 표현된다.

if 문은 가장 기본적인 조건문으로, 주어진 조건식이 참일 경우에만 특정 코드 블록을 실행한다.70

if (score >= 90)
{
    printf("A 학점입니다.\n");
}

else를 사용하면 if의 조건식이 거짓일 때 실행될 코드를 지정할 수 있다. else if를 추가하면 여러 조건을 연쇄적으로 검사하는 것이 가능하다.71

if (score >= 90)
{
    printf("A 학점입니다.\n");
}
else if (score >= 80)
{
    printf("B 학점입니다.\n");
}
else
{
    printf("C 학점 이하입니다.\n");
}

if-else if-else 구조는 위에서 아래로 순차적으로 조건을 검사하며, 하나의 조건이라도 참이 되어 해당 블록이 실행되면 나머지 else ifelse 부분은 검사하지 않고 전체 구조를 빠져나온다.72

switch 문은 하나의 정수형 변수나 수식의 값이 여러 개의 특정 상수 값과 일치하는 경우를 처리하는 데 특화된 다중 분기문이다.71

switch (level)
{
    case 1:
        printf("초급 사용자\n");
        break;
    case 2:
        printf("중급 사용자\n");
        break;
    case 3:
        printf("고급 사용자\n");
        break;
    default:
        printf("알 수 없는 레벨\n");
        break;
}

if-elseswitch는 선택의 문제이며, 그 결정은 주로 ‘조건의 형태’와 ‘성능’이라는 두 가지 측면에서 이루어진다.

결론적으로, 여러 개의 특정 값과 비교해야 하는 상황에서는 switch문이 가독성, 유지보수성, 성능 모든 면에서 더 나은 선택이다.

반복문은 특정 코드 블록을 정해진 횟수만큼 또는 특정 조건이 만족되는 동안 반복적으로 실행하는 구문이다.

for 문은 반복 횟수가 명확하게 정해져 있을 때 가장 일반적으로 사용된다.76 반복을 제어하는 데 필요한 세 가지 핵심 요소인 초기식, 조건식, 증감식을 괄호 안에 한 줄로 명시하여 구조가 명확하고 가독성이 높다.78

for (int i = 0; i < 5; i++)
{
    printf("반복 %d\n", i);
}

for 문의 실행 순서는 다음과 같다.

  1. 초기식 (int i = 0): 루프에 진입하기 전 단 한 번만 실행된다. 주로 반복 제어 변수를 선언하고 초기화한다.
  2. 조건식 (i < 5): 매 반복이 시작되기 전에 평가된다. 이 식이 참이면 루프 본문을 실행하고, 거짓이면 루프를 종료한다.
  3. 루프 본문 ({...}): 조건식이 참일 경우 실행된다.
  4. 증감식 (i++): 루프 본문이 실행된 후 매번 실행된다. 주로 제어 변수의 값을 변경하여 언젠가 조건식이 거짓이 되도록 만든다.
  5. 다시 2번(조건식 평가)으로 돌아가 반복한다.

while 문은 반복 횟수가 정해져 있지 않고, 특정 조건이 만족되는 동안 계속해서 반복해야 할 때 유용하다.77 조건식을 루프의 시작 부분에서 검사한다.

int count = 0;
while (count < 5)
{
    printf("count: %d\n", count);
    count++;
}

만약 count의 초기값이 5 이상이었다면, while의 조건식은 처음부터 거짓이므로 루프 본문은 한 번도 실행되지 않는다.

do-while 문은 while 문과 매우 유사하지만, 조건식을 루프의 끝에서 검사한다는 결정적인 차이가 있다. 이 때문에 do-while 루프의 본문은 조건식의 참/거짓 여부와 관계없이 최소 한 번은 반드시 실행된다.76

int selection;
do
{
    printf("1. 시작 2. 종료\n");
    printf("선택: ");
    scanf("%d", &selection);
} while (selection!= 1 && selection!= 2);

위 예제처럼 사용자에게 메뉴를 보여주고 입력을 받는 경우, 최소 한 번은 메뉴를 출력해야 하므로 do-while 문이 매우 적합하다.

분기 제어문은 반복문의 정상적인 흐름을 벗어나 다른 곳으로 실행을 이동시키는 역할을 한다.

goto 문은 프로그램의 논리적 흐름을 예측하기 어렵게 만드는 주범으로, 소위 ‘스파게티 코드’를 유발할 수 있다.84 구조적 프로그래밍의 원칙을 해치므로 사용을 극도로 지양해야 한다. 대부분의 경우 break, continue, return 또는 함수 분리를 통해 goto 없이 더 나은 구조의 코드를 작성할 수 있다. 예외적으로 깊게 중첩된 루프를 한 번에 탈출하는 등 매우 제한적인 상황에서만 고려될 수 있으나, 이 역시 좋은 설계로 보기 어렵다.

이 파트에서는 코드를 재사용 가능하고 관리하기 쉬운 단위로 만드는 ‘함수’에 대해 배운다. 함수의 선언과 정의, 다양한 값 전달 방식, 그리고 강력한 프로그래밍 기법인 재귀 호출을 탐구한다.

함수(function)는 특정 작업을 수행하기 위해 설계된 독립적인 코드 블록이다. 잘 설계된 함수는 코드의 재사용성을 높이고, 프로그램을 논리적인 단위로 분해하여 전체적인 구조를 이해하기 쉽게 만든다.86 C 프로그램은 이러한 함수들의 집합으로 구성된다.

함수는 선언(declaration)정의(definition)라는 두 가지 요소로 구성된다.87

함수 선언이 필요한 이유는 C 컴파일러의 동작 방식과 관련이 있다. C 컴파일러는 기본적으로 소스 코드를 위에서 아래로 한 번만 훑으며 번역한다. 만약 main 함수에서 add 함수를 호출하는데, add 함수의 정의가 main 함수보다 아래쪽에 위치한다면 컴파일러는 add라는 이름의 함수를 처음 마주했을 때 그 정체를 알지 못해 오류를 발생시킨다.88

이때, 소스 코드 상단에 함수 선언을 미리 해두면 컴파일러는 “아, add라는 함수는 정수 두 개를 인자로 받아 정수를 반환하는 함수구나”라고 인지하고 넘어갈 수 있다. 실제 함수의 몸체는 링킹(linking) 단계에서 찾아 연결된다. 따라서 함수 선언은 함수의 정의 위치에 구애받지 않고 자유롭게 함수를 호출할 수 있도록 해주는 필수적인 요소다. 일반적으로 함수 선언은 헤더 파일(.h)에 모아두고, 함수 정의는 소스 파일(.c)에 작성하여 관리한다.87

함수를 호출할 때 인자(argument)를 매개변수(parameter)에 전달하는 방식은 크게 두 가지로 나뉜다.

C 언어의 기본적인 함수 호출 방식이다. 함수를 호출할 때, 인자로 전달되는 변수의 값(value)이 복사되어 함수의 매개변수에 전달된다.91

#include <stdio.h>

void increment(int num) // num은 value의 복사본
{
    num = num + 1;
    printf("함수 안: %d\n", num); // 출력: 11
}

int main(void)
{
    int value = 10;
    increment(value);
    printf("함수 밖: %d\n", value); // 출력: 10
    return 0;
}

위 예제에서 increment 함수가 호출될 때 main 함수의 value 변수 값인 10이 increment 함수의 매개변수 num에 복사된다. 함수 안에서 num의 값을 11로 변경하더라도, 이는 복사본을 변경한 것이므로 main 함수의 원본 변수 value에는 아무런 영향을 미치지 않는다.92

때로는 함수 안에서 함수 밖의 원본 변수 값을 직접 변경해야 할 필요가 있다. C 언어는 ‘참조’라는 개념을 직접 지원하지는 않지만, 포인터를 사용하여 동일한 효과를 구현할 수 있다. 이는 변수의 값을 복사해서 넘기는 대신, 변수가 저장된 메모리 주소(address)를 전달하는 방식이다.91

#include <stdio.h>

// 두 변수의 값을 교환하는 함수
void swap(int* a, int* b) // 주소를 받기 위해 매개변수를 포인터로 선언
{
    int temp = *a; // a가 가리키는 주소의 값
    *a = *b;       // a가 가리키는 주소에 b가 가리키는 값을 저장
    *b = temp;
}

int main(void)
{
    int x = 10, y = 20;
    printf("바꾸기 전: x=%d, y=%d\n", x, y);
    swap(&x, &y); // 변수의 주소를 인자로 전달
    printf("바꾼 후: x=%d, y=%d\n", x, y);
    return 0;
}

swap 함수는 매개변수로 정수 포인터 int*를 받는다. main 함수에서는 swap을 호출할 때 변수 xy의 주소를 주소 연산자 &를 이용해 전달한다. swap 함수 내에서는 간접 참조 연산자 *를 사용하여 전달받은 주소를 통해 main 함수의 원본 변수 xy에 직접 접근하여 값을 변경할 수 있다. 이 기법은 C 프로그래밍에서 매우 중요하고 빈번하게 사용된다.92

재귀 함수는 함수 내부에서 자기 자신을 다시 호출하는 방식으로 동작하는 함수다.96 복잡한 문제를 더 작고 동일한 구조의 문제로 나누어 해결하는 데 효과적이다. 모든 재귀 함수는 반드시 두 가지 핵심 요소를 갖추어야 한다.

  1. 종료 조건 (Base Case): 더 이상 재귀 호출을 하지 않고 특정 값을 반환하며 재귀의 연쇄를 멈추는 부분이다. 종료 조건이 없으면 함수가 자기 자신을 무한히 호출하다가 스택 오버플로우(stack overflow) 오류를 발생시키며 프로그램이 비정상 종료된다.97
  2. 재귀 호출 (Recursive Step): 문제를 더 작은 단위로 만들어 자기 자신을 호출하는 부분이다. 재귀 호출을 거듭할수록 문제는 점점 단순해져서 마침내 종료 조건에 도달해야 한다.97

팩토리얼(Factorial) 계산은 재귀 함수의 대표적인 예다. 팩토리얼은 수학적으로 $n! = n \times (n-1)!$로 정의되며, $0! = 1$이라는 종료 조건을 가진다. 이 정의는 재귀 함수의 구조와 완벽하게 일치한다.

#include <stdio.h>

long long factorial(int n)
{
    // 종료 조건 (Base Case)
    if (n == 0)
    {
        return 1;
    }
    // 재귀 호출 (Recursive Step)
    else
    {
        return n * factorial(n - 1);
    }
}

int main(void)
{
    printf("5! = %lld\n", factorial(5)); // 출력: 120
    return 0;
}

factorial(5)가 호출되면, 내부적으로 5 * factorial(4), 4 * factorial(3),…, 1 * factorial(0) 순으로 연쇄적인 호출이 일어난다. factorial(0)이 종료 조건에 도달하여 1을 반환하면, 호출의 역순으로 값이 계산되어 최종 결과인 120이 반환된다.98

재귀는 문제의 정의를 코드로 간결하고 우아하게 표현할 수 있게 해주지만, 함수 호출에 따르는 부하(overhead)가 있어 단순 반복문보다 성능이 저하될 수 있다. 특히 피보나치 수열처럼 하나의 문제를 해결하기 위해 자기 자신을 여러 번 호출하는 경우, 동일한 계산이 불필요하게 반복되어 성능이 급격히 나빠질 수 있다.99 따라서 재귀는 문제 해결을 위한 강력한 사고의 도구로 활용하되, 실제 구현 시에는 성능을 고려하여 반복문으로의 변환을 고려하거나 메모이제이션(memoization) 같은 최적화 기법을 함께 사용하는 것이 현명하다.

이 파트에서는 C 언어를 가장 C 언어답게 만드는 핵심 기능인 포인터를 심도 있게 다룬다. 메모리 주소의 개념부터 시작하여 포인터 연산, 배열과의 밀접한 관계, 그리고 함수 포인터와 같은 고급 활용법까지 정복한다.

포인터(Pointer)는 변수다. 하지만 일반 변수처럼 데이터 값 자체를 저장하는 것이 아니라, 다른 변수나 데이터가 저장된 메모리의 주소(address)를 값으로 저장하는 특별한 변수다.53 컴퓨터의 메모리(RAM)는 데이터를 저장하는 수많은 바이트(byte) 공간들이 일렬로 늘어선 것과 같으며, 각 바이트 공간에는 고유한 번호, 즉 주소가 부여되어 있다. 포인터는 바로 이 주소 값을 다루기 위한 도구다.

포인터의 핵심 연산자는 두 가지다.

포인터는 다음과 같이 선언하고 사용한다.

#include <stdio.h>

int main(void)
{
    int num = 100;      // 정수형 변수 num 선언 및 100으로 초기화
    int* ptr;           // 정수형 변수를 가리킬 포인터 변수 ptr 선언

    ptr = &num;         // ptr에 num 변수의 주소를 저장. 이제 ptr은 num을 가리킨다.

    printf("num의 값: %d\n", num);                 // 출력: 100
    printf("num의 주소: %p\n", &num);              // num의 메모리 주소 출력
    printf("ptr에 저장된 값: %p\n", ptr);          // ptr이 저장하고 있는 값(num의 주소) 출력
    printf("ptr이 가리키는 값: %d\n", *ptr);       // ptr이 가리키는 주소에 있는 값(num의 값) 출력

    *ptr = 200;         // ptr이 가리키는 곳의 값을 200으로 변경
    printf("값 변경 후 num의 값: %d\n", num);      // 출력: 200

    return 0;
}

포인터를 선언할 때 자료형* 포인터이름; 형식에서 자료형은 포인터 변수 자체의 타입이 아니라, 그 포인터가 가리킬 대상의 자료형을 의미한다.100 모든 포인터 변수는 시스템 아키텍처에 따라 동일한 크기(예: 64비트 시스템에서 8바이트)를 가지지만, 가리키는 대상의 자료형을 명시하는 것은 매우 중요하다.

포인터에 타입 정보가 필요한 이유는 크게 두 가지다. 첫째, 메모리 해석의 기준을 제공한다. 컴파일러는 int* 포인터를 역참조할 때 해당 주소부터 sizeof(int)(예: 4바이트)만큼을 하나의 정수로 읽어오고, char* 포인터를 역참조할 때는 sizeof(char)(1바이트)만큼을 문자로 읽어온다. 타입 정보가 없다면 메모리를 몇 바이트 단위로 어떻게 해석해야 할지 알 수 없다.102

둘째, 주소 연산의 기준을 제공한다. int* 타입의 포인터에 1을 더하면 주소 값은 sizeof(int)만큼 증가한다. 이는 포인터가 배열처럼 연속된 메모리 공간을 올바르게 탐색할 수 있도록 하는 핵심 원리다.

포인터 변수에는 제한된 산술 연산이 가능하다. 이는 메모리 상에서 데이터를 순차적으로 접근하기 위해 설계되었다.

포인터끼리 더하거나, 곱하거나, 나누는 연산은 논리적으로 의미가 없으므로 허용되지 않는다.103

C 언어에서 포인터와 배열은 매우 밀접한 관계를 맺고 있으며, 문법적으로 거의 동일하게 사용될 수 있다.

“배열의 이름은 포인터다”라는 말은 흔히 사용되지만, 정확히는 ‘배열의 이름은 그 배열의 첫 번째 요소의 주소를 가리키는 포인터 상수(constant pointer)’이다.107

int arr = {10, 20, 30, 40, 50};
int* ptr = arr; // 배열의 이름 arr은 &arr과 같으므로 포인터에 대입 가능

이러한 미묘하지만 중요한 차이점을 이해하는 것은 포인터와 배열을 정확하게 다루는 데 필수적이다.

함수 포인터(Function Pointer)는 변수나 배열이 아닌, 함수의 시작 주소를 저장하는 특별한 포인터다.111 프로그램이 컴파일되면 함수 코드 역시 메모리의 특정 영역(코드 세그먼트)에 위치하게 되며, 함수 이름은 그 코드의 시작 주소를 나타내는 포인터 상수처럼 사용될 수 있다.112

함수 포인터의 선언 문법은 다소 복잡하다.

반환_타입 (*포인터_이름)(매개변수_타입_목록);

예를 들어, int를 반환하고 두 개의 int를 매개변수로 받는 함수를 가리킬 수 있는 함수 포인터 fp는 다음과 같이 선언한다.

int (*fp)(int, int);

여기서 (*fp)의 괄호는 매우 중요하다. 만약 int *fp(int, int);라고 쓰면, 이는 두 개의 int를 인자로 받아 int*를 반환하는 fp라는 이름의 ‘함수’를 선언하는 것이 되어 의미가 완전히 달라진다.113

#include <stdio.h>

int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }

int main(void)
{
    int (*fp)(int, int); // 함수 포인터 선언

    fp = add; // fp가 add 함수의 주소를 가리킴
    printf("결과: %d\n", fp(10, 5)); // 출력: 15

    fp = subtract; // fp가 subtract 함수의 주소를 가리킴
    printf("결과: %d\n", fp(10, 5)); // 출력: 5

    return 0;
}

함수 포인터는 다음과 같은 고급 프로그래밍 기법을 가능하게 한다.

함수 포인터는 C 언어의 유연성과 확장성을 극대화하는 강력한 도구로, 잘 활용하면 매우 정교하고 효율적인 프로그램을 작성할 수 있다.

이 파트에서는 기본 데이터 타입을 조합하여 더 복잡하고 의미 있는 데이터를 표현하는 방법을 배운다. 다차원 배열, 문자열, 그리고 C의 강력한 사용자 정의 자료형인 구조체, 공용체, 열거형을 다룬다.

다차원 배열은 배열의 배열이다. 가장 흔하게 사용되는 2차원 배열은 행(row)과 열(column)으로 구성된 테이블이나 행렬과 같은 데이터를 표현하는 데 적합하다.115

2차원 배열은 자료형 배열이름[행의_개수][열의_개수]; 형태로 선언한다.

int matrix; // 3행 4열의 정수형 2차원 배열

초기화는 중첩된 중괄호를 사용하여 각 행의 데이터를 지정하는 것이 일반적이다.

int matrix = {
    {1, 2, 3, 4},
    {5, 6, 7, 8},
    {9, 10, 11, 12}
};

초기화 값을 1차원 배열처럼 나열할 수도 있지만, 가독성이 떨어진다.115 초기화 값이 부족할 경우 나머지 요소들은 모두 0으로 자동 초기화된다.117

논리적으로는 2차원 테이블 구조이지만, 실제 컴퓨터 메모리에는 1차원 공간에 연속적으로 저장된다. matrix 배열의 요소들은 메모리에 matrix, matrix,…, matrix, matrix,… 순서로 빈틈없이 나열된다.119 이러한 메모리 구조 때문에, 배열을 선언하거나 함수의 매개변수로 전달할 때 첫 번째 차원(행)의 크기는 생략할 수 있어도, 두 번째 차원(열)부터의 크기는 반드시 명시해야 한다. 컴파일러가

matrix과 같이 다음 행의 시작 주소를 계산하려면 한 행이 몇 개의 요소로 이루어져 있는지(열의 크기)를 알아야 하기 때문이다.115

C 언어에는 별도의 문자열 타입이 존재하지 않는다. 대신, char 타입의 배열을 사용하여 문자열을 다룬다. C 스타일 문자열의 가장 중요한 특징은 문자열의 끝을 표시하기 위해 항상 널(NULL) 문자 \0가 마지막에 추가된다는 점이다.47 예를 들어, "hello"라는 문자열은 메모리에 'h', 'e', 'l', 'l', 'o', '\0' 순서로 총 6바이트를 차지한다.

char str1 = "Hello"; // 컴파일러가 크기를 6으로 자동 계산
char str2 = "World"; // 크기를 10으로 지정. 나머지 공간은 널 문자로 채워짐

문자열을 다루는 작업은 매우 빈번하므로, C 표준 라이브러리는 <string.h> 헤더 파일을 통해 다양한 문자열 처리 함수를 제공한다.121

C는 기본 자료형들을 조합하여 프로그래머가 직접 새로운 자료형을 만들 수 있는 강력한 기능을 제공한다.

구조체(Structure)는 이름, 학번, 학점처럼 서로 다른 타입이지만 논리적으로 연관된 데이터들을 하나의 단위로 묶어 새로운 자료형을 정의하는 기능이다.126

// '학생'이라는 새로운 자료형을 정의
struct Student {
    char name;
    int studentId;
    double gpa;
};

int main(void) {
    // Student 타입의 변수 s1 선언
    struct Student s1;

    // 멤버 접근 연산자(.)를 사용하여 멤버에 값 할당
    strcpy(s1.name, "홍길동");
    s1.studentId = 20240001;
    s1.gpa = 4.3;

    printf("이름: %s, 학번: %d, 학점: %.2f\n", s1.name, s1.studentId, s1.gpa);

    // 선언과 동시에 초기화
    struct Student s2 = {"이순신", 20240002, 4.5};

    return 0;
}

구조체 변수를 선언할 때마다 struct Student라고 쓰는 것이 번거로울 수 있다. typedef 키워드를 사용하면 구조체에 별칭(alias)을 부여하여 더 간결하게 사용할 수 있다.128

typedef struct {
    char name;
    int studentId;
    double gpa;
} Student; // 이제 'Student'가 새로운 자료형 이름처럼 사용된다.

Student s1; // 'struct' 키워드 없이 선언 가능

구조체 변수를 가리키는 포인터를 선언하고 사용할 수 있다. 구조체 포인터를 통해 멤버에 접근할 때는 점(.) 연산자 대신 화살표 연산자(->)를 사용한다.130

ptr->member(*ptr).member와 완전히 동일한 표현이지만 훨씬 간결하다.132

Student s1 = {"홍길동", 20240001, 4.3};
Student* p_s1 = &s1; // 구조체 포인터 p_s1이 s1을 가리킴

printf("이름: %s\n", p_s1->name); // 화살표 연산자로 멤버 접근
p_s1->gpa = 4.4; // 포인터를 통해 원본 구조체의 멤버 값 변경

구조체를 함수에 인자로 전달할 때, 구조체 자체를 값으로 넘기면 구조체 전체가 복사되어 비효율적이다. 특히 구조체의 크기가 클 경우 성능 저하가 발생할 수 있다. 반면, 구조체의 주소(포인터)를 전달하면 주소 값만 복사되므로 매우 효율적이다. 또한, 함수 내에서 원본 구조체의 값을 변경해야 할 경우 반드시 포인터를 사용해야 한다. 이러한 이유로 C 프로그래밍에서는 함수에 구조체를 전달할 때 포인터를 사용하는 것이 일반적인 관례다.130

공용체(Union)는 구조체와 선언 방식이 유사하지만, 모든 멤버가 동일한 메모리 공간을 공유한다는 결정적인 차이가 있다.134 공용체의 전체 크기는 멤버 중에서 가장 큰 자료형의 크기로 결정된다.136

union Data {
    int i;
    float f;
    char str;
};

Data 공용체의 크기는 가장 큰 멤버인 str의 크기인 20바이트가 된다. i, f, str 멤버는 모두 이 20바이트의 메모리 공간을 공유한다. 따라서 한 번에 하나의 멤버만 의미 있는 값을 가질 수 있다. i에 값을 저장한 후 f에 값을 저장하면, i의 값은 의미를 잃게 된다.134 공용체는 서로 다른 종류의 데이터를 같은 메모리 영역에서 다루어야 할 때, 예를 들어 통신 프로토콜의 패킷을 해석하거나 메모리를 절약해야 하는 특수한 상황에서 사용된다.137

열거형(Enumeration)RED, GREEN, BLUE와 같이 서로 연관된 정수형 상수에 의미 있는 이름을 부여하여 코드의 가독성을 높이는 기능이다.138

enum Weekday { SUN, MON, TUE, WED, THU, FRI, SAT };
// 별도로 값을 지정하지 않으면 SUN=0, MON=1, TUE=2,... 순으로 자동 할당

열거형으로 정의된 이름들은 정수 상수로 취급된다. 특정 값부터 시작하도록 초기화할 수도 있으며, 중간에 값을 지정하면 그 다음 멤버는 지정된 값에서 1씩 증가한다.140

enum MachineState { STOPPED, RUNNING = 5, PAUSED }; // STOPPED=0, RUNNING=5, PAUSED=6

열거형은 #define을 사용하여 상수를 정의하는 것보다 타입 검사 측면에서 더 안전하며, 특히 switch 문과 함께 사용될 때 코드의 의도를 명확하게 드러내어 유지보수를 용이하게 한다.142

이 파트에서는 프로그램이 실행되는 동안 필요한 메모리를 동적으로 할당하고 해제하는 방법과, 데이터를 영구적으로 저장하기 위해 파일 시스템과 상호작용하는 방법을 다룬다. C의 로우 레벨 특성이 가장 잘 드러나는 영역이다.

프로그램이 실행될 때 필요한 메모리의 크기를 미리 알 수 없는 경우가 많다. 예를 들어, 사용자로부터 몇 개의 데이터를 입력받을지 모르는 상황에서 그 데이터를 저장할 배열의 크기를 미리 정할 수는 없다. 이럴 때 필요한 것이 동적 메모리 할당이다.

C에서 메모리 할당 방식은 크게 두 가지로 나뉜다.

스택과 힙의 가장 큰 차이는 ‘관리 주체’와 ‘생명 주기’에 있다. 스택은 컴파일러와 운영체제가 자동으로 관리하며 생명 주기가 함수 호출에 묶여 있지만, 힙은 프로그래머가 수동으로 관리하며 생명 주기를 직접 제어할 수 있다. 따라서 크기를 예측할 수 없거나 함수 호출을 넘어서까지 데이터가 유지되어야 할 경우 힙을 사용한 동적 할당이 필수적이다.

C 표준 라이브러리(<stdlib.h>)는 힙 메모리 관리를 위한 네 가지 주요 함수를 제공한다.

프로그램이 종료되면 변수에 저장된 데이터는 모두 사라진다. 데이터를 영구적으로 보존하기 위해서는 하드 디스크나 SSD와 같은 저장 장치에 파일 형태로 저장해야 한다. C는 파일로부터 데이터를 읽고 쓰는 파일 입출력 기능을 제공한다.

파일은 저장 방식에 따라 크게 두 종류로 나뉜다.

fopen 함수에서 파일 열기 모드를 t(text)로 지정하면 텍스트 모드, b(binary)로 지정하면 이진 모드로 동작한다. 모드를 명시하지 않으면 기본적으로 텍스트 모드로 열린다.156

파일에 접근하기 위해서는 먼저 스트림(stream)을 생성해야 한다. 스트림은 프로그램과 파일 사이의 데이터 통로 역할을 한다. fopen 함수는 파일을 열고 이 스트림을 생성하여, 파일을 제어하는 데 필요한 정보를 담고 있는 FILE 구조체의 포인터, 즉 파일 포인터(FILE*)를 반환한다.157

파일 작업이 모두 끝나면, 반드시 fclose 함수를 호출하여 스트림을 닫아야 한다. fclose는 버퍼에 남아있던 데이터를 파일에 완전히 기록하고, 파일과 연결된 시스템 자원을 해제하는 중요한 역할을 한다.156

#include <stdio.h>

int main(void)
{
    FILE* fp = NULL; // 파일 포인터 선언 및 NULL로 초기화

    fp = fopen("data.txt", "w"); // "data.txt" 파일을 쓰기("w") 모드로 연다.
    if (fp == NULL)
    {
        printf("파일 열기 실패!\n");
        return 1;
    }

    //... 파일 작업 수행...

    fclose(fp); // 파일 닫기

    return 0;
}
모드 설명 파일이 없을 경우 파일이 있을 경우
"r" 읽기 전용으로 연다. 오류 (NULL 반환) 파일의 처음부터 읽는다.
"w" 쓰기 전용으로 연다. 새로 생성한다. 기존 내용을 모두 지우고 새로 쓴다.
"a" 추가 모드로 연다. 새로 생성한다. 파일의 끝에 내용을 추가한다.
"r+" 읽기/쓰기    
  1. C언어의 역사,특징 및 개발순서, 8월 15, 2025에 액세스, https://it-scitech.tistory.com/entry/C%EC%96%B8%EC%96%B4%EC%9D%98-%EC%97%AD%EC%82%AC%ED%8A%B9%EC%A7%95-%EB%B0%8F-%EA%B0%9C%EB%B0%9C%EC%88%9C%EC%84%9C
  2. C언어란? - 정리블로그, 8월 15, 2025에 액세스, https://juns0208.tistory.com/1
  3. C (프로그래밍 언어) - 위키백과, 우리 모두의 백과사전, 8월 15, 2025에 액세스, https://ko.wikipedia.org/wiki/C_(%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D_%EC%96%B8%EC%96%B4)
  4. C 언어 소개: 역사와 특징 - 재능넷, 8월 15, 2025에 액세스, https://www.jaenung.net/tree/1262
  5. 2) C언어 기초 - 코딩의 시작, TCP School, 8월 15, 2025에 액세스, https://tcpschool.com/c/c_intro_basic
  6. C언어의 역사와 특징, 8월 15, 2025에 액세스, https://idevsigner.tistory.com/22
  7. [C] C언어, 특징과 장단점 - 잡동사니 - 티스토리, 8월 15, 2025에 액세스, https://bonsilrote.tistory.com/7
  8. [Knowledge] 프로그래밍 언어 별 특징 (C, C++, C#), 8월 15, 2025에 액세스, https://printscanf.tistory.com/entry/Knowledge-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%96%B8%EC%96%B4-%EB%B3%84-%ED%8A%B9%EC%A7%95-C-C-C
  9. [설계] C* 언어 철학 - 코드쉼터 - 티스토리, 8월 15, 2025에 액세스, https://serene-code.tistory.com/entry/C-%EC%B2%A0%ED%95%99
  10. C언어의 장단점과 활용 방법 - 코딩의신, 8월 15, 2025에 액세스, https://dgnam90.tistory.com/entry/C%EC%96%B8%EC%96%B4%EC%9D%98-%EC%9E%A5%EB%8B%A8%EC%A0%90%EA%B3%BC-%ED%99%9C%EC%9A%A9-%EB%B0%A9%EB%B2%95
  11. C 언어를 배워야 하는 이유, 8월 15, 2025에 액세스, https://argentdarae.tistory.com/116
  12. 프로그램과 C언어특징, 8월 15, 2025에 액세스, https://nomad-jh.tistory.com/112
  13. [C] C 언어의 역사, 특징, 8월 15, 2025에 액세스, https://coddish.tistory.com/12
  14. C(프로그래밍 언어)/상세 - 나무위키, 8월 15, 2025에 액세스, https://namu.wiki/w/C(%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%20%EC%96%B8%EC%96%B4)/%EC%83%81%EC%84%B8
  15. C 언어는 주로 어떤 분야에서 사용하나요?, 8월 15, 2025에 액세스, https://hongong.hanbit.co.kr/faq-items/c-%EC%96%B8%EC%96%B4%EB%8A%94-%EC%A3%BC%EB%A1%9C-%EC%96%B4%EB%96%A4-%EB%B6%84%EC%95%BC%EC%97%90%EC%84%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EB%82%98%EC%9A%94/
  16. gcc로 컴파일 하는 방법, 8월 15, 2025에 액세스, https://seamless.tistory.com/2
  17. [Linux System Programming] GCC 컴파일러 사용법 - velog, 8월 15, 2025에 액세스, https://velog.io/@jc3wrld999/Linux-System-Programming-GCC-%EC%BB%B4%ED%8C%8C%EC%9D%BC%EB%9F%AC-%EC%82%AC%EC%9A%A9%EB%B2%95
  18. 컴파일 과정 (C언어) : 전처리, 컴파일, 어셈블, 링크 - 티스토리, 8월 15, 2025에 액세스, https://iforint.tistory.com/36
  19. [Linux] 리눅스환경(Ubuntu)에서 C언어 코딩하기 - P&H_Station - 티스토리, 8월 15, 2025에 액세스, https://ludeno-studying.tistory.com/38
  20. [C언어] Linux에서 C언어 컴파일하기 - IT 공부 - 티스토리, 8월 15, 2025에 액세스, https://ljy98.tistory.com/144
  21. Visual Studio 프로젝트의 Clang/LLVM 지원 - Microsoft Learn, 8월 15, 2025에 액세스, https://learn.microsoft.com/ko-kr/cpp/build/clang-support-msbuild?view=msvc-170
  22. [임베디드 과제] 클랭(Clang) 컴파일러 - 2sjin - 티스토리, 8월 15, 2025에 액세스, https://2sjin.tistory.com/101
  23. C 개발 환경 설정 (Visual Studio Code) - velog, 8월 15, 2025에 액세스, https://velog.io/@kij723/C-%EA%B0%9C%EB%B0%9C-%ED%99%98%EA%B2%BD-%EC%84%A4%EC%A0%95-Visual-Studio-Code
  24. [C/C++ 프로그래밍] 1. 개발 환경 설정, 8월 15, 2025에 액세스, https://gdngy.tistory.com/146
  25. [Windows] C 언어 설정 - vscode - Sims의 문제해결 저장소 - 티스토리, 8월 15, 2025에 액세스, https://sims-solve.tistory.com/116
  26. Mac 에서 C 언어 개발 환경설정 (Xcode) - 나도코딩 - 티스토리, 8월 15, 2025에 액세스, https://nadocoding.tistory.com/94
  27. Mac 에서 C 언어 개발 환경설정 (Visual Studio Code) - 나도코딩 - 티스토리, 8월 15, 2025에 액세스, https://nadocoding.tistory.com/95
  28. VSCode로 C++ 개발 환경 구축하기 (알고리즘) - Amylo’s blog, 8월 15, 2025에 액세스, https://blog.amylo.diskstation.me/algorithm/Starting_Algorithm_with_VSCode_C++/
  29. [Visual Studio Code] VS Code C++ 개발 환경 설정 (MinGW) - 모징이의 개발 경험치, 8월 15, 2025에 액세스, https://mojing.tistory.com/entry/Visual-Studio-Code-VS-Code-C-%EA%B0%9C%EB%B0%9C-%ED%99%98%EA%B2%BD-%EC%84%A4%EC%A0%95
  30. [Visual Studio] C++ 프로젝트 생성 및 솔루션 관리 방법 - 시나브로 - 티스토리, 8월 15, 2025에 액세스, https://enjoy-coding-together.tistory.com/12
  31. [C언어] Visual Studio 2022 설치하고 C 프로그램 만들기 - 혼공학습단, 8월 15, 2025에 액세스, https://hongong.hanbit.co.kr/c%EC%96%B8%EC%96%B4-visual-studio-2022-%EC%84%A4%EC%B9%98%ED%95%98%EA%B3%A0-c-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8-%EB%A7%8C%EB%93%A4%EA%B8%B0/
  32. 비주얼 스튜디오 2019에서 C언어 프로젝트 만드는 방법 - 나는 개발자다 - 티스토리, 8월 15, 2025에 액세스, https://studyc.tistory.com/36
  33. 3.1 새 프로젝트 만들기 - C 언어 코딩 도장, 8월 15, 2025에 액세스, https://dojang.io/mod/page/view.php?id=6
  34. [VSCODE] C++ 개발환경 세팅 macos (1) :: 포크레인보다 삽질하는 블로그, 8월 15, 2025에 액세스, https://life-is-good-keep-go-on.tistory.com/entry/VSCODE-C-%EA%B0%9C%EB%B0%9C%ED%99%98%EA%B2%BD-%EC%84%B8%ED%8C%85-macos-1
  35. 맥에서 vscode와 clang을 이용한 C/C++환경 설정하기 - 천사친구의 이야기, 8월 15, 2025에 액세스, https://gloria1004.tistory.com/288
  36. [C]Xcode에서 C프로젝트 만들기, 8월 15, 2025에 액세스, https://kamang-it.tistory.com/entry/CXcode%EC%97%90%EC%84%9C-C%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0
  37. [Xcode에서 Obj-C] 프로젝트 만들기 - 시작이 반, 8월 15, 2025에 액세스, https://miyanims.tistory.com/25
  38. 리눅스 C/C++ 개발 환경 설정 (Vim, Visual Studio Code) - 몽구의 우당탕탕 개발 공부, 8월 15, 2025에 액세스, https://mong9data.tistory.com/99
  39. 간단한 gcc 사용법 - 제로벨씨 오늘도 개소리네, 8월 15, 2025에 액세스, https://seolin.tistory.com/73
  40. Visual Studio Code 개발환경 세팅 (C++), 8월 15, 2025에 액세스, https://goodgodgd.github.io/ian-flow/archivers/vscode-tutorial
  41. Ubuntu 22.04에 VSCode C++ 개발 환경 구축 - For a better world - 티스토리, 8월 15, 2025에 액세스, https://roytravel.tistory.com/381
  42. C 언어의 특징 - C를 배우기 전 알아야할 것들 (1) - 핵문과의 도전일기, 8월 15, 2025에 액세스, https://progresspast.tistory.com/entry/C-%EC%96%B8%EC%96%B4%EC%9D%98-%ED%8A%B9%EC%A7%95-C%EB%A5%BC-%EB%B0%B0%EC%9A%B0%EA%B8%B0-%EC%A0%84-%EC%95%8C%EC%95%84%EC%95%BC%ED%95%A0-%EA%B2%83%EB%93%A4-1
  43. 상수와 변수 - [c언어 기초], 8월 15, 2025에 액세스, https://opentutorials.org/module/3921/23508
  44. ([C언어] 4강) scanf함수와 printf함수로 변수 출력 (scanf 오류해결), 8월 15, 2025에 액세스, https://jeckl.tistory.com/entry/C%EC%96%B8%EC%96%B4-4%EA%B0%95-scanf%ED%95%A8%EC%88%98%EC%99%80-printf%ED%95%A8%EC%88%98%EB%A1%9C-%EB%B3%80%EC%88%98-%EC%B6%9C%EB%A0%A5%ED%95%98%EA%B8%B0
  45. C 언어 3 - 1 변수와 상수 - Arkeiyou - 티스토리, 8월 15, 2025에 액세스, https://arkeiyou.tistory.com/31
  46. C언어)상수와 변수 - 코딩하는 거북이 - 티스토리, 8월 15, 2025에 액세스, https://code-rjqnrdl.tistory.com/entry/C%EC%96%B8%EC%96%B4%EC%83%81%EC%88%98%EC%99%80-%EB%B3%80%EC%88%98
  47. [C언어] 상수와 변수의 이해 - thgusnee - 티스토리, 8월 15, 2025에 액세스, https://sohyxzn.tistory.com/10
  48. c언어 변수 선언과 자료형의 종류 - 컴코딩, 8월 15, 2025에 액세스, https://edu-coding.tistory.com/3
  49. [C언어 강좌-5] 상수 (Constant) - Peter의 우아한 프로그래밍 - 티스토리, 8월 15, 2025에 액세스, https://gracefulprograming.tistory.com/43
  50. [C언어] 기본 자료형(data type)의 크기와 범위 - Hello World! - 티스토리, 8월 15, 2025에 액세스, https://idevsigner.tistory.com/20
  51. c언어 기본 자료형의 종류와 데이터의 표현 범위 - 유니디니, 8월 15, 2025에 액세스, https://go-hard.tistory.com/112
  52. C 언어 기본 자료형, 8월 15, 2025에 액세스, http://www.angel25.com/ClanguageStudy1.html
  53. [C 언어 기초 정리 06] 포인터 - 곰곰의 일지, 8월 15, 2025에 액세스, https://secundo.tistory.com/63
  54. c 언어[007] 자료형(데이터 타입) short, int,long, float, double, char 등 표현가능한 수의 범위 , 데이터 크기 알아보기sizeof(변수), 8월 15, 2025에 액세스, https://sf2020.tistory.com/15
  55. c언어 연산자의 종류 - 컴코딩, 8월 15, 2025에 액세스, https://edu-coding.tistory.com/6
  56. C언어 연산자 종류와 우선순위 (왕초보 개념잡기) - 뽀짝뉴스, 8월 15, 2025에 액세스, https://ppojjaknews.tistory.com/41
  57. 25.0 연산자 우선순위 알아보기 - C 언어 코딩 도장, 8월 15, 2025에 액세스, https://dojang.io/mod/page/view.php?id=188
  58. C언어 6-1 : 연산자 기본개념, 우선순위, 결합성 - YouTube, 8월 15, 2025에 액세스, https://www.youtube.com/watch?v=mP6qJa5eNBs
  59. 평가의 우선 순위 및 순서 - Microsoft Learn, 8월 15, 2025에 액세스, https://learn.microsoft.com/ko-kr/cpp/c-language/precedence-and-order-of-evaluation?view=msvc-170
  60. printf와 scanf 제대로 알고 가기 - 잇창명 개발 블로그, 8월 15, 2025에 액세스, https://eatchangmyeong.github.io/2022/07/08/all-about-printf-and-scanf.html
  61. 변환문자 의미 자료형 (C언어 형식 지정자) - MGoon’s Story, 8월 15, 2025에 액세스, https://mgoons.tistory.com/6
  62. [C언어] 서식 지정자의 모든것 (서식문자) - IT는 뭐하는 곳일까 - 티스토리, 8월 15, 2025에 액세스, https://hackerpark.tistory.com/entry/C%EC%96%B8%EC%96%B4-%EC%84%9C%EC%8B%9D-%EC%A7%80%EC%A0%95%EC%9E%90%EC%9D%98-%EB%AA%A8%EB%93%A0%EA%B2%83-%EC%84%9C%EC%8B%9D%EB%AC%B8%EC%9E%90
  63. 85.2 서식 지정자 - C 언어 코딩 도장, 8월 15, 2025에 액세스, https://dojang.io/mod/page/view.php?id=736
  64. 독학으로 배우는 C언어 005 형식 지정자 사용 - 미래와 소통, 8월 15, 2025에 액세스, https://smmi.tistory.com/entry/%EB%8F%85%ED%95%99%EC%9C%BC%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-C%EC%96%B8%EC%96%B4-005-%ED%98%95%EC%8B%9D-%EC%A7%80%EC%A0%95%EC%9E%90-%EC%82%AC%EC%9A%A9
  65. C언어 기초 (printf,scanf,if~else,switch~case) - youngowo - 티스토리, 8월 15, 2025에 액세스, https://youngowo.tistory.com/4
  66. [C언어] 표준 입력 함수 scanf - velog, 8월 15, 2025에 액세스, https://velog.io/@limehee/C%EC%96%B8%EC%96%B4-%ED%91%9C%EC%A4%80-%EC%9E%85%EB%A0%A5-%ED%95%A8%EC%88%98-scanf
  67. [잼민이도 이해하는 C언어 강의] 5. 입력하기 / #scanf - 정고리즘, 8월 15, 2025에 액세스, https://jeongorithm.tistory.com/6
  68. [홍정모의 따라하며 배우는 C언어] 4.10 scanf() 함수의 사용법 ~ 5.2 대입 연산자와 몇 가지 용어들 - 천릿길도 한 걸음부터 - 티스토리, 8월 15, 2025에 액세스, https://youngseong.tistory.com/27
  69. 기초적인 C언어 탐구 3–2/ 형식지정자에 관하여 - Medium, 8월 15, 2025에 액세스, https://medium.com/@seominsang/%EA%B8%B0%EC%B4%88%EC%A0%81%EC%9D%B8-c%EC%96%B8%EC%96%B4-%ED%83%90%EA%B5%AC-3-2-%ED%98%95%EC%8B%9D%EC%A7%80%EC%A0%95%EC%9E%90%EC%97%90-%EA%B4%80%ED%95%98%EC%97%AC-bd00d1117d79
  70. C언어 강좌 7편. 제어문-1 (if~else, switch, case) - 끝나지 않는 프로그래밍 일기, 8월 15, 2025에 액세스, https://blog.hexabrain.net/14
  71. C 언어 if문, switch문 사용법과 실생활 예제 - Snug Archive, 8월 15, 2025에 액세스, https://www.snugarchive.com/blog/c-conditional-statements/
  72. [C언어 기초] if, switch문으로 조건 걸기 - HOIL - 티스토리, 8월 15, 2025에 액세스, https://hoil2.tistory.com/9
  73. switch 문과 if문의 차이 (언제 switch를 쓰고 언제 if를 사용할까?) - ITHouse - 티스토리, 8월 15, 2025에 액세스, https://securityholic.tistory.com/90
  74. switch와 if else 중 어떤 것을 써야하는가? - Nested nest - 티스토리, 8월 15, 2025에 액세스, https://aahc.tistory.com/6
  75. switch vs if 어떤 때 어느게 효율적인가요? - KLDP, 8월 15, 2025에 액세스, https://kldp.org/node/62262
  76. C언어 - 반복문(while문, do~while문, for문) - 학교 공부, 개인 공부 - 티스토리, 8월 15, 2025에 액세스, https://jjunsu.tistory.com/7
  77. C 언어 for문, while문, do while문 사용법과 실생활 예제 - Snug Archive, 8월 15, 2025에 액세스, https://www.snugarchive.com/blog/c-iterative-statements/
  78. [잼민이도 이해하는 C언어 강의] 8. 반복문 / #while, #for, #do-while - 정고리즘, 8월 15, 2025에 액세스, https://jeongorithm.tistory.com/9
  79. [C] 반복문(while, do-while, for) - 취준생 일지 - 티스토리, 8월 15, 2025에 액세스, https://andjjip.tistory.com/212
  80. 반복문: while문, do while문,for each반복문 - 붕어의 코딩세상 - 티스토리, 8월 15, 2025에 액세스, https://mustbebetter.tistory.com/11
  81. [C언어 기초코딩: 예제로 간단 정리] 4. 조건문(Conditions) : if, if else, switch, break, continue, goto - mainCodes:: 메인코즈 - 티스토리, 8월 15, 2025에 액세스, https://maincodes.tistory.com/23
  82. C언어 - 분기문 (goto, break, continue, return) - 범작물 연습장 - 티스토리, 8월 15, 2025에 액세스, https://bjack.tistory.com/entry/C%EC%96%B8%EC%96%B4-%EB%B6%84%EA%B8%B0%EB%AC%B8-goto-break-continue-return
  83. C,C++언어 break 와 continue문 - 플로렌스라는 개발자 - 티스토리, 8월 15, 2025에 액세스, https://plorence.tistory.com/383
  84. [C언어] 기타 제어문 (break,continue,goto,return) - youngowo - 티스토리, 8월 15, 2025에 액세스, https://youngowo.tistory.com/6
  85. C# Jump 문 : break, continue, return, goto - 끄적끄적 코딩 공방 - 티스토리, 8월 15, 2025에 액세스, https://coding-shop.tistory.com/108
  86. [C언어] 함수 선언, 호출, 정의 - thgusnee - 티스토리, 8월 15, 2025에 액세스, https://sohyxzn.tistory.com/8
  87. 함수 선언 및 정의 - IBM, 8월 15, 2025에 액세스, https://www.ibm.com/docs/ko/i/7.6.0?topic=functions-function-declarations-definitions
  88. C언어 선언과 정의, 매크로에 대한 정리 - Unknownpgr, 8월 15, 2025에 액세스, https://unknownpgr.com/posts/c-lang/index.html
  89. [C언어 강좌-12] 함수 (Function) - Peter의 우아한 프로그래밍 - 티스토리, 8월 15, 2025에 액세스, https://gracefulprograming.tistory.com/77
  90. 선언과 정의 - C언어의 기초 문법, 8월 15, 2025에 액세스, https://opentutorials.org/module/5371/30529
  91. white-world.tistory.com, 8월 15, 2025에 액세스, [https://white-world.tistory.com/165#:~:text=%EA%B8%B0%EB%A1%9D%2FC%20Language-,%5BC%EC%96%B8%EC%96%B4%5D%20call%20by%20value%2C%20call%20by%20reference%20%7C,%ED%98%B8%EC%B6%9C%2C%20%EC%B0%B8%EC%A1%B0%EC%97%90%20%EC%9D%98%ED%95%9C%20%ED%98%B8%EC%B6%9C&text=%EA%B0%92%EC%97%90%20%EC%9D%98%ED%95%9C%20%ED%98%B8%EC%B6%9C%EC%9D%80,%EB%A7%A4%EA%B0%9C%EB%B3%80%EC%88%98%EB%A1%9C%20%EB%B0%9B%EB%8A%94%20%EA%B2%83%EC%9D%B4%EB%8B%A4.](https://white-world.tistory.com/165#:~:text=기록%2FC Language-,[C언어] call by value%2C call by reference ,호출%2C 참조에 의한 호출&text=값에 의한 호출은,매개변수로 받는 것이다.)
  92. [C / C++] Call by value(값에 의한 호출), Call by Reference(참조에 의한 호출), 무엇이 다르지?, 8월 15, 2025에 액세스, https://0xffffffff.tistory.com/73
  93. [C, C++] Call by value, Call by reference 쉽게 이해하기 - 좋아하는 일 그리고 잘하는 일, 그 사이 어딘가, 8월 15, 2025에 액세스, https://kangworld.tistory.com/64
  94. 값에 의한 전달(call by value) - 코딩의 시작, TCP School, 8월 15, 2025에 액세스, https://tcpschool.com/c/c_pointer_callBy
  95. [C언어] call by value, call by reference 값에 의한 호출, 참조에 의한 호출 - 준성 스페이스, 8월 15, 2025에 액세스, https://white-world.tistory.com/165
  96. (C 예제) 재귀 함수 - HCR Daily, 8월 15, 2025에 액세스, https://hcr3066.tistory.com/143
  97. 재귀함수 예제로 이해하기, 3가지 규칙 - 타깃코더스, 8월 15, 2025에 액세스, https://targetcoders.com/%EC%9E%AC%EA%B7%80%ED%95%A8%EC%88%98-%EC%98%88%EC%A0%9C-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0/
  98. [C언어_14] 재귀함수의 개념과 공부하는 이유 - 끄적임 - 티스토리, 8월 15, 2025에 액세스, https://swdoodle.tistory.com/19
  99. Chapter 1. 재귀(Recursion) : 개념과 기본 예제들 - 평생 공부 블로그, 8월 15, 2025에 액세스, https://ansohxxn.github.io/algorithm%20lesson%201/chapter1-1/
  100. 포인터의 개념 - 코딩의 시작, TCP School, 8월 15, 2025에 액세스, https://tcpschool.com/c/c_pointer_intro
  101. C언어 기초 - 포인터 와 주소 이해하기, pointer, 8월 15, 2025에 액세스, https://diyver.tistory.com/87
  102. C 언어 기초#8 포인터(pointer) - 코딩상륙작전 - 티스토리, 8월 15, 2025에 액세스, https://operationcoding.tistory.com/17
  103. 27) 포인터 연산 - 코딩의 시작, TCP School, 8월 15, 2025에 액세스, https://tcpschool.com/c/c_pointer_calculation
  104. 44.1 포인터 연산으로 메모리 주소 조작하기 - COS Pro - 코딩 도장, 8월 15, 2025에 액세스, https://dojang.io/mod/page/view.php?id=1925
  105. 59.0 포인터 연산 사용하기 - C 언어 코딩 도장, 8월 15, 2025에 액세스, https://dojang.io/mod/page/view.php?id=508
  106. [C 언어] 포인터로 1차원 배열 다루기 (주소 접근 및 원소 값 접근) - Wonit, 8월 15, 2025에 액세스, https://wonit.tistory.com/526
  107. tcpschool.com, 8월 15, 2025에 액세스, https://tcpschool.com/c/c_pointerArray_relation#:~:text=%ED%8F%AC%EC%9D%B8%ED%84%B0%EC%99%80%20%EB%B0%B0%EC%97%B4%EC%9D%80%20%EB%A7%A4%EC%9A%B0,%EC%83%81%EC%88%98(constant%20pointer)%EC%9E%85%EB%8B%88%EB%8B%A4.
  108. [C] 배열과 포인터의 관계 (변수형 포인터, 상수형 포인터), 포인터로 배열 변경하기, 8월 15, 2025에 액세스, https://devshovelinglife.tistory.com/606
  109. 30) 포인터와 배열의 관계 - TCP School, 8월 15, 2025에 액세스, https://tcpschool.com/c/c_pointerArray_relation
  110. [C언어] - 배열과 포인터의 관계 - 소웨카이나 - 티스토리, 8월 15, 2025에 액세스, https://kangdy25.tistory.com/62
  111. [C] 함수 포인터 개념과 사용 방법 정리., 8월 15, 2025에 액세스, https://eunjinii.tistory.com/32
  112. 68.1 함수 포인터 만들기 - C 언어 코딩 도장, 8월 15, 2025에 액세스, https://dojang.io/mod/page/view.php?id=592
  113. [C] 함수포인터 기초 - Done is better than perfect - 티스토리, 8월 15, 2025에 액세스, https://googleyness.tistory.com/entry/C-%ED%95%A8%EC%88%98%ED%8F%AC%EC%9D%B8%ED%84%B0-%EA%B8%B0%EC%B4%88
  114. 69.3 함수 포인터를 함수의 매개변수로 사용하기 - C 언어 코딩 도장, 8월 15, 2025에 액세스, https://dojang.io/mod/page/view.php?id=599
  115. [C언어] 2차원 배열 선언과 초기화 - 개인노트 - 티스토리, 8월 15, 2025에 액세스, https://billnairk.tistory.com/55
  116. COS Pro 2급 C 언어: 34.1 2차원 배열을 선언하고 요소에 접근하기 - 코딩 도장, 8월 15, 2025에 액세스, https://dojang.io/mod/page/view.php?id=1765
  117. 25) 다차원 배열 - 코딩의 시작, TCP School, 8월 15, 2025에 액세스, https://tcpschool.com/c/c_array_twoDimensional
  118. 34.2 2차원 배열을 초기화하기 - COS Pro - 코딩 도장, 8월 15, 2025에 액세스, https://dojang.io/mod/page/view.php?id=1766
  119. [C programming] 다차원 배열(2차원 배열)의 정의, 선언, 초기화, 주소와 값의 참조, 8월 15, 2025에 액세스, https://monosandalos.tistory.com/50
  120. C언어_자료형(int, char, float, double) - 개발일지 - 티스토리, 8월 15, 2025에 액세스, https://giveme-happyending.tistory.com/52
  121. [C] C언어에서 문자열을 다루는 방법, 문자열 관련 함수 정리 - 프린세스 다이어리, 8월 15, 2025에 액세스, https://eunjinii.tistory.com/28
  122. C 문자열 함수 - [정보통신기술용어해설], 8월 15, 2025에 액세스, http://www.ktword.co.kr/test/view/view.php?no=5812
  123. C언어 문자열을 처리하는 함수들(String.h) - 원원이의 블로그, 8월 15, 2025에 액세스, https://wowon.tistory.com/16
  124. [C언어] string.h 포함 함수 정리 (strcmp, strncmp, strcat, strncat, strstr, strlcat), 8월 15, 2025에 액세스, https://develop-with-kkomaeng.tistory.com/9
  125. [C언어] 문자열 처리 함수
  126. [C 언어] struct, 구조체의 기본과 사용 방법 - Wonit - 티스토리, 8월 15, 2025에 액세스, https://wonit.tistory.com/529
  127. [C] 구조체(struct). 구조체의 개념과 배열 사용 예시 by EunJin Medium, 8월 15, 2025에 액세스, https://jin0904.medium.com/c-%EA%B5%AC%EC%A1%B0%EC%B2%B4-struct-a82bae699581
  128. [C언어/C++] 구조체 사용법 & 예제 총정리 - 코딩팩토리 - 티스토리, 8월 15, 2025에 액세스, https://coding-factory.tistory.com/639
  129. 48.2 typedef로 struct 키워드 없이 구조체 선언하기 - C 언어 코딩 도장, 8월 15, 2025에 액세스, https://dojang.io/mod/page/view.php?id=409
  130. [C언어] - 구조체 (Struct) - Shin._.Mallang - 티스토리, 8월 15, 2025에 액세스, https://ttl-blog.tistory.com/726
  131. 구조체(7) 구조체와 포인터 & 간접 멤버 연산자 - bss 영역 - 티스토리, 8월 15, 2025에 액세스, https://sean.tistory.com/125
  132. 49.1 구조체 포인터를 선언하고 메모리 할당하기 - C 언어 코딩 도장, 8월 15, 2025에 액세스, https://dojang.io/mod/page/view.php?id=418
  133. [C 언어] 구조체 포인터와 화살표 연산자 - Wonit - 티스토리, 8월 15, 2025에 액세스, https://wonit.tistory.com/530
  134. [C언어] union으로 공용체 정의하기 - 나무보다 숲을 - 티스토리, 8월 15, 2025에 액세스, https://laurent.tistory.com/entry/C%EC%96%B8%EC%96%B4-union%EC%9C%BC%EB%A1%9C-%EA%B3%B5%EC%9A%A9%EC%B2%B4-%EC%A0%95%EC%9D%98%ED%95%98%EA%B8%B0
  135. C언어 - 공용체 - 나만의 별책부록 - 티스토리, 8월 15, 2025에 액세스, https://responding.tistory.com/26
  136. 【 C 언어 】 #42 공용체 (union) 이해하기 - 라즈이노 iOT - 티스토리, 8월 15, 2025에 액세스, https://rasino.tistory.com/74
  137. [C] UNION 공용체와 Struct 구조체를 이용해 간단한 패킷 만들기 - Embeded-Korea - 티스토리, 8월 15, 2025에 액세스, https://coding-yoon.tistory.com/120
  138. c언어 열거형 - enum - 컴코딩, 8월 15, 2025에 액세스, https://edu-coding.tistory.com/18
  139. [C] Enum 사용법 , C언어 열거형 사용법 열거형(Enum) - Kaen’s Ritus - 티스토리, 8월 15, 2025에 액세스, https://kaen2891.tistory.com/8
  140. 57.1 열거형 정의하기 - C 언어 코딩 도장, 8월 15, 2025에 액세스, https://dojang.io/mod/page/view.php?id=480
  141. C언어 - 열거형 - 나만의 별책부록 - 티스토리, 8월 15, 2025에 액세스, https://responding.tistory.com/27
  142. [C언어/C++] 열거형 enum 사용법 & 예제 - 코딩팩토리 - 티스토리, 8월 15, 2025에 액세스, https://coding-factory.tistory.com/641
  143. habitus92.tistory.com, 8월 15, 2025에 액세스, https://habitus92.tistory.com/13#:~:text=%EB%8F%99%EC%A0%81%ED%95%A0%EB%8B%B9%EC%9D%80%20%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8%EC%9D%84,%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8%EC%9D%B4%20%EB%81%9D%EB%82%98%EB%A9%B4%20%EC%86%8C%EB%A9%B8%EB%90%9C%EB%8B%A4.
  144. ([C++] 23강) 메모리 동적할당 new, delete, 8월 15, 2025에 액세스, https://jeckl.tistory.com/entry/C-23%EA%B0%95-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EB%8F%99%EC%A0%81%ED%95%A0%EB%8B%B9-new-delete
  145. [메모리] 동적할당과 정적할당 특징 비교 - IT팩토리 - 티스토리, 8월 15, 2025에 액세스, https://habitus92.tistory.com/13
  146. 동적 메모리 할당 - 위키백과, 우리 모두의 백과사전, 8월 15, 2025에 액세스, https://ko.wikipedia.org/wiki/%EB%8F%99%EC%A0%81%EB%A9%94%EB%AA%A8%EB%A6%AC%ED%95%A0%EB%8B%B9
  147. 동적할당과 정적할당의 장단점 - 설계의 품격 - 티스토리, 8월 15, 2025에 액세스, https://goodmean.tistory.com/38
  148. 동적 메모리 할당 (malloc / calloc / realloc / free) - K_Coder(転職資料) - 티스토리, 8월 15, 2025에 액세스, https://kcoder.tistory.com/entry/%EB%8F%99%EC%A0%81-%EB%A9%94%EB%AA%A8%EB%A6%AC-%ED%95%A0%EB%8B%B9-malloc-calloc-realloc-free
  149. [C] malloc, calloc, realloc을 이용한 메모리 동적 할당 - My DevHub - 티스토리, 8월 15, 2025에 액세스, https://dsnight.tistory.com/51
  150. C/C++ 동적 메모리할당 malloc, calloc, realloc 함수 비교 및 예제 - 공돌창고 - 티스토리, 8월 15, 2025에 액세스, https://hijuworld.tistory.com/60
  151. [C/C++] 메모리 동적할당 2 (realloc, calloc) - 일상을 개발하다 - 티스토리, 8월 15, 2025에 액세스, https://geuninote.tistory.com/94
  152. POCU C언어 정주행 14회차 - malloc과 free, 메모리 함수, 메모리 관리 기법, 8월 15, 2025에 액세스, https://dafher-diary.tistory.com/16
  153. [C 이론] 16. 파일 입출력, 8월 15, 2025에 액세스, https://olive-su.tistory.com/99
  154. Text file과 Binary file - WonnyDocs - 티스토리, 8월 15, 2025에 액세스, https://dawonny.tistory.com/202
  155. 파일(file)이란? - 코딩의 시작, TCP School, 8월 15, 2025에 액세스, http://www.tcpschool.com/c/c_io_file
  156. [C언어/C++] 파일 입출력 fopen, fclose 함수에 대해서 - 가면 뒤의 기록, 8월 15, 2025에 액세스, https://blockdmask.tistory.com/392
  157. [C언어] - 파일입출력 관련 여러 함수들 - 개발의아들, 8월 15, 2025에 액세스, https://freeservice-son-of-programming.tistory.com/6
  158. C언어 - 파일 입출력, fopen(), fclose(), 8월 15, 2025에 액세스, https://itdexter.tistory.com/470