티스토리 뷰

저자는 메모리 동적 할당 및 해제를 "어른스러운 혹은 자유에 대한 책임이 따르는 메모리 사용방법"이라고 비유합니다.

 

malloc() 함수와 free()함수를 소개하겠습니다.

 

이 함수들을 호출하기 위해서는 헤더에 #include<stdlib.h>를 포함해야합니다.

 

malloc() 함수는 인수로 전달받은 정수만큼의 바이트 단위 메모리를 동적으로 할당하고 주소를 반환합니다. 이 주소는 할당받은 메모리 전체에 대한 기준주소입니다. 따라서 이 주소를 기준으로 나머지에 접근할 수 있습니다.

그리고 사용이 끝난 다음에는 반드시 free() 함수를 이용해 메모리를 운영체제에 반환해야합니다.

 

void *malloc(size_t size);
인자 size  할당받을 메모리의 바이트 단위 크기
반환값

힙 영역에 할당된 메모리 덩어리 중 첫 번째 바이트 메모리의 주소

에러가 발생하면 NULL 반환

설명 할당받은 메모리는 반드시 free() 함수를 이용하여 반환해야 하며, 메모리를 초기화하려면 memset() 함수를 이용해야합니다. 기본적으로는 쓰레기 값이 들어 있습니다.
void free(void *memblock);
인자 memblock  반환할 메모리의 주소
반환값 없음
설명 동적으로 할당받은 메모리를 운영체제에 반환하는 함수

 

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

int main(void) {
	int* pList = NULL, i = 0;

	//12바이트(sizeof(int) * 3) 메모리를 동적 할당하고 시작주소를 pList 포인터 변수에 저장.
	pList = (int*)malloc(sizeof(int) * 3);

	//동적 할당한 대상 메모리를 배열 연산자로 접근한다.
	pList[0] = 10; // *(pList + 0) = 10;
	pList[1] = 20; // *(pList + 1) = 20; 과 같은코드도 똑같이 작동
	pList[2] = 30;

	for (i = 0; i < 3; i++)
		printf("%d\n", pList[i]);

	//동적 할당한 메모리를 해제한다.
	free(pList);
	return 0;
}

동적할당된 주소에 포인터 변수를 이용해 값을 할당하는 모습

 

메모리 초기화 및 사용(배열)

변수를 선언하면 즉시 0으로 초기화하는 것이 일반적입니다. 그러므로 할당된 메모리는 일단 0으로 초기화하는 것이 바람직합니다.

 

동적 할당된 메모리를 초기화하는 두 가지 방법을 교재에서는 소개하고 있습니다.

 

#include<stdio.h>
//malloc(), calloc() 함수를 위한 헤더 포함
#include<stdlib.h>
//memset() 함수를 위한 헤더 포함
#include<string.h>

int main(void) {
	int* pList = NULL, * pNewList = NULL;

	//A. int형 3개 배열 선언 및 정의(0 초기화)
	int aList[3] = { 0 };

	//B. int형 3개를 담을 수 있는 크기의 메모리를 동적으로 '할당한 후 메모리를 모두 0으로 초기화'
	pList = (int*)malloc(sizeof(int) * 3);
	memset(pList, 0, sizeof(int) * 3);

	//C. int형 3개를 담을 수 있는 메모리를 0으로 '초기화한 후 할당'받음
	pNewList = (int*)calloc(3, sizeof(int));

	//동적 할당한 메모리들을 해제
	free(pList);
	free(pNewList);
	return 0;
}

여기에서 쓰인 memset()함수와 calloc()함수에 대해 알아보겠습니다.

 

void *memset(void *des, int c , size_t count);
인자

dest

초기화할 대상 메모리 주소

c

초깃값, 이 값이 0이면 메모리를 0으로 초기화

count

초기화 대상 메모리의 바이트 단위 크기

반환값 대상 메모리 주소
설명 동적으로 할당받은 메모리에는 쓰레기 값이 있으므로 일반적으로 0으로 초기화하여 사용한다.
void *calloc(size_t num, size_t size);
인자 num 요소의 개수
size 각 요소의 바이트 단위 크기
반환값

힙 역역에 할당된 메모리 덩어리 중 첫 번째 바이트 메모리의 주소

할당된 메모리  크기는 num 인자와 size 인자의 값을 곱한 크기

설명 이 함수는 malloc() 함수와 달리 할당받은 메모리를 0으로 초기화하여 전달한다.

////

#include<stdio.h>
//malloc(), calloc() 함수를 위한 헤더 포함
#include<stdlib.h>
//memset() 함수를 위한 헤더 포함
#include<string.h>

int main(void) {
	// 선언할 배열 요소의 크기를 기술하지 않았지만 초깃값을 기준으로 자동으로 크기가 결정된다. (NULL 문자 포함)
	char szBuffer[] = { "Hello" };

	//"Hello" 문자열이 저장된 메모리의 주소로 초기화되는 포인터 변수
	char* pszBuffer = "Hello"; // 동적할당 x

	//동적 할당한 메모리의 주소가 저장될 포인터 선언 및 정의
	char* pszData = NULL;
	//메모리를 동적으로 할당하고 "Hello"문자열로 초기화
	pszData = (char*)malloc(sizeof(char) * 6);
	pszData[0] = 'H';
	pszData[1] = 'e';
	pszData[2] = 'l';
	pszData[3] = 'l';
	pszData[4] = 'o';
	pszData[5] = '\0';

	puts(szBuffer);
	puts(pszBuffer);
	puts(pszData);
	
	free(pszData);
	return 0;
}

