본문으로 바로가기

파일의 IT 블로그

  1. Home
  2. 프로그래밍/C
  3. [C] 문자열을 다룰 땐 항상 깊은 복사와 얕은 복사를 고려합시다..

[C] 문자열을 다룰 땐 항상 깊은 복사와 얕은 복사를 고려합시다..

· 댓글개 · KRFile

요새 UNIX 시스템 프로그래밍을 배우면서 C언어로 system call() 을 호출해서 리눅스 tree 명령어 출력을 C언어에서 그대로 구현하는 과제를 진행중입니다.

 

코딩병이 도져서 오후 11시쯤부터 도전해서 오전 6시까지 프로그래밍 하는 기행을 보였으나.. 완성이 머지 않았는데 재귀적으로 tree() 를 호출하면서 출력을 진행 하면서 중간에 자꾸 메모리가 소멸하는 문제가 발생하였습니다.

 

디버깅.. 디버깅을 해야하는데..! 리눅스를 VMware 가상 환경으로 돌리고 있어서 훌륭한 디버거 기능을 가진 Visual Studio는 윈도우 전용이라 사실상 사용할 수 없었고, VSCode 에서 gdb를 이용해서 하나 하나 디버깅을 해야 하는 골때리는 상황이 생겼습니다. 사실 저는 주 관심사가 C#이나 Python 같은 언어들이라 한 줄씩 변수 변화를 보면서 디버깅 해본 경험은 그렇게 많지 않습니다.

 

보통 감으로 때려서 출력값 보고 고치는 정도?

이번에 디버깅을 제대로 배우면서 했으면 좋았을탠데 일단은 몇년전에 C언어 강좌 작성한 짬이랑 떠오르는 아이디어로 고쳤습니다. ^^;;

 

아이러니 하게도 문제를 발생시키는 건 딱 "코드 한 줄" 이였습니다

해당 함수의 경우, 디렉토리 경로를 받은 후 2차원 문자열 배열을 동적 할당한 다음 파일을 읽고 그곳에 차곡차곡 파일 이름을 담은 후 정렬하는 logic을 수행하는 함수입니다.

 

readdir() 로 반복적으로 파일을 읽어오면서 구조체에 d_name 멤버 객체에 포인터로 접근을 하였는데 이것이 char * .포인터라서 단순히 file_name 이라는 이름으로 이 주소를 얕은 복사하고 그대로 동적할당한 공간에 넣어준게 문제였습니다 ㅠ

 

저기서 접근하는 dir_info->d_name; 의 경우 문자열이 저장된 공간을 가리키게 되는데 내부적으로 static이나 동적할당된 공간이라 계속 남아있는 공간이 아닌 임시적으로 곧 소멸될 공간이기 때문에 시간이 지나면 파일 리스트에 담아둔 내용들이 자꾸 소멸해버리는 것이였습니다.

 

한마디로 파일 리스트는 파일 이름이 저장된 주소만 가리키고 있었는데 나중에 이 가리키는 주소에 있는 내용이 메모리에서 소멸하고 빈 메모리를 가리키게 되서 메모리가 날라가게 된 것이였죠.

 

그래서 strcpy로 d_name 의 내용들을 통째로 복사 하고 (깊은 복사 하고) 문제를 해결 할 수 있었습니다.

C에서 지원하는 strcpy() 함수로요.

 

사실 코드는 한 줄 인데 내부적으로 C가 동작하는 방식을 모르면 절대 고칠 수 없었을 거 같습니다. ㅎㄷㄷ

 

[1970889 2049 -rw-rw-r-- file      326]   README.md
[1970931 2049 drwxrwxr-x file     4.0K]   Sandbox
--[1970935 2049 -rw-rw-r-- file        0]   a
--[1970938 2049 drwxrwxr-x file     4.0K]   gdb
----[1990781 2049 drwxrwxr-x file     4.0K]   original
------[1970947 2049 -rw-rw-r-- file        0]   a
------[1970950 2049 -rw-rw-r-- file        0]   makefile
------[1970953 2049 -rw-rw-r-- file        0]   q5.h
------[1970948 2049 -rw-rw-r-- file        0]   main.c
------[1970949 2049 -rw-rw-r-- file        0]   main.o
------[1970952 2049 -rw-rw-r-- file        0]   operation.o
------[1970951 2049 -rw-rw-r-- file        0]   operation.c
----[1968424 2049 drwxrwxr-x file     4.0K]   error
------[1970943 2049 -rw-rw-r-- file        0]   makefile
------[1970946 2049 -rw-rw-r-- file        0]   q5.h
------[1970941 2049 -rw-rw-r-- file        0]   main.c
------[1970942 2049 -rw-rw-r-- file        0]   main.o
------[1970945 2049 -rw-rw-r-- file        0]   operation.o
------[1970944 2049 -rw-rw-r-- file        0]   operation.c
------[1968444 2049 -rw-rw-r-- file        0]   a
--[1970913 2049 -rw-rw-r-- file        0]   a.c
--[1970937 2049 -rw-rw-r-- file        0]   a.sh
--[1970988 2049 drwxrwxr-x file     4.0K]   test
----[1971059 2049 -rw-rw-r-- file        0]   a
----[1971060 2049 -rw-rw-r-- file        0]   b
----[1971061 2049 -rw-rw-r-- file        0]   c
----[1971062 2049 -rw-rw-r-- file        0]   d
[1971102 2049 -rw-rw-r-- file      231]   Makefile
[1966436 2049 -rw-rw-r-- file        0]   make 파일도 제작해야함
[1971136 2049 -rw-rw-r-- file      310]   tempCodeRunnerFile.c
[1971137 2049 -rwxrwxr-x file    13.4K]   mytree
[1968442 2049 -rw-rw-r-- file    11.1K]   mytree.c
[1971068 2049 -rw-rw-r-- file     9.9K]   system.c
[1970905 2049 -rw-rw-r-- file     1.2K]   system.h

어쨌던 삽질 끝에 과제 요구사항대로 tree를 잘 구현할 수 있었습니다.

사실 테스트 케이스가 아직 제공이 안되서 출력 포맷이 정확히 이게 맞는진 모르겠습니다만.. 제발 C로는 문자열 다루는거나 정렬은 안하고 싶네요 진짜로 ㅡㅡ;

SNS 공유하기
💬 댓글 개
이모티콘창 닫기
울음
안녕
감사해요
당황
피폐

이모티콘을 클릭하면 댓글창에 입력됩니다.