현재 사용하고 있는 거의 모든 컴퓨터 시스템에서 사용할 수 있는 프로그래밍 언어
저급 언어와 고급 언어의 특징을 모두 가지고 있는 절차지향 프로그래밍 언어
(절차지향 프로그래밍 언어란? 순차적 프로그래밍이라고도 하며, 해야할 작업을 순서대로 코딩을 한다. 구조적 프로그래밍에서는 함수 단위로 구성되며 기능별로 묶어놓은 특징이 있다.)
프로그래밍이란 목적에 맞는 알고리즘으로부터 프로그래밍 언어를 사용하여 구체적인 프로그램을 작성하는 과정을 의미한다.
이렇게 작성된 프로그램은 먼저 실행 파일(executable file)로 변환되어야 실행할 수 있다.
소스 파일(source file)의 작성
C언어를 사용하여 문법에 맞게 논리적으로 작성된 프로그램을 원시 파일
선행처리기(preprocessor)에 의한 선행처리
소스 파일 중에서도 선행처리 문자(#)로 시작하는 선행처리 지시문의 처리 작업
선행처리기는 코드를 생성하는 것이 아닌, 컴파일하기 전 컴파일러가 작업하기 좋도록 소스를 재구성해주는 역할
컴파일러(compiler)에 의한 컴파일
소스 파일을 컴퓨터가 알아볼 수 있는 기계어로 변환 -> 컴파일
컴파일은 컴파일러에 의해 수행되며, 컴파일이 끝나 기계어로 변환된 파일을 오브젝트 파일(object file)이라고 함
링커(linker)에 의한 링크
하나 이상의 오브젝트 파일과 라이브러리 파일, 시동 코드 등을 합쳐 하나의 파일로 만드는 작업
링크는 링커(linker)에 의해 수행되며, 링크가 끝나면 하나의 새로운 실행 파일이나 라이브러리 파일이 생성
실행 파일(executable file)의 생성
소스 파일은 선행처리기, 컴파일러 그리고 링커에 의해 위와 같은 과정을 거쳐 실행 파일로 변환
프로그래밍에서 함수(function)란 하나의 특별한 목적의 작업을 수행하기 위해 독립적으로 설계된 프로그램 코드의 집합으로 정의할 수 있다.
C 프로그램은 이러한 함수들로 구성되며, 포함된 함수들을 사용하여 프로그램의 목적을 달성하게 된다.
C언어에서 함수는 크게 표준 함수와 사용자 정의 함수로 구분할 수 있다.
C언어에서는 변수의 선언 위치에 따라 해당 변수의 유효 범위, 메모리 반환 시기, 초기화 여부, 저장되는 장소 등이 변경된다.
C언어에서 변수는 위와 같은 특징들을 기준으로 다음과 같이 나눌 수 있다.
지역 변수(local variable)
지역 변수란 '블록' 내에서 선언된 변수를 의미
지역 변수는 변수가 선언된 블록 내에서만 유효하며, 블록이 종료되면 메모리에서 사라진다.
이러한 지역 변수는 메모리상의 스택(stack) 영역에 저장되며, 초기화하지 않으면 의미 없는 값(쓰레기값)으로 초기화된다.
함수의 매개변수 또한 함수 내에서 정의되는 지역 변수로 취급된다.
전역 변수(global variable)
전역 변수란 함수의 외부에서 선언된 변수를 의미
전역 변수는 프로그램의 어디에서나 접근할 수 있으며, 프로그램이 종료되어야만 메모리에서 사라진다.
이러한 전역 변수는 메모리상의 데이터(data) 영역에 저장되며, 직접 초기화하지 않아도 0으로 자동 초기화된다.
정적 변수(static variable)
static 키워드로 선언한 변수를 의미
이렇게 선언된 정적 변수는 지역 변수와 전역 변수의 특징을 모두 가지게 된다.
함수 내에서 선언된 정적 변수는 전역 변수처럼 단 한 번만 초기화되며(초기화는 최초 실행 시 단 한번만 수행됨), 프로그램이 종료되어야 메모리상에서 사라진다.
또한, 이렇게 선언된 정적 변수는 지역 변수처럼 해당 함수 내에서만 접근할 수 있다.
레지스터 변수(register variable)
지역 변수를 선언할 때 register 키워드를 붙여 선언한 변수를 의미
이렇게 선언된 레지스터 변수는 CPU의 레지스터(register) 메모리에 저장되어 빠르게 접근할 수 있게 된다.
C언어에서 포인터(pointer)란 메모리의 주소값을 저장하는 변수이며, 포인터 변수라고도 부른다.
char형 변수가 문자를 저장하고, int형 변수가 정수를 저장하는 것처럼 포인터는 주소값을 저장한다.
자료가 저장되는 기억장치의 기억주소를 가리키는 지시자로써 포인터는 다른 기억장소의 자료를 참조하는데 사용되는 데이터이다.
주소값이란?
해당 데이터가 저장된 메모리의 시작 주소를 의미
C언어에서는 이러한 주소값을 1바이트 크기의 메모리 공간으로 나누어 표현
예를 들어, int형 데이터는 4바이트의 크기를 가지지만, int형 데이터의 주소값은 시작 주소 1바이트만을 가리킨다.
포인터를 사용하는 이유?
어떠한 변수이든지 어떠한 버퍼를 할당 받아서 사용하는데, 모든 변수의 저장과 참조는 변수가 저장될 혹은 저장된 주소를 알아야 가능하다.
그래서 컴퓨터는 변수를 참조할 때 그 변수가 저장되어 있는 주소를 먼저 찾아내고 그 주소가 가리키는 내용을 참조하게 된다. 이렇게 변수의 주소를 저장하거나 사용하기 위한 변수가 포인터이다.
포인터를 사용하면 간결하고 효율적인 표현과 처리가 가능하고 더 빠른 기계어 코드를 생성할 수 있으며, 복잡한 자료 구조(배열, 구조체 등)와 함수의 쉬운 접근이 가능하다. 또한, 포인터를 사용하지 않았을 때 코드로 표현할 수 없는 경우가 생길 수 있다.
포인터 사용 시 장점
메모리 주소를 참조해서 다양한 자료형 변수들의 접근과 조작 용이
메모리 주소를 참조하여 배열과 같은 연속된 데이터에 접근과 조작 용이
동적 할당된 메모리 영역(힙 영역)에 접근과 조작 용이
한 함수에서 다른 함수로 배열이나 문자열을 편리하게 보낼 수 있음
복잡한 자료구조를 효율적으로 처리
배열로 생성할 수 없는 데이터를 생성
메모리 공간을 효율적 사용
call by reference에 의한 전역 변수의 사용을 억제
코드(code) 영역
실행할 프로그램의 코드가 저장되는 영역으로 텍스트(code) 영역이라고도 부른다.
CPU는 코드 영역에 저장된 명령어를 하나씩 가져가서 처리하게 된다.
데이터(data) 영역
전역 변수와 정적(static) 변수가 저장되는 영역
데이터 영역은 프로그램의 시작과 함께 할당되며, 프로그램이 종료되면 소멸한다.
힙(heap) 영역
사용자가 직접 관리할 수 있는 '그리고 해야만 하는' 메모리 영역
힙 영역은 사용자에 의해 메모리 공간이 동적으로 할당되고 해제된다.
힙 영역은 메모리의 낮은 주소에서 높은 주소의 방향으로 할당된다.
구조체(structure type)란 사용자가 C언어의 기본 타입을 가지고 새롭게 정의할 수 있는 사용자 정의 타입
구조체는 기본 타입만으로는 나타낼 수 없는 복잡한 데이터를 표현할 수 있다.
배열이 같은 타입의 변수 집합이라고 한다면, 구조체는 다양한 타입의 변수 집합을 하나의 타입으로 나타낸 것이다. 이때 구조체를 구성하는 변수를 구조체의 멤버(member) 또는 멤버 변수(member variable)라고 한다.