Skip to main content

11/2/2025

1. Summary

정보처리기사 실기 시험을 준비하면서 C를 학습했습니다.
처음엔 막연히 무섭게만 생각했는데, 문제 풀이와 함께 문법 및 개념을 정리했더니,
문제를 풀 수 있을 정도로는 이해가 갑니다.

여전히 어렵게만 느껴져도, 프로그래밍 언어의 근본(?)이라는 이야기를 많이 들어,
꼭 알아야겠다는 마음이 듭니다.

이 챕터에선 C언어의 기본적인 개념과 원리를 살펴보겠습니다.
이번 글은 제가 궁금했던 언어의 기본 문법 및 개념들 위주로 간략히 살펴봅니다.

1. 자료형과 타입, 키워드​

기본 자료형​

자료형크기(일반적)설명
char1바이트문자 1개 저장 (ASCII 코드)
int4바이트정수형 기본 타입
short2바이트짧은 정수형
long4~8바이트긴 정수형
float4바이트단정도 실수
double8바이트배정도 실수
void0바이트반환 값이나 포인터가 없음을 의미

double이 좀 낯설었는데, "8바이트 크기를 가지는 실수형(부동소수점) 데이터 타입"이라고 합니다.
float보다 더 넓은 범위의 값을 표현할 수 있으며, 소수점 이하 약 15자리까지의 정밀도를 가집니다.

키워드(예약어)​

타입 앞에 키워드(예약어)가 붙는 경우가 있어 정리했습니다.
static, const는 낯익지만, 키워드가 놓이는 위치가 낯설게 느껴졌습니다.

  • struct: asd
  • static: 지역 변수의 생명 주기 유지, 전역 변수의 접근 제한
  • const: 상수화 (값 변경 불가)
  • signed / unsigned: 부호 여부 지정 (unsigned int는 0 이상의 정수만)
  • short, long: 저장 크기 변경
  • volatile: 최적화 방지용 (하드웨어 접근 시 사용)
  • extern: 외부 파일의 전역 변수 참조

포인터 관련 타입 선언​

타입에 포인터가 붙거나, 변수명 앞에 붙는 경우가 어떤 차이인지 궁금하여 더 찾아봤습니다.

  • int *p; : int형 변수를 가리키는 포인터
  • char **p; : char형 포인터를 가리키는 포인터(이중 포인터)
  • struct node *p; : 구조체를 가리키는 포인터

ref-type​

C 언어는 엄밀한 의미에서 "참조 타입"을 직접적으로 지원하지는 않는다고 합니다.
대신, **포인터(Pointer)**를 사용하여 메모리 주소를 직접 다루며,
이를 통해 다른 언어의 참조와 유사한 역할을 수행합니다.

C에서 배열이나 구조체(struct) 변수를 사용하기 위해 {}를 사용합니다. 리스트(배열) 타입은 여러 개의 값을 묶어서 하나의 변수에 할당하기 위해 사용합니다.


2. 포인터​

개념​

포인터(pointer)는 메모리 주소를 저장하는 변수입니다.
변수의 값을 직접 저장하지 않고, 변수의 주소를 가리켜 간접적으로 접근하게 됩니다. 앞서 살핀 참조 타입의 리스트, 구조체나 함수와 함께 많이 사용됩니다.

자료형크기(일반적)설명
* (포인터)4 또는 8바이트변수의 메모리 주소를 저장하는 타입
& (주소 연산자)-변수의 주소를 얻는 데 사용되는 연산자
* (역참조 연산자)-포인터가 가리키는 메모리 위치의 값을 가져오는 데 사용되는 연산자
void *4 또는 8바이트모든 타입의 주소를 저장할 수 있는 제네릭(Generic) 포인터

주요 특징​

