시작은 미약하였으나 , 그 끝은 창대하리라

제7강 포인터 본문

프로그래밍/C언어

제7강 포인터

애플파ol 2022. 2. 10. 09:03

목차:

*포인터의 개념

*변수의 주소

 * 포인터의 선언

 * 간접 참조 연산자

 * 포인터 연산

 * 포인터와 배열

 * 포인터와 함수

 

 

1. 포인터의 개념

   정의) 주소를 저장하는 변수 (데이터를 저장하는 변수 X)

 

   tip) 변수는 메모리에 저장되며, 메모리는 바이트 단위이고, 각각의 바이트 마다 주소가 부여가 됨.

         ex) int = 4byte , char = 1byte , float = 4byte 

 

2. 변수의 주소

   정의) 해당하는 변수의 주소를 계산하는 연산자 : &(앤퍼센트)

            - referencing연산자,대상의 주소를 얻어오는 연산자

                  ex)  변수 i의 주소 -> &i  

                        변수 i의 값 ->  i=10

#include <stdio.h>
int main(void)
{
    int i = 10;
    char c = 69;
    float f = 12.3;
    
    printf("i의 주소: %u\n", &i);              // &(앤퍼센트) 기호로 주소값 호출중
    printf("c의 주소: %u\n", &c);
    printf("f의 주소: %u\n", &f);
    return 0;
}


i의 주소: 1769731892                //시스템에 임의로 부여한 주소값임.
c의 주소: 1769731924
f의 주소: 1769731956

3. 포인터의 선언

     정의) 변수의 주소를 가지고(저장) 있는 변수

             syntax) int * p ; 

                   = 정수를(원하는 type)/ 가리키는(포인터 입니다)/ 포인터p(변수명)

     주의) (1) 실제 가르키는 변수의 type에 따라 알맞게 포인터의 type을 선언해야함

             (2) 포인터의 초기화는 꼭 하자 NULL 사용.

// 포인터와 변수의 연결

int i = 10;            // 정수형 변수 i 선언
int*p;                 // 포인터 변수 p 선언     
p=&i                   // 변수 i의 주소가 포인터p로 할당됨


//위와 동일함
int i = 10;            // 정수형 변수 i 선언
int*p=&i;              // 포인터 변수 p 선언과 동시에 변수i의 주소가 할당됨
<주의 해야할 점(1)>

char c = 'A'      		  // 문자형 변수 c 선언
flaot f = 36.5;	    	  // 실수형 변수 f 선언
double d = 3.141592;      // 실수형 변수 d 선언

char*pc = &c;		   	  // 문자형을 가리키는 포인터pc
float*pf = &f;            // 실수형을 가리키는 포인터pf
double *pd = &d;		  // 실수형을 가리키는 포인터pd


<주의 해야할 점(2)>
int i = 10;
int*pi=NULL;              // 포인터의 초기화는 필수!!
pi=&i;

print("%u,%u",pi,&i);

>>>1768820 1768820        // 동일한 주소값이 출력이 됨

 

4. 간접(역) 참조 연산자 *

    정의) 포인터가 가리키는 값을 가져오는 연산자

            -deferencing 연산자, referencing의 역과정으로 주소로부터 대상변수를 얻어오는 것

 

int i=10;         // i에 10을 할당함
int *p=&i;		  // 포인터p에 i의 주소를 할당함.
printf("%d",*p)

>>> 10       // 10 이 출력됨

 

#include <stdio.h>

int main(void)
{
	int x=3;
    int *ptr_x=&x
    print("주소=%5d\n",ptr_x);      // 주소 값 출력
    print("값= %5d\n",*ptr_x);	   // 주소가 지칭하는 값 출력
    return 0;
}

0x0061FF08
3

정리)  & 연산자

        * 연산자

  의미 읽는법
&연산자 변수의 주소를 반환 함 &x -> x의 주소
*연산자 포인터가 가리키는 곳의 내용을 반환 함 *x  -> x의 포인터

포인터 예제#1

