일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- C++ 언어 # 핵심 정리
- C언어 #핵심정리
- C언어 # 핵심 정리
- PHP #핵심정리
- shell_script
- Hacking #Baic
- Bandit
- C++ 언어 # 핵심정리
- C++ 언어 #핵심정리
- HTML #핵심정리
- C언어 #부록
- MySQL #핵심정리
- C언어 # 부록
- Today
- Total
cCcode
C Language [핵심정리] - 45 본문
1. 노드 추가 함수 사용하기
그전에는 단일 연결 리스트를 구현했는데요. 오늘은 연결리스트의 중간에 새로운 노드를 끼워넣는 함수를 사용할 예정입니다.
여기서 중요한 점은 cursor = head->next 형식으로 할당한다면 노드의 주소를 저장하기 때문에 해당 cursor 순회용 포인터를 해제하면 당연스레 해당 순회용 포인터에 저장된 노드 또한 해제 된다는 점입니다.
따라서 노드의 동적할당을 해제하는 부분을 보시면 우선 구조체를 선언합니다. 해당 구조체로 선언한 변수는 cursor 의 다음 주소를 저장하게 됩니다. 왜냐하면 노드를 해제하려면 필연적으로 cursor 도 해제되어야 하는데 cursor을 해제하게 되면 다음 노드의 주소로 접근할 수 없기 때문입니다. 그래서 cursor의 다음 주소를 임시로 저장해줄 변수가 필요한거에요.
여기선 head 함수만 따로 해제했는데, 그 이유는 while 문을 통해 어디까지 동적할당이 해제되었는지 보면 됩니다.
위에서 생성된 연결리스트 구조는 head -> node1 -> new_node (단일 연결리스트 구조) 입니다. 이제 동적할당을 천천히 따라가보면
1) cursor = head->next (= node1)
2) Next = cursor( = node 1)->next (= new_node)
3) free(cursor(= node1))
4) cursor = Next(= new_node)
5) Next = cursor(= new_node)->next (= NULL)
6) free(new_node)
7) cursor = NULL;
NULL 이므로 while문 종료
따라서, 해당 while문에서는 처음 노드(=head 노드)를 제외한 나머지 모든 노드들을 해제합니다. 그래서 여기서 해제하지 못한 head 노드를 따로 해제해주는 것이죠
2. 노드 삭제 함수 사용하기
이번에는 노드를 삭제하는 함수를 사용하겠습니다.
이 부분만 제외하곤 나머지 모두 동일해요. 지금 해당 부분을 단일 연결 리스트를 그림으로 표현하면 다음과 같아요.
따라서 head 뒤에 있는 Node를 삭제하면 Node3 즉, 8이라는 데이터를 가진 노드만 남게되는 것이죠. 여기서 head 를 node2 위 코드에선 node1으로 수정하게 된다면
Node3가 사라지고 Node2 (= node1)이 마지막 노드가 됩니다. 그리고 연결리스트 구현시 노드가 NULL인지 검사해야 합니다.
왜냐하면 그전에 말씀드린 것처럼 노드의 마지막에 NULL을 지정하는 데 만약 실수일지라도 마지막 노드가 아닌 다른 노드에 NULL 값이 들어가면 제대로 된 결과를 낼 수 없기 때문입니다.
3. 매크로 사용하기
C언어에서는 컴파일러에서 특정작업을 미리 명시해두고 프로그램이 실행되기 전 수행하는 전처리기(preprocessor)라는게 있습니다.
프로그래밍을 하다보면 중복되는 값을 사용할 때가 있는데요. 근데 의미가 같음에도 불구하고 그게 literal 값으로 적혀있다면, 해당 값들 사이에 동일 여부를 판단하기 어려울 때가 있습니다. 그럴 때는 define 지시자를 사용해 정의하면 좀 더 값들을 이해할 수 있습니다. (어디에 사용되는 값인지) 보통 매크로로 정의할 때는 대문자를 사용해요.
누가봐도 어떤 곳에 사용하는 값인지 한 눈에 보이지 않나요? 이뿐만 아니라 코드가 길어졌을 때 생길 수 있는 실수를 줄일 수 있다는 점에서 매크로를 사용하는 게 낫습니다. 매크로는 값을 정의할 수도 있지만 매크로로 다른 매크로를 정의할 수 도 있습니다.
근데.. 이걸 쓸 일이 있을까요.. 의문이네요 이렇게 정의한 매크로 값은 상수로 유지되는 데, 프로그래밍 도중 어느 한 부분에서는 그 값이 수정되어야 할 수 도 있잖아요. 그 경우에는 undef 매크로로 정의한 매크로를 해제한 후 다시 정의합니다. 아마 define 한 걸 해제 한다는 뜻에서 un - 접두사(prefix)가 붙은 건 아닐까..? 조심스레 추측해봅니다. 사실 이렇게 매크로나 함수 이름의 어원을 추측하는 건 추측이 틀릴지라도 해당 함수명을 외우는 데 도움이 되니 한번 시도해서 나쁠 건 없다 생각합니다.
define 매크로는 함수 모양으로도 정의할 수 있습니다.. 무슨 거의 만능키마냥 쓰이네요.
○ #define 매크로명(n) 함수(n) - 괄호 안에 변수는 자료형을 명시하지 않습니다.
+ 함수를 지정한 뒤 공백을 주면 함수를 호출하지 못하게 할 수도 있습니다.
이걸 이용하면 다른 사람과 협업을 할 때 어떤 함수를 사용하면 안되는 부분인데, 실수로 사용해서 발생하는 여러가지 문제들을 사전에 막을 수 있겠네요.
이외에도 define은 \ (역 슬래시)를 사용해서 여러 줄의 매크로를 만들 수 있습니다. (마지막 줄은 굳이 \를 사용할 필요 없습니다.) 주의해야 할점은 여러 줄의 매크로를 사용하기 때문에 각 줄을 구분하기 위해 각 줄 마지막에 세미콜론(;)을 포함해야 한다는 점입니다.
이 때는 매크로 함수 하나를 사용하지만 실제로는 그 함수하나가 printf 3개로 치환되기 때문에 if문이나 for문을 사용할 때는 중괄호를 사용해야 합니다.
+ 매크로는 연산자보다 우선순위가 낮습니다.
2번째 계산식에서 함수 호출이 먼저 되었더라면 값은 3이 아니라 2가 되었을겁니다. 4번째 계산식 역시 함수가 먼저 호출 되었더라면 0 이 아니라 40 이 나왔을겁니다. 이처럼 매크로의 함수호출은 일반적인 연산자보다 우선 순위가 낮다는 걸 알 수 있습니다. 그래서 이로인한 잘못된 연산 수행을 방지하려면 해당 부분을 괄호로 묶어 우선순위로 정하면 됩니다.
define 지시자에서 '##'을 사용하면 여러 값을 이어 붙일 수 있습니다.
● #define 매크로명(a, b) a##b
이어 붙인 값에 1을 더해 19가 되는 것으로 봐서, 문자열처럼 붙이기만 한게 아니라 실제로 정수로서의 의미를 갖는다고 할 수 있습니다. 이를 이용해 함수를 호출할 수도 있습니다.
4. 조건부 컴파일
조건부 컴파일을 할 때는 ifdef 나 endif 지시자를 사용합니다. ifdef 는 앞에 있는 if 로 알 수 있듯이 해당 매크로가 정의되어 있을 때만 해당 코드를 실행합니다.
만약 FILE 매크로가 정의되어 있지 않다면?
+ 디버그 코드에 사용되는 매크로
ifdef 매크로 지정한 매크로의 존재 여부만 판단해서 코드를 실행시켰다면 if 매크로는 값 또는 식을 판별해 컴파일 합니다.
그리고 if 와 defined 를 조합하면 하나의 매크로 여부만 확인하던 ifdef 와 다르게 논리 연산자를 사용해 복잡한 논리 연산을 수행할 수 있습니다.
그리고 논리 연산의 순서를 명확하게 나타내기 위해 괄호로 묶습니다.
이번에는 elif 와 else 을 사용하겠습니다.
USB 와 HDMI 둘다 존재하지 않는다면?
ifndef 매크로는 해당 매크로가 정의되어 있지 않을 때 사용합니다.
C언어의 기초적인 골격이였던 #include 의 # 은 전처리기를 호출하는 특수문자입니다. 따라서 include는 전처리기가 되겠죠. 다만 이 지시자가 헤더파일(.h) 소스파일(.c)을 포함할 때는 < > 와 " " 로 나뉘어지는 데 차이는 다음과 같습니다.
이를 이용해서 실제로 헤더파일을 만들어보고 해당 헤더파일을 소스파일에서 실행해보겠습니다.
'C Language Basic' 카테고리의 다른 글
C Language [핵심정리] - Last (0) | 2021.08.05 |
---|---|
C Language [핵심정리] - 44 (0) | 2021.07.29 |
C Language [핵심정리] - 43 (0) | 2021.07.27 |
[부록] 막대 그래프(완성본), 체스 말 움직이는 모션(완성본) (0) | 2021.07.24 |
C Language [핵심정리] - 41 (0) | 2021.07.22 |