본문 바로가기

씨플플

[C++] memset 함수 주의점에 대해서

대표적으로 배열과 같은 특정한 범위에 있는 연속적인 메모리에 값들을 지정할 때

memset 함수를 사용한다면 for문 보다 더 빠른 속도를 낼 수 있는 경우도 있다.

 

우선 함수의 원형은 void * memset ( void * ptr, int value, size_t num ); 이다.

이때 ptr은 채우고자 하는 메모리의 시작 주소이고, value는 값, num은 메모리의 크기이다.

 

다만 주의해야 할 점은 value가 int형이지만 내부적으로는 unsigned char(1byte)로 변환되어 저장된다.

#include <iostream>
#include <memory.h>
using namespace std;
int main()
{
	int arr[10];
	int brr[10];
	memset(arr, 0, sizeof(arr));
	memset(brr, -1, sizeof(brr));

	for (int i = 0; i < 10; i++)
		cout << arr[i] << ' ' << brr[i] << endl;
}

 

따라서 위의 예제 코드를 살펴보면 arr[10]과 brr[10]에 각각 0과 1로 초기화는 성공한 것을 확인할 수 있다.

내부적으로 살펴보면 정수 '0'과 '-1'은

각각 '00000000000000000000000000000000', '11111111111111111111111111111111'로 저장된다.

#include <iostream>
#include <memory.h>
using namespace std;
int main()
{
	int arr[10];
	memset(arr, 1, sizeof(arr));
	for (int i = 0; i < 10; i++)
		cout << arr[i]<<endl;
}

 

하지만 위와 같이 1로 초기화를 하려는 시도는 엉뚱한 값들이 들어간다.

이는 '1'이라는 정수가 내부에서는 '00000001000000010000000100000001'로 변환되기 때문이다.

 

따라서 1byte의 변수(char, unsigned char 등)를 제외하고는 0과 -1로만 초기화할 수 있다.


두 번째, 동적할당된 메모리를 초기화 할 때 조심해야 한다.

#include <iostream>
#include <memory.h>
using namespace std;
int main()
{
	int N;
	cin >> N;
	int* arr = new int[N];
	memset(arr, 0, sizeof(arr));
	for (int i = 0; i < N; i++)
		cout << arr[i] << endl;
}

 

엥? arr[0]은 0으로 초기화가 잘됐지만 arr[1]부터는 이상한 값들이 들어갔다.

위 코드에서 문제는 memset(arr, 0, sizeof(arr)); 이다.

왜냐하면 여기서 sizeof(arr)은 포인터의 크기 4byte이다. 따라서 arr이 가르키는 주소에서 시작해서

4byte만큼만 0으로 초기화하는 의미가 된다. 그래서 int형 배열의 하나의 원소(4바이트)만 초기화 된다.

 

#include <iostream>
#include <memory.h>
using namespace std;
int main()
{
	int N;
	cin >> N;
	int* arr = new int[N];
	memset(arr, 0, sizeof(int) * N);
	for (int i = 0; i < N; i++)
		cout << arr[i] << endl;
}

 

 memset(arr, 0, sizeof(int) * N); 로 바꾸니까 올바른 결과값이 나온다!


셋 째.

new, malloc등을 이용하여 동적으로 배열을 생성하는 변수가 있는 구조체나 클래스는 memset으로 초기화를 할 수 없다.

 

#include <iostream>
#include <memory.h>
using namespace std;
struct A
{
	int i;
	char* c;
};
void main()
{
	A a;
	a.c = new char[100];
	memset(&a, 0, sizeof(A));
	if (a.c != NULL)
	{
		delete[] a.c;
		a.c = NULL;
	}
}

위 예제코드에서 sizeof(A)는 8바이트( int i(4byte) + char*c(4byte) )가 된다.

따라서 memset(&a, 0, sizeof(A)); 는 a의 변수 i와 c의 값을 모두 0으로 설정한다.

이때, a.c에 동적으로 할당된 배열들은 초기화가 되지 못하고 메모리 누수가 발생한다.

a.i = 0;
memset(a.c, 0, sizeof(char)*100);

그러므로 이 경우처럼 동적으로 할당될 때는 위와 같이 따로 초기화 해야한다.


참고: https://beautyrain.tistory.com/7