대외활동, 서포터즈/한빛아카데미 혼공학습단 12기

[혼공C] 6주차_포인터

gureumsocute 2024. 8. 18. 21:31

벌써 마지막이네요!

계속 파이썬만 해서 c는 까먹기 직전이었는데 이렇게나마 복습할 수 있어서 너무너무 좋았습니다 😊

다음 스터디도 신청할게요 크크

 

아는 언니한테 톡이 왔는데 개강이 2주 남았다네요?

이것 뭐에요 ~?

저는 올클해서 19학점을 듣습니다...

아아 졸업할 수 있어서 좋은데 안 좋아

아 심란해 엽떡 시켜 먹을게요 

 

며칠 전에 그냥 읽으려고 한빛아카데미 - 네트워크 해킹과 보안을 구매했는데

재밌고 완전 만족스럽고 그렇습니다 다들 츄라이츄라이 ~

책장 보는데 생각보다 한빛미디어 책을 많이 샀더라고요?

회고를 올리면서 다른 책들 리뷰도 한번 해볼까 합니다 많관부 ~

그리고 코난 전시회를 다녀왔는데요

제 최애는 괴도키드입니다 네

 

 


 

 

포인터란?

사용 범위를 벗어나도 데이터를 공유할 수 있게 도와주는 것

⭐ 변수는 함수 내부에서만 사용할 수 있었으나, 함수 외부에서도 같은 데이터를 공유하기 위해 포인터를 사용한다.

 

 

 

메모리란?

데이터를 넣고 꺼내 쓰는 공간

⭐ 프로그램이 사용하는 메모리의 위치를 주소 값으로 식별 가능함

 

이미지처럼 int형 변수 a가 메모리 100번부터 할당되었을 때 100부터 103까지 4바이트에 걸쳐 할당됨

변수 선언 이후에 4바이트를 a로 사용하는 것 

혼자 공부하는 C 언어(한빛미디어) p.263

 

a = 10;은 4바이트의 공간에 10을 저장했다는 의미

a + 20;은 그 4바이트의 공간에 저장된 값과 20을 더하는 연산이라고 보면 된다.

 

 

 

주소 연산자(&)

변수를 이름이 아닌 주소로는 어떻게 사용할 수 있을까?

주소는 변수가 할당된 메모리 공간의 시작 주소를 의미함

메모리 주소를 전달하는 것이므로 메모리 효율성이 있는 방법 

또, 주소를 전달해도 여러 함수에서 동일한 위치를 참조할 수 있어서 쉬운 공유 가능

 

//변수의 메모리 주소 확인
#include <stdio.h>

int main() {
    int a;      // int(정수)형 변수 선언 
    double b; // double(실수)형 변수 선언 
    char c;    // char(문자)형 변수 선언

    printf("a의 주소: %p\n", (void*)&a);
    printf("b의 주소: %p\n", (void*)&b);
    printf("c의 주소: %p\n", (void*)&c);

    return 0;
}


//결과
a의 주소: 0x7ffee28d6a34
b의 주소: 0x7ffee28d6a28
c의 주소: 0x7ffee28d6a27

 

⭐ 주소를 통해 메모리 배치를 알 수 있다.

 

 

 

포인터의 선언과 사용

#include <stdio.h>

int main() {
    int a = 10;    // int(정수)형 변수 선언
    int *pa;        // int(정수)형 포인터 선언

    pa = &a;        // a 주소 대입 
    *pa = 10;       // 포인터로 변수 a에 10 대입

    // a의 값과 주소 출력
    printf("a의 값: %d\n", a);
    printf("a의 주소: %p\n", &a);

    // p가 가리키는 값과 p 자체의 주소
    printf("p가 가리키는 값: %d\n", *p);
    printf("p의 값: %p\n", p);

    return 0;
}

 

 

여기에서 '*'는 포인터임을 표시하는 기호라는 것을 잊지 말아야 한다. 

