Category (Click)
개발보드 덕질하기

[2023 방통대 C 스터디] 11. [memory.h] 데이터를 복사할 땐,

2023 방통대 C 스터디 강의노트
한국방송통신대학교 컴퓨터과학과의 C언어 스터디에 사용한 자료입니다.
배움은 끝이 없기에 강의노트라 하더라도 오류가 있을 수 있으며, 이 점에 대해서는 둥글게 지적 부탁드립니다.
읽기 전 아래 내용을 숙지하여주시기 바랍니다.
강의 노트에서 중요한 부분은 이렇게 노란색 전구()로 강조합니다.
한국어로 번역했을 때 뜻이 명확하지 않은 일부 용어는 의미를 분명히 하기 위해 한국어로 뜻을 번역하지 않고 영어 원문을 그대로 사용하거나 말음을 한국어로 표기합니다.
강의 노트는 스터디 내용을 대체할 수 없으며 이해를 위한 자세한 내용은 스터디에서 언급합니다.
강의 노트는 Light 테마에서 보시는것을 권장합니다.
스터디는 Windows 11, Visual Studio IDE 환경에서 진행합니다.
mac인 경우 패러렐즈를 이용해 Windows 11 ARM을 설치하여 동일하게 진행할 수 있습니다.
모든 강의 노트의 저작권은 작성자 차완기에게 있으며 무단 복제를 금합니다.

#방통대 2023 C 스터디 강의노트 태그 전체 글보기

앞서 알아본 string.h 라이브러리를 사용하면 문자열을 간편하게 복사할 수 있었습니다. 그럼 문자열 이외의 숫자 배열이나 구조체의 배열 등은 어떻게 복사할까요?
일반적인 자료형의 변수부터 배열, 주조체 등 모든 변수들은 메모리에 저장되기 때문에 메모리 속의 내용을 복사해버리면 간단하게 해결됩니다. memory.h 라이브러리 의 주요 함수를 알아보도록 하겠습니다.

데이터 복사 - memcpy()

memcpy() 함수는 메모리를 복사하는 함수입니다.
void *memcpy(void *dest, const void *src, size_t n);
C
복사
dest : 복사 대상 메모리 블록을 가리키는 포인터
src : 복사할 메모리 블록을 가리키는 포인터
n : 복사할 바이트 수
반환값 : 복사 성공 시 *dest
일반적으로 복사할 바이트의 수의 계산에는 sizeof() 연산자를 사용합니다. 예를 들어 char타입의 4칸짜리 배열(또는 길이가 4인 문자열)의 크기는 아래와 같이 알아낼 수 있습니다.

배열의 복사

코드
위 코드는 member_t 형 구조체 배열인 members를 동일한 구조체 배열인 members_cpy에 복사하는 예제 코드입니다. 배열이건 구조체건 간에 메모리에 연속적으로 저장된 데이터이기 때문에 복사 할 데이터의 시작 지점(포인터)과 데이터의 크기만 알면 복사할 수 있습니다. 여기에서는 members의 크기를 알아내기 위해 구조체의 크기를 sizeof() 연산자를 통해 알아낸 뒤 배열의 길이인 2를 곱해 memcpy()함수의 세 번째 인자값으로 전달하였습니다.
출력은 다음과 같습니다.
m_id: 1 m_nm: qwer m_age:10 m_id: 2 m_nm: asdf m_age:20
Plain Text
복사

non-null-terminated 문자열의 복사

이전 [string.h] 파이썬은 되던데… 과정에서 문자열의 복사에는 strcpy()함수를 사용한다고 하였습니다. 이 함수 대신 memcpy()함수를 이용해서도 문자열을 복사할 수 있습니다. 가끔 문자열이 non-null-terminated 형태로 길이와 함께 전달되거나 문자열 안에 NULL기호가 들어있어야 한다면 memcpy()를 사용하면 간편하고 효율적입니다.
코드
위 코드의 출력은 다음과 같습니다.
asdf
Plain Text
복사

null-terminated 문자열의 복사

strcpy()를 사용해도 무방하지만 memcpy()strlen()을 사용하여도 동일하게 동작합니다. 다만, strcpy() 함수는 NULL 문자 탐색으로 인해 반복문으로 메모리를 복사하는 반면, memcpy() 함수는 운영체제의 메모리 복사 API를 사용해 strcpy()에 비해 일부 상황에서 효율적일 수 있습니다.
코드
위 코드의 출력은 다음과 같습니다.
asdf
Plain Text
복사

메모리 byte 특정 값 설정 - memset()

memset()함수는 지정한 공간의 메모리 블럭을 특정 값으로 설정하는 함수입니다. 보통 구조체나 배열을 생성할 때 데이터를 0으로 초기화할 때 주로 사용합니다.
void *memset(void *s, int c, size_t n);
Plain Text
복사
void *s : 설정할 메모리 블록을 가리키는 포인터
int c : 설정할 값
size_t n : 설정할 바이트 수
반환값 : 설정이 완료된 메모리 블럭 포인터
코드
위 예제에서는 student_t 타입 구조체의 멤버 변수를 0으로 초기화하는 방법을 보여줍니다. memset() 함수를 사용하여 구조체의 포인터와 크기를 전달하여 0으로 초기화합니다. 이렇게 초기화하면 구조체의 모든 멤버 변수가 0 또는 NULL로 설정됩니다.
위 코드의 출력은 다음과 같습니다. 이름의 경우 ASCII에서 NULL 문자에 대응하는 0으로 채워져 아무런 문자가 출력되지 않습니다.
id: 0 name: age: 0
Plain Text
복사
여기서 착각하기 쉬운게, 설정할 값으로 1을 넣는다고 해서 변수의 값이 1이 되는 것은 아닙니다. memset() 함수는 전달한 범위 만큼의 메모리 블럭을 특정 수로 설정하는것이며, 이때 4 byte의 저장공간을 가지는 int형 변수의 경우 변수의 데이터를 담고 있는 4개의 각 블럭에 1(0b00000001)이 저장되어 실제로 저장되는 수는 signed int 타입이기 때문에 16843009(0b00000001000000010000000100000001)가 됩니다.

메모리 블록 데이터 비교 - memcmp()

string.hstrcmp()가 있듯이, memory.h에도 메모리를 비교하는 함수가 있습니다.
int memcmp(const void *s1, const void *s2, size_t n);
C
복사
const void *s1 : 비교할 첫 번째 메모리 블록을 가리키는 포인터
const void *s2 : 비교할 두 번째 메모리 블록을 가리키는 포인터
size_t n : 비교할 바이트 수
반환값 : 두 메모리 데이터가 같으면 0, 다르면 음수 또는 양수 반환
코드
member_t 타입의 구조체 s1에 데이터를 입력하고 이를 memcpy() 함수를 이용해 s2에 복사한 후 s1s2를 비교하는 예시입니다. 당연하게도 내용이 복사되었기 때문에 두 구조체의 데이터는 동일합니다.
위 코드의 출력은 다음과 같습니다.
두 구조체의 내용은 동일합니다.
Plain Text
복사