달력

52024  이전 다음

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
C에서 배열은 포인터와 혼용되면서 많은 혼란을 가져오는 특징 중의 하나이다.
그러한 배열을 선언할 때는 그 크기를 지정해 주어야 하며
다만 배열을 선언하면서 동시에 그 값을 채워줄 때는 크기를 지정하지 않아도 되는 것으로 알고 있었다.
그래서 char a[] = "ab"; 는 가능해도 char a[]; 는 에러가 된다.

그런데 구조체 속에 선언한 크기 미지정의 배열은 어떻게 될까? 에러일까?
정답부터 말하면 가능하다.

좀더 말해서 해당 구조체 메모리 할당시 구조체 안에 크기 미지정의 배열에 대한
메모리는 할당되지 않는 것 같다.
이는 구조체에서 이 크기 미지정의 배열 대신 포인터를 넣으면
포인터 크기, 주로 4byte가 잡히는 것과 비교할 때 특이한 점이라 할 수 있다.
이러한 특징을 이용해서 구조체의 가장 끝 필드(Field)값으로 이러한 크기 미지정 배열을 넣고,
이 구조체에 대한 메모리를 할당할 때 구조체 자체의 메모리 크기에 더해서
해당 배열의 타입(type)의 배수 크기로 추가적인 메모리를 잡으면
그 배열 이름과 인덱스(index)로 추가된 메모리를 접근할 수 있다.
이 경우 구조체 메모리를 할당할 때마다 해당 배열의 크기를 원하는 만큼으로 조절할 수 있는 장점이 있다.

아래 코드는 이를 확인하기 위해 작성한 것으로서
특이한 사항은 추가적인 메모리를 할당하던 안 하던 크기 미지정 배열의 주소가
int 변수의 주소값에서 4만큼 큰 주소값이라는 것이다.
메모리는 할당되지 않지만 주소값은 있는 것처럼 보이는 것이다.



#include <stdio.h>
#include <stdlib.h>


typedef struct _T1{
int a;  // 4bytes
char * ch; // 4byte
}T1, *PT1;


typedef struct _T2{
int a;  // 4bytes
char ch[]; // 0byte
}T2, *PT2;


int main()
{
PT1 p1 = (PT1)malloc(sizeof(PT1)+sizeof(char)*5);
PT2 p2 = (PT2)malloc(sizeof(PT2)+sizeof(char)*5);
PT2 p3 = (PT2)malloc(sizeof(PT2));

printf("T1 size : [%d], T2 size : [%d]\n", sizeof(T1), sizeof(T2));
printf("sizeof(int) : [%d]\n\n", sizeof(int));

// error - a->ch[0] = 'A';
p2->ch[0] = 'B';

printf("p1 : [%x], &p1->a : [%x], &p1->ch : [%x]\n\n", p1, &p1->a, &p1->ch);

printf("p2->ch[0] : [%c]\n", p2->ch[0]);
printf("p2 : [%x], &p2->a : [%x]\n", p2, &p2->a);
printf("&p2->ch : [%x], &p2->ch : [%x], &p2->ch[0] : [%x]\n", &p2->ch, p2->ch, &p2->ch[0]);

printf("\np3 : [%x], &p3->a : [%x]\n", p3, &p3->a);
printf("&p3->ch : [%x], &p3->ch : [%x], &p3->ch[0] : [%x]\n", &p3->ch, p3->ch, &p3->ch[0]);

return 0;
}

사용자 삽입 이미지

Posted by neodelicious
|