Community

동적 할당 풀이

아직 미숙한 점이 많아, 해당 자료에 틀린 점이 상당히 많을 수 있음을 사전에 알려드립니다. 오류를 검토하고, 지적해주실 여러분들을 손꼽아 기다리고 있습니다. #include #include #include int main(void){ int n, m; printf("원하는 데이터 수를 입력하시오 : "); scanf("%d", &n); //데이터 크기 char** StringList = (char**)malloc(sizeof(char*)*n); 1. 2차원 배열 char String[6][7]을 예시로 들어보겠습니다. String[0][0]부터 [0][4]까지 “APPLE”이라는 문자열을 저장하고 있고, 이후 String[1][0]~[1][5], …의 형식으로 이루어져 있습니다. 이러한 데이터는 테이블 형태로 인식되지만, 실제로는 일렬로 배열되어 있는 메모리를 이해하기 쉽게 만든 것입니다. 실제로 2차열 배열을 단순화시키자면, 1차열 배열을 여러 개 가지고 있는 것 이라고 할 수 있습니다. 문자열을 배열에 저장하는 방식에서는, 배열 요소 하나 하나에 문자가 저장됩니다. 일반적으로 배열에 문자열과 NULL을 저장한 뒤 남는 공간에는 모두 NULL이 들어갑니다. 2. 동적 할당의 필요성 여기서 중요한 점은, 남는 공간에는 모두 NULL이 들어간다는 것입니다. 만일, 입력할 문자열을 알 수 없어 여유롭게 String[100][100]만큼 메모리를 선언했는데, 정작 입력하는 데이터가 짧은 단어라면 사용하지 않는 잉여 메모리, 즉 NULL이 매우 많아지게 됩니다. 반대로, 위 배열의 상황에서 “INEFFICIENT”라는 데이터를 입력하고 싶어도, 사용 가능한 문자 갯수가 6개이므로 수용 가능치를 초과하는 상황이 발생할 수 있습니다. 어떠한 상황이든 메모리 사용 효율성이 떨어지는 방식이므로, 원할 때 메모리를 할당했다가, 필요 없어지면 해지시킬 수 있도록 메모리를 할당하는 동적 할당을 사용하는 것이 적절합니다. 3. 이중 포인터의 역할 제작한 코드는 ‘원하는 만큼 문자열을 입력해, 이를 출력하는’ 목적을 지니고 있습니다. 먼저, 문자열은 ‘문자들의 배열’로 해석하겠습니다. 입력할 문자열의 길이를 알 수 없으므로, 입력한 만큼 메모리를 할당할 수 있는 동적 할당이 필요할 것입니다. 여기서 중요한 것은, ’원하는 만큼‘ 문자열을 입력하고 싶다는 것입니다. 이 또한 사전에 알 수 있는 방법이 없으므로, 동적 할당이 필요할 것입니다. 말그대로 동적 할당이 필요한 동적 할당의 데이터 유형이 필요하다는 것입니다. 이를 정리하자면, 문자열은 1차원 배열의 형태를 지닙니다. 각각의 1차원 배열들을 동적 메모리 할당하기 위해서는 포인터가 필요합니다. 그리고, 원하는 문자열들은 임의의 문자열의 집합이므로 크기를 예측할 수 없기에, 그들의 포인터에 의존할 수 밖에 없습니다. 즉, 문자열 갯수는 이러한 배열들이 동적 메모리 할당에 의해 리턴된 주소값들을 원소로 갖는 1차원 배열이 됩니다. 따라서 포인터의 배열을 저장하기 위해서는 포인터에 포인터를 붙힌 이중 포인터(**)가 필요한 것입니다. 결론적으로, StringList는 이중 포인터를 활용한 동적 할당을 선언하게 되었습니다. 4. 이중 포인터의 특성 char **StringList 나 char *newstr 등, 앞에 명시된 자료형은 포인터 변수가 가리키는 주소 데이터의 자료형에 대한 정보일 뿐, 포인터 자체를 의미하진 않습니다. 이때 주소 값의 크기는 동일하게 4 byte입니다. char tmp[100]; for(int i=0; i<n; i++){ printf("%d번째 데이터 값을 입력하시오 : ", i+1); //scanf("%[^\n]s", &tmp); scanf("%s", &tmp); 공백을 포함한 문자열을 받을 때, scanf("%s")로는 해결되지 않습니다. 스페이스 또한 입력의 끝으로 받기 때문입니다. 이와 같이 입력받은 문자열에 공백(Space)이 존재할 경우, 공백 이후의 데이터를 처리하지 못 하는 문제가 발생합니다. 따라서 [^'문자']를 활용해, 해당 문자가 나오기 전까지 모든 입력을 받을 수 있도록 해야 합니다. 추가로, %[^\n]s는 개행(엔터)가 나오기 전까지 공백을 포함한 모든 문자열을 받겠다는 의미입니다. int l=sizeof(tmp); StringList[i] = (char**)malloc(sizeof(char*)*l); //printf(tmp); char* newstr = (char*)malloc(sizeof(char)*(l+1)); 위에서 설명했듯이 StringList의 각 원소들은 문자열을 입력받게 됩니다. 각각의 1차원 배열들을 동적 메모리 할당하기 위해서는 포인터가 필요합니다. StringList[i]는 포인터를 활용한 동적 할당을 선언하게 되었습니다. strcpy(newstr, tmp); StringList[i]=newstr; //printf("%d번째 데이터: %s\n", i, StringList[i]); } printf("=====================\n"); for(int i=0; i<n; i++){ printf("%s ", StringList[i]); //저장된 데이터를 모두 출력합니다. } for(int i=0; i<n; i++){ free(StringList[i]); 동적 할당된 메모리를 해제하지 않으면, 메모리가 부족해질 수 있습니다. 할당된 메모리가 더 이상 필요하지 않으면 free함수를 이용하여 메모리를 해제해야 합니다. } } 이런 식으로 코드를 체계적으로 정리한 적은 처음이 될 것 같습니다. 이후에도 코드를 완성할 경우, 차근차근 풀어나가도록 하겠습니다. + 이중포인터는 이 블로그 글을 참고하여 작성하였습니다. https://m.blog.naver.com/sharonichoya/220529804336 + 아래는 원본 글의 주소입니다. https://blog.naver.com/choi1058cjf/223170034956

알림

알림이 없습니다