#include <stdio.h>
int main(void)
{
    int i = 3000;
    int* p = NULL;

    p = &i;    //이렇게 해야 연결이 됨

    printf("i=%d\n", i);         // 변수의 i 의값 출력
    printf("&i= %u\n", &i);      // 변수 i 의 주소 출력
    printf("p=%u\n",p);          // 포인터의 값 출력
    printf("*p=%d\n", *p);       // 포인터를 통한 간접 참조 값 출력
    return 0;
}

>>>
i=3000
&i=1245024
p=1245025
*p=3000

포인터 예제#2

#include <stdio.h>
int main(void)
{
    int i = 10;
    int* p = NULL;

    p = &i;    //이렇게 해야 연결이 됨
    printf("i=%d\n", i);
    
    *p = 20;   //  포인터르 통하여 변수의 값을 변경한다, i=*p=20 과 동일한 의미
    printf("i=%d\n", i);
    return 0;
}

>>>
i=10
i=20

5. 포인터 연산

  - 가능한 연산: 증가, 감소, 덧셈, 뺄셈 연산

  - 증가 연산의 경우 증가되는 값은 포인터가 가리키는 객체의 크기

포인터 타입 ++연산후 증가되는 값
char 1
short 2
int 4
float 4
double 8

<증가연산 예제 (바이트만큼 커진다는것을 알 수 있다.)(감소도 동일함)>

#include <stdio.h>
int main(void)
{
    char* pc;
    int* pi;
    double* pd;

    pc = (char*)10000;
    pi = (int*)10000;
    pd = (double*)10000;
    printf("증가 전 pc=%d,pi=%d,pd=%d\n", pc, pi, pd);

    pc++;            //증가된 후에 저장이 되어서 증가된값들이 pc,pi,pd가 됨.
    pi++;
    pd++;
    printf("증가 후 pc=%d,pi=%d,pd=%d\n", pc, pi, pd );
    printf("pc+2=%d, pi+2=%d, pd+2=%d\n", pc + 2, pi + 2, pd + 2);  
    return 0;
}


>>>
증가 전 pc=10000,pi=10000,pd=10000
증가 후 pc=10001,pi=10004,pd=10008
pc+2=10003, pi+2=10012, pd+2=10024

<간접 참조 연산자와 증감 연산자>

● *p++  : 주소를 증가   

                -> p(주소)가 가리키는 위치에서 값을 가져온 후에 p(주소)를 증가함.

●(*p)++ : 값을 증가 

                -> p가 가리키는 위치의 값을 증가한다.

#include <stdio.h>
int main(void)
{
    int i = 10;
    int* pi = &i;
    printf("i=%d, pi=%p\n", i, pi);
    (*pi)++;                           // pi가 가리키는 위치의 값을 증가한다.
    printf("i=%d, pi=%p\n", i, pi);

    printf("i=%d, pi=%p\n", i, pi);
    *pi++;                            // pi가 가리키는 위치에서 값을 가져온 후에 pi를 증가한다.
    printf("i=%d, pi=%p\n", i, pi);
    
    return 0;
}


>>>
i=10, pi=00000015E119FB44
i=11, pi=00000015E119FB44             // i 의 값이 증가됨을 알 수 있다.
i=11, pi=00000015E119FB44
i=11, pi=00000015E119FB48             // 주소값이 4byte(int임으로)증가함을 알수있다.

<포인터의 형변환>

   syntax:    double*pd=&f;

                int *pi;          

                pi=(*int)pd;    

 

 

<인수 전달 방법>

->함수 호출 시에 인수 전달 방법

    (1) 값에 의한 호출(call by value)

         -> 함수로 값의 복사본이 전달됨

         -> 기본적인 방법

    (2) 참조에 의한 호출(call by reference)

         -> 함수로 주소가(원본이) 전달됨.

         -> C에서는 포인터를 이용하여 흉내 낼 수 있다.

 

     <swap함수 #1 값에 의한 호출>

#include <stdio.h>

void swap(int x, int y)
{
    int tmp;
    printf("x=%d y=%d\n", x, y);

    tmp = x;
    x = y;
    y = tmp;

    printf("x=%d y=%d\n", x, y);
}

