[C]memset
memset함수는 크기만큼 문자를 채우는 함수입니다.
1️⃣ 함수원형
< memset >
void *memset(void *ptr, int value, size_t size)
2️⃣ 헤더파일, 반환값
반환값:
조건 반환값(void *) 성공시 복사완료된배열의 주소 ptr이 NULL일때 segmentation fault size > ptr크기 윈도우: 경고없이 컴파일됨
리눅스: 경고출력, 컴파일에러size = ptr크기 컴파일됨(위험한상태) 헤더파일: <string.h>
3️⃣ 함수구현
< memset >
void *memset(void *ptr, int value, size_t size)
{
unsigned char *pb;
pb = ptr;
while (size-- > 0)
*pb++ = value;
return (ptr);
}
4️⃣ 특징 & 주의사항
- 자료형이 size_t인 size의 값이 음수가 되면 버퍼오버플로우(size_t는 unsigned형으로 선언되어 있기 때문)가 일어납니다. 컴파일러에 따라서 경고메시지를 출력해주고 컴파일이 되지 않습니다. 하지만 컴파일이 되는 경우가 있는데 소유하고 있지않는 메모리에 value값이 채워지므로 위험해질 수 있습니다.
- 메모리를 잘 다룰 수 있지 않는이상 1byte크기의 자료형만 사용하는 것이 좋습니다.(아래 자세한 내용)
- 0으로 초기화하는데 좋은 함수이며 2차원배열도 0으로 초기화 시켜줄 수 있습니다.(아래 자세한 내용)
- NULL문자(‘\0’)를 문장끝에 붙여주지 않기 때문에 크기를 잘 고려해서 사용해야 됩니다.
ex>char word[5];
를 다룬다면 3번째 인자의 값이 4가 되도록하여 끝의 ‘\0’를 그대로 두는 것이 안전 합니다.
5️⃣ 코드예시(특이케이스)
1. < 1byte가아닌 자룔형으로 memset함수 사용할 경우(특징2) >
#include <stdio.h>
#include <string.h>
int main(void)
{
int word[6] = {1,2,3,4,5};
int *temp;
temp = k_memset(word, 3, 5 * sizeof(int));
for (int i = 0; i < 5; i++)
printf("%d ", temp[i]);
printf("\n");
}
/* ---결과--- */
50529027 50529027 50529027 50529027 50529027
- 기대값:
3 3 3 3 3
- 출력값:
50529027 50529027 50529027 50529027 50529027
- 원인: 4byte크기의 int자료형을 사용
이유: memset함수는 내부적으로 (unsigned char[1byte])단위로 복사하게 됩니다. 위 코드의 경우 int형 자료형의 메모리가 1byte단위로 3이 복사되어 ‘03 03 03 03’가 되고 10진수로 50529027(= 0x03030303)이 됩니다.
- 결론: 1byte단위로 값을 채우는 형식이기 때문에 1byte의 크기가아닌 자료형을 사용하면 예상치 못한 결과가 생길 수 있습니다. 하지만 단순히 0으로 초기화하는 것이 목적이라면 어떤한 자료형도 상관 없을 것 같습니다.
2. < 0으로 초기화할 경우(특징3) >
int main(void)
{
char sample1[20];
char sample2[6][10];
int sample3[20];
char *result1;
int *result2;
result1 = memset(sample1, 0, 20);
printf("일차원배열: %s\n", result1);
result2 = memset(sample2, 0, 6 * 10);
printf("이차원배열: %s\n", result2[0]);
result2 = memset(sample2, 0, 20 * sizeof(int));
printf("int자료형: ");
for(int i = 0; i < 19; i++)
printf("%d ", result2[i]);
printf("\n");
}
/*---출력---*/
일차원배열:
이차원배열: (null)
int자료형: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 이차원배열 또한 NULL포인터(void*(0))로 초기화가 잘 되었습니다.