이러한 방식으로도 다룰수 있다.

 

메모리 복사

배열처럼 여러 인스턴스가 뭉쳐진 경우엔 절대로 단순 대입으로 r-value를 l-value로 복사할 수 없습니다. 

 

memcpy() 함수를 이용하여 인수로 전달된 두 주소의 메모리에 담긴 정보를 복사할 수 있습니다.

void *memcpy(void *dest, const void *serc, size_t count)
인자 dest 대상 메모리 주소
src 복사할 원본 데이터가 저장된 메모리 주소
count 복사할 메모리의 바이트 단위 크기
반환값 대상 메모리 주소
설명 특정 주소로 시작하는 일정 길이의 메모리에 저장된 값을 대상 메모리에 그대로 복사해준다.
#include<stdio.h>
//malloc(), calloc() 함수를 위한 헤더 포함
#include<stdlib.h>
//memset() 함수를 위한 헤더 포함
#include<string.h>

int main(void) {
	char szBuffer[12] = { "HelloWorld" };
	char szNewBuffer[12] = { 0 };

	memcpy(szNewBuffer, szBuffer, 4);
	puts(szNewBuffer);

	memcpy(szNewBuffer, szBuffer, 6);
	puts(szNewBuffer);

	memcpy(szNewBuffer, szBuffer, 12);
	puts(szNewBuffer);
	return 0;
}

'szNewBuffer = szBuffer;' 라는 코드의 개념적 의미는 짐작할수 있지만, 문법적으로는 절대 허용되지 않는 연산입니다.

 

그러므로, 이연산이 가능하도록 하려면 각 배열의 요소만큼 반복문을 수행하여 요솔별로 일일이 단순 대입 연산을 수행해주어야 합니다. 그러나 이 귀찮은 일을 memcpy() 함수가 대신 할 수 있습니다.

 

메모리 비교 - memcmp(), strcmp()

int memcmp(const void *buf1, const void *buf2, size_t count);
인자 buf1 비교 원본 메모리 주소
buf2 비교 대상 메모리 주소
count 비교할 메모리의 바이트 단위 크기
반환값

결과가 0이면 두 값은 같음

0보다 크면 buf1이 buf2보다 더 큼

0보다 작으면 buf2가 buf1보다 더 큼

단, 뺄셈 연산을 수행할 때 unsigend char형으로 처리, 따라서 -1은 255로 처리

설명 첫 번째 인자로 전달된 주소의 메모리에 저장된 값에서 두 번째 인자로 전달된 주소에 저장된 메모리의 값을 뺴서 두 값이 같은지 비교한다. 즉, 주어진 길이만큼 두 메모리를 비교하는 함수이다.
int strcmp(const char *string1, const char *string2);
인자 string1 비교할 문자열이 저장된 메모리 주소
string2 비교할 문자열이 저장된 메모리 주소
반환값

두 문자열이 같으면 0 반환

만일 0보다 큰 수를 반환하면 string1이 string2보다 알파벳 순서상 나중이고,

0보다 작으면 string2가 나중임을 의미

설명 대소문자를 식별하여 두 문자열이 같은지를 비교하는 함수
#include<stdio.h>
#include<string.h>

int main(void) {
	char szBuffer[12] = { "TestString" };
	char* pszData = "TestString";

	// 다음 코들은 주소와 상관없이 대상 메모리에 ㅔ저장된 문자열이 같은 비교한다.
	// 만일 길이가 다르면 무조건 같은 문자열이 아니다.
	printf("%d\n", strcmp(szBuffer, pszData));
	printf("%d\n", strcmp("TestString", pszData));
	printf("%d\n", strcmp("Test", pszData));

	return 0;
}

 

문자열 검색 - strstr()

char *strstr(const char *string, const char *strCharSet);
인자 string 검색 대상이 될 문자열이 저장된 메모리 주소
strCharSet 검색할 문자열이 저장된 메모리 주소
반환값

문자열을 찾으면 해당 문자열이 저장된 메모리 주소 반환

찾지 못하면 NULL 반환

설명 임의의 대상 문자열에서 특정 문자열을 검색하는 함수

 

*(기준주소 + 인덱스) 나 기준주소[인덱스] 나 같은 의미입니다.

 

realloc(), sprintf() 함수

void   *realloc(void *memblock, size_t siez);
인자 memblock

기존에 동적 할당된 메모리 주소

만일 이 주소가 NULL이면 malloc() 함수와 동일하게 동작

size 다시 할당받을 메모리의 바이트 단위 크기
반환값

다시 할당된 메모리 덩어리 중 첫 번째 바이트의 메모리 주소

만일 다시 할당하는 데 실패하면 NULL 반환

이 경우 첫 번째 인자로 전달된 메모리를 수동으로 해제해야 함

설명

만일 이미 할당된 메모리 영역에서 크기를 조정할 수 있다면, 반환된 주소는 첫 번째 인자로 전달된 주소와 같다.

그러나 불가능하다면 기존의 메모리를 해제하고 새로운 영역에 다시 할당한 후, 새로 할당된 메모리의 주소를 반환한다.

int sprintf(char *buffer, const char *format [, argument] ...);
인자 buffer 출력 문자열이 저장될 메모리 주소
format 형식 문자열이 저장된 메모리 주소
[, argument] 형식 문자열에 대응하는 가변 인자들
반환값 출력된 문자열의 개수
설명 형식 문자열에 맞추어 특정 메모리에 문자열을 저장하는 함수

ex) sprintf(pszNewBuffer, "%s", "TestStringData");

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   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
글 보관함