본문 바로가기

C++

[TIL 14장] 메모리 함수, 콘솔/파일 입출력 함수[text]

오늘의 TIL 목차 (22.08. 11)

 

  • 메모리 함수 ( memset, memcpy, memmove )
  • 입출력 ( feat. stream )

메모리 함수


1. memset ( = ZeroMemory )     2. memcpy     3. memmove

[ 메모리 함수 ]

: 메모리 대 메모리로 단위로 데이터들을 변경하는 기능의 함수

[ memset ] = [ ZeroMemory ]

: 메모리 초기화 함수

#include <windows.h> // ZeroMemory 함수 사용 시 <windows.h> 헤더파일 포함

memset(void*  _Dst, int _Val, size_t _Size);
//(초기화하는 메모리 공간의 주소 값, 어떤 값으로 초기화 할 것인가, 얼마만큼의 메모리 크기를 초기화 할 것인가)

ZeroMemory(void*  _Dst, size_t _Size);
// (초기화하는 메모리 공간의 주소 값, 초기화할 메모리 크기)

■ 기능 / 주의

  • ZeroMemory() 함수 사용 시 <windows.h> 헤더파일을 포함시켜야 한다. 
  • memset은 초기값이 0, -1만 가능
  • ZeroMemory는 초기값 0 고정 ( 매개변수에 초기값 할당 X )

■ 예시

	int iArray[5] = { 1,2,3 };
	int iArray2D[][2] = { 10, 11, 12, 13, 14, 15 };

	cout << iArray1 << endl;
	cout << iArray2D[0][1] << endl;
	cout << iArray2D[1][0] << endl;

	cout << "memset = ZeroMemory" << endl;
	memset(iArray, 0, 4); // 초기값은 0과 -1만 가능
	cout << sizeof(iArray2D) / sizeof(int) << endl;
	ZeroMemory(iArray2D, 5); // int형이므로 4당 원소 하나 초기화
	cout << iArray2D[0][0] << endl << iArray2D[0][1] << endl;

	cout << iArray[1] << endl;
	/*for (int i = 0; '\0' != i; ++i)
	{
		cout << iArray[i] << endl;
	}*/

※ 주의사항

