ft_calloc & ft_memset

ft_calloc & ft_memset

“ft_calloc, ft_memset에 대하여”

<목차>

1. MY CODES

2. MAN CALLOC

3. MAN MEMSET

4. MEMSET 주의점

calloc — Memory Allocation

memset — fill a byte string with a byte value

(1) MY CODES

#include "libft.h"

// here ft_calloc()
void	*ft_calloc(size_t count, size_t size)
{
	void	*ptr;

	ptr = malloc(count * size);
	if (!ptr)
		return (NULL);
	ft_memset(ptr, 0, count * size);
	return (ptr);
}

// here ft_memset()
void	*ft_memset(void *dest, int c, size_t n)
{
	unsigned char	*new_dest;
	unsigned char	src;
	size_t			i;

	new_dest = dest;
	src = c;
	i = 0;
	while (i++ < n)
		*new_dest++ = src;
	return (dest);
}

(2) MAN CALLOC

SYNOPSIS
 #include <stdlib.h>

  void *malloc(size_t size);

  void *calloc(size_t count, size_t size);

DESCRIPTION
 The malloc() function allocates size bytes of memory and returns a pointer to the allocated memory.

 The calloc() function contiguously allocates enough space for count objects
 that are size bytes of memory each and returns a pointer to the allocated
 memory. The allocated memory is filled with bytes of value zero.
  • malloc()의 경우, size bytes 만큼의 메모리를 할당하고, 그 첫 번째 주소를 반환한다.
  • calloc()의 경우, 연속적으로 count만큼의 영역에, size bytes 만큼의 메모리를 할당한다. 할당된 메모리는 0으로 초기화된다.
  • 두 함수의 사용법이 미묘하게 다른데, 본질적으로는 동일하게 사용된다. 아래는 5개짜리 int 배열을 만들고 0으로 초기화하는 간단한 코드이다.

  • count나 size가 0이면 calloc()은 NULL을 반환하거나, 이후 free()에 무사히 전달할 수 있는 고유한 포인터 값을 반환한다.

    -> calloc(3) - Linux man page

    ” The calloc() function allocates memory for an array of nmemb elements of size bytes each and returns a pointer to the allocated memory. The memory is set to zero. If nmemb or size is 0, then calloc() returns either NULL, or a unique pointer value that can later be successfully passed to free().

  • count와 size의 곱이 정수 오버플로우를 일으킬 경우 calloc()은 errno를 설정하고(ENOMEM) NULL을 반환한다.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main()
{
	int*	arr = malloc(sizeof(int) * 5);
	memset(arr, 0, 5 * sizeof(int));
	int*	arr_c = calloc(5, sizeof(int) * 5);

	printf("%d, %d\n", arr[0], arr_c[0]);
}
output: 0, 0
  • malloc은 기본적으로 할당한 메모리를 초기화하지 않기 때문에, 별도의 초기화 작업이 반드시 필요하다. 이 부분을 소홀히 하면 나중에 난리가 날 수 있기 때문에 신경써주도록 하자…

(3) MAN MEMSET

SYNOPSIS
 #include <string.h>

  void *memset(void *b, int c, size_t len);

DESCRIPTION
 The memset() function writes len bytes of value c (converted to an unsigned char) to the string b.

RETURN VALUES
 The memset() function returns its first argument.
  • 첫 번째 인자는 초기화하고자 하는 메모리의 첫 번째 주소, 두 번째 인자는 세팅하고자 하는 값 value, 세 번째 인자는 시작 메모리로부터 초기화하고자 하는 메모리의 size이다.
  • 성공하면 초기화한 메모리의 첫 번째 주소를 반환하고 실패하면 NULL을 반환하는데, 보통은 반환받지 않고 동적 할당한 메모리를 초기화하는 용도로 주로 사용했던 기억이 난다.

(4) MEMSET 주의점

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

int main()
{
	int*	arr = malloc(sizeof(int) * 5);
	memset(arr, 1, 5 * sizeof(int));

	for (int i = 0; i < 5; i++)
		printf("arr[%d] : %d\n", i, arr[i]);
}
output:
        arr[0] : 16843009
        arr[1] : 16843009
        arr[2] : 16843009
        arr[3] : 16843009
        arr[4] : 16843009
  • 정수로 초기화하겠다는 것은 4 bytes로 초기화하겠다는 것을 의미한다. 그러나 memset()은 1바이트씩 초기화하기 때문에 예상할 수 없는 방식으로 작동한다.
  • 따라서 0으로만 초기화하거나, 제한적으로 char만을 사용하여 초기화하는 것이 안전한 방법이다.
      0001  0001  0001  0001 => 16843009
     1byte 1byte 1byte 1byte
    
      0000  0000  0000  0001 => 1
                      4bytes
    
  • 저 16843009의 경우, 위와 같은 모습때문에 등장하게 된 숫자이다. memset에 0이외의 정수를 넣고 초기화하는 것이 어떤 식으로 작동하게 될 지 간접적으로 볼 수 있는 예제이기도 하다.