• 카테고리

    질문 & 답변
  • 세부 분야

    프로그래밍 언어

  • 해결 여부

    미해결

8:26 resizing

21.02.05 19:21 작성 조회수 180

1

안녕하세요. 비전공자입니다.

#include <iostream>

using namespace std;

int main()
{
	/**********resizing**********/

	int* fixed_arr2 = new int[] { 1, 2, 3 };

	//1. 기존 array element 및 메모리 주소 출력

	for (int i = 0; i < 3/*아쉬운 부분*/; i++)
		cout << fixed_arr2[i] << "\t\t" << (uintptr_t)&fixed_arr2[i] << endl;

	//2. resizing 할 메모리 크기 입력

	int mdf_length;
	while (1)
	{
		cout << "\nWhat number would you like to resize this array? (n > 3) : ";
		cin >> mdf_length;

		if (cin.fail())
		{
			cin.clear();
			cin.ignore(32767, '\n');
			continue;
		}
		else break;
	}

	//3. 더 큰 메모리 정의 및 element 복붙

	int* mdf_arr2 = new int[mdf_length];

	for (int i = 0; i < 3; i++)
		mdf_arr2[i] = fixed_arr2[i];

	//4. 나머지 메모리 element 입력

	for (int i = 0; i < mdf_length - 3; i++)
	{
		int j;

		while (1)
		{
			cout << i + 3 + 1 << "번째 element를 입력하세요. : ";
			cin >> j;
			if (cin.fail())
			{
				cin.clear();
				cin.ignore(32767, '\n');
				continue;
			}
			else break;
		}

		mdf_arr2[i + 3] = j;
	}

	//5. 기존 array 반환

	delete[] fixed_arr2;

	//6. resizing한 array element 및 메모리 주소 출력

	for (int i = 0; i < mdf_length; i++)
		cout << mdf_arr2[i] << "\t\t" << (uintptr_t)&mdf_arr2[i] << endl;

	delete[] mdf_arr2;

	return 0;
}

array resizing 코드를 직접 짜봤는데요.

/*아쉬운 부분*/에서 매직넘버 3을

sizeof(fixed_arr2) / sizeof(int)

로 표현하지 못하는게 조금 아쉽네요. fixed_arr2는 동적 할당시킨 포인터(4바이트)니까요.

동적 할당된 array 크기를 나타내는 매직 넘버를 표현할 다른 테크닉이 있을까요?

그리고 결과가 아래 사진과 같은데,

원래 15529624로 시작하던 메모리 주소가 새로 복붙한 array는 15492176으로 시작하니 제가 의도하던 resize가 아닌 것 같아서 여쭙습니다. 정확히 기존에 차지하던 15529624 주소부터 시작할 방법은 없을까요??

그리고 3. 더 큰 array에 element를 복붙하는 과정에서 오버런 경고는 어느정도 이해가 갑니다. 20바이트 자리에 8(element 3개 = 12가 아닌가?)바이트만 썼다고 하네요.

 근데 동적 할당하기 위해 포인터로 선언한 mdf_arr2와 fixed_arr2는 각 요소를 dereference하기 위해 아래와 같이 * 문자를 써야 하지 않나요? 이렇게 쓰니 오류가 납니다.

*mdf_arr2[i] = *fixed_arr2[i];   혹은   mdf_arr2[i] = *fixed_arr2[i];

질문이 많네요 ㅎㅎ 읽어주셔서 감사합니다. 항상 질문 탭에서도 도움받고 있습니다.

답변 2

·

답변을 작성해보세요.

4

안소님의 프로필

안소

2021.02.06

안녕하세요.

1.

검색해보니 _msize 라는 함수가 있다고 나오네요. 포인터를 넘기면 그 포인터가 참조 하고 있는 힙 메모리의 유효한 크기 알려주는 함수라고 합니다. 

2.

int* mdf_arr2 = new int[mdf_length]; 로 기존 메모리와 관련 없이 운영체제로부터 전혀 다른 공간의 새로운 힙메모리를 생성 받고 그 곳에 데이터를 전부 복사하여 새로운 사본을 만든 것이나 마찬가지이니 resize 하기 전 주소와 다를 수 밖에 없습니다.