다음과 같은 특징이 있습니다. 코드와 문법을 함께 살피면 이해가 빠릅니다.

  • 주소 저장: 포인터는 값 자체가 아니라, 값이 저장된 메모리 공간의 시작 주소를 보관합니다.
  • 간접 접근: 포인터를 통해 원본 데이터가 저장된 메모리 위치에 간접적으로 접근하여 데이터를 읽거나 수정할 수 있습니다.
  • 동적 메모리 할당: malloc(), calloc() 등의 함수를 사용하여 힙(Heap) 영역에 메모리를 동적으로 할당하고 포인터로 관리합니다.
  • 함수로 데이터 전달: 함수 호출 시 파라미터로 포인터를 전달하면, 함수 내에서 원본 변수의 값을 직접 변경할 수 있습니다 (Call-by-Reference 효과).
  • 크기: 포인터 변수의 크기는 운영체제(CPU 아키텍처)에 따라 달라지며, 32비트 시스템에서는 4바이트, 64비트 시스템에서는 8바이트가 일반적입니다. (가리키는 데이터의 타입 크기와는 무관합니다.)

문법과 역할​

int a = 10;
int *p = &a; // a의 주소를 p에 저장
  • *p : 포인터가 가리키는 주소의 값(dereference)
  • &a : 변수 a의 주소(address-of)

포인터 위치에 따른 의미 차이​

선언의미
int* p;p는 int를 가리키는 포인터
int *p, q;p는 포인터, q는 일반 int
int* p1, *p2;p1과 p2 모두 int 포인터

*은 변수 단위에 적용되므로, 혼동하기 쉬워 주의가 필요합니다.

Call by Value/Reference​

함수 파라미터에 포인터를 사용하여 스코프 밖의 변수값을 변경할 수 있습니다.

  • 값에 의한 호출(Call by Value): 인자 값을 복사하여 함수로 전달
    • (원본 변수에는 영향 없음)
  • 참조에 의한 호출(Call by Reference)
    • **인자의 주소(포인터)를 전달 **(원본 값 변경 가능)

함수, 스코프 챕터에서 관련 내용을 더 살펴보겠습니다.

포인터 연산 우선순위​

포인터 연산에서 우선순위가 혼동되어 간략히 표로 정리했습니다:

연산자의미우선순위
*p포인터가 가리키는 값높음
p++다음 메모리 주소(타입 크기만큼 이동)중간
(*p)++포인터가 가리키는 값 증가 괄호로 구분필요
&*p다시 주소로 변환 (p와 동일) 주의:우선순위는 *보다 &가 낮음

3. 함수와 스코프​

함수의 개념​

함수(function)는 특정 기능을 수행하는 코드 블록으로, 반복되는 코드를 재사용하고 프로그램을 모듈화하는 데 사용됩니다.

함수의 기본 구조​

반환타입 함수명(매개변수1, 매개변수2, ...) {
// 함수 본문
return 반환값;
}

주요 특징​

  • 선언(Declaration)과 정의(Definition)

    • 선언: 함수의 프로토타입(시그니처)만 작성 (int add(int a, int b);)
    • 정의: 함수의 실제 구현 코드 작성
    • 선언은 호출 전에 필요하며, 정의는 한 번만 작성
  • 반환 타입

    • void: 반환값이 없을 때 사용
    • int, char, double 등: 해당 타입의 값을 반환
    • 포인터나 구조체도 반환 가능
  • 매개변수(Parameter)

    • 함수 호출 시 전달받는 값
    • 기본적으로 값 복사(Call by Value) 방식
    • 포인터를 사용하면 원본 수정 가능(Call by Reference)

스코프(Scope)​

스코프는 변수가 접근 가능한 영역을 의미합니다.
변수는 선언된 위치에 따라 접근 범위가 결정됩니다.

스코프의 종류​

스코프설명생명주기
전역 스코프함수 밖에서 선언된 변수프로그램 종료 시까지
지역 스코프함수 내부 또는 블록({}) 내에서 선언된 변수블록을 벗어나면 소멸
파라미터 스코프함수의 매개변수함수 호출 시 생성, 종료 시 소멸