- memset ( 주소, 초기값,  초기화할 메모리 크기

- 복사할 메모리 크기가 5이면 int형 2차원 배열 iArray2D를 기준으로 원소 5개가 초기화되는 것이 아니라 원소 1개 = 4byte이므로 4byte + 1byte로 총 2개의 원소가 초기화된다. 

[ memcpy ]

: 메모리 복사 함수

memcpy(void* _Dst, void const* _Src, size_t _Size);
//(복사 받을 변수의 메모리 공간의 주소, 복사 할 원본 메모리 공간의 주소, 복사할 메모리 크기)

■ 예시

int iArray[5] = { 1,2 }; // 나머지 3개는 자동 0 초기화
int iArray2D[][2] = { 10, 11, 12, 13, 14, 15 }; 

// 크기는 4byte만큼 변경이므로 iArray2D[1]행의 0번째부터 12byte(int형 4byte * 3)인 3개 원소가 iArray값으로 대체
memcpy(iArray2D[1], iArray, 12); 

for (int i = 0; sizeof(iArray2D)/sizeof(int)>i; ++i)
	cout << *(*iArray2D + i) << "\t"; // 2차원 배열에서 *iArray2D + i는 시작주소부터 열단위로 i만큼 주소 이동

memcpy(iArray, iArray2D[2], sizeof(iArray));
cout << iArray[0] << "\t" << iArray[1] << endl;

출력 결과:
10	11	1	2	0	15
0	15 // iArray2D 2행이 iArray 크기 (4byte * 원소 개수)만큼 iArray에 복사된다.

※ 주의사항

- memcpy ( 주소, 주소, 복사할 메모리 크기

- sizeof(iArray) 해야 전체 배열 원소 변경, sizeof(iArray) / sizeof(int)를 해버리면 원소 개수인 5가 되면서 5byte 크기만큼 총 원소 2개만 복사 변경 된다.

[ memmove ]

: 메모리 이동 함수, 동작은 memcpy와 같지만 내부 동작이 다름 ( memcpy는 속도, memmove는 안전성 )

memmove(void* _Dst, void const* _Src, size_t _Size);
//(복사 받을 변수의 메모리 공간의 주소, 복사 할 원본 메모리 공간의 주소, 복사할 메모리 크기)

■ 예시

char cArray[] = "DainnGoHome";
char cDest1[] = "abcdefghijklmnop";
char cDest2[] = "abcdefghijklmnop";
char cDest3[] = "abcdefghijklmnop";

cout << sizeof(cArray) << endl; // 널 포함 문자열 길이

memmove(cDest1, cArray, sizeof(cArray) - 1); // 널 제외 문자열 길이칸큼 복사
memmove(cDest2, cArray, sizeof(char) * sizeof(cArray)); // 널 포함 문자열 길이만큼 복사
// 널 포함 복사 시 널까지만 출력
memmove(cDest3 + 5, cArray, sizeof(char) * 5); // cDest의 5 글자 뒤부터 5크기만큼 복사

cout << cDest1 << "\t" << cDest2 << "\t" << cDest3 << endl;
    
출력 결과:
12
DainnGoHomelmnop        DainnGoHome     abcdeDainnklmnop

※ TIP

- 널 제외 복사 시 복사받은 문자열에서 복붙하고 남은 문자열은 이어서 출력

- 널 포함 복사 시 널까지만 출력

입출력 ( feat. stream )


1. 콘솔 입출력     2. 파일 입출력

[ 콘솔 입출력 ]

  • 텍스트 모드 : 문자열 단위로 수행하는 작업
  • 바이너리 모드 : 2진 코드 단위로 수행하는 작업

[ stream ]

: 전달 통로(매개체), 프로그램을 드나드는 데이터를 바이트의 흐름으로 표현한 단어

  • stdin : 표준 입력 스트림, 기본 키보드 대상
  • stdout : 표준 출력 스트림, 기본 모니터 대상
  • stderr : 표준 에러 스트림, 기본 모니터 대상, 우리가 사용하지 않음

※ 표준 입출력

: 어떤 프로그램에 있어 사용자가 명시하지 않는 이상 프로그램 개발 시

기본적으로 사용할 입출력 대상을 '표준 입출력' 이라고 한다.

우리 프로그램은 키보드 입력을 표준 입력, 모니터 콘솔 출력을 표준 출력으로 한다.

■ 단일 문자 출력 함수 ( 텍스트 모드 함수 )

[ putchar ] 

: stdout으로 스트림 고정(=콘솔 출력 고정)

putchar(값); // 값은 숫자 또는 문자 혹은 변수

[ fputc ]

: 파일 또는 콘솔에 값 추가

fputc(값, 파일 주소 또는 stdout) // 값은 파일에 넣을 숫자 또는 문자, 파일 주소는 stdout

■ 문자열 출력 함수

[ puts ] 

: stdout으로 스트림 고정(= 콘솔 출력 고정)

puts("문자열"); // stdout으로 스트림 고정, 자동 개행을 제공

[ fputs ]

: 파일 또는 콘솔에 출력

fputs("문자열", 파일 주소 또는 stdout); // 자동 개행을 제공하지 않음

 

 

■ 단일 문자 입력 함수

[ getchar ] 

: 문자열 배열 입력 시, 널 값을 제외한 [크기]만큼 단문자를 받는 함수

int ch = getchar(); // 띄어쓰기까지 입력 받음
#Define Size 3

char arr[3] = {};
int i = 0;
for (i = 0; sizeof(arr) / sizeof(char) > i ; ++i) 
{
	fgets(arr, sizeof(arr), stdin);
	arr[i] = getchar();
	cout << arr[i];
}

[ fgetc ]

: 문자 단위로 읽어들이는 함수, 파일의 단일 문자를 읽어들임

fgetc(파일 포인터명);

 

■ 문자열 입력 함수

[ gets_s ] 

: stdin으로 스트림 고정(=키보드 입력 고정)

get_s(저장할 배열, 크기); // 공백(스페이스)를 읽어들임
char szName[8] = "";
get_s(szName, sizeof(szName)); // szName의 문자열 길이만큼 해당 배열에 저장
puts(szName); // 콘솔 출력 ; puts는 stdout 고정

[ fgets ]

: 파일에서 행 단위로 취득하고 싶은 경우 사용, 스트림을 직접 지정 가능(=파일 또는 콘솔에 입력), 

fgets(저장할 배열, 크기, 파일주소 또는 stdin); // 크기는 1행 최대 문자수
char szName[8] = "";
fgets(szName, sizeof(szName), stdin); // 키보드 입력으로 szName 길이만큼 szName에 입력
puts(szName); // 콘솔 출력 ; puts는 stdout 고정

※ fgets와 gets_s 중 fgets 사용 권장

→ 공통점 : 성공 시 입력 받은 문자열의 시작 주소 반환, 실패 또는 파일의 끝에 도달할 경우 null 반환

- fgets_senter(\n) 읽어들이고 '\0' 문자를 고려하여 읽어들이기가 가능하다. 널까지만 입력하며 선언한 배열의 크기만큼 널을 포함해서 읽어들인다. ( 입력한 크기가 배열의 크기를 초과하면 배열의 크기 - 1만큼 받고, 자동으로 널을 넣는다. )

- gets_s는 선언한 배열의 크기보다 입력한 크기가 커도 입력이 되고 논리적 오류가 뜨기 때문에 오버로드가 발생한다.

 

[ EOF ] End of FIle

: 파일의 끝을 표현하기 위한 상수로 -1 이다.

char text = 0;

while (text != EOF)
{
	text = getchar();
	putchar(text);
}

※ 콘솔 입출력에서는 ctrl + z를 이용하여 입력 버퍼에 EOF를 삽입할 수 있다.