Computer Science
탄탄한 기반 실력을 위한
전공과 이론 지식 모음
Today I Learned!
배웠으면 기록을 해야지
TIL 사진
Flutter 사진
Flutter로 모바일까지
거꾸로캠퍼스 코딩랩 Flutter 앱개발 강사
스파르타코딩클럽 즉문즉답 튜터
카카오테크캠퍼스 3기 학습코치
프로필 사진
박성민
임베디드 세계에
발을 들인 박치기 공룡
임베디드 사진
EMBEDDED SYSTEM
임베디드 SW와 HW, 이론부터 실전까지
ALGORITHM
알고리즘 해결 전략 기록
🎓
중앙대학교 소프트웨어학부
텔레칩스 차량용 임베디드 스쿨 3기
애플 개발자 아카데미 1기
깃허브 사진
GitHub
프로젝트 모아보기
Instagram
인스타그램 사진

TIL

[250820] Day 10 - &&__ ** 별보러가자

sm_amoled 2025. 8. 21. 09:43

들어가며

오늘은 좀 피곤하네 ^,^

오늘도 간단하게 수업을 하고 왔다. 이번 주제는 다중 포인터! 피어한테 설명해주면서 배열등가포인터 또는 배열을 가리키는 포인터를 다른 포인터 변수에 담아주는 경우에, 해당 변수로는 배열의 크기를 전달해줄 수 없다는 결론에 이르렀다… 나는 당연히 될 줄 알고 “이렇게 하면 될 것 같은데요?!” 라면서 코드를 두드려봤는데, 시간을 날리고 클로드에게 물어보니 안되는거라고 하더라.. 😢

오늘의 키워드

배열의 이름

배열의 이름을 이용해 연산자를 호출하면 조금 특별하게 작동함.

int main(void) {
    int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
    printf("%d \n", sizeof(a));          // 48
    printf("%d \n", sizeof(a[1]));       // 16
    printf("%d \n", sizeof(a[0][1]));    // 4
    printf("%d \n", sizeof(*a));         // 16
    printf("%d \n", sizeof(*(a+1)));     // 16
    printf("%d \n", sizeof(a+1));        // 4  정수연산으로 pointer
    printf("%d \n", sizeof(&a));         // 4  &배열명은 주소는 같지만 pointer
    printf("%d \n", sizeof(*&a));        // 48 배열 자기자신
    printf("%d \n", sizeof(*&a));        // 48 배열포인터의 값 => 배열
    printf("%d \n", sizeof(&*a));        // 4  배열 첫 원소값의 주소 => 포인터

    printf("----------\n");
    int (*p)[4] = a;
    printf("%d \n", sizeof(p));          // 4  얘는 pointer
    printf("%d \n", sizeof(p[1]));       // 16 근데 얘는 배열이네? 타고 들어가서 그런가보오
    printf("%d \n", sizeof(p[0][1]));    // 4
    printf("%d \n", sizeof(*p));         // 16
    printf("%d \n", sizeof(*(p + 1)));   // 16
    printf("%d \n", sizeof(p + 1));      // 4
    printf("%d \n", sizeof(&p));         // 4
    printf("%d \n", sizeof(*&p));        // 4  포인터 자기자신  => 포인터
    printf("%d \n", sizeof(&*p));        // 4  첫 원소의 주소값 => 포인터

    return 0;
}

  • sizeof(포인터상수) 의 결과는 상수(배열)가 사용하는 메모리의 크기
  • sizeof(&포인터상수) 의 결과는 포인터가 사용하는 메모리의 크기
    • 다만 &의 연산 결과가 포인터 상수인 경우에는 상수가 사용하는 메모리크기를 뱉음

아래 수식의 결과는 다르다!!! 단순히 *&&*는 컴파일러에 의해 알아서 상쇄되는 연산이 아니라, 각각 순서대로 연산이 처리되는 무언가라는 것을 반드시 기억하기!! 결과 보고 깜짝 놀랐다!!!

`printf("%d \n", sizeof(*&a));        // 48` 
`printf("%d \n", sizeof(&*a));        // 4`   

그런데 두 값 모두 같은 주소를 가리키고 있다. 타입은 다음과 같다.

  • *&aint(**)[3][4] 타입의 포인터가 가리키는 값이므로 int(**)[4]
  • &*aint* 타입의 값의 주소이므로 그냥 ‘포인터’ 이다.

 

