• [컴퓨터] 초보놈의 소소한 C질문2012.06.15 AM 01:23

게시물 주소 FONT글자 작게하기 글자 키우기

명시적 형변환이었나 그게 예를들면 (int)라는건 정수형으로 형변환을 하는 거잖아요?

동적 메모리 할당 함수 malloc은 void *malloc(unsigned int); 으로 정의되어있고

원하는 포인터 변수에 연결해 동적으로 메모리를 할당할 때 예를 들어 정수형이라 한다면

(int *)malloc(4); 라고 하잖아요.

여기서 그냥 궁금한게 (int) 와 (int *)의 표현의 차이는 무엇인가요

함수의 리턴값이나 원래 변수가 포인터형일 때 (int *)라고 해야만 에러가 안나는건가요?

만약 (int)*malloc(4); 라던가 실수형 포인터 변수 a를 (int)a라고 했을때 어떤 의미가 되는건지 궁금하네요..



추가로
int *pt;
pt = (int *)malloc(5*sizeof(int));
라고 하면 pt는 그냥 20바이트짜리 정수 하나를 가리키는 건가요?

int는 기본적으로 4바이트인데 malloc으로 저렇게 크게 잡으면 자동으로 배열이 되는건지 아님 다른 의미가 있는건지 모르겠네요..

혹여 지나가다가 아시는 고수분이 계시면 알기 쉽게 설명해주시면 감사하겠습니다 ㅠㅠ
댓글 : 7 개
음.. 배열과 포인터 부분을 배우고 계신가보네요.. 'ㅅ'?
아닐수도 있지만...

기본적으로 자료형을 표현할 때 Int 형식의 자료를 저장할수 있는 메모리 공간을 할당해서 사용할때 int a 뭐 이런식으로 선언해서 쓰게됩니다.
그럼 int *a 는 뭐냐.. 인데 이때의 *는 이 변수가 가지는 메모리 영역은 int형의 자료를 저장하기 위한 공간이 아니라 int형의 자료를 저장하는 공간의 메모리 주소를 저장하는 변수라는 의미입니다.

말로 풀어쓰니 좀 어려울 수도 있는데요...
메모리 공간에 어떤 데이터를 저장하기 위한 자료형을 설정하는 부분이
int 라던가, char라던가 라는게 있는거고
int * 라던가 char * 라는 자료형이 또 있다고 생각하시면 됩니다.
int는 정수를 담기 위해서 4바이트의 자료형을 Ansi C에서 사용하고 있고, char는 1바이트 데이터를 저장하기 위해 사용하고 있는데요.
*가 붙은 변수는 모두다 4바이트의 주소를 저장하기 위한 공간으로 사용됩니다.
(32비트에서 4바이트입니다. 64비트에서는 메모리 주소 크기가 커졌으니 8바이트를 사용하겠ㅤㅉㅛㅤ 'ㅅ'?... 8바이트가 맞나..... )

malloc 이라는 함수는 인자로 전달받은 크기만큼의 메모리 블럭의 주소를 반환하게 됩니다.
위에서 설명했듯이 모든 *변수는 동일한 크기니까 어떤 형태의 포인터 변수에 할당 할 수 있기 때문에 void *라는 형식을 쓰는겁니다.

여튼 int * 라는 자료형을 가진 포인터 변수는 int 를 저장하는 메모리 블럭을 가리키게 되므로 할당된 메모리 영역에서 4바이트(int의 크기)씩 연산하게 됩니다.
pt는 할당한 메모리의 오프셋0 부분이고, pt[0]과도 동일합니다. 물론 *pt와도 동일하죠.
그 다음의 pt[1]이나 *(pt+1)의 경우에는 실제 메모리 영역에서는 4바이트째인 오프셋 4부터라고 생각하시면 되는데요...
이게 글로만 설명하려고 하니... 굉장히 힘드네요 ㅠ_ㅠ)

더 이해가 안가시게 적은거 같기도하고...
int형은 말그대로 정수고 int*형은 포인터형입니다. 32bit 컴파일러에서는 int형 공간에도 메모리 주소를 담을 수는 있습니다 주소 담는데 4byte가 필요하니깐요.

(int)*malloc(4); 는 해보진 않았지만 컴파일 에러를 뱉을 거 같네요.

실수형 포인터 변수 a면 float* a; 말씀하신거면 그것을 (int)a로 컨버팅 했을 때

말그대로 a가 가르키는 주소를 int 형으로 옳긴거라고 해야겠네요. 좀더 예를들면

