Taking baby-developer steps

2022.04.12. push_swap - main문 나누기(규정에 맞춰 refactoring 하기), 스택에 입력값 저장 본문

Logs/학습 log

2022.04.12. push_swap - main문 나누기(규정에 맞춰 refactoring 하기), 스택에 입력값 저장

Surin Lee 2022. 4. 12. 15:29

어제 기록한 대로, 정렬부를 구현하기 전, int main문을 한번 작은 함수들로 나누고 가야할것 같다. norm 규정상 하나의 함수가 25 line을 넘을 수 없기 때문이기도 하지만, main 문이 너무 길어지면 가독성이 너무 떨어져서 편의상으로도 필요하다. 리팩토링 과정이기 때문에, 수정 전과 후에 결과물에 변화가 없는지 중간중간 테스트를 병행하면서 진행했다.

refactoring 중인 main function

refactoring 도중, 스택에 추가할 새 노드를 만드는 make_a_node 함수에서 변경해야할 사항이 생겼다. 

이전 포스팅에서도 한번 언급 한적이 있었는데, make_a_node 함수 내에 arr4i배열 내에 존재하는 content의 값을 찾아, 해당 값의 index를 노드의 index 값에 저장하는 부분이 있는데, 

현재 argv를 한번 훑으면서 arr4i와 스택 a에 동시에 값을 저장하려고 해서, 전체 arr4i의 오름차순 정렬이 끝나지 않은 상태에서 make_a_node에 의해 index가 저장되는 것이었다. 처음에는1. " make_a_node에서 index를 찾아 넣는 부분은 빼고, content만 스택 a에 차례대로 저장하고 index를 저장하는 함수를 따로 만들어 후에 호출하자"라는 구상이 떠올랐으나, 어차피 현재 arr4i를 생성하고 정렬하는 함수가 25줄을 넘어서서, 2."차라리 이 함수는 arr4i를 생성하고 값을 넣는 역할만 하게하고, 다시 한번 처음부터 인풋값을 보면서 값을 넣고, 정렬이 끝난 arr4i에서 make_a_node를 통해 index가 저장되게 하자"는 구상이 더 적합하다는 생각이 들었다.

 

- index_input함수 refactoring

refactoring 전 (중요부분 line 수 : 27줄)
refactoring 후 (중요부분 line 수 : 22줄)
refactoring 후의 index_input 함수의 전체 모습

refactroing으로 5줄을 줄였지만..! 현재 사용하는 인덱스 관련 변수가 3개나 되고, 변수 선언과 초기화를 동시에 할 수 없는 rule이 있는 관계로.. 32줄에서 더이상 줄일 수 없겠다는 판단이 섰다. => 그런데 더 줄일수 있었다..!

