#include <stdio.h>
void hello(); // 함수 선언 (함수 원형)
int main() {
hello(); // 아직 정의 안 됐지만 호출 가능
return 0;
}
void hello() {
printf("hi\n");
}
// void hello();는 함수 원형(prototype)이라고 불리며
// 컴파일러에게 "hello라는 함수가 있을 거니까 걱정하지 마" 하고 미리 알려주는 역할을 함
#include <stdio.h>
void main()
{
int iNum = 90; // 정수형 변수 iNum에 90이라는 값을 저장
// iNum 변수의 값을 출력 (%d는 정수를 출력하는 형식 지정자)
printf("iNum 값은: %d\n", iNum);
// iNum 변수의 메모리 주소를 출력 (&iNum은 iNum의 주소를 의미)
printf("iNum 주소는: %p\n", &iNum);
}
① 포인터란?
포인터는 다른 변수의 메모리 주소를 저장하는 특별한 변수
실제 데이터가 저장된 위치를 가르키는 "주소록" 역할
② & (주소 연산자, Ampersand)
변수명과 함께 사용하며 변수의 메모리 주소를 얻을 때 사용하는 연산자
변수가 참조하는 메모리 공간의 첫 byte 주소를 가져옴
변수 앞에 &를 붙이면, 그 변수가 메모리에서 차지하는 공간의 시작 주소를 반환
printf( ) 함수를 사용하여 출력할 경우, %p %x 포멧을 사용하여 메모리 주소값을 출력 가능
// 실행결과 예상
iNum 값은: 90
iNum 주소는: 0x7fff5fbff6ac (실제 주소는 실행할 때마다 다를 수 있음)
③ 메모리구조 (거대한 아파트 단지라 예시)
각 아파트 호수가 메모리 주소
각 아파트에 사는 사람이 저장된 값
iNum이라는 변수는 특정 아파트 호수(주소)에 90 이라는 값 저장
④ 형식 지정자
%d: 정수 값 출력할 때 사용
%p: 포인터(주소) 값을 16진수로 출력할 때 사용
※ 모든 선언된 변수명 앞에 &연사를 붙여 해당 변수가 참조하는메모리 공간의 첫번째 바이트를 식별 할 수 있는
// 예시
int num = 100;
printf("%d", num); // 100 출력 (변수의 값)
printf("%p", &num); // 0x0061FF22 출력 (주소를 값으로 사용)
int *ptr = # // 주소를 다른 변수에 저장
printf("%p", &ptr); // 0x0061FF22 출력이 됨
#include <stdio.h>
void main()
{
int iNum = 90; // 변수 선언 및 초기화
printf("iNum의 값: %d\n", iNum); // 90 출력
printf("iNum의 주소: %p\n", &iNum); // 메모리 주소 출력 (예: 0x7fff1234)
}
① int uNum = 90;
컴퓨터가 메모리에서 4바이트 공간을 찾음
그 공간에 90이라는 값을 저장
그 공간에 iNum이라는 이름을 붙임
②%iNum
iNum이 저장된 메모리 공간의 시작 주소를 반환
예) 1000번지라면 1000을 반환
주소는 16진수로 표현, 메모리 주소를 간결하게 표현하기 위해
※ 주소는 시행할 때마다 다를 수 있음
운영체제가 프로그램에게 메모리를 동적으로 할당하기 때문
※ 데이터 타입별 메모리 크기
int iNum = 90; // 4바이트 사용
char cChar = 'A'; // 1바이트 사용
double dNum = 3.14; // 8바이트 사용
printf("int 주소: %p\n", &iNum); // 4바이트 공간의 시작 주소
printf("char 주소: %p\n", &cChar); // 1바이트 공간의 시작 주소
printf("double 주소: %p\n", &dNum); // 8바이트 공간의 시작 주소
3. 주소연산자의 활용
#include <stdio.h>
// 값만 받는 함수 (원본 변경 불가)
void changeValue1(int num)
{
num = 100; // 복사본만 변경됨
}
// 주소를 받는 함수 (원본 변경 가능)
void changeValue2(int *pNum)
{
*pNum = 100; // 원본이 변경됨
}
void main()
{
int iNum = 90;
printf("원본 값: %d\n", iNum); // 90
changeValue1(iNum); // 값을 복사해서 전달
printf("함수1 후 값: %d\n", iNum); // 90 (변경되지 않음)
changeValue2(&iNum); // 주소를 전달
printf("함수2 후 값: %d\n", iNum); // 100 (변경됨)
}
4. 주소연산자 사용시 주의사항
① 형식 지정자
// 올바른 사용
printf("주소: %p\n", &iNum); // %p 사용
// 잘못된 사용
printf("주소: %d\n", &iNum); // %d는 정수용이므로 부적절
② 상수에서는 사용 불가
int iNum = 90;
printf("%p\n", &iNum); // 가능: 변수의 주소
printf("%p\n", &90); // 불가능: 상수는 메모리 위치가 없음
// 초기 상태(프로그램 시작)
int num = 0; // 변수 선언 및 초기화
┌───────────────────────────────────────────┐
│ 메모리 주소: 0x7fff1000 │
├───────────────────────────────────── │
│ 바이트 단위로 보면: │
│ [00000000][00000000][00000000][00000000] │
│ ↑ │
│ 4바이트 = 32비트 = 0 (십진수) │
│ │
│ 변수명: num │
│ 값: 0 │
│ 주소: 0x7fff1000 │
└───────────────────────────────────────────┘
// scanf() 함수 호출
scanf("%d", &num); // 사용자 입력 대기
scanf 함수가 &num을 통해 주소값 0x7fff1000을 받음
사용자가 "90" 입력 후 Enter
문자열 "90 읽기": 키보드에서 '9', '0' 문자 읽음
문자 숫자 변환: "90" 문자열을 90 정수로 변환
이진수 변환: 90(십진수) 01011010(이진수)
메모리 저장: 받은 주소 (0x7fff1000) 에 저장
변화 전:
┌───────────────────────────────────────────┐
│ 메모리 주소: 0x7fff1000 │
├───────────────────────────────────────────┤
│ [00000000][00000000][00000000][00000000] │
│ 값: 0 │
└───────────────────────────────────────────┘
변화 후:
┌───────────────────────────────────────────┐
│ 메모리 주소: 0x7fff1000 │
├───────────────────────────────────────────┤
│ [01011010][00000000][00000000][00000000] │
│ 값: 90 │
└───────────────────────────────────────────┘
③ 실제 메모리 변화
#include <stdio.h>
int main(void)
{
int num = 0;
// 입력 전 상태 확인
printf("=== 입력 전 ===\n");
printf("num의 값: %d\n", num);
printf("num의 주소: %p\n", &num);
// 메모리 내용을 바이트 단위로 확인
unsigned char *ptr = (unsigned char*)#
printf("메모리 내용 (바이트 단위): ");
for(int i = 0; i < 4; i++) {
printf("%02X ", ptr[i]);
}
printf("\n\n");
// 사용자 입력
printf("정수를 입력하세요: ");
scanf("%d", &num);
// 입력 후 상태 확인
printf("\n=== 입력 후 ===\n");
printf("num의 값: %d\n", num);
printf("num의 주소: %p (변하지 않음)\n", &num);
// 메모리 내용을 바이트 단위로 확인
printf("메모리 내용 (바이트 단위): ");
for(int i = 0; i < 4; i++) {
printf("%02X ", ptr[i]);
}
printf("\n");
return 0;
}
// 실행 결과 예시
=== 입력 전 ===
num의 값: 0
num의 주소: 0x7fff5fbff6ac
메모리 내용 (바이트 단위): 00 00 00 00
정수를 입력하세요: 90
=== 입력 후 ===
num의 값: 90
num의 주소: 0x7fff5fbff6ac (변하지 않음)
메모리 내용 (바이트 단위): 5A 00 00 00
// 주소는 변화지 않음
// 바이트 단위 덮어쓰기
④ scanf() 함수의 메모리 변경 과정
주소 수신: &num으로 받은 주소 0x7fff1000 확인
입력 파싱: "90" 문자열을 90 정수로 변환
이진 변환: 90 → 01011010 (이진수)
메모리 쓰기: 해당 주소의 4바이트에 새 값 저장
완료: 이전 값(0)은 완전히 사라지고 새 값(90)만 남음
변수의 주소는 절대 변하지 않음
변하는 것은 오직 그 주소에 저장된 값
새로운 값이 이전 값을 완전히 덮어 씀
이 모든 과정은 scanf 함수 내부에서 자동으로 처리
// 변화 전 초기상태
int num = 0; 선언 시
메모리 주소 0x7fff1000에 저장된 값:
00000000 00000000 00000000 00000000
↑ ↑
32비트 (4바이트) 모두 0 = 십진수 0
// 변화 후
scanf("%d", &num); 으로 90 입력 시
메모리 주소 0x7fff1000에 저장된 값:
00000000 00000000 00000000 01011010
↑ ↑
상위 24비트는 0 하위 8비트가 01011010 = 십진수 90
90을 이진수로 변환하는 과정:
90 ÷ 2 = 45 나머지 0 ← 나머지 0 // 이진수는 2를 기준으로 하는 수 체계이기 때문에 2로 나눔
45 ÷ 2 = 22 나머지 1 ← 나머지 1
22 ÷ 2 = 11 나머지 0 ← 나머지 0
11 ÷ 2 = 5 나머지 1 ← 나머지 1
5 ÷ 2 = 2 나머지 1 ← 나머지 1
2 ÷ 2 = 1 나머지 0 ← 나머지 0
1 ÷ 2 = 0 나머지 1 ← 나머지 1
나머지를 아래에서 위로 읽으면: 1011010
아래에서 위로 읽으면: 1011010
8비트로 맞추면: 01011010
32비트로 맞추면: 00000000 00000000 00000000 01011010
변화 전: 00000000 00000000 00000000 00000000
변화 후: 00000000 00000000 00000000 01011010
↑ ↑ ↑ ↑
변화없음 변화없음 변화없음 변화됨
주소: 0x7fff1000 0x7fff1001 0x7fff1002 0x7fff1003
변화 전: [00000000] [00000000] [00000000] [00000000]
변화 후: [01011010] [00000000] [00000000] [00000000]
↑ 여기만 ↑ 변화없음 ↑ 변화없음 ↑ 변화없음
변화됨
└ Little Endian 방식
낮은 자리수가 낮은 주소에 저장
90 = 01011010이 첫 번째 바이트에 저장
나머지 3 바이트는 모두 0
// 시각적 확인 코드
#include <stdio.h>
int main(void)
{
int num = 0;
printf("=== 초기 상태 ===\n");
printf("십진수: %d\n", num);
printf("이진수: ");
// 32비트를 8비트씩 나누어 출력
for (int i = 31; i >= 0; i--) {
printf("%d", (num >> i) & 1);
if (i % 8 == 0 && i != 0) printf(" ");
}
printf("\n\n");
printf("90을 입력하세요: ");
scanf("%d", &num);
printf("\n=== 변화 후 ===\n");
printf("십진수: %d\n", num);
printf("이진수: ");
// 32비트를 8비트씩 나누어 출력
for (int i = 31; i >= 0; i--) {
printf("%d", (num >> i) & 1);
if (i % 8 == 0 && i != 0) printf(" ");
}
printf("\n");
return 0;
}
// 실행 결과
=== 초기 상태 ===
십진수: 0
이진수: 00000000 00000000 00000000 00000000
90을 입력하세요: 90
=== 변화 후 ===
십진수: 90
이진수: 00000000 00000000 00000000 01011010