[c] - 42서울을 위한 C공부 - 식빵 포인터 !

devicii·2021년 8월 11일
1

c

목록 보기
1/6
post-thumbnail

🎃 What is Pointer ?

많은 입문자를 좌절시킨 그 이름 포인터.
아직도 아리쏭 하지만 C의 최고의 무기는 포인터라고 했다.
우리 함께 라피신 통과를 위해 공부해보자.

포인터는 아주 쉽게 생각해 주소를 저장하는 변수라고 생각하자!

1. 포인터 기초

- 포인터 선언 방법
 포인터는 이렇게 자료형 뒤에 *를 붙이는 것으로 사용할 수 있다!
 int* p;
 
 *의 용도는 크게 두 개로 나뉜다.
 1.포인터를 위와 같이 선언할 때.
 2.해당 주소의 값에 접근할 때 사용.

&의 용도는 한 가지이다.
1. 원하는 변수의 주소를 나타내고 싶을 떄.

 int main(){
     int a = 5;
     int* pa;

     pa = &a;


     printf("주소값을 확인하려면 그냥 변수값을 쓰자. %x \n", pa);
     printf("주소의 값을 접근하려면 이렇게 사용하자. %d \n", *pa);
     return 0; 
 };
 
 //출력
 주소값을 확인하려면 그냥 변수값을 쓰자. x234e0
 주소의 값을 접근하려면 이렇게 사용하자. 5
 
 위와 같이 pa는 a의 주소값을 할당받고,
 *pa는 a의 값이 출력되게 된다.
 

2. 포인터 응용

int minus(int num1, int num2) {
	return num2-num1;
};

여기서 포인터를 활용하는 이유는 그냥 값을 전달해준다면 컴퓨터는 인식하지 못한다.
따라서 a와 b의 주소를 주고 a와 b의 값을 서로 바꿔주면 된다.
+ swap함수 단계에선 값이 바뀌지만, main함수로 돌아가면 다시 똑같은 값이다.

//2.넘어온 a와 b의 주소값의 값을 받아주고 리턴한다.
int swap(int* num1, int* num2){
	int temp;
    temp = *num1;
    *num1 = *num2;
    *num2 = temp;
    
    return 0;
};

int main() {
	int a = 5;
    int b = 10;
    int* pa;
    int* pa2;
    
    //a의 주소값을 pa에 할당
    pa = &a;
    //b의 주소값을 pa2에 할당
    pa2 = &b;
    
    printf("포인터끼리의 연산 : b - a : %d \n ", *pa - *pa);
    
    printf(" add함수 사용 : %d \n , add(*pa, *pa2));
    
    //swap함수 사용
    //1.a와 b의 값을 넘겨주는 것이 아닌 주소를 넘겨준다.
   swap(&a, &b);
   printf("swap함수 사용 : a = %d , b = %d \n", a , b);
   
   return 0;
};

swap함수 개념

💯보충!

3. 포인터로 연산하기

#include <stdio.h>

int main(){

    int a;
    int* pa;
    pa = &a;

    char b;
    double c;
    
    char* pc = &b;
    double* pb = &c; 
    
    printf("pa의 값 : %p \n", pa);
    printf(" (pa + 1)의 값  : %p \n", pa + 1);
    printf("pc의 값 : %p \n", pc);
    printf(" (pc + 1)의 값  : %p \n", pc + 1);
    printf("pb의 값 : %p \n", pb);
    printf("(pc + 1)의 값  : %p \n", pb + 1);


    printf("pa의 값 : %p \n", pa);
    printf(" (pa - 1)의 값  : %p \n", pa - 1);
    printf("pc의 값 : %p \n", pc);
    printf(" (pc - 1)의 값  : %p \n", pc - 1);
    printf("pb의 값 : %p \n", pb);
    printf("(pc - 1)의 값  : %p \n", pb - 1);

    return 0;
}


// 출력

// pa의 값 : 000000000061FE04 
//  (pa + 1)의 값  : 000000000061FE08
// pc의 값 : 000000000061FE03
//  (pc + 1)의 값  : 000000000061FE04
// pb의 값 : 000000000061FDF8
// (pc + 1)의 값  : 000000000061FE00
// pa의 값 : 000000000061FE04
//  (pa - 1)의 값  : 000000000061FE00
// pc의 값 : 000000000061FE03
//  (pc - 1)의 값  : 000000000061FE02
// pb의 값 : 000000000061FDF8
// (pc - 1)의 값  : 000000000061FDF0
...

이렇게 결과를 보면 자료형 크기만큼 더해진다.
pa의 경우는 16진수를 기준으로 4씩 커지고, pb는 char이 1byye니 1씩, double은 8씩
커짐을 알 수 있다.

반대로 빼는 연산을 해도 동일하다.

4. 포인터 with 배열

// #include <stdio.h>

// int main(){

//     int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9 ,10};

//     for(int i = 0; i < 10; i++){
//         printf("%d번째의 주소값은 : %p입니다. \n", i, &arr[i]);
//     }
//     return 0;
// }

//출력 
// 0번째의 주소값은 : 000000000061FDF0입니다. 
// 1번째의 주소값은 : 000000000061FDF4입니다.
// 2번째의 주소값은 : 000000000061FDF8입니다.
// 3번째의 주소값은 : 000000000061FDFC입니다.
// 4번째의 주소값은 : 000000000061FE00입니다. 
// 5번째의 주소값은 : 000000000061FE04입니다.
// 6번째의 주소값은 : 000000000061FE08입니다.
// 7번째의 주소값은 : 000000000061FE0C입니다.
// 8번째의 주소값은 : 000000000061FE10입니다.
// 9번째의 주소값은 : 000000000061FE14입니다.

위 3번에서 공부한 대로 우리는 해당 반복문의 결과를 어느 정도 유추할 수 있을 것이다.
p+1는 p의 주소값에 p + 4를 의미하고 , p+3은 p + (3x4)를 의미한다는 것을 알 수 있다.



#include <stdio.h>

int main(){

    int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9 ,10};
    int* parr;
    int i;
    parr = &arr[0];

    for (int i = 0; i < 10; i++)
    {
       printf("arr[%d]의 주소 : %p \n", i, &arr[i]);
       printf("(parr + %d)의 값 : %p  \n", i, (parr + i));

    if(&arr[i] == (parr +i)){
        printf(" --> 일치 \n");
    }else{
        printf(" --> 불일치 \n");
    }
    }
    
   
    return 0;
}


