[고급 C++]포인터 4편(다중 포인터/함수 포인터/void형 포인터)

 

 

 

 

 

 

[고급 C++]포인터 1편(프로세스/포인터변수/포인터연산/NULL포인터)

프로세스 프로세스 정의 메모리에서 실행중인 프로그램 특징 - xx번지라고 하는 주소 개념을 가짐 - 메모리 주소 공간은 스택 세그먼트 / 힙세그먼트 / 데이터 / 코드 세그먼트로 구분 - 제한된 공

mk28.tistory.com

 

 

[고급 C++]포인터 2편(배열과 포인터)

배열과 포인터 1차원 배열과 포인터  배열 특성 - 배열의 이름은 배열의 시작주소(num = &num[0] =배열의 시작주소) - 연속적인 메모리 할당 보장  1  #include  2  int main()  3  {  4 int num[5] = {1..

mk28.tistory.com

 

 

[고급 C++]포인터 3편(배열 포인터/포인터 배열/문자열 상수 포인터)

[고급 C++]포인터 1편(프로세스/포인터변수/포인터연산/NULL포인터) 프로세스 프로세스 정의 메모리에서 실행중인 프로그램 특징 - xx번지라고 하는 주소 개념을 가짐 - 메모리 주소 공간은 스택 세

mk28.tistory.com

 

다중포인터

특성

- 포인터 변수의 시작주소를 다른 포인터변수의 데이터로 이용

- 포인터 변수가 변수의 시작주소를 저장하는데 반해 이중 포인터 변수는 포인터 변수의 시작주소를 저장

 

선언

자료형  **변수명;

 

#include <stdio.h>

int main()
{
	int num, *ip, **mip;
	printf("%d %d %d \n", sizeof(num), sizeof(ip), sizeof(mip));

	ip = &num;
	mip = &ip;
    
	**mip = 500;

	printf("%d %d %d \n", num, *ip, **mip);
	return 0;
 }

4 4 4
500 500 500

※  ** 단항 연산자 우선순위 : 우→좌

※ **mip=500  ==  *(*(mip))=500

 

 

활용 - 다중포인터를 통한 문자열 출력

#include <stdio.h>
int main()
{

	int num, *ip, **mip;
	char *ptr[] = {"kingdom", "Advanced C program", "C++ prog", "C# program", "one two three", "seoul 서울시 강남구 역삼동 100번지",
"busan 부산시 해운대구 해운대동 200번지", NULL};  // 다중포인트 마지막에 NULL하면 크기 카운트 안해됨

	printf("%d %d %d \n", sizeof(num), sizeof(ip), sizeof(mip));
	
    ip = &num;
	mip = &ip;
	**mip = 500;

	printf("%d %d %d \n", num, *ip, **mip);

	funcA(ptr);
	
    return 0;
 }

// ptr에 저장된 문자열 출력
funcA(char **tmp)
{
	while(*tmp)
	{
		printf("%s \n", *tmp);
		tmp++;
	}
}

4 4 4
500 500 500
kingdom
Advanced C program
C++ prog
C# program
one two three
seoul 서울시 강남구 역삼동 100번지
busan 부산시 해운대구 해운대동 200번지

 

 

 

함수포인터

특성

- 포인터 변수가 함수의 시작주소를 저장하여 포인터를 참조하여 함수를 호출할 수 있음

- 콜백함수에서 사용

 

 

선언

자료형 (*변수명)(매개변수 리스트);

 

- int (*funcP)(char*);

 

     1  #include <stdio.h>
     2
     3  void myFunc(char* tmp);
     4
     5  int main()
     6  {
     7     // 함수명으로 호출
     8     // myFunc는 코드 세그먼트에 있음
     9     // myFunc("this is a test.");
    10
    11     // 함수포인터 변수 선언
    12     // 컴파일러에게 알려
    13     // 선언 : just memory 할당. 인자 변수명 필요 없음(함수 실행시 필요)
    14     // STACK에 있음
    15     // 함수포인터로 부르려면 원형(return value)알고있어야해
    16     void (*funcP)(char*);
    17
    18     printf("funcP size :%d\n", sizeof(funcP));
    19     funcP = myFunc; // 함수주소 할당(함수 시작주소 저장)
    20
    21     (*funcP)("Advanced C.");   // 함수 호출
    22     funcP("Multi Campus.");    // 함수 주소로 불러도 되니까 이렇게 동일
    23
    24     return 0;
    25  }

    28  void myFunc(char* tmp)

    29  {

    30     printf("myFunc : %p, %s \n", tmp, tmp);

    32  }

