정처기 실기 : 2025년 1회차 기출, 1️⃣1️⃣ ~ 2️⃣0️⃣

m_ngyeong·2025년 4월 22일
0
post-thumbnail

정보처리기사 실기


📝 2025년 1회차 기출, 1️⃣1️⃣ ~ 2️⃣0️⃣

11. C Lang. - 이중 포인터, malloc

#include <stdio.h>
#include <stdlib.h>

void set(int** arr, int* data, int rows, int cols) {
    for (int i = 0; i < rows * cols; ++i) {
    arr[((i + 1) / rows) % rows][(i + 1) % cols] = data[i];
    }
}

int main() {
    int rows = 3, cols = 3, sum = 0, i;
    int data[] = {5, 2, 7, 4, 1, 8, 3, 6, 9};
    int** arr;
    
    arr = (int**) malloc(sizeof(int*) * rows);
    for (i = 0; i < rows; i++) {
        arr[i] = (int*) malloc(sizeof(int) * cols);
    }
    
    set(arr, data, rows, cols);
    
    for (i = 0; i < rows * cols; i++) {
        sum += arr[i / cols][i % cols] * (i % 2 == 0 ? 1 : -1);
    }
    
    for(i=0; i<rows; i++) {
        free(arr[i]);
    }
    free(arr);
    
    printf("%d", sum);
    return 0;
}

🖍️ 13

  • data 배열에 있는 값을 2차원 배열 arr에 특정 방식으로 저장 (set 함수)
  • 저장된 배열 값을 홀수 인덱스에서는 음수, 짝수 인덱스에서는 양수로 합산
  • 최종적으로 sum을 출력

🧩 2차원 배열을 동적으로 할당:

arr = (int**) malloc(sizeof(int*) * rows);
  • arrint 포인터의 포인터, 즉 int**
    arrint* 배열로 만들고 싶음
  • sizeof(int*) * rows: int* 타입을 rows개 만큼 메모리 할당
    즉, 행(row) 개수만큼 포인터 공간을 확보
arr
 │
 ├───► arr[0] → ?
 ├───► arr[1] → ?
 └───► arr[2] → ?
for (i = 0; i < rows; i++) {
    arr[i] = (int*) malloc(sizeof(int) * cols);
}
  • arr[i]는 각 행에 해당하는 포인터
  • sizeof(int) * cols: 열(col) 수만큼 정수 배열을 만듦
    즉, 각 행에 실제 데이터를 저장할 공간을 할당
arr
 │
 ├───► arr[0] → [ int ][ int ][ int ] 
 ├───► arr[1] → [ int ][ int ][ int ] 
 └───► arr[2] → [ int ][ int ][ int ] 

🧩 set() 함수

void set(int** arr, int* data, int rows, int cols) {
    for (int i = 0; i < rows * cols; ++i) {
        arr[((i + 1) / rows) % rows][(i + 1) % cols] = data[i];
    }
}
  • 행 인덱스: ((i + 1) / rows) % rows
  • 열 인덱스: (i + 1) % cols
    즉, i가 0부터 8까지 순회하면서, data[i] 값을 위의 인덱스 계산으로 arr에 넣음

🧩 최종 arr 상태:

arr = {
  {9, 5, 2},
  {7, 4, 1},
  {8, 3, 6}
};

🧩 sum 계산

for (i = 0; i < rows * cols; i++) {
    sum += arr[i / cols][i % cols] * (i % 2 == 0 ? 1 : -1);
}

2차원 배열을 순서대로 탐색하면서:

  • 짝수 인덱스 (i % 2 == 0) → 더함
  • 홀수 인덱스 → 뺌

➡︎ 9 - 5 + 2 - 7 + 4 - 1 + 8 - 3 + 6 = 13


12. 결합도

① 다른 모듈 내부에 있는 변수나 기능을 다른 모듈에서 사용하는 경우의 결합도
② 모듈 간의 인터페이스로 배열이나 오브젝트, 자료구조 등이 전달되는 경우의 결합도
③ 파라미터가 아닌 모듈 밖에 선언되어 있는 전역 변수를 참조하고 전역 변수를 갱신하는 식으로 상호작용하는 경우의 결합도

🖍️ ① 내용 결합도 ② 스템프 결합도 ③ 공통 결합도


13. Java Lang. - OOP 개념

상속(Inheritance), 메서드 오버라이딩(Method Overriding), 정적 변수(Static Variable), 변수 숨김(Variable Shadowing)

class parent{
    static int total = 0;
    int v = 1;
    
    public parent(){
        total += (++v);
        show();
    }
    public void show(){
        total += total;
    }
}