포인터를 잘 사용하려면

  • 포인터 상수인지 포인터 변수인지 파악한다.
    • char* p = "abc"p[1] = 'x' 를 할 수 없음.
    • 요거슨 P가 상수포인터이기 때문임 (read-only memory에 저장됨)
    • char p[4] = “abc” 처럼 작성하면 복사해서 스택에 넣기 때문에 p 값 변경이 가능함!
  • 포인터는 타입이 중요함.
    • 포인터의 값 : 가리키는 데이터의 시작 주소
    • 포인터의 타입 : 주소의 데이터를 읽고 쓰는 단위
  • 포인터의 자료형을 바꿀 수 있다.
    • 데이터는 1byte, 4byte, 8byte 등의 여러 크기로 저장되지만, 포인터는 항상 동일한 4byte 포인터에 담긴다.
    • 포인터가 가리키는 값을 어떤 크기 단위로 읽어올지는 자료형이 결정한다.
    • 내가 작성한 데이터를 어떤 단위로 읽어올지는 타입캐스팅을 통해 변경 가능하다.

여전히 포인터 상수와 상수 포인터가 헷갈린다…

둘 뒤에 일단 ‘가’를 붙여서, 상수 포인터는 상수가(리키는) 포인터 / 포인터 상수는 포인터가 상수 라고 우선은 기억을 하고, 좀 더 익숙해질 필요가 있겠ㄷr…

배열명은 포인터상수!!!

”문자열”을 가리키면 상수포인터!!!

 

&를 붙일 수 있는 건 l-value 뿐

&의 뒤에는 l-value OR 배열명만 올 수 있다.

⇒ 연산결과인 숫자 등은 못온다.

  • &a : 가능
  • &(a+3) : 불가능

함수의 파라미터로 배열의 포인터를 넘길 때는 [배열표현]을 지양하자.

  • 함수의 파라미터에는 가능하면 배열형식으로 작성하기보다는 포인터 형식으로 작성하자.
void func(int arr[][4])
void func(int ** arr)

ㅤㅤ

배열이름의 타입과 이중 포인터는 다르다.

배열 등가 포인터로 다중 포인터를 만들면 행 단위 이동을 할 수 없다

int (*p)[4] != int** p

이중포인터는 주로 포인터 배열에 대한 연산을 처리하기 위해 사용한다.

char* str[5];

char** p = str;

포인터 변수로는 사이즈를 전달할 수 없다.

과제를 위해 대가리를 박으며 배웠다. 나는 될 줄 알았다.

sizeof(배열명) 을 하면 배열이 메모리에서 차지하는 크기를 구할 수 있다. 그리고 나는 &배열명 의 형식으로 포인터로 넘겨 함수 블럭 내에서 sizeof(배열명) 을 통해 배열의 크기를 구해보고 싶었다. 그러나 열심히 여러가지 방법들을 츄라이 해봤지만 타이틀의 결론을 내리게 되었다.

포인터 변수는 결국 포인터이고, 배열의 크기를 담아서 함수에게 전달해줄 방법은 없는 것 같다. ;ㅅ;

⇒ 배열명은 2가지 정보를 한 번에 담고있음

  • 포인터로서의 배열명 : 배열의 첫 주소값 + 가리키는 대상의 타입
  • 배열로서의 배열명 : 배열의 첫 주소값 + 배열의 전체 크기

배열등가포인터에 이 주소를 담는다면 “포인터로서의 배열명”에 대한 정보만 남게된다!

딥다이브

배열의 이름을 보내는 대신, 배열의 포인터(&ary)를 넘기면 함수에서 사이즈를 찾을 수 있다.

다만, 행 단위 이동에 대한 정보를 표현하기 위해 (사이즈를 알기위해) 인자에 해당 정보를 입력해둬야한다.

void print_aryy(int(*ary)[3][4])
{
    int r = sizeof(*ary) / sizeof(**ary);
    int c = sizeof(**ary) / sizeof(***ary);

    int (*pp)[4] = ary;
    for (int i = 0; i < r; i++)
    {
        for (int j = 0; j < c; j++)
        {
            printf("%d ", pp[i][j]);
        }
    }
    printf("\n");
}

...

int array[3][4] = {1, 2, ... , 12};
print_ary(&array);
// 사이즈를 넘길 필요가 없다!
320x100