ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [SW 정글 31일차] 오늘은 C 포인터
    기타/SW 사관학교 정글 2021. 9. 2. 01:57

     

    오늘은 어제에 이어 C언어를 공부했다.

    C언어의 장벽인 포인터 공부를 했고 아직은 이해할만한 영역이라고 생각한다.

    일단은 포인터를 써서 뭔가 구현한 것은 아니여서 어려움을 느끼지는 못했지만 내 것처럼 잘 쓰면 좋겠다.

     

     

     

    1. 포인터란?

    포인터(pointer)는 직관적으로 의미하는 것을 말하면 '가리키는 것'이다.

    int, float, char 형(type)과 같은 변수와 마찬가지로 포인터(pointer)도 하나의 변수이다.

    포인터는 변수로서 메모리 상에 위치한 특정 데이터의 시작 주소값을 보관한다.

     

    c언어에서는 변수를 선언할 때 int형인지 char형인지 미리 같이 선언하여 해당 변수가 어떠한 type의 데이터를 담을지를 알려준다.

    포인터(pointer)도 마찬가지로 int, char 같은 형(type)을 가진다.

    그냥 주소를 담고있는 포인터라면 어차피 시작주소는 32bit운영체제면 4바이트이고 64bit 운영체제면 8바이트로 고정인데 왜 형(type)을 가질까?

    이 의문은 아래에서 풀어보자.

     

    포인터(pointer)를 정의하는 방법은 아래와 같다.

    (데이터의 형(type)) *(포인터명);
    (데이터의 형(type))* (포인터명);
    int* p;
    int *p;

     

     

     

     

    2. & 연산자와 * 연산자

    우리가 포인터를 배우면서 같이 알아야 할 2가지의 연산자가 있다.

    먼저, & 연산자를 알아보자.

    &는 보통 두 개의 피연산자 사이에 쓰여 AND 연산자 역할을 하는 것으로 알고 있다.

    하지만, 피연산자가 1개인 단항 연산자로도 정해진 기능을 한다.

    &변수

    위에 쓴 것처럼 이미 선언되 변수명 앞에 &연산자를 붙이면 메모리 상에서 해당 변수가 올라가있는 주소값을 불러온다.

     

    다음으로 * 연산자를 알아보자.

    *는 보통 두 개의 피연산자 사이에 쓰여 두 피연산자를 곱하는 역할을 하는 것으로 알고 있다.

    하지만 피연산자가 1개인 단항 연산자로 쓰면 포인터로 사용할 변수 앞에 *를 붙여 주소값을 보관하는 변수라고 선언해주는 역할을 한다.

    & 연산자가 어떠한 데이터의 주소값을 얻어내면 거꾸로 주소값에서 해당 주소값에 대응되는 데이터를 가져오는 역할을 * 연산자가 하는 것이다.

    "나(포인터)를 나에게 저장된 주소값에 위치한 데이터로 생각해줘!"

     

    포인터 P와 P가 가리키는 변수 a가 메모리에서는 어떻게 표현되는지를 알 수 있는 그림이다.

    출처: https://modoocode.com/23

     

     

     

    3. 포인터도 타입을 가지고 있는 이유를 알아보자

    1. 포인터란?에서 포인터도 int, char 등의 형(type)을 가진다고 말했고 왜 필요할까? 라는 의문을 던졌다.

    그러면 먼저 포인터가 int, char 등의 형(type)이 없고 pointer라는 타입을 가지는 변수라고 생각해보자.

    그러면 32비트 운영체제에서는 4바이트, 64비트 운영체제에서는 8바이트 고정일 것이다.

    #include<stdio.h>
    
    int main() {
        int a;
        pointer *p;
        p = &a;
        *p = 4;
        
        return 0;
    }

    위 코드를 생각해보면 p = &a를 통해 p에 a의 주소가 들어갈 것이다.

    문제는 *p = 4에서 발생한다.

    p에는 a가 차지하고 있는 메모리 상의 전체 주소가 아닌 시작 주소만 가지고 있다.

    그렇게 되면 *p라고 선언했을 때 컴퓨터가 메모리에서 시작 주소부터 얼만큼을 읽어야 할지 알 수가 없다.

     

    그러면 p을 int 형(type)으로 선언하면 어떨까?

    #include<stdio.h>
    
    int main() {
        int a;
        int *p;
        p = &a;
        *p = 4;
        
        return 0;
    }

    p가 int *으로 선언되었다는 것을 파악하고 p라는 포인터는 int 데이터를 가리킨다고 인식하여 p에 담고 있는 시작 주소로부터 4바이트를 읽을 수 있게 된다.

     

    이제 왜 포인터도 int, char 등의 형(type)과 같이 선언되는지 이해가 됐다.

     

     

     

    4. 포인터는 변수니까

    맨 처음에 포인터도 하나의 변수라고 말했다.

    변수라는 것은 언제든 값이 변할 수 있다는 것이다.

    그러면 아래의 코드는 어떨까?

    #include <stdio.h>
    int main() {
      int a;
      int b;
      int *p;
    
      p = &a;
      *p = 2;
      p = &b;
      *p = 4;
    
      return 0;
    }

    처음에 p = &a를 통해 p에는 메모리 상의 a의 시작주소가 담긴다.

    *p = 2로 a의 값을 바꿀 수 있고 다음 코드를 보면 p = &b를 선언했다.

    p는 포인터이고 하나의 변수이기에 기존에 담고 있던 a의 시작주소에서 b의 시작주소를 담고 있는 것으로 바뀐다.

    그렇게 되면 다음에 선언한 *p = 4를 통해 b의 데이터를 4로 바꾸게 된다.

     

    지금까지는 어느정도 포인터를 이해했고 그래도 쓸 수는 있을 것같다.

    조금 더 심화된 내용을 보면 얼마나 난이도가 높을지 궁금하다.


    [오늘의 나는 어땠을까?]

    오늘은 DP와 그리디를 공부하는 마지막 주차로 그동안 공부했던 것을 복습하며 새로운 문제들을 풀었다.

    주어진 문제들 중에는 외판원 순회와 가장 긴 공통 문자열은 풀지 못했다.

    일요일에 시간이 되면 이해해보려고 노력해봐야겠다.

    DP와 그리디는 문제를 정말 많이 접해보고 문제접근방법을 떠올리는 연습을 해야하는 알고리즘인 것같다.

    특히 DP는 2차원배열로 tabluation을 하는 문제들은 너무 어렵다.

    꾸준히 노력하다보면은 어느순간 자연스럽게 풀 수 있을테니 지금은 너무 스트레스 받지 말아야겠다.

     

    내일부터는 C언어를 사용해서 B트리를 구현하는 주차가 시작되는 날인데 뒤쳐지지 않고 다른 동료들에게 도움을 줄 수 있는 지식을 갖도록 노력할 것이다.

    나의 성장을 위해서


    <참고 자료>

    https://modoocode.com/23

     

    댓글

Designed by Tistory.