int main(void)
{
    int a = 100, b=200;
    printf("a=%d b=%d\n", a, b);
    
    swap(a, b);
    
    printf("a=%d b=%d\n", a, b);
    
    return 0;
}


>>>
a=100 b=200
x=100 y=200
x=200 y=100             // 로컬 변수 이기 때문에 함수 내부에서만 유지됨.
a=100 b=200

    <swap함수 #2 참조에 의한 호출>

#include <stdio.h>

void swap(int *px, int *py)       //주소에 있는 값 전달
{
    int tmp;
    
    tmp = *px;
    *px = *py;
    *py = tmp;

}

int main(void)
{
    int a = 100, b=200;
    printf("a=%d b=%d\n", a, b);
    
    swap(&a, &b);
    
    printf("a=%d b=%d\n", a, b);
    
    return 0;
}

>>>
a=100 b=200
a=200 b=100

 

 

6. 포인터와 배열

    -> 포인터는 배열처럼 사용할 수 있다.

    -> 인덱스 표기법을 포인터에 사용할 수 있다.

// 포인터와 배열의 관계 예시
#include<stdio.h>

int main(void)
{
	int a[] = { 10,20,30,40,50 };    //각각의 배열이 4바이트씩 차지함.
	printf("&a[0]=%u\n", &a[0]);
	printf("&a[1]=%u\n", &a[1]);
	printf("&a[2]=%u\n", &a[2]);

	printf("a=%u\n", a);

	return 0;
}


>>> 
&a[0]=2503932216
&a[1]=2503932220    // 다음 int 공간에서 가장작은 값 나옴
&a[2]=2503932224    // 다음 int 공간에서 가장작은 값 나옴
a=2503932216        // a는 가장 작은 주소를 가리킨다
//포인터를 배열처럼 사용 예시

#include<stdio.h>

int main(void)
{
	int a[] = { 10,20,30,40,50 };    //각각의 배열이 4바이트씩 차지함.
	int* p;
	p = a;    // p에다가 a의 주소 가져옴
	printf("a[0]=%d a[1]=%d a[2]=%d \n", a[0],a[1],a[2]);   // line 10,11을 보고 배열은 결국
	printf("p[0]=%d p[1]=%d p[2]=%d \n", p[0],p[1],p[2]);   // 포인터로 구현 된다는것을 알수있다.

	p[0] = 60;       //포인터를 통해 배열원소를 변경할수 있다.
	p[1] = 70;
	p[2] = 80;

	printf("a[0]=%d a[1]=%d a[2]=%d \n", a[0], a[1], a[2]);
	printf("p[0]=%d p[1]=%d p[2]=%d \n", p[0], p[1], p[2]);
	

	return 0;
}


>>>
a[0]=10 a[1]=20 a[2]=30
p[0]=10 p[1]=20 p[2]=30
a[0]=60 a[1]=70 a[2]=80
p[0]=60 p[1]=70 p[2]=80

7. 포인터와 함수

//포인터와 함수의 관계
#include <stdio.h>

void sub(int b[], int n[]);

int main(void)
{
	int a[3] = { 1,2,3 };
	printf("%d%d%d\n", a[0], a[1], a[2]);
	sub(a, 3);
	printf("%d%d%d\n", a[0], a[1], a[2]);

	return 0;


}

void sub(int b[], int n)          // ( 배열을 받은 포인터, 개수)
{
	b[0] = 4;
	b[1] = 5;
	b[2] = 6;

}


>>>
123
456
// 다음 두가지 방법은 완전히 동일함


//방법1_ 배열 매개변수

void sub(int b[], int size[])   //(b[] 배열의 이름과 포인터는 근복적으로 같다.
{
	b[0] = 4;
	b[1] = 5;
	b[2] = 6;

}

//방법 2_ 포인터 매개변수

void sub(int* b, int size)
{
	b[0] = 4;                 //line18,19,20   배열 표기법을 사용하여 배열에 접근
	b[1] = 5;
	b[2] = 6;
}

'프로그래밍 > C언어' 카테고리의 다른 글

제8강 문자열  (0) 2022.02.10
제6강 배열  (0) 2022.01.07
Comments