변수의 생명주기​

  • 자동 변수(지역 변수): 블록 진입 시 생성, 블록 종료 시 자동 소멸
  • 전역 변수: 프로그램 시작 시 생성, 종료 시 소멸
  • 정적 변수(static): 프로그램 시작 시 생성, 종료 시 소멸 (단, 선언된 블록 내에서만 접근 가능)

static 키워드의 스코프 적용​

앞서 키워드 섹션에서 static을 다뤘는데, 스코프에서의 역할을 정리하면:

  • 지역 변수에 static 사용
    • 변수의 생명주기가 프로그램 종료까지 유지됨
    • 함수 호출 간 값이 유지되어 상태를 보존할 수 있음
void counter() {
static int count = 0; // 함수 호출 간 값 유지
count++;
printf("%d\n", count);
}
  • 전역 변수에 static 사용
    • 해당 파일 내에서만 접근 가능 (다른 파일에서 extern으로 참조 불가)
    • 파일 스코프 제한 효과

함수와 포인터​

함수에서 포인터를 사용하면 Call by Reference 방식으로 원본 값을 수정할 수 있습니다. 포인터 섹션에서 언급한 내용의 실제 사용 예시입니다.

void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
  • 매개변수로 포인터를 전달하면 함수 내에서 원본 변수의 값을 변경할 수 있습니다.
  • 배열도 포인터로 전달되어 함수 내에서 배열 요소를 수정할 수 있습니다.

4. 표준 라이브러리​

C 언어의 표준 라이브러리는 프로그래밍에 필요한 기본 기능들을 제공합니다.
각 헤더 파일(.h)을 #include로 포함하여 사용합니다.

stdio.h (Standard Input/Output)​

입출력 관련 함수들을 제공하는 표준 라이브러리입니다.
콘솔, 파일, 문자열을 대상으로 데이터를 읽고 쓸 수 있습니다.

함수설명
printf()형식 지정 출력 (콘솔)
scanf()형식 지정 입력 (콘솔)
putchar() / getchar()문자 단위 입출력
puts() / gets()문자열 단위 입출력 (단, gets()는 보안상 사용 금지)
fopen() / fclose()파일 열기/닫기
fread() / fwrite()파일 입출력 (바이너리 모드)

주요 포인트​

  • printf()와 scanf()는 형식 지정자(%d, %s, %f 등)를 사용하여 다양한 타입의 데이터를 입출력합니다.
  • 파일 작업 시 fopen()으로 파일을 열고, 사용 후 반드시 fclose()로 닫아야 합니다.
  • gets() 함수는 버퍼 오버플로우 보안 취약점이 있어 사용을 지양하며, fgets()를 대신 사용하는 것이 권장됩니다.

stdlib.h (Standard Library)​

표준 유틸리티 함수들을 제공하는 라이브러리입니다.
동적 메모리 관리, 타입 변환, 난수 생성 등 다양한 기능을 포함합니다.

함수설명
malloc(size)동적 메모리 할당 (초기화 X)
calloc(n, size)동적 메모리 할당 (0으로 초기화)
realloc(ptr, new_size)기존 메모리 크기 재조정
free(ptr)동적 메모리 해제
rand() / srand()난수 생성 / 시드 설정
atoi() / atof()문자열을 숫자(int, double)로 변환
abs()정수 절댓값 반환
exit(status)프로그램 종료
system(cmd)시스템 명령 실행

주요 포인트​

  • malloc()과 calloc()은 힙(Heap) 영역에 메모리를 할당합니다. 포인터 섹션에서 언급한 동적 메모리 할당과 관련됩니다.
  • malloc()은 메모리를 초기화하지 않지만, calloc()은 0으로 초기화됩니다.
  • 동적으로 할당한 메모리는 반드시 free()로 해제해야 메모리 누수를 방지할 수 있습니다.
  • atoi()와 atof()는 문자열의 시작 부분부터 숫자로 변환하며, 변환할 수 없는 문자가 나오면 중단합니다.