티스토리 뷰

기본적인 문자열 할당 및 포인터 사용 - Heap

#include "stdafx.h"
#include "string.h"
#include "malloc.h"

const char *pcChar = "Test const string";
#define ALLOC_SIZE 100

int main(int argc, char *argv[])
{
	// '\0' 문자열을 포함해 99바이트를 저장할 수 있다.(ascii)
	char *test = (char *)malloc(ALLOC_SIZE);
	test[ALLOC_SIZE-1] = '\0';
	
	printf("%d\n", strlen(test));	

	strncpy(test, pcChar, strlen(pcChar) + 1);
	printf("%d\n", strlen(test));
	printf("%s\n", test);
	free(test);
	return 0;
}
힙을 사용하게 될 경우, malloc(int size) 를 통해 할당받고, 포인터를 받는다.

* malloc
return 받게 되는 포인터를 컴파일러는 어떠한 데이터형의 포인터인지 알 수 없으므로, (char *)와 같이 명시적 캐스트를 통해 알려주어야 한다.
만약, 동적 메모리 할당에 실패하게 된다면, NULL(0x00000000) 을 반환한다.
스택에 배열로 선언하는 경우와 다르게, malloc으로 받아오는 힙 메모리는 사용이 끝난 후 free(void * memoryPtr)를 이용해 해제하지 않으면 포인터를 잃어버린 상태로 메모리가 해제되지 않아 메모리 누수(Leak) 현상이 일어나므로 주의해야 한다.
할당된 메모리 공간에는 쓰레기 값이 들어있게 된다. 초기화하려면 memset(char * dest, int data, int size) 을 이용한다.

* 힙 사용의 장점
스택 공간의 경우 최대 1M(시스템, 컴파일러 따라 다름)까지 할당받을 수 있는 것과 다르게 좀 더 많은 메모리를 할당 받을 수 있다.
realloc(void * memoryPtr, int size)를 통해 할당된 메모리 크기를 변경할 수 있다. - 동적 할당 가능.
(경우에 따라 메모리 주소가 아예 변경되기도 하며, 이전의 메모리는 자동으로 해제됨)

문자열의 동적 할당에 대한 경우에는 메모리의 마지막을 알려주기 위해 배열 마지막에 terminator char 를 붙여준다.

* 문법
포인터로 선언한 경우, ex) char *ptr
ptr = &anotherVal;  // 특정 변수의 메모리 주소를 저장한다. 
printf("%x\n", &ptr); // 메모리 주소를 저장하고 있는 변수(포인터)의 메모리 주소를 반환한다.
printf("%c\n", ptr[idx]); // 포인터를 배열처럼 사용할 경우, 해당 데이터 (포인터 + idx 의 주소에 있는 데이터) 에 액세스 할 수 있다.

* 문자열 관련 작업 시 주의사항.
malloc을 통해 메모리를 할당받을 때는 저장하고 싶은 문자열 길이 + 1 을 할당받아야 한다.
이는 C, C++ 계열의 언어에서는 문자열의 끝을 나타내기 위해 terminator char가 반드시 필요하기 때문이다.
strncpy(char * dest, const char * src, int len)을 이용해 문자열을 복사할 경우에는 종료 문자를 뒤에 붙여주지 않기 때문에 수동으로 넣어줘야 함을 유의하자.



기본적인 문자열 할당 및 포인터 사용 - Stack
#include "stdafx.h"
#include "string.h"
#include "malloc.h"

const char *pcChar = "Test const string";

int main(int argc, char *argv[])
{
	char test[20];
	
	strncpy(test, pcChar, sizeof(test));
	printf("%d\n", sizeof(test));
	printf("%s\n", test);
}
스택을 사용하게 될 경우, 배열을 선언함은 곧 메모리를 할당받는다는 것을 의미한다.

* 문법
char mychar[size]; 
와 같이 메모리를 할당받을 때, size에는 무조건 상수가 입력되야 하며, 런타임 시에 변경될 수 없다.
(스택 프레임의 구조를 런타임마다 변경할 수 없음)

strncpy 함수는 dest 인자값을 char * 형식으로 받는다.
하지만 dest 인자값에 test 대신 &test 으로 전달하게 되면,
gcc 기반 컴파일러에서는 경고를 표시하지만 Visual C++ 기반 컴파일러에서는 에러를 낸다. (gcc 기반에서 컴파일하면 두 경우 모두 asm 코드가 같음.)

배열로 선언된 변수는 "[idx]" 를 붙이지 않고 사용하면, 기본적으로 "&" 를 사용해 포인터 주소를 가져온 것과 동일하게 사용할 수 있다.
-> printf("%x\n", arr_char); // 배열의 메모리 주소값을 hex로 반환

"[idx]" 를 사용하게 되면 배열의 시작점 + idx 를 이동한 메모리 주소의 값을 가져오거나, 설정할 수 있다.
-> printf("%c\n", arr_char[3]); // 배열의 4번째에 있는 문자 
// 이 상황에서 포맷 스트링으로 %s 을 사용하면, 2번째 인자의 값을 포인터로 취급하고 메모리에 액세스하므로, 프로그램이 Crash 될 확률이 대단히 높다.


* 또 다른 문법 (선언)
char *test = "My new string";
-> 이 때는 컴파일러가 자동으로 문자열의 갯수를 재서 최대 len(str) = sizeof(test)의 크기를 가지는 스택 프레임을 생성한다.

char test[] = "My new string";
-> 이 때도 마찬가지로 컴파일러가 자동으로 문자열의 갯수를 재서 최대 len(str) = sizeof(test)의 크기를 가지는 스택 프레임을 생성한다.

결국은 어떻게 선언해도 동일하게 배열 포인터로 사용할 수 있다. Handray 에서 조금 더 자세히 다룸. < LINK 1 >


'Programing > C++' 카테고리의 다른 글

C++ Assert를 이용한 프로그램 디버깅  (0) 2016.08.02
C++ 함수 오버로딩, 오버라이딩  (0) 2016.08.01
C++ 구조체, 구조체 포인터  (0) 2016.07.31
C++ 다중, 더블 포인터  (0) 2016.07.29
C++ 데이터 형  (0) 2016.07.23
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/01   »
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
글 보관함