funcP size :4
myFunc : 04000840, Advanced C.
myFunc : 04000850, Multi Campus.

 

 

활용 - 함수포인터를 이용하여 +-*/ 계산만들기

- add, sub, mul, div 는 코드세그먼트에 저장

- ptrArr는 Stack 영역에 저장

#include <stdio.h>

int add(int x, int y);
int sub(int x, int y);
int mul(int x, int y);
int div(int x, int y);

int main(void)
{

	// 함수포인터 배열
	int (*ptrArr[4])(int x, int y)={ add, sub, mul, div };
	int menu_no, num1, num2, result;
	char op[4] = { '+', '-', '*', '/' };

	while(1)
	{
		printf("\n1. add\n");
		printf("2. subtract\n");
		printf("3. multiply\n");
		printf("4. divide\n");
		printf("5. end\n");

		printf("\nSelect(1-5) --> ");
		scanf("%d",&menu_no);

		if(menu_no==5)
		break;

		printf("Input the two numbers --> ");
		scanf("%d %d",&num1, &num2);

		result = (*ptrArr[menu_no-1])(num1, num2);

		printf(" %d %c %d = %d \n", num1, op[menu_no-1], num2, result);
	}

	return 0;
}


int add(int x, int y)
{
	return x+y;
}

int sub(int x, int y)
{
	return x-y;
}

int mul(int x, int y)
{
	return x*y;
}

int div(int x, int y)
{
	if(y==0)
	{
		printf("can not divide by 0\n");
		return -1;
	}

	return x/y;
}

 

 

※ 포인터 형태 참고

- int (*a1)[3];  배열포인터 변수(4Byte)

- int *a2[3];     포인터배열 변수(12Byte)

- int (*a3)(int); 함수포인터 변수 (4Byte)

 

 

함수 포인터와 typedef

함수포인터 자료형을 자주 사용하면 매번 선언해야하는 번거로우므로 typedef로 함수 포인터의 별칭을 정의

 

    1  #include <stdio.h>

     2

     3  int add(int x, int y)

     4  {

     5     return x+y;

     6  }

     7

     8  int sub(int x, int y)

     9  {

    10     return x-y;

    11  }

    12

    13  // 자료형 재정의

    14  // 함수포인터 자료형 정의

    15  typedef int (*FP)(int, int);

    16  // 함수포인터를 typedef로 선언하면 함수포인터 변수 선언문이아닌,

    17  // 함수포인터 자료형(별명)이 된다.

    18

    19  // void funCalc(int (*f4)(int, int))

    20  void funCalc(FP f4)

    21  {

    22     printf("funcCalc() : %d \n", (*f4)(300, 30));

    23  }

    24

    25  int main()

    26  {

    27     printf("함수포인터와 typedef문 \n");

    28

    29     int result;

    30

    31     // 1. 함수포인터 변수 선언

    32     int (*f1)(int, int);

    33     f1 = add;

    34     result = (*f1)(100, 30);

    35

    36     printf("f1 add : %d \n", result);

    37

    38     // 2. FP를 사용하여 함수포인터 변수 선언

    39     FP f2;

    40     f2 = sub;

    41     result = (*f2)(100, 30);

    42

    43     printf("f2 sub : %d \n", result);

    44

    45     // 3. FP를 사용하여 함수포인터 배열 사용

    46     FP f3[5];

    47     f3[0] = add;

    48     f3[1] = sub;

    49

    50     printf("add() : %d\n", (*f3[0])(200,30));

    51     printf("sub() : %d\n", (*f3[1])(200,30));

    52

    53     // 4. 함수 호출 시 함수주소 전달

    54     funCalc(sub);

    55     return 0;

    56

    57  }

함수포인터와 typedef문
f1 add : 130
f2 sub : 70
add() : 230
sub() : 170
funcCalc() : 270

 

 

포인터 형변환

캐스트 연산자를 통해 포인터 자료형의 타입 형 변환 가능

 

#include <stdio.h>
int main()
{
	char ch='A';
	int num=10;
	double dnum=3.5;
	char *ptr=&ch;

	printf("&ch: %p, ptr: %p \n", &ch, ptr);
	printf("sizeof(ch): %d, sizeof(ptr): %d \n", sizeof(ch), sizeof(ptr));
	printf("sizeof(&ch): %d, sizeof(*ptr): %d \n", sizeof(&ch), sizeof(*ptr));

	printf("\nsizeof(ptr): %d \n", sizeof(ptr) );
	printf("sizeof((int *)ptr): %d \n", sizeof((int *)ptr) );
	printf("sizeof((double *)ptr): %d \n", sizeof((double *)ptr));

	printf("\nsizeof(*ptr): %d \n", sizeof(*ptr) );
	printf("sizeof(*(int *)ptr): %d \n", sizeof(*(int *)ptr) );
	printf("sizeof(*(double *)ptr): %d \n", sizeof(*(double *)ptr) );

	return 0 ;
}