while 문과 if 문에 중첩되는 부분이 있어서, j 인덱스를 증가 시키는 부분을 위치를 이동시키고, 필요 없는 if 문을 한번 삭제했다. 그래도 25줄 이하로 줄이는건 어림없어서..!(변수 선언과 초기화 부가 거의 7줄을 차지 하고, 증가 시키는 부분 까지 하면 9줄이기 때문에..! 어쩔수 없었다. refactoring을 하는 도중에,

"3 2 1"과 같은 인풋을 현재 프로그램이 error로 처리하는것을 알게되었고, j 인덱스를 옮겨 갈때 생긴 문제 때문이었다. 이를 해결하자,

"  3 2 1"과 같은 input을 정상 처리하는 모습
"            3   2 1" "0 -1" 과 같이 두번째 행에 space를 포함한 string이 오는 경우도 제대로 처리가 안되는 것을 확인 했다.
다음에 오는게 string이 아닌 경우에는 정상 작동했다.

이미 이전의 오류를 잡을때, lldb 디버거를 통해, sort4i에서 호출하는 print_error 호출로 인해 나오는 에러 메시지 였음을 확인 했으므로, 이번에도 j 인덱스의 문제일 가능성이 높다고 판단했다.=> 결국, 이전에 refactoring 도중에 while 문으로 space이면 j 인덱스를 1만큼 올리는 부분을 적절하지 않은곳으로 옮긴것이 화근이었다.

space를 입력값으로서 인식하지 않기 위해 j++하는 while문의 위치를 변경하고 나니
이전의 error 처리된 정상 input 값을 정상 처리했다. 그러나
input 값이 모두 들어왔지만 space가 아직 남은 경우엔 정상 작동하지 못했다.

refactoring을 할때 정말 주의 해야하는 부분을 깨달은것 같다. 일반적인 경우에는 중첩되는 부분이라고 생각하고 줄였다가, 특수한 경우 결과가 달라지는 경우를 잠시 망각하는 것을 조심 해야겠다. 틈틈히 테스트하길 정말 잘했다..!

(왼) while과 if문 중첩 부 refactoring 이전의 모습 / (오) space로 문장이 끝나는 경우를 고려, 다시 refactoring 한 모습

사실 중첩부분이라고 생각하고 삭제한 부분을 다시 살리면 되긴 하지만, 그렇게 하면 3줄("if (~~~)", "{", "}")이 증가하는 것에 비해 space일때 j인덱스 1증가 부분을 추가하면 2줄("while(~~~)", "j++")만 증가하기 때문에, 2줄만 추가하는 쪽으로, 오른쪽과 같이 리팩토링 했다.

다시 정상 작동 하는 모습

 다시 25줄 이슈로 돌아가서, 해당 부의 중요 부분을 하나의 부분 함수로 빼기로 결정했다.

index_input 함수에서 arr4i에 input string을 int값으로 변환해서 저장하고, 이 배열을 오름차순 정렬하는 부분을 store_and_sort 함수로 명명하고 새로 정의했다.
부분함수를 빼낸 이후에도 정상 작동 확인

=> 그러나..! 동작은 잘 되었으나, Norm 규정에 의해 하나의 함수가 받을 수 있는 parameter의 수는 4개로 한정 되어있고, 따라서 다시 리팩토링을 해야만 했다. 현재 캐릭터 더블 포인터 형인 argv와 i, j를 받고 있는데, 이를 합쳐서 아예 char *으로 파라미터를 넘겨 버리는게 좋겠다고 생각했다. 따라서, 아래와 같이 refactoring 하게 되었다. 

리팩토링 이후 정상작동 확인

k를 store_and_sort 내에서 static 변수로 선언 하고 해결할까도 생각해봤지만, char * str으로 넘겨주어 파라미터의 수를 줄이는게 더 덜 번잡하다고 판단이 되어 이 방법을 택했다. 근데, k를 store_and_sort내에서 static으로 선언하고 하는 편이 더 나을거 같기도 하다..! index_input 함수에서 변수 k를 선언할 필요도 없어지니까..!또 k가 증가하는 부분은 store_and_sort 내에 밖엔 없어서, 이 함수 내부에서 선언해 주는게 더 나을것 같다.  나중에 refactoring 한번 더 할 때 생각해보기로 하자.

 

이제 받은 입력값을 스택 a에 arr4i에서의 index 정보와 함께 저장할 차례이다.

main 함수에서 put2stack을 호출하면, 입력 문자열에서 유효한 int 값을 변환해 스택의 각 노드에 stack 값에 저장하고, 이 stack값과 같은 value를 arr4i에서 찾아 해당 index를 노드의 index에 저장하게 의도했다. 그러나,

value는 잘 저장이 되었으나, index가 모두 0으로 되어있음을 확인 했다. 이는 init 이후에 index 값이 바뀌지 않은 것이다.

make_a_node 함수에서 Printf문을 호출해서 각 값을 확인 해본 결과, 이 함수 내의 변수 i (index)에 문제가 있는 것으로 보였다.

Comments