수업 목표

  • 주소 연산자와 역참조 연산자에 대해 배워본다.
  • 참조와 역참조에 대해 배워본다.
  • Swap() 함수를 배워본다.

지난 시간에 메모리 주소를 저장하는 방법에 대해 배웠습니다.

그럼 메모리 주소는 어떻게 얻을까요?

 

주소 연산자(address-of operator) &

피연산자의 메모리 주소를 반환하는 연산자. 기호 &(Ampersand)를 사용합니다.

 

사실 scanf() 함수에서 사용 했었던 주소 연산자

~에”라고 해석하자고 배웠었습니다. 사실은 변수 앞에 &를 붙혀서 그 변수의 메모리 주소를 얻은 것입니다. 해당 메모리 주소에 입력 받은 값을 저장할 수 있게된 것입니다.

 

메모리 주소를 얻을 수 있는 두 가지 방법

1. 주소 연산자

2. 배열의 이름

 

메모리 주소는 어떻게 얻는지 배웠습니다.

해당 메모리 주소에 저장 되어 있는 값을 알고 싶다면 어떻게 해야할까요?

 

 

역참조 연산자(indirection operator) *

피연산자로 포인터를 받아서, 해당 메모리 주소에 저장된 값을 읽거나 값을 수정할 때 사용하는 연산자.

 

 

[좋은습관] “메모리 그리기”

포인터 관련 예제를 풀 때는 “메모리 그리기”를 해봅시다. 사각형을 그린 다음, 변수들을 적고 각 변수에 메모리 주소를 0x100번지부터 적어줍니다. 그 상태로 한 줄씩 소스코드를 분석해봅시다. “천천히 읽기” + “메모리 그리기”

 

Ex070201) 주소 연산자와 역참조 연산자 1 [중요 샘플 코드]

아래 소스코드를 따라서 작성해봅시다.

따라 적은 코드의 출력 결과를 예측해보고, 예측 결과와 실행 결과를 비교해봅시다.

 

// Main.c

#include <stdio.h>

int main(void)
{
	int X = 10;
	int* PtrToX = &X;

	printf("%d\n", *PtrToX);

	*PtrToX = 100;

	printf("%d\n", *PtrToX);

	return 0;
}

 

<예측 결과>

10
100

 

<실행 결과>

10
100

 

Ex070202) 주소 연산자와 역참조 연산자 2

아래 소스코드를 따라서 작성해봅시다. 따라 적은 코드의 출력 결과를 예측해보고, 예측 결과와 실행 결과를 비교해봅시다.

// Main.c

#include <stdio.h>

int main(void)
{
	int X = 10;
	int* PtrToX = &X;

	printf("%d\n", *PtrToX);

	*PtrToX = *PtrToX * 2;

	printf("%d\n", *PtrToX);

	return 0;
}

 

<예측 결과>

20

 

Ex070203) 주소 연산자와 역참조 연산자 3

아래 소스코드를 따라서 작성해봅시다.

따라 적은 코드의 출력 결과를 예측해보고, 예측 결과와 실행 결과를 비교해봅시다.

// Main.c

#include <stdio.h>

int main(void)
{
	int X = 10, Y = 20;
	int* PtrToX = &X;

	printf("%d\n", *PtrToX);

	*PtrToX = *PtrToX * 2;
	PtrToX = &Y;

	printf("%d\n", *PtrToX);

	return 0;
}

 

Ex070204) 주소 연산자와 역참조 연산자 4

아래 소스코드를 따라서 작성해봅시다.

따라 적은 코드의 출력 결과를 예측해보고, 예측 결과와 실행 결과를 비교해봅시다.

[여기]에서 연산자 우선순위와 결합법칙 표를 볼 수 있습니다.

 

// Main.c

#include <stdio.h>

int main(void)
{
	int X = 10;
	int* PtrToX = &X;

	printf("%d\n", X);
	printf("%d\n", (*PtrToX)++);
	printf("%d\n", X);
	printf("%d\n", *PtrToX++); 
		// 문제 속의 문제. 계산될 연산자의 순서를 맞추시오.

	return 0;
}

 

포인터 Vs. 역참조 연산자 Vs. 곱셈 연산자

셋은 모두 *(Asterisk) 기호를 사용합니다.

포인터: 자료형 오른쪽에 붙습니다.

역참조 연산자: 피연산자가 한 개. 특히 피연산자로 메모리 주소를 받습니다.

곱셈 연산자: 피연산자가 두 개.

 

Ex070205) 주소 출력

메모리 주소를 출력할 때 %X로 출력하는 것은 올바르지 않습니다.

형식 지정자 %p로 메모리 주소를 출력하는 게 올바르나, void* 자료형으로 형변환이 필요합니다.

아래 소스코드를 따라서 작성 후 실행 해봅시다.

 

// Main.c

#include <stdio.h>

int main(void)
{
	int Num = 100;
	int* PointerToNum = &Num;

	printf("Num:               %d\n", Num);
	printf("&Num:              %X\n", &Num);
	printf("&Num:              %p\n", (void*)&Num);
	printf("PointerToNum:      %X\n", PointerToNum);
	printf("PointerToNum:      %p\n", (void*)PointerToNum);
	printf("*PointerToNum:     %d\n", *PointerToNum);
	printf("*PointerToNum:     %d\n", *(&Num)); // 올바르진 않지만, 소거하는 식으로라도 이해해 보자.
	printf("(*PointerToNum)*2: %d\n", (*PointerToNum) * 2);

	return 0;
}

 

