• 카테고리

    질문 & 답변
  • 세부 분야

    프로그래밍 언어

  • 해결 여부

    미해결

(1:40) flexible array member을 갖는 구조체, 스택 vs 힙 메모리 위치가 궁금합니다.

22.11.23 01:07 작성 조회수 312

0

★작성하다보니 글이 길어졌는데, 번호로 굵은 표시해놓은 부분과 그림만 살펴봐주셔도 될 것 같습니다.
--------------------
#define CRTSECURE_NO_WARNINGS

#include <stdio.h>

#include <stdlib.h>

int main()

{

/*

Flexible array member (struct hack in GCC)

*/

struct flex

{

size_t count;

double average;

double values[]; //flexible array member (last member!)

};

const size_t n = 3;

printf("%zd\n", sizeof(float));

struct flex* pf = (struct flex*)malloc(sizeof(struct flex) + n * sizeof(double));

if (pf == NULL) exit(1);

printf("%lld\n", (long long)pf);

printf("%lld\n", (long long)&pf->count);

printf("%zd\n", sizeof(pf->count));

printf("%lld\n", (long long)&pf->average);

printf("Address of pf->values %lld\n", (long long)&pf->values);

printf("Value of pf->values %lld\n", (long long)pf->values);

printf("Sizeof pf->values %zd\n", sizeof(pf->values));

pf->count = n;

pf->values[0] = 1.1;

pf->values[1] = 2.1;

pf->values[2] = 3.1;

pf->average = 0.0;

for (unsigned i = 0; i < pf->count; ++i)

pf->average += pf->values[i];

pf->average /= (double)pf->count;

printf("Average = %f\n", pf->average);

현재 구조체 flex는 main함수 내에서 선언하여 스택 메모리에 위치하고 있습니다.

구조체 flex의 멤버 size_t형 count와 double형 average는 구조체 포인터가 선언됨과 동시에 스택에 메모리 공간을 차지하였습니다.

구조체 flex의 마지막 멤버는 가변길이 배열(flexible arrays)으로서 동적할당으로부터 변수를 통해 크기를 할당받는다고 이해했습니다.

Q1. 구조체 포인터를 선언할 때 struct flex* pf;라고 하는데,
이때 pf는 내부적으로 구조체 flex의 데이터들을 가리키는 것인지 궁금합니다.
: 이 순간부터 pf는 구조체 flex와 관련이 있는것인가요? 관련이 있다면 어떤 것인가요?
*지금까지 너무 자연스럽게 Q1-1처럼 struct 구조체Tag를 하나의 자료형으로만 생각해왔습니다.

Q1-1. 단순히 struct flex라는 것은 하나로 묶어 (구조체를 다루는) 하나의 자료형으로 취급하는 것이 아닌가요?

Q2. 스택 내에 구조체 flex에 대한 메모리 공간, 구조체 포인터 pf에 대한 메모리 공간 서로 따로 존재하며
구조체 포인터 pf가 동적할당받은 메모리 주소를 가리킨다고 이해했습니다.
*사진 첨부

그런데 어떻게 구조체 포인터 pf를 통해 스택에 있는 구조체 멤버인 count와 average에 접근할 수 있는 것인지 잘 모르겠습니다.

Q3. 구조체 flex의 멤버인 배열 values가 동적할당 메모리를 이용한 가변길이 배열로 설정하기 위함이라면

동적할당을 받을 때, 배열이 필요로하는 n * sizeof(double)만 할당받아오면 됐을 것 같은데

sizeof(struct flex)를 추가로 받아오는 이유가 궁금합니다.

+구조체 포인터 pf를 통해 count와 average에 접근할 수 있던 것과 관련이 있을 것 같습니다.
--------------------
: 앞에서 말씀하셨듯 구조체 포인터 pf는 'flex라는 Tag를 갖는 구조체 변수'의 포인터'라고 하는데 Tag는 모든 멤버의 데이터를 담고있는 것인가요?

구조체 멤버 또는 구조체 포인터가 선언됨에 따라 구조체의 멤버들은 메모리 공간을 할당받고
구조체 포인터를 ->연산자를 통해 멤버에 접근할 수 있다는 것은 이해했습니다.

(Q2)※다만 제가 여기서 궁금한 것은 구조체 포인터에 단순히 동적할당 받은 힙 메모리의 주소를 대입했음에도
어째서 동적할당 메모리를 가리키는 포인터 pf를 통해 멤버에 접근이 가능한지..입니다.

답변 1

답변을 작성해보세요.

0

상현님의 프로필

상현

질문자

2022.11.23

아....! 이해했습니다.
스택에는 '구조체에 접근하기 위한' 포인터만 공간을 갖고있고

구조체 변수 또는 포인터가 선언되는 순간 구조체의 멤버들에 메모리 공간이 할당됩니다.

struct flex pf; 이렇게 선언됐다면 스택에 구조체 멤버들을 위한 공간이 확보되겠지만, (block scope에 입력된 구조체의 경우)
※file scope에 입력된 구조체라면, 초기화 여부에 따라 BSS또는 DATA Segment에 저장.

struct flex *pf; 이렇게 선언하면 스택에는 포인터를 위한 공간이 일단 확보되는데,
1) 구조체가 file scope에 입력됐다
→ 구조체는 초기화 여부에 따라 BSS 또는 DATA Segment에 저장

2) 구조체가 함수 내에 입력됐다. (이번 예제)
2-1) 그런데 구조체 포인터가 힙으로부터 동적할당받은 메모리를 가리킨다.
→ 구조체는 힙(heap) 메모리 공간을 할당받아 저장
2-2) 구조체 포인터가 그냥 선언만 됐다.
→구조체는 스택에 메모리 공간을 할당받아 저장

그러니까 이번 예제는 스택에는 포인터 pf에 대한 공간만 잡혀있고
힙에는 구조체 flex의 전 멤버에 대한 공간이 잡혀있는 것입니다.

위에 제가 이해한 내용이 맞을까요?

강민철님의 프로필

강민철

2022.11.23

정리해주신 내용 흥미롭게 잘 읽었습니다.

네 맞게 정리해주신듯 합니다 :)