반드시 주소 위치에 있는 변수의 자료형을 적어야 한다.

혼자 공부하는 C 언어(한빛미디어) p.266

 

 

a가 메모리의 100부터 103까지 할당되었다면 주소 값 100은 pa에 저장된다.

혼자 공부하는 C 언어(한빛미디어) p.267

 

 

 

 

간접 참조 연산자

//간접 참조 연산자
// * == 간접 참조 연산자
// pa == 포인터
*pa

 

 

 

 

여러 가지 포인터 사용해 보기

// p.269 예제 9-3

#include <stdio.h>

int main() {
    int a = 10, b = 15, total; // 변수 선언과 초기화
    double avg; // 평균 저장할 변수
    int *pa, *pb; // 포인터 동시 선언
    int *pt = &total; // 포인터 선언과 초기화
    double *pg = &avg; // double형 포인터 선언과 초기화

    pa = &a; // 포인터 pa에 변수 a의 주소 대입
    pb = &b; // 포인터 pb에 변수 b의 주소 대입

    *pt = *pa + *pb; // a값과 b값 더해 total에 저장
    *pg = *pt / 2.0; // total 값을 2로 나눈 값을 avg에 저장

    printf("두 정수의 값: %d, %d\n", *pa,*pb);  // a값과 b값 출력
    printf("두 정수의 합: %d\n", *pt); // total 값 출력
    printf("두 정수의 평균: %.1lf\n", *pg); // avg 값 출력
}



// 결과
두 정수의 값: 10, 15
두 정수의 합: 25
두 정수의 평균: 12.5

 

 

 

const를 사용한 포인터

const를 사용하면 가리키는 변수의 값을 바꿀 수 없다는 의미가 됨

// p.272 예제 9-4

#include <stdio.h>

int main() {
    int a = 10, b = 20;
    const int *pa = &a;  // 포인터 pa는 변수 a를 가리킨다.

    printf("변수 a 값: %d\n", *pa);  // 포인터로 간접 참조해 a 출력
    pa = &b;  // 포인터가 변수 b를 가리키게 한다.
    printf("변수 b 값: %d\n", *pa);  // 포인터로 간접 참조해 b 출력
    pa = &a;  // 포인터가 다시 변수 a를 가리킨다.
    a = 20;   // a를 직접 참조해 값을 바꾼다.
    printf("변수 a 값: %d\n", *pa);  // 포인터로 간접 참조해 바뀐 값 출력

    return 0;
}


// 결과
변수 a 값: 10
변수 b 값: 20
변수 a 값: 20

 

 

 

포인터 완전 이해하기

 

포인터

1. 주소 저장

2. 포인터끼리 대입 가능

3. 대입 연산 기준 엄격

 

 

주소와 포인터의 차이?

주소는 변수에 할당된 메모리 저장 공간의 시작 주소 값 자체

포인터는 그 값을 저장하는 다른 메모리 공간

변수의 주소는 변하지 않지만, 포인터는 가리키는 주소를 바꿀 수 있어 다른 변수를 참조하게 할 수 있다.

 

아래 사진과 같이 지정했더라도

혼자 공부하는 C 언어(한빛미디어) p.276

 

 

이렇게 하나의 변수를 지정하도록 주소를 바꿀 수 있다.

혼자 공부하는 C 언어(한빛미디어) p.276

 

 

 

주소와 포인터의 크기

포인터도 저장 공간이기 때문에 크기가 있다.

그 크기는 저장할 주소의 크기에 따라 결정되는데 크기가 클수록 더 넓은 범위의 메모리를 사용할 수 있다.

포인터의 크기는 컴파일러에 따라 다를 수 있지만, 모든 주소와 포인터는 가리키는 자료형과 상관없이!

그 크기가 같다.

 

 

 

포인터의 대입 규칙 

1. 포인터는 가리키는 변수의 형태가 같을 때만 대입해야 한다. 

2. 형 변환을 사용한 포인터의 대입은 가능하다.