## 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 (리스트 순회)
: 리스트 순회
-
'Programming' 카테고리의 다른 글
| [C] 함수 포인터 (개념간단정리) (0) | 2025.10.10 |
|---|---|
| [C] C언어 특성 정리 (2) - 포인터 (0) | 2025.10.08 |
| [C] C언어 특성 정리 (1) - 선언,정의,static,extern,enum,union,빌드과정 (0) | 2025.10.08 |