프로그래밍
첫 페이지 회원가입 로그인
비공개 손님 2016-09-14 11:48:37
C 포인터 질문좀 드려요!! 몇시간째 고민중입니다 ㅠㅠ

안녕하세요

C 포인터 책을 보고있는데 의문이 생겨서 질문드립니다

int형의 2차원 배열 a[3][2] 가 있다고 할때

a와 *a 를 출력하면 둘다 같은 포인터값을 반환합니다. 그런데 sizeof를 해보면

a는 당연히 전체 배열 크기 24를 반환하지만 *a는 첫번째행의 크기 4를 반환합니다.

---

int imsi[3][2];

        printf("%x %dn", *imsi, sizeof(*imsi));
        printf("%x %dn", imsi, sizeof(imsi));

---


a 배열명은 a배열 전체가 대상체인 a[0][0]의 포인터값을 나타내는것은 알겠는데
*a는 왜 첫번째 행이 대상체가 되는거죠?

한줄요약 : int a[3][2]일때 왜 sizeof(a) == sizeof(*a) 가 아닌가요?

질문 | 1066명이 읽었어요. 3.238.90.95 |

0
1 비공개 손님 2016-09-14 13:56:33
예전에 제 은사님이 하신 설명이 있습니다.

* 는 칼입니다. 형에 해당하는 사이즈대로 자르는 칼입니다. 어디서 자르느냐 * 뒤의 값에 해당하는 메모리에서 정해진 사이즈 만큼 잘라냅니다

예를 들어보죠

int a = 300;
*a 는 멀까요? 300 번지에 해당하는 메모리에서 int 형 그러니까 4바이트만큼 잘라냅니다.

int a[10];
*((char*)(a+3))

는 멀까요? a 는 배열의 시작 주소입니다 a[10] 이 배열이라고 생각하면 헷갈립니다 그냥 40바이트 메모리 청크이고 그 첫번째 주소가 a 라고 생각하세요. a+3 은 그 40바이트 짜리 매모리 청크의 시작 주소에서 4바이트만큼씩 3번 건너뛴 주소입니다 예를 들어서 40바이트짜리 메모리 청크의 시작 주소가 2000 이라고 하면 a+3 은 2012 입니다. 여기까지는 인트형 포인터라 4바이트씩 뛰죠 이걸 char* 로 형변환 합니다 이제 1바이트씩 뛴다고 보면 됩니다 그리고 마지막에 * 칼로 자릅니다.

그러면 2012 메모리 번지에서 1바이트 만큼을 잘라옵니다.
이렇게 이해하시면 포인터는 쉽습니다. 포인터는 말그대로 포인터에서 메모리를 가르키고 있습니다 무슨 변수나 배열의 주소 그런게 아니에요. 걍 메모리 주소에서 그때 연산은 그 포인터 형의 사이즈만큼 되는 거고 * 는 그 자리에서 정해진 크기만큼 잘라내는 칼이라고 보시면 됩니다
2 비공개 손님 2016-09-14 14:01:17
sizeof(a) 와 sizeof(*a) 가 왜 다르냐는 질문은 좋은 질문입니다. sizeof 는 그 형의 크기를 반환합니다 다른 이유는 말그대로 a 의 형태의 크기와 *a 의 형태의 크기가 다르기 때문입니다. 형이 다르죠.

a 는 뭔가요? int a[3][2] 라고 했을때 a 는 배열의 시작지점 여기서는 24바이트 메모리 청크의 시작 주소를 나타내는 포인터입니다. 즉 형은 int* 입니다 주소번지를 나타내는 포인터는 64비트 컴퓨터에서 8바이트입니다.
*a 는 머냐 말그대로 a 가 가르키는 주소에서 크기만큼 잘라냅니다 int* 이니까 인트형만큼 잘라내는 거죠. 즉 *a 는 int 형입니다. 그러니까 4바이트죠.

32비트 컴퓨터에소 하셨으면 같겠네요
3 비공개 손님 2016-09-14 14:03:41
아 위에 잘못쓴게 있네요

int a=300;
int b = *a;

하시면 컴파일 에러 날겁니다 a 가 포인터형이 아니라서
int b = *((int*)a);
하시면 300번지에서 4바이트만큼 잘라서 그 값을 b 에 넣을 겁니다
아마 억세스 바이얼레이션이 뜨겠죠. 300번지는 아마 코드 영역일테니까요
4 비공개 손님 2016-09-14 14:29:49
포인터는 말 그대로 메모리 어딘가를 가리키는 정보를 저장하는 것이지 실제 배열 데이터를 저장하는 것이 아닙니다.
5 비공개 손님 2016-09-14 15:29:36
1// 아아..; *a가 첫번째 행의 크기라고 한건 잘못된거였네요; 첫번째 행의 크기는 8인데.. 포인터 크기가 4니까 4가 나온거군요..

오오 정말 감사합니다. 좋은 설명이네요!

4// 그렇군요.. 감사합니다.
6 비공개 손님 2016-09-14 16:38:05
1. 배열과 포인터는 다릅니다. 배열의 값도 주소를 나타내고 있고 포인터의 값도 주소를 나타내고 있지만 둘은 다른 개념입니다. 배열은 그 자체의 크기도 포함하고 있는 자료형입니다. 그렇기 때문에 배열에 sizeof 연산을 했을 때는 배열의 크기가 나오게 됩니다.

2. 역참조연산 (*)을 할 경우에는 간단하게, 그 주소에 들어있는 값을 가져오게 됩니다. 해당 배열의 형은 int**가 아니라 배열 자체의 크기를 담고있는 int[3][2]라고 생각하시면 됩니다. 그래서 sizeof 연산을 거치면 3 * 2 * sizeof(int) = 24의 값이 나오게 됩니다.

3. 2차원 배열을 역참조하면 그 역참조된 배열 자체가 형으로 튀어나오게 됩니다. int[3][2]를 역참조하면 int*가 아니라 int[2]가 튀어나오게 됩니다. 그래서 *a를 하게 된다면 int[2]형태의 값이 나오는게 맞습니다. 결론적으로 sizeof(*a)를 하면 2 * sizeof(int) = 8이 나오는게 맞습니다.

4. 배열 자체는 포인터형으로 형변환이 가능합니다. int *p = *imsi; 같은 식이 가능합니다. *imsi는 int[2]의 형태지만 int*형태로 자동으로 캐스팅 됩니다. 그렇게 들어간 포인터 변수 p를 sizeof연산을 할 경우에는 pointer의 크기인 4가 반환되게 되는 것입니다.
7 비공개 손님 2016-09-14 16:39:57
6/ 그렇군요. sizeof 할때 배열 크기가 나오는지는 몰랐네요.
8 비공개 손님 2016-09-14 16:42:08
글이 1,2,3,4가 무색하게 뒤죽박죽 섞여있네요..
9 비공개 손님 2016-09-14 16:49:58
http://ideone.com/M3y7LU

이걸 보시면 쉽게 이해가 되실 것 같습니다.
댓글을 작성하실 수 없습니다.
(권한이 없는 회원레벨)
목록으로
이용약관 | 광고/제휴 | 개인정보취급방침 | 문의/신고 | 모바일 TE31 | 서버 부하 : 3.75%
실시간 Issue 커뮤니티 TE31 [알지롱] ⓒ 2002-2021
TOP arrow_upward