//출력 

// arr[0]의 주소 : 000000000061FDE0 
// (parr + 0)의 값 : 000000000061FDE0
//  --> 일치
// arr[1]의 주소 : 000000000061FDE4
// (parr + 1)의 값 : 000000000061FDE4
//  --> 일치
// arr[2]의 주소 : 000000000061FDE8 
// (parr + 2)의 값 : 000000000061FDE8
//  --> 일치
//  ...

parr+1 parr+2 ...가 될 때마다 다음 인덱스의 값을 의미하기 때문에,
&arr[1]이나 parr+1은 동일하다.

예를 들어
arr[1]랑 *(parr+1)를 하게 된다면 요소의 값은 의미하기 때문에
아래와 같은 출력이 나온다.
+ 추가 - 배열에서 배열의 이름은 배열의 첫 번째 인덱스를 나타낸다.

// arr[0]의 주소 : 1 
// (parr + 0)의 값 : 1  
//  --> 일치
// arr[1]의 주소 : 2
// (parr + 1)의 값 : 2
//  --> 일치
// arr[2]의 주소 : 3
// (parr + 2)의 값 : 3
//  --> 일치
// arr[3]의 주소 : 4

5. 🙄포인터의 포인터 이중 포인터.

// #include <stdio.h>

#include <stdio.h>

int main(){
    int a;
    int *pa;
    int **ppa;

    pa = &a;
    ppa = &pa;

    a = 3;  

    printf(" a : %d // *pa : %d // **ppa : %d \n", a , *pa, **ppa);
    printf(" a : %p // pa : %p // *ppa : %p \n", &a, pa, *ppa);
    printf(" a : %p // ppa : %p \n", &pa, ppa);
    return 0;
}

// 출력
//  a : 3 // *pa : 3 // **ppa : 3 
//  a : 000000000061FE14 // pa : 000000000061FE14 // *ppa : 000000000061FE14
//  a : 000000000061FE08 // ppa : 000000000061FE08

위 코드에서 
pa는 a를 가리키고, ppa는 pa를 가리킨다.
 ppa -> pa -> pa라고 생각하면 된다.
 그러니 즉 동일한 값이 출력된다.

7. 이차원 배열 활용


int main(){
    int arr[2][3] = { {1, 1, 1}, {2, 2, 2}};
    printf("전체 크기 : %d \n", sizeof(arr));
    printf("총 열의 갯수 : %d \n", sizeof( arr[0]) / sizeof(arr[0][0]));
    printf("총 행의 개수 : %d \n" , sizeof(arr) / sizeof(arr[0]));

    return 0;
}

//출력
//전체 크기  : 24 
//총 열의 개수 : 3
//총 행의 개수 : 2

위에서 arr[0]이라 선언하면 자동적으로 컴파일러가 arr[0][3]이라고 생각한다.
첫 번째 결과의 이유는 int형 요소가 3개인 배열 2개가 존재하니 4 * 3 * 2라서 결과가 이렇게 나온 것이고,
두 번째는 arr[0]은 arr[0][3]이니 즉 12이다. (4*3) 거기다 나누기 arr[0][0]이니깐 (4)
12 /4 3이다.
세 번째는 arr = 24m arr[0]은 12이니깐 24 / 12 즉 2.

profile
Life is a long journey. But code Should be short :)

0개의 댓글