class child extends parent{
    int v = 10;
    
    public child(){
        v += 2;
        total += v++;
        show(); 
    }
    @Override
    public void show(){
        total += total*2;
    }
}

class Main {
    public static void main(String[] args) {
        new child();
        System.out.println(parent.total);
    }
}

🖍️ 54

🩵 코드 시작:

new child();

1️⃣ 먼저 parent 생성자가 실행

int v = 1;
++v;                // v는 2가 됨
total += v;         // total = 0 + 2 = 2
show();             // 여기서 child의 show()가 호출됨

⚠️ 중요 포인트
show()parent 클래스의 메서드처럼 보이지만, child 클래스에서 오버라이딩했기 때문에, 실제로는 childshow()가 실행됨

// child의 show() 실행
total += total * 2;  // 2 + (2 * 2) = 6
  • total = 6

2️⃣ child 생성자가 실행

int v = 10;     // child의 v (부모 v와는 다른 변수)
v += 2;         // v는 12
total += v++;   // total = 6 + 12 = 18, v는 13이 됨
show();         // 다시 child의 show() 실행
total += total * 2;  // 18 + (18 * 2) = 54

🔚 최종 결과

System.out.println(parent.total);  // 결과: 54
  • 동적 바인딩으로 인해 부모 생성자에서도 자식의 메서드가 호출됨
  • static 변수 덕분에 값이 누적되어 최종적으로 54가 출력됨

14. 디자인 패턴

  • Wrapper라고도 불림
  • 다른 클래스가 이용할 수 있도록 인터페이스 변환해주는 패턴

🖍️ adapter


15. 구문 커버리지(Statement Coverage)

정확하지 않음

int main() {
    int a = 0;
    while (조건문) {
        if (B[a] < 0)
            B[a] = -B[a];
        a++;
    }
    return(1);
}

🖍️

순서: ➊→➋→➌→➍→➎→➋→➏

흐름도 구성 노드

[Start] --> [a = 0]
           |
           v
    [➊ while (조건문)]	<------------------------
         /       \  					   		|
       No         Yes  					   		|
       |           |  					   		|
 [➋ return 1]     v  					   		|
               [➌ if (조건문)]					|
                 /      \						|
              No         Yes					|
               |          |						|
               |          v						|
               |      [➍ B[a] = -B[a]] 				|
                \       /						|
                    |							|
                 [➎ a++]  -----------------------
                 	|
    		  [➏ return 1] 

16. Java Lang. - 재귀 함수

public class Main {
    static int comp(int[] a, int st, int end) {
        if (st >= end) return 0;
        int mid = (st + end) / 2;
        return a[mid] + Math.max(comp(a, st, mid), comp(a, mid + 1, end));
    }
    public static void main(String[] args) {
        int[] values = {3, 5, 8, 12, 17};
        System.out.println(comp(values, 0, values.length - 1));
    }
}

🖍️ 20

🧩 main 함수

public static void main(String[] args) {
    int[] values = {3, 5, 8, 12, 17};
    System.out.println(comp(values, 0, values.length - 1));
}
  • comp 함수는 values 배열을 0부터 values.length - 1 (즉, 0부터 4까지)까지의 범위로 분할하여 실행
  • comp 함수는 재귀적으로 배열을 나누고, 각 부분에서 가장 큰 값을 구해 반환

🧩 comp 함수

static int comp(int[] a, int st, int end) {
    if (st >= end) return 0;
    int mid = (st + end) / 2;
    return a[mid] + Math.max(comp(a, st, mid), comp(a, mid + 1, end));
}

comp 함수는 배열 a와 인덱스 st(start)end(end)를 인자로 받아서 부분 배열의 합을 구하고, 그 중에서 최대값을 반환하는 함수

  • 재귀 종료 조건: st >= end이면 0을 반환, 이 조건은 배열의 크기가 1 이하일 때 재귀가 종료
  • 분할: 배열을 두 부분으로 나눔, mid는 배열의 중간 인덱스
  • 부분합 계산: comp(a, st, mid)st부터 mid까지의 부분 배열을 처리하고, comp(a, mid + 1, end)mid + 1부터 end까지의 부분 배열을 처리
  • 최대값 구하기: 두 부분의 결과를 비교한 후 더 큰 값을 선택하고, a[mid] 값을 더해 최종 결과를 계산

✅ comp(values, 0, 4) 실행 흐름 표