<?> (void*)의 의미를 모르겠다.

 

포인터의 단점

큰 데이터들의 시작 메모리 주소만으로 가볍게 공유할 수 있다는 점은 좋습니다.

다만, 공유 받은 사람이 착한 사람인지는 모릅니다.

해당 주소로 가서 들어있는 값을 마음대로 수정 할수도 있습니다.

아주 강력한 기능임과 동시에 그만큼 잘못쓰면 큰일 날 수도 있습니다.

 

Ex070206) 다양한 자료형과 포인터

아래 소스코드를 따라서 작성해봅시다.

따라 적은 코드의 출력 결과를 예측해보고, 예측 결과와 실행 결과를 비교해봅시다.

// Main.c

#include <stdio.h>

int main(void)
{
	char Character = 'C';
	char* PtrToChar = &Character;
	short Num1 = 10;
	short* PtrToShort = &Num1;
	int Num2 = 11;
	int* PtrToInt = &Num2;
	float Num3 = 3.14f;
	float* PtrToFloat = &Num3;
	double Num4 = 3.141592;
	double* PtrToDouble = &Num4;

	printf("%p: %c(%d)\n", (void*)PtrToChar, Character, Character);
	printf("%p: %d\n", (void*)PtrToShort, Num1);
	printf("%p: %d\n", (void*)PtrToInt, Num2);
	printf("%p: %f\n", (void*)PtrToFloat, Num3);
	printf("%p: %f\n", (void*)PtrToDouble, Num4);

	return 0;
}

 

Ex070207) char 자료형과 포인터

아래 소스코드를 따라서 작성해봅시다.

따라 적은 코드의 출력 결과를 예측해보고, 예측 결과와 실행 결과를 비교해봅시다.

// Main.c

#include <stdio.h>

int main(void)
{
	char Char1 = 'L';
	char Char2 = 'O';
	char* PtrToChar = &Char1;

	printf("%p: %c\n", (void*)PtrToChar, *PtrToChar);

	PtrToChar = &Char2;
	printf("%p: %c\n", (void*)PtrToChar, *PtrToChar);

	PtrToChar = &Char1;
	printf("%p: %c\n", (void*)PtrToChar, *PtrToChar);

	return 0;
}

 

Ex070208) 뒤섞기 1

아래 소스코드를 따라서 작성해봅시다.

따라 적은 코드의 출력 결과를 예측해보고, 예측 결과와 실행 결과를 비교해봅시다.

// Main.c

#include <stdio.h>

int main(void)
{
	int Num1 = 10;
	int Num2 = 20;
	int Num3 = 30;

	int* Ptr1 = &Num1;
	int* Ptr2 = &Num2;
	int* Ptr3 = &Num3;

	Ptr3 = Ptr2;
	Ptr2 = Ptr1;
	Ptr1 = Ptr2;

	/* Q. num1을 가리키는 포인터는? */
	printf("%p: %d\n", (void*)Ptr1, *Ptr1);
	printf("%p: %d\n", (void*)Ptr2, *Ptr2);
	printf("%p: %d\n", (void*)Ptr3, *Ptr3);

	return 0;
}

 

 

Ex070209) 뒤섞기 2

아래 소스코드를 따라서 작성해봅시다.

따라 적은 코드의 출력 결과를 예측해보고, 예측 결과와 실행 결과를 비교해봅시다.

// Main.c

#include <stdio.h>

int main(void)
{
    int Num1 = 15;
    int Num2 = 30;
    int Num3 = 45;

    int* Ptr1 = &Num1;
    int* Ptr2 = &Num2;
    int* Ptr3 = &Num3;

    Ptr1 = Ptr2;
    Ptr2 = Ptr3;

    *Ptr3 *= 2;
    *Ptr1 += *Ptr3;
    *Ptr2 *= 2;

    /* Q. 출력 결과는? */
    printf("%d %d %d", Num1, Num2, Num3);

    return 0;
}

90

120

180

 

 

참조에 의한 호출 Vs. 값에 의한 호출

참조에 의한 호출 Vs. 값에 의한 호출

원본값이 바뀌냐 Vs. 안 바뀌냐.

함수 A가 함수 B를 호출 할 때, 인자를 전달하면서 호출한다고 가정해봅시다.

함수 B가 종료될 때 인자의 원본값도 바뀐다면 참조에 의한 호출입니다.

인자의 원본값이 바뀔 수 없다면 값에 의한 호출이라고 부릅니다.

'C언어 공부 > C언어 강의' 카테고리의 다른 글

챕터 7-1 : 포인터  (0) 2026.03.06
챕터 6-5 : 변수의 종류  (0) 2026.03.06
챕터 6-4 : 전방 선언  (0) 2026.03.06
챕터 6-3 : 스코프  (0) 2026.03.06
챕터 6-2 : [심화] 스택 프레임  (0) 2026.03.06

+ Recent posts