Programming

[C] C언어 특성 정리 (4) - 배열,가변인자,전처리명령어

Nobb 2025. 10. 9. 19:31

## C 프로그램의 메모리 구조

 

 

## C 변수 종류

  지역변수 정적 지역변수 전역변수 정적 전역변수
선언 위치 함수 내부 함수 내부 함수 바깥 함수 바깥
수명 함수 실행중 프로그램 전체 프로그램 전체 프로그램 전체
접근 범위 함수 내부만 함수 내부만 모든 파일 현재 파일만
메모리 위치 Stack Data > .data Data Data

 

> 정적 변수: static 키워드

> 전역 변수: extern 키워드 (외부에서 접근하려면) 

 

 

 

## C에서의 배열

  : 같은 타입의 데이터들을 메모리에서 연속적으로 저장하는 공간

 

- 선언:

int arr[5];

 

-특징:

    > 배열 이름이 주소 ([0]의 주소)   >> arr = &arr[0]     # 배열이름이 포인터처럼 행동하지만 진짜 포인터는 아님

    > 같은 타입의 데이터를 메모리에서 연속적으로 저장하는 공간

    > 포인터와 달리, 주소 고정 (주소 수정 불가)

    > 크기도 선언 시 고정되어있음

 

 - 2차배열:  1차원 배열이 행 단위로 이어진 구조

     > 얘도 사실은 1차원 덩어리

int a[2][3] = {
    {1,2,3},
    {4,5,6}
};

>> 메모리상 저장방식: [1][2][3][4][5][6]

 

 

 

## Call-By-Value  VS  Call-By-Reference  (값 전달 vs 주소 전달)

: 인자 전달 방식

    - 함수 호출 시, 값 복사해서 넘기기 VS 주소 넘기기(=>원본 건드리기 가능)

## Call-By-Value (값 복사 방식) ========
void change(int x){
    x = 99;
}

int main(){
    int a = 10;
    change(a);
    printf("%d\n", a);	# 10 (안 바뀜)
}
## Call-By-Reference ========
void change(int *p){
    *p = 99;
}

int main() {
    int a = 10;
    change(&a);
    printf("%d\n", a);	# 99
}

 

<배열>

 - 자동으로 <주소 전달>처럼 동작함

void fill(int arr[]) {
	arr[0] = 100;
}

int main(){
    int nums[3] = {1,2,3};
    fill(nums);
    printf("%d\n", nums[0]);  #100

 

 

 

## 가변인자

  : 매개변수 개수를 정해두지 않고 함수 호출 시 원하는 만큼 넘기는 기능

 

# 가변인자함수 ----

   : 인자의 개수/타입이 고정되지 않은 함수

     - ex)  printf() - 인자 개수 다를 수 있는 함수    >>가변 인자 함수 덕분(stdio.h > printf선언문에 가변인자O)

printf("hi");
printf("%d %d", 10, 20);
printf("%s %d", "레몬", 100);

#### printf()의 원형
int printf(const char *format, ...); // '...': 가변인자 받는다는 표식

    > 표준라이브러리(stdio.h + libc) 내부에 이미 구현되어있어 직접 include나 가변인자 다룰 필요 없음.

 

    - 제공 헤더파일: #include <stdarg.h>

    - 정의된 매크로 함수들:   (va_list는 함수 아니고 타입)

va_list 가변 인자 목록(주소)을 가리키는 포인터 변수 타입
va_start() va_list변수 초기화-> 가변인자목록 첫번째 인자 가리키도록 설정
va_arg() 하나씩 꺼내기 _ 현재 va_list가 가리키는 인수를 지정된 타입으로 가져오고,
포인터를 다음 인수로 이동시킴
va_end() 사용 종료 _ 사용된 va_list 변수 정리

 

#include <stdarg.h>

void printNums(int count, ....) {
    va_list args;
    va_start(args, count);
    
    for (int i = 0; i < count; i++){
        int n = va_arg(args, int);
        printf("%d", n);
    }
    va_end(args);
}

 

 

 

## 전처리 명령어

**전처리단계

  : 컴파일 전에 전처리기가  #으로 시작하는 명령어들 코드로 처리하는 과정

 

** 전처리 명령어 종류

종류 예시 설명
매크로 정의 #define PI 3.14 특정 이름을 값으로 치환
매크로 해제 #undef PI 정의된 매크로를 없앰
파일 포함 #include <stdio.h> 다른 파일(헤더) 불러옴
조건부 컴파일 #ifdef, #ifndef, #if,
#else, #endif
특정 조건에 따라 코드 일부를 포함하거나 제외
라인 제어 #line 100 "file.c" 컴파일러가 인식하는 줄 번호/파일명 변경
오류 출력 #error "message" 컴파일 중단시키며 메세지 표시

 

** 예시)

>>>> 전처리 단계 전 ===========
#include <stdio.h>  //표준 입출력 라이브러리 함수
#define PI 3.14  //매크로 정의
#define AREA(r) ((r)*(r)*PI)  //매크로 함수

int main(){
    double r = 5;
    printf("원 넓이: %.2f\n", AREA(r)); ##
    return 0;
}

>>>> 전처리 단계 후 ===========
printf("원 넓이: %.2f", ((5)*(5)*3.14));

 

 

 

## typedef

   : 기존 복잡한 자료형에 새로운 이름을 붙이는 기능 

    - 가독성 목적

    - 컴파일 단계에서 처리

    - 특히 포인터, 함수 포인터, 구조체 쓸 때 거의 필수처럼 쓰임

 

** 기본문법

typedef 기본자료형 새이름;
====
typedef unsigned long ulong;

 

** ex)

## 기본 예시 ========
typedef unsigned long ulong;

ulong value = 123456789;


## 구조체 예시 ========
>>>> 원래 ================================
struct Student{
	char name[20];
    int age;
};
struct Student s1;

>>>> typedef ================================
typedef struct Student{
	char name[20];
    int age;
} Student; ##

Student s1;


## 배열 예시 ========
typdef int IntArray_10[10];

int main(){
	IntArray_10 arr = {1,2,3,4,5,6,7,8,9,10};
}


## 함수 포인터 예시 ========
((((공사중))))

 

 

 

## list iteration  (리스트 순회)

  : 리스트 순회

  -