&ch: 7ffff0f0, ptr: 7ffff0f0

sizeof(ch): 1, sizeof(ptr): 4 (포인터=주소)

sizeof(&ch): 4(주소), sizeof(*ptr): 1 (char)

 

(주소는 4!)

sizeof(ptr): 4

sizeof((int *)ptr): 4

sizeof((double *)ptr): 4

 

sizeof(*ptr): 1

sizeof(*(int *)ptr): 4                 // 포인터 형변환

sizeof(*(double *)ptr): 8        // 포인터 형변환

 

 

void형 포인터

특성

- 어느 것이든 가리킬 수 있는 포인터

- void형 포인터는 참조할 대상체가 정해져있지 않은 포인터

- 실행중에 다양한 타입의 주소를 받을때 사용

 

선언 형식

 void * 변수명;

 

참조형식

*(형*)변수명;

 

 

예시

#include <stdio.h>
int main()
{
	char ch = 'A';
	int num = 500;
	double dnum = 1.3;

	void *ptr; // void형 포인터

	printf("ptr sizeof : %d \n", sizeof(ptr)); // 주소니까 4

	ptr = &ch;  // O ch의 주소 저장
	// printf("%c \n", *ptr); // compile err
	// 주소는 아는데, 몇바이트 참조할지몰라

	printf("%c \n", *(char*)ptr); // O 주소 알고, 1바이트인거 알고!
	// 다시 void형되었고

	ptr = &num;
	printf("%d \n", *(int*)ptr);

	ptr = &dnum;
	printf("%lf \b", *(double*)ptr);

	return 0;
}

ptr sizeof : 4
A
500
1.300000

 

 

활용 - 오버로딩이 가능한  swap 함수

  3  int main()

     4  {

     5     short int n1 = 100, n2 = 150;

     6     long int x = 300, y = 350;

     7     double d1 = 1.3, d2 = 5.6;

     8     char names[2][20] = {"kim", "lee ??"};

     9

    10     swap(&n1, &n2);

    11

    12     printf("n1 : %hd, n2: %hd \n", n1, n2);

    13

    14     return 0;

    15  }

    16

    17  swap(short int *sour, short int *dest)

    18  {

    19     short int tmp;

    20

    21     tmp = *sour;

    22     *sour = *dest;

    23     *dest = tmp;

    24  }

- 이렇게 하면 다양한 자료형을 매개변수로 swap함수를 호출할 수 없음, 지정된  타입만 가능하지 이건아니야!

 

#include <stdio.h>
void swap(void *sour, void* dest, int size);

int main()
{
	short int n1 = 100, n2 = 150;
	long int x = 300, y = 350;
	double d1 = 1.3, d2 = 5.6;
	char names[2][20] = {"kim", "lee ??"};
    
	// 타입이 지정되어있음
	// swap(&n1, &n2);
	// swap(&x, &y);

	swap(&n1, &n2, sizeof(n1));
	swap(&x, &y, sizeof(x));
	swap(&d1, &d2, sizeof(double));
	swap(names[0], names[1], sizeof(names[0]));

	printf("n1 : %hd, n2: %hd \n", n1, n2);
	printf("x : %d, y : %d \n", x, y);
	printf("d1 : %lf, d2 : %lf \n", d1, d2);
	printf("names[0] : %s, names[1] : %s\n", names[0], names[1]);

	return 0;
}

void swap(void *sour, void* dest, int size)
{

	// 1Byte씩
	char tmp;
	int i;
	for(i=0;i<size;i++)
	{
		tmp = *((char*)sour+i);
		*((char*)sour+i) = *((char*)dest+i);

		*((char*)dest+i) = tmp;
	}
}

 

n1 : 150, n2: 100
x : 350, y : 300
d1 : 5.600000, d2 : 1.300000

names[0] : lee ??, names[1] : kim

 

 

 


 

 

 

 

 

궁금한 사항은 댓글로 남겨주세요💃💨💫
좋아요와 구독(로그인X)은 힘이 됩니다 🙈🙉

 

반응형
그리드형

댓글

❤️김세인트가 사랑으로 키웁니다❤️