memset 함수의 manual은 다음과 같다!

#include <string.h>
void *memset(void *b, int c, size_t len);
memset의 첫번째 인자는 void *b이다.
b는 일반적으로 메모리 블록을 가리키는 변수의 이름으로 사용되며, 흔히 block 또는 buffer를 의미한다.
void *는 c언어에서 모든 데이터 타입을 가리킬 수 있는 포인터 타입이다. 특정 데이터 타입에 구애받지 않고 임의의 메모리 주소를 가리킬 수 있는 포인터로 범용성을 위한 포인터이다.
아래의 예시를 보면 이해하기 더 좋을 것이다.
int main() {
int i_val = 42;
double d_val = 3.14;
char c_val = 'a';
void *ptr;
// int 타입 변수 가리키기
ptr = &i_val;
printf("i_val = %d\n", *(int *)ptr);
// double 타입 변수 가리키기
ptr = &d_val;
printf("d_val = %.2lf\n", *(double *)ptr);
// char 타입 변수 가리키기
ptr = &c_val;
printf("c_val = %c\n", *(char *)ptr);
return 0;
}
대신 가리키는 변수를 사용할 때는 적절한 타입으로 캐스팅해야 한다.
void 포인터가 필요한 이유typedef struct s_node {
void *data;
struct s_node *next;
} t_node; //링크드 리스트, 트리 등의 노드가 다양한 타입의 데이터를 저장할 수 있도록 `void *`를 사용
malloc과 같은 동적 메모리 할당 함수는 메모리 블록을 반환하지만, 반환되는 블록의 타입을 미리 알 수 없기에 void *를 사용하여 타입에 관계없이 동적 메모리를 관리할 수 있다.memset함수는 len바이트만큼을 c로(unsigned char로 변환된) 문자열 b에 쓴다.char buffer[100];
int array[50];
// buffer를 0으로 초기화
memset(buffer, 0, sizeof(buffer));
// array를 -1로 초기화
memset(array, -1, sizeof(array));
b를 반환한다.굳이 반환값을 가질 필요가 있을까 싶지만 아래와 같은 이유로 반환값 b를 가진다!
strcpy(memset(buffer, 0, sizeof(buffer)), "Hello, World!");
C 표준 라이브러리의 많은 함수들은 입력 포인터를 반환하는 패턴을 따른다.
이는 함수의 일관된 인터페이스를 유지하게 해주며,
개발자가 이러한 함수들을 사용할 때 예측 가능한 동작을 제공한다.
직접 루프를 작성하여 값을 설정하는 것보다 memset 함수가 최적화되어 있어 더 빠르다.
memset을 사용하여 메모리를 명확히 초기화함으로써 이전에 저장된 임의의 데이터에 의한 예기치 않은 동작을 방지한다.
초기의 컴퓨터 시스템은 메모리 초기화 작업이 자주 필요했으며, 이를 최적화하기 위해 하드웨어 레벨에서 빠르게 수행될 수 있는 함수가 필요했고 이러한 필요에 따라 memset이 최적화된 메모리 초기화 방법을 제공한다.
void *ft_memset(void *b, int c, size_t len)
{
unsigned char *ptr; // Description에서 `c`는 unsigned char로 변환되어 쓰이기에 unsigned char *로 선언
unsigned char value; // Description에서 `c`는 unsigned char로 변환되어 쓰이기에 unsigned char로 선언
ptr = (unsigned char *) b;
value = (unsigned char) c;
while (0 < len) // len > 0으로 쓰는 것이 더 전통적인 방법이긴 하다.
{
*ptr = value;
ptr++;
len--;
}
return (b);
}