질문자님께서 원하시는 것은 resize할 때 아예 새로운 메모리로 이사가는 것이 아닌, 추가하려고 할 때마다 기존 메모리의 뒷 부분을 새롭게 할당받아 그곳에 추가하여 기존 메모리가 이사가는 일 없도록, 주소가 바뀌는 일 없도록 하고 싶으신 것으로 이해했는데 맞을까요? 

가능은 합니다. 특정한 주소에다가 동적할당을 받는 방법은 아래 링크들을 참고해주세요.

https://stackoverflow.com/questions/10364582/can-i-allocate-a-specific-memory-address-using-pointers-in-c

https://stackoverflow.com/questions/25269071/specific-memory-allocation-c

그러나 굳이 이렇게 할 필요가 없습니다. 주소를 반드시 유지해야할 특별한 이유가 있는 것이 아니라면 이렇게 하는 것은 비효율적인 코드 입니다.

동적 할당받는 것은 나름 비싼 연산입니다. 그래서 동적 할당 받는 행위는 줄이는게 프로그램 성능에 좋습니다. 위와 같이 하면 추가할 때마다 계속 그 추가하는 만큼을 기존 메모리의 뒤에다가 할당 받기 위하여 위 링크에서 소개하는 방법으로 특정한 주소에다가 매번 동적할당 받는 일을 해야한다는 것인데 조금 부담스러운 일이 될 수 있습니다.

그래서 특별히 주소를 유지해야할 사항이 있는게 아니라면 처음부터 좀 여유로운 공간의 동적할당을 한꺼번에 할당 받고, 추가할 때마다 동적할당 받을 필요 없이, resizing 할 필요 없이 원래 있는 장소인데 새롭게 추가된 것처럼 여유 공간에다가 값을 대입해 추가하는.. 이런식으로 보통 코드를 짭니다! 

 C++ STL 에서 제공하는 동적배열인 vector 또한 뒤에 추가하는 push_back도 위와같이 구현이 되어 있습니다. 처음부터 좀 여유롭게 크게 메모리를 잡아두고 실제로 vector의 원소 개수라고 사용되는 공간은 그것보다 작지만 추가할 때마다 새롭게 동적할당 받을 필요 없이 원래 크게 잡아둔 여유 공간에다가 값을 대입하고 원소 개수가 늘었다고 꼼수를 쓰는 것이죠! 

3. 

https://docs.microsoft.com/ko-kr/cpp/code-quality/c6386?view=msvc-160

https://stackoverflow.com/questions/41943803/visual-studio-2015-code-analysis-c6386-warns-of-buffer-overrun

https://stackoverflow.com/questions/37205179/vs2015-c6386-buffer-overrun-while-writing-even-for-same-index-value

오버런에 대해서는 위 링크들을 읽어보시면 도움 되실 것 같습니다. 

fixed_arr2이 가리키고 있는 공간은 12byte겠지만 그건 프로그램을 실행 해 봐야 알 수 있는 부분입니다. 동적으로 할당받기 때문입니다. 이렇게 프로그램 실행 전인, 밑줄로 경고를 해주는 시점에선 fixed_arr2의 길이가 어떤지 알 수 없습니다. mdf_arr2의 길이도 마찬가지구요.

그래서 진짜로 8byte만 사용했다고 경고하는 의미는 아닐 것입니다. 정적 배열이 아니라 동적 배열이다보니 아직 프로그램 실행 안해봐서 잘 모르지만 프로그램 막상 실행하면 혹시라도 범위 벗어날지도 모르니 확인해봐 정도의 경고로만 이해해주시면 될 것 같아요!  

*는 안쓰셔도 됩니다. fixed_arr2[i] 자체가 dereferencing 한 것입니다. 

포인터[n] 연산은 곧 *(포인터 + n) 산술 연산에 dereferencing 한 것과도 같습니다.

fixed_arr2[i]  는 *(fixed_arr2 + i) 와도 같습니다.

이 부분은 앞에서 배우신 포인터와 배열 부분을 다시 한번 생각해주세요! 

0

po127992님의 프로필

po127992

질문자

2021.02.06

메모리 주소까지 지정하는 치밀한 코딩은 지양하는가 보군요!
링크 꼼꼼히 읽어보았고 궁금한 점들이 시원하게 해결되었습니다. 감사합니다:)