1. 공백있는 문자열을 받고
2. 그 문자열을 공백없는 문자열로 만들고
3. 공백없는 문자열을 회문판별하는 코드 만들기
이렇게 머리속으로 생각하고 문제를 풀고 있었는데요.
2번 공백있는 문자열을 공백없는 문자열로 만드는 과정중
strtok 을 이용해 나온 값을 strcat을 이용해 이어 붙히고 저장하기 위해 non_space 라는 메모리를 할당했습니다.(char* non_space = malloc(sizeof(char) * 30);)
그리고 바로 실행을 해보니 袴袴袴袴袴袴袴袴袴袴袴袴袴袴袴羲羲nursesrun 이렇게 나오면서 올바른 값이 안나옵니다.
고민하다가 memset(non_space, NULL, 30); 한 줄을 추가해서 실행해보니 잘 됩니다.
여기서 궁금한게 메모리를 이미 할당했는데 그 공간을 꼭 NULL 값 으로 초기화시켜줘야 하나요? 왜 초기화 시키지 않고 그냥 할당된 메모리에 저장하면 이상한 문자가 나오나요? 곰곰히 생각해봤는데 아직 이해가 잘 안됩니다.
혹시 포인터는 주소 값만 받기 때문에 그 안에 있는 내용들은 이전에 사용하던 메모리 찌꺼기가 남아서 그런건가요? 쓰레기값?
그리고
char* non_space = malloc(sizeof(char) * 30);
memset(non_space, NULL, 30);
이 코드와
char non_space[30] = { NULL, };
이 코드가 완벽히 같나요?
결과는 똑같이 나오는데 차이점이 없나요?
현대 운영체제는 모든 프로그램 중에 가장 효율적으로 동작하게 설계되어야 하는 소프트웨어입니다.
운영체제가 비효율적이면 다른 모든 소프트웨어가 느리게 동작하게 됩니다. 그래서 가장 효율적으로 동작해야 합니다.
운영체제가 하는 핵심은 메모리 관리입니다. 프로그램을 실행할 메모리를 할당하고, 프로그램을 종료하면 사용한 메모리를 회수합니다.
게임을 실행해서 3GB의 메모리를 사용했는데, 게임을 종료하면 3GB의 메모리를 회수하게 됩니다. 이때 메모리에 3GB의 공간을 모두 0으로 지우는 작업을 하게 된다면 매우 비효율적입니다. 다른 프로그램이 실행되면 어차피 그 공간을 덮어쓰게 되니까 굳이 0으로 지우는 작업을 하지 않아도 되는 것이죠. 그래서 운영체제는 프로그램 실행이 종료된 메모리를 자유 공간(free space)이라고 표시만 해두는 방법으로 관리합니다.
다른 프로그램이 실행되거나 C 언어에서 메모리를 할당하는 요청이 들어오면 자유 공간에서 요청한 공간 만큼의 메모리를 사용하라고 할당해줍니다. 이렇게 할당된 공간에는 이전 프로그램이 사용한 값들이 그대로 남아 있을 것입니다. 이를 쓰레기 값이라고 부릅니다.
메모리 공간을 할당했을 때 할당된 공간을 바로 쓰기에 모두 사용할 것이라고 프로그래머가 확정적으로 판단할 수 있다면 memset을 생략해도 됩니다. 예를 들어 파일 복사 프로그램을 작성한다면 읽어들인 크기 만큼만 쓰기 작업을 하기 때문에 memset으로 초기화하지 않아도 됩니다.
지금 풀고 있는 심사문제처럼 사용자가 최대 30자까지 문자열을 입력할 수 있는데, 10자를 입력할지, 15자를 입력할지 알 수 없으니까 이럴 때는 memset으로 초기화해야 합니다.
또한, 최대 30자라면 문자열 끝을 나타나는 널(NULL) 문자가 필요하니 31자까지 할당해야 합니다. 온라인 심사는 문제에서 반드시 요구한 최대 길이까지의 데이터를 입력했을 때도 심사를 통과할 수 있는지 확인합니다.
문자열 저장을 위한 공간을 malloc으로 동적 할당할 것인가, 배열처럼 정적 할당할 것인가의 문제입니다. 지금처럼 최대 크기가 정해진 문제에서는 둘 다 사용할 수 있습니다. 그러나 현실에서는 미리 크기를 알 수 없는 문제가 더 많습니다. 간단하게는 메모장 프로그램도 읽어들이는 텍스트 파일의 크기에 따라 메모리를 할당하게 됩니다. 이는 동적 할당을 써야 한다는 뜻이지요. 최대 2GB까지 읽어들이기 위해 메모장을 실행할 때마다 메모리를 2GB씩 할당하면 사람들이 "메모리 먹는 괴물 프로그램"이라고 할 겁니다.
malloc으로 의도적으로 메모리를 왕창 할당해서 값을 쓰는 방식으로 운영체제에 실제 메모리를 할당하게 만들어서 시스템 메모리를 고갈시키는 공격을 리소스 공격이라고 합니다. malloc으로 메모리를 할당하고 rand로 임의의 값을 쓰는 걸 반복문 안에서 1억번 정도 반복하게 하면 되겠죠? 옛날에는 운영체제가 이를 방어하지 못해서 실행하면 무조건 컴퓨터를 꺼야 했습니다. 요즘은 운영체제에서 해당 프로그램을 강제 종료할 수 있습니다.
상황에 따라 동적 할당을 쓸 것인가, 정적 할당을 쓸 것인가를 선택하는 문제입니다. 현실에서는 위와 같은 이유로 동적 할당을 쓰는 빈도가 훨씬 더 높습니다.