comp(0,4) → 8+12
├── comp(0,2) → a[1]+3+0 = 8
│   ├── comp(0,1) → a[0]+0+0 = 3
│   │   ├── comp(0,0) → 0
│   │   └── comp(1,1) → 0
│   └── comp(2,2) → 0
├── comp(3,4) → a[3]+0+0 = 12
│   ├── comp(3,3) → 0
│   └── comp(4,4) → 0

17. Python Lang. - 이진 트리

class TreeNode:
    def __init__(self, value):
        self.value = value
        self.children = []

def build_tree(li):
    nodes = [TreeNode(i) for i in li]
    for i in range(1, len(li)):
        nodes[(i - 1) // 2].children.append(nodes[i])
    return nodes[0]

def calc(node, level=0):
    return node.value if level % 2 else 0 + sum(calc(n, level + 1) for n in node.children) if node else 0

li = [3, 5, 8, 12, 15, 18, 20]
root = build_tree(li)
print(calc(root))

🖍️ 13

🩵 클래스 TreeNode 정의

class TreeNode:
    def __init__(self, value):
        self.value = value
        self.children = []
  • TreeNode 클래스는 트리의 각 노드를 나타냄
  • __init__(): 노드의 값을 설정, 자식 노드들을 담을 children 리스트를 초기화

🩵 build_tree 함수

def build_tree(li):
    nodes = [TreeNode(i) for i in li]
    for i in range(1, len(li)):
        nodes[(i - 1) // 2].children.append(nodes[i])
    return nodes[0]
  • build_tree 함수는 입력 리스트 li를 이용해 트리를 만듦
    먼저, li의 각 값에 대해 TreeNode 인스턴스를 만들어 nodes 리스트에 저장
  • 이후 for 루프를 통해 각 노드의 부모 노드를 찾아서 자식으로 추가
    • nodes[(i - 1) // 2]는 현재 노드 i의 부모 노드를 가리킴
    • 예를 들어, i = 1일 때, (i - 1) // 2 = 0으로, 노드 1의 부모는 노드 0
  • 마지막으로 트리의 루트 노드(nodes[0])를 반환

🌳 결과 트리 구조

nodes[0]: 3
├── nodes[1]: 5
│   ├── nodes[3]: 12
│   └── nodes[4]: 15
└── nodes[2]: 8
    ├── nodes[5]: 18
    └── nodes[6]: 20

🩵 calc 함수

calc 함수는 트리의 각 노드를 깊이 우선 탐색(DFS) 방식으로 순회하며 계산한다.

def calc(node, level=0):
    return node.value if level % 2 else 0 + sum(calc(n, level + 1) for n in node.children) if node else 0
  • level=0: 루트(시작점)
  • level: 현재 노드가 트리의 몇 번째 레벨인지를 나타냄

🔍 핵심: 조건부 삼항 연산자

return (
    node.value if level % 2           # 👉 레벨이 홀수면 자기 값 반환
    else 0 + sum(...)                 # 👉 짝수면 자기 값 무시하고 자식 노드들의 결과만 합침
    if node                           # 👉 node가 None이면 무조건 0 반환
    else 0
)
  • True = 1 / False = 0
  • node.value: 현재 노드 값
  • 기본적으로, 노드의 값은 깊이에 따라 다르게 처리됨
    • level % 2 == 1: 홀수, node.value + 자식들 합
    • level % 2 == 0: 짝수, 자신의 값은 무시 + 자식들 합
  • sum(calc(n, level + 1) for n in node.children)
    현재 노드의 모든 자식 노드들에 대해 calc()를 호출해서 합산, 재귀 호출
  • node == None일 경우, 0을 반환
nodes[0]: 3 → 무시
├── nodes[1]: 5 → 포함
│   ├── nodes[3]: 12 → 무시
│   └── nodes[4]: 15 → 무시
└── nodes[2]: 8 → 포함
    ├── nodes[5]: 18 → 무시
    └── nodes[6]: 20 → 무시

🩵 실행

li = [3, 5, 8, 12, 15, 18, 20]
root = build_tree(li)
print(calc(root))
        3
       / \
      5   8
     / \  / \
    12 15 18 20
  • 5 + 8 = 13

18. C Lang. - 연결리스트

#include <stdio.h>
#include <stdlib.h>

typedef struct Node {
    int value;
    struct Node *next;
} Node;

Node* createNode(Node* head, int value) {
    Node* new_node = (Node*)malloc(sizeof(Node));
    new_node->value = value;
    new_node->next = head;
    return new_node;
}

Node* reconnect(Node* head, int disconnect_count) {
    Node *prev = NULL, *curr = head;

    while (curr && curr->value != disconnect_count) {
        prev = curr;
        curr = curr->next;
    }

    if (!curr || curr == head) return head;

    prev->next = curr->next;
    curr->next = head;
    head = curr;

    return head;
}

int main() {
    Node *head = NULL, *curr, *temp;
    for (int i = 1; i <= 5; i++)
        head = createNode(head, i);

    head = reconnect(head, 3);

    for (curr = head; curr != NULL; curr = curr->next)
        printf("%d", curr->value);

    // 메모리 해제
    curr = head;
    while (curr != NULL) {
        temp = curr;
        curr = curr->next;
        free(temp);
    }

    return 0;
}

🖍️ 35421

🧩 구조체 정의

typedef struct Node {
    int value;
    struct Node *next;
} Node;
  • Node라는 이름의 구조체를 정의
  • value: 노드가 가지고 있는 값 (int형).
  • next: 다음 노드를 가리키는 포인터, 이 포인터를 통해 연결된 리스트를 구성

🧩 새 노드 생성 함수

Node* createNode(Node* head, int value) {
    Node* new_node = (Node*)malloc(sizeof(Node));
    new_node->value = value;
    new_node->next = head;
    return new_node;
}

createNode() 함수는 새로운 노드를 생성하여 리스트의 맨 앞에 추가하는 함수

  • malloc을 사용하여 새로운 Node를 동적으로 할당
  • 할당된 새로운 노드의 value를 주어진 value로 설정
  • 새로운 노드의 next는 현재의 head를 가리키도록 설정하여, 리스트의 맨 앞에 이 노드를 추가
  • 함수는 생성된 new_node를 반환

🧩 연결 리스트에서 특정 노드를 맨 앞으로 이동시키는 함수

Node* reconnect(Node* head, int disconnect_count) {
    Node *prev = NULL, *curr = head;
	...
}

reconnect 함수는 특정 값(disconnect_count)을 가진 노드를 리스트에서 찾아 맨 앞으로 이동시키는 함수

  • prev: 현재 노드의 이전 노드를 가리키는 포인터
  • curr: 현재 노드를 가리키는 포인터, 초기에는 head로 설정됨
while (curr && curr->value != disconnect_count) {
      prev = curr;
      curr = curr->next;
}

while 루프를 통해 리스트를 탐색하여 disconnect_count 값과 일치하는 노드를 찾음

  • prev는 항상 curr의 이전 노드를 추적
  • curr는 현재 노드를 추적
if (!curr || curr == head) return head;
  • currNULL이면 값을 찾지 못한 경우이고, curr == head이면 이미 맨 앞에 있는 경우
  • 그런 경우에는 아무것도 하지 않고 head를 그대로 반환
prev->next = curr->next;
curr->next = head;
head = curr;
  • prev->next = curr->next: prev 노드의 nextcurrnext를 가리키도록 하여 curr 노드를 리스트에서 분리
  • curr->next = head: curr 노드를 리스트의 맨 앞에 추가하기 위해 curr->next를 기존 head로 설정
  • head = curr: headcurr로 변경하여 리스트의 첫 번째 노드를 curr로 설정
head
 ↓
[5] → [4] → [3] → [2] → [1] → NULL
 ↑      ↑
prev   curr
head
 ↓
[5] → [4] → [3] → [2] → [1] → NULL
               ↑      ↑
             prev    curr
• prev->next = curr->next → 4 → 2
• curr->next = head → 3 → 5
• head = curr → 새로운 head는 3

🧩 main 함수

int main() {
    Node *head = NULL, *curr, *temp;
    for (int i = 1; i <= 5; i++)
        head = createNode(head, i);
    ...
}
  • Node *head = NULL: 리스트의 헤드를 NULL로 초기화(빈 리스트)
  • for (int i = 1; i <= 5; i++): 1부터 5까지 숫자를 가진 노드들을 생성하여 연결 리스트를 만듦
  • createNode 함수를 사용하여 각 숫자에 대한 노드를 리스트의 맨 앞에 추가
    결과적으로 head5 -> 4 -> 3 -> 2 -> 1로 초기화됨
head = reconnect(head, 3);
  • 3을 리스트에서 찾아서 맨 앞에 이동시킴
  • 결과적으로 리스트는 3 -> 5 -> 4 -> 2 -> 1
for (curr = head; curr != NULL; curr = curr->next)
   printf("%d", curr->value);
  • 리스트의 모든 값을 출력하는 루프
  • head부터 시작하여 각 노드를 출력

🧩 메모리 해제

curr = head;
while (curr != NULL) {
    temp = curr;
    curr = curr->next;
    free(temp);
}

동적으로 할당한 메모리를 해제하는 코드

  • curr는 리스트의 현재 노드를 가리키고, temp는 메모리 해제를 위한 임시 포인터
  • curr를 리스트를 따라 이동시키면서, 각 노드의 메모리를 free 함수로 해제
  • free(temp)curr가 가리키는 노드를 해제한 후, curr을 다음 노드로 이동시킴

19. C Lang. - 16진수

#include <stdio.h>

typedef struct student {
    char* name;
    unsigned int score[3];
} Student;

int dec(int enc) {
    return enc & 0xA5;
}

int sum(Student* p) {
    return dec(p->score[0]) + dec(p->score[1]) + dec(p->score[2]);
}

int main() {
    Student s[2] = { "Kim", {0xF0, 0xF5, 0xDB}, "Lee", {0xED, 0xD3, 0xF2} };
    Student* p = s;
    int result = 0;
    
    for (int i = 0; i < 2; i++) {
        result += sum(&s[i]);
    }
    printf("%d", result);
    return 0;
}

🖍️ 908

🧩 구조체 정의

typedef struct student {
    char* name;
    int score[3];
} Student;
  • Student 구조체는 학생의 이름과 점수 3개를 저장
  • score[3] 배열은 3개의 정수 점수를 저장
    다만, 이 점수는 인코딩된 형태

🧩 디코딩 함수

int dec(int enc) {
    return enc & 0xA5;
}
  • & 연산자는 비트 AND 연산
  • 0xA5는 16진수로 10100101
  • 즉, 인코딩된 점수에서 특정 비트만 남겨서 "디코딩"하는 역할
Kim:
0xF0(11110000)` & 0xA5(10100101) = 0xA0(10100000) = 160
0xF5(11110101) & 0xA5 = 0xA5 = 165
0xDB & 0xA5 = 0x81 = 129 
→ Kim의 총합: 160 + 165 + 129 = 454
Lee:
0xED & 0xA5 = 0xA5 = 165 
0xD3 & 0xA5 = 0x81 = 129 
0xF2 & 0xA5 = 0xA0 = 160
→ Lee의 총합: 165 + 129 + 160 = 454

🧩 합산 함수

int sum(Student* p) {
    return dec(p->score[0]) + dec(p->score[1]) + dec(p->score[2]);
}
  • 특정 학생 포인터 p의 세 점수를 디코딩해서 더함

🧩 main 함수

for (int i = 0; i < 2; i++) {
        result += sum(&s[i]);
    }
    printf("%d", result);
  • result = sum[0] + sum[1] = 454 + 454 = 908

20. Java Lang. - 재귀 함수, Overloading

public class Main {
    public static void main(String[] args) {
    System.out.println(calc("5"));
    }

    static int calc(int value) {
        if (value <= 1) return value;
        return calc(value - 1) + calc(value - 2);
    }
    
    static int calc(String str) {
        int value = Integer.valueOf(str);
        if (value <= 1) return value;
        return calc(value - 1) + calc(value - 3);
    }
}

🖍️ 4

🩵 main()

public class Mian {
    public static void main(String[] args) {
        System.out.println(calc("5"));
    }
  • main() 함수에서 "5"라는 문자열을 calc() 함수에 넘김
  • 문자열이므로 호출되는 건 calc(String str)

🩵 메서드 오버로딩 (Overloading)

static int calc(String str) {
    int value = Integer.valueOf(str);
    if (value <= 1) return value;
    return calc(value - 1) + calc(value - 3);
}
  • Integer.valueOf(str); : 문자열을 정수로 변환
  • 재귀적으로 calc(int)를 호출! (value - 1, value - 3)
  • ⚠️ 주의: 여기서 호출되는 calc(value - 1) + calc(value - 3)int 버전의 calc()

🔍 동작 순서 분석

"5"calc(String) 호출됨
value = 5
calc(5 - 1) + calc(5 - 3) = calc(4) + calc(2)

📌 calc(4) - static int calc(int value)

calc(4 - 1) + calc(4 - 2)
= calc(3) + calc(2)
= (calc(2) + calc(1)) + (calc(1) + calc(0))
= ((calc(1) + calc(0)) + 1) + (1 + 0)
= ((1 + 0) + 1) + (1 + 0)
= (1 + 1) + 1 
= 2 + 1 = 3

📌 calc(2) - static int calc(int value)

calc(2 - 1) + calc(2 - 2)
calc(1) + calc(0) 
= 1 + 0 = 1

🩵 최종 결과

calc("5") = calc(4) + calc(2) = 3 + 1 = 4
profile
ʚȉɞ

0개의 댓글