포인터와 배열. 오류를 지적해 주세요
글쓴이: freegagamel / 작성시간: 목, 2006/02/02 - 3:54오전
안녕하세요.
포인터와 배열에 관한 질문이 있습니다.
아래와 같은 코드가 있습니다.
#include <stdio.h> int main(void) { int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; int (*pai)[]; pai = &a; <---(1) printf("pai=%d, &a=%d, a=%d, &a[0]=%d, (a + 0)=%d\n", pai, &a, a, &a[0], (a + 0)); printf("%d, %d\n", (*pai)[0], a[0]); printf("%d, %d\n", (*pai)[2], a[2]); return (0); }
실행을 하면 아래와 같은 결과가 나옵니다.
pai=2293568, &a=2293568, a=2293568, &a[0]=2293568, (a + 0)=2293568
0, 0
2, 2
위와 같이 하면 잘 됩니다.
그런데 (1)의 부분을 pai = &a; ---> pai = a로 변경 하면 Dev-C++에서 아래와 같은 warning 발생합니다. (터보C에서도 마찬가지로 warning 발생)
7 C:\TCWIN\test\array2.c [Warning] assignment from incompatible pointer type
결과는 warning외에는 위의 결과와 같은 결과가 나옵니다.
pai = a와 pai = &a의 차이라면 어떤게 있나요?
a라는 배열에서 배열의 이름은 배열의 첫번째 주소와 같은 걸로 알고 있습니다.
또한 pai는 배열을 가리키는 포인터 이므로 굳이 주소연산자를 안쓰고 pai = a라고 해도 되지 않을까요?
Forums:
만일 C++라면 에러가 날겁니다. 타입 불일치라고...단순히 배열
만일 C++라면 에러가 날겁니다. 타입 불일치라고...
단순히 배열/포인터 구분 안하고 타입을 말씀드리면...
a는 int* (때문에 &a는 int**), pai는 당연히 아시겠지만 int**가 됩니다.
pai=2293568, &a=2293568, a=2293568, &a[0]=2293568, (a + 0)=2293568
여기서 [pai, &a] ///// [a, &a[0], (a + 0)] 요렇게 진영이 엇갈리는 (-_-) 건 아실 겁니다.(위쪽 코드에서요)
실제는 5개가 모두 같은 값으로 나오지만 전자는 int**, 후자는 int* 타입입니다.
C++에서는 타입 불일치이지만 C에서는 걍 관대하게(?) 넘어가주는 겁니다.
그러나 그러면 a, &a의 주소값이 왜 같은지에 대한 의문이 생길 지 모릅니다.
단순합니다만 &a와 a가 같은 까닭은 다음과 같군요...
"스택에 배열을 만들 때 따로 이 배열을 가리키는 포인터를 만들지는 않는다."
스택에 배열 a가 만들어졌습니다. int[10]만큼의 크기가 할당된 겁니다. 그럼 a[0]의 주소, 즉 배열의 가장 앞쪽 끝을 a로 표시(포인터)해주는 것은 맞습니다.
그럼, 포인터 "a"가 실제 메모리를 잡아먹는 변수인가요? 아니잖습니까...
이건 단순히 &a[0]일 뿐 a 자체가 따로 포인터 변수로 선언되어 &a로 주소 참조할만한 메모리 주소가 있는 게 아닙니다.
(물론 int *a 해놓고 malloc 해준다면 &a값은 다른 것으로 나옵니다. 왜냐하면 a라는 포인터 변수가 메모리에 저장되어 할당된 int[10]을 가리키기 때문입니다.)
솔직히 &a 부분에서 경고나 에러가 안 나는지는 이해가 안되지만...
그래서 아마 같은 것으로 표시하나 본데, 그래서 &a와 a값이 같은 것일듯 하네요.
[code:1]int *(pai2)[10];
이 것은 맞습니다.
이 두개는 다릅니다. 위의 것은 다시 assignment from incompatible pointer type.
설명은 다른분께서.. 명쾌하게 설명을 못하겠어요 :oops:
윗분이 적어주셨네요~
어떤 책에서는 대상체라고 하더군요 :)
포인터를 다룰 때에는 늘 주소값 외에도 그것의 타입에 대해서 염두에 두고
포인터를 다룰 때에는 늘 주소값 외에도 그것의 타입에 대해서 염두에 두고 있어야 합니다. 같은 주소값을 가리키고 있다고 해서 같은 데이터형이라 가정해서는 안됩니다. 다음과 같은 경우에, 같은 주소값이라 해도 서로 다른 데이터형이 될 수 있습니다.
* 배열형과 그 배열의 첫번째 원소
* 구조체형과 그 구조체의 첫번째 맴버 변수
int a[10];
배열이름 a는 수식에서는 그 자신의 첫번째 원소를 가리키는 포인터 주소값으로 치환됩니다. a[3] 이 *(a+3)과 완전히 동일하다는 것도 이를 아신다면 이해가 빠르실 것입니다.
단, 위의 배열 이름의 치환규칙이 다음과 같은 경우에는 위의 규칙이 적용되지 않습니다.
* & 연산자의 피연산자
* sizeof() 연산자의 피연산자
* char[]형의 초기화 : 오른쪽과 같은 경우를 뜻함 -> char str[] = "string";
sizeof(a)를 한다면, a 전체의 크기인 4 * 10을 반환하게 됩니다. &a의 경우에도, pointer to array of int[] 타입의 포인터 주소값을 반환하게 됩니다.
[quote="idned"]단순히 배열/포인터 구분 안하고 타입을 말씀드
아닙니다. pai는 선언된 그대로 int(*)[] 즉 pointer to array of ints입니다.
그리고 a는 int[10]이니까 &a는 int(*)[10] 즉 pointer to array of 10 ints입니다.
이 두 타입은 서로 호환되는(compatible) 형이므로 원코드의 (1)과 같은 대입이
가능합니다.
배열과 포인터는 반드시 구분해야 합니다. :-)
&a로 참조할 수 있는 주소가 없다면 그와 같은 수식이 허용되는 이유를 설명할 수 없죠.
a는 포인터가 아니라 배열이고 실제로 메모리를 차지합니다. 많은 문맥에서 배열명은
첫번째 요소를 가리키는 포인터로 암시적 변환이 되지만, 번지연산자 &나 sizeof의
피연산자일 경우에는 그러한 변환이 일어나지 않습니다. 따라서 &a의 뜻은 10개의
int를 한 덩어리(대상체)로 볼 때 그 덩어리를 가리키는 포인터이며 그 값은 그 덩어리의
시작 주소가 됩니다. 당연히 &a[0]과 일치하지만 형은 다르죠.
댓글 달기