float* a = (float*)malloc(4);
*a = 3.14f;
int b = (int)a;
a = (float*)b;
printf("%f\n", *a);
를 해도 똑같은 3.14 가 나올겁니다. 하지만 중간에 b 값을 바꿔 버리면
주소 값이 바꾸기 때문에 런타임 에러가 발생할 수 있습니다.

추가
20 바이트 짜리 메모리 공간을 가르킨다고 생각하시면 편하겠네요. 그게 가르키는 포인터형에 따라 배열 모양이 바뀝니다.
int *pt;
char* pt2;
pt = (int *)malloc(20); // int형 공간 5개의 해당되는 배열이 되고
pt2 = (char*)pt2; // char형 공간 20개의 해당되는 배열이 됩니다.
가볍게 말해보자면, int 형태의 배열로 동적할당 하셨잖아요?
그 공간을 가르키는 포인터(메모리상의 주소)를 반환한다는 뜻입니다.
int형 이기 때문의 int형의 포인터인 int*으로 형변환 해서 반환하겠다는 뜻입니당
첫 번째는 (int)*malloc 으로 적으면 에러가 날 것 같네요.. 그건 많은 분들이 설명해주셨고,

pt = (int *)malloc(5*sizeof(int)); 하면 '밖에서 봤을 때' 5개의 int 형 원소를 가질 수 있는 배열이 생깁니다. 이게 결론입니다만, 내부 원리를 보면 확실히 이해하실 겁니다.

malloc으로 할당 후, pt[0]이 첫 번째 원소, pt[1]이 두 번째 원소.. 로 표현이 가능할텐데 사실 이런 식으로 접근하는 원리가 '인덱스 번호 * 4바이트만큼 뒤에 있는 위치서부터 4바이트를 읽어오라' 는 이야기가 됩니다. malloc으로 20바이트를 할당받으면, pt는 20바이트의 시작지점이 되는 주소를 저장하게 되고, pt[0]은 그냥 시작지점에서 4바이트를 읽어낼 겁니다. (이미 pt는 int형을 가리키는 놈이라고 첫 줄에 명시했으니 float도 char도 아닌 int형의 공간 4바이트씩 읽어냅니다) 그럼 pt[1]은 그 뒷 4바이트 위치, [2]는 또 뒤의 4바이트 위치..

배열선언을 할때, 사이에 어떤 메모리 배리어가 존재하는 것이 아님을 알아두세요.
반대로, int pt2[5] = {1,2,3,4,5}; 라고 선언해도, 내부 원리는 pt2에는 저 배열이 연속으로 들어있는 메모리 시작지점을 가지고 있는 것입니다. pt2가 20바이트짜리 커다란 정수가 아니듯이, 앞서 설명한 예제 역시 20바이트짜리 정수가 아닌 셈이죠.
잠이 안와서 계속 적어봅니다.

첫 번째에서 malloc의 원래 반환형이 void * 라는 이야기는, '내가 메모리 어딘가에 사용 가능한 영역을 잡아두고, 그 시작지점의 '주소'를 반환하겠다' 라는 뜻인데 '그런데 잡아둔 메모리를 어떤 자료형으로 '쪼갤지'는 반환해주는 나도 모르겠다' 이기 때문에 void * 형태입니다.

따라서 int* pt; 가 이 malloc의 결과를 받기 위해서는 캐스팅(명시적 형변환)을 통해 '지금 내가 너에게 전해주는 주소는 int형으로 사용될 메모리의 시작지점이란다' 라는 뜻입니다. 어쨌든 '주소'를 넘겨주므로 *를 붙여 (int*)로 캐스팅해야 합니다. 그런데 최신 컴파일러는 (당연히 불안정한 결과를 초래할 수 있지만) 따로 캐스팅을 안 해줘도 error를 발생시키지 않습니다. 왜냐하면 결국 주소를 저장하는 변수 pt는 int* 형이거든요. '누가 뭐래든 난 int형으로 이 메모리를 쪼개 쓸거야' 라고 말이죠.

만약 이걸 (void)로 캐스팅해버리면 컴파일러가 '야, 너 주소 넘겨주기로 했는데 왜 아무것도 안 넘겨주냐?' 라며 warning을 냅니다. (확신이 없네요) (int)로 캐스팅하면 '너 주소 넘겨주기로 했는데 이 주소값 32bit를 '정수'로 반환하냐?' 며 warning을 냅니다. (이건 확실합니다)
으헉 답변들 감사합니다. 지금 읽는중인데 먼저 감사의 말씀 올립니다 ㅠ
친구글 비밀글 댓글 쓰기