공부

strlen, strcpy, strcmp / memcpy, memcmp 구현

CodingNabi 2026. 7. 11. 04:15

strlen

size_t strlen(const char* str);
  • 인자: str — 길이를 잴 널 종단 문자열의 시작 주소
  • 반환값: size_t — \0 직전까지의 문자 개수 (\0 자체는 카운트 안 함)
  • 설명: str부터 한 칸씩 전진하며 \0을 만날 때까지 카운트. \0을 찾아야 끝나는 구조라 시간복잡도 O(n). 순수 바이너리 데이터에 쓰면 안 됨(중간에 우연히 0바이트가 있으면 거기서 멈춰버림).

strcpy

char* strcpy(char* dest, const char* src);
  • 인자: dest — 복사받을 목적지 버퍼(반드시 src 길이+1 이상 크기여야 함) / src — 복사할 원본 널 종단 문자열
  • 반환값: char* — dest의 시작 주소 (체이닝 목적)
  • 설명: src를 처음부터 \0까지 한 바이트씩 dest에 복사, \0도 포함해서 복사함. dest 크기 체크를 안 해서 버퍼 오버플로우 위험이 있는 대표적 함수(strcpy_s, strncpy가 대안). src와 dest가 겹치면 undefined behavior.

strcmp

int strcmp(const char* s1, const char* s2);
  • 인자: s1, s2 — 비교할 두 널 종단 문자열
  • 반환값: int — s1 < s2면 음수, 같으면 0, s1 > s2면 양수
  • 설명: 앞에서부터 한 바이트씩 비교하다가 다른 문자를 만나거나 둘 중 하나가 \0에 도달하면 종료. 바이트는 unsigned char로 해석해서 비교(부호 문제 방지). strncmp(s1, s2, n)은 최대 비교 길이 n이 추가된 버전.

memcpy

void* memcpy(void* dest, const void* src, size_t n);
  • 인자: dest — 목적지 버퍼 / src — 원본 버퍼 / n — 복사할 바이트 수
  • 반환값: void* — dest의 시작 주소
  • 설명: \0이나 데이터 의미와 무관하게 무조건 n바이트를 그대로 복사. 구조체, 배열, 임의 바이너리 데이터에 다 사용 가능. dest와 src가 겹치면 undefined behavior — 겹칠 가능성이 있으면 memmove 사용해야 함.

memcmp

int memcmp(const void* s1, const void* s2, size_t n);
  • 인자: s1, s2 — 비교할 두 버퍼 / n — 비교할 바이트 수
  • 반환값: int — 첫 차이 지점에서 (unsigned char)s1[i] - (unsigned char)s2[i] 부호, 끝까지 같으면 0
  • 설명: \0을 특별 취급하지 않고 무조건 n바이트를 끝까지(또는 다른 지점까지) 비교. 구조체 비교, 해시값 비교, 바이너리 패킷 비교 등에 사용.

핵심 구분 기준

 

계열 str 계열 mem 계열
대상 텍스트(문자열), \0 종단 전제 순수 바이트 블록, 타입/의미 무관
길이 파악 직접 \0 찾아가며 판단 인자로 받은 n 그대로 사용
\0 만나면 거기서 비교/복사 종료 무시하고 계속 진행
대표 용도 문자열 처리 구조체, 바이너리 패킷, 해시값 비교/복사

구현

size_t my_strlen(const char* buf) {
	const char* b_temp = buf;
	while(*b_temp != '\0') {
		b_temp++;
	}
	return b_temp - buf;
}

char* my_Strcpy(char* dest, const char* src) {
	char* d_temp = dest;
	while (*src != '\0') {
		*dest = *src;
		dest++;
		src++;
	}
	*dest = '\0';
	return d_temp;
}


int my_strcmp(const char* buf1,const char* buf2, size_t t) {
	const unsigned char* b1_temp = (const unsigned char*)buf1;
	const unsigned char* b2_temp = (const unsigned char*)buf2;

	for (size_t i = 0; i < t; i++) {
		if (b1_temp[i] != b2_temp[i]) {
			return  b1_temp[i] - b2_temp[i];
		}
		if (b1_temp[i] == '\0') {
			return 0;
		}
	}
	return 0;
}

void* my_memcpy(void* dest, void* src, size_t t) {
	//파라미터가 void*형 변수이기 때문에 캐스팅을 하려 1바이트씩 복사.
	unsigned char* d_temp = (unsigned char*)dest;
	const unsigned char* s_temp = (const unsigned char*)src;
	for (size_t i = 0; i < t; i++) {
		d_temp[i] = s_temp[i];
	}
	return dest;
}

int my_memcmp(void* buf1, void* buf2, size_t t) {
	const unsigned char* b1_temp = (const unsigned char*)buf1;
	const unsigned char* b2_temp = (const unsigned char*)buf2;

	for (size_t i = 0; i < t; i++) {
		if (b1_temp[i] != b2_temp[i]) {
			return  b1_temp[i] - b2_temp[i];
		}
	}
	return 0;
}