C 기출의 절반이 포인터와 배열이다. 주소를 그림으로 그리고 첨자를 손으로 세면 답이 하나로 좁혀진다
*(p+1) 과 *p+1 의 차이, 2차원 배열의 행 · 열 첨자, 매개변수로 넘어간 배열이 포인터가 되는 것 — 이 넷이 15문항의 전부다. 종이에 칸을 그리며 추적하는 절차를 세운다.왜 이걸 하나 — 프로그래밍 91문항 중 C 가 42문항이고, 그중 15문항이 포인터 · 배열이다. 11회 중 9회에 나왔다.
11회분 220문항 중 이 장의 기출은 15문항이다. 2023년 2회에는 4문항(순환 출력 · 스택 · 공유 버퍼 · 선택 정렬)이 몰렸고, 2026년 2회 12번(sizeof)까지 이어진다. 코드 추적 훈련 10문항(훈련 C 1~4 · 23~26 · 28 · 29)이 이 장에 붙는다.
| 꼴 | 몇 문항 | 무엇을 적나 | 보기 |
|---|---|---|---|
| 문자열 포인터 출력 | 4 | %s · %c 로 여러 줄 | 2023-1회 2번 · 2023-3회 3번 · 2025-1회 10번 · 2025-3회 2번 |
| 배열 · 2차원 배열 계산 | 5 | 합 · 평균 · 특정 칸 값 | 2024-2회 11번 · 15번 · 2025-1회 11번 · 2026-1회 2번 · 2026-2회 12번 |
| 빈칸 채우기 | 3 | 변수명 · 첨자 식 · 비교 연산자 | 2023-1회 14번 · 2023-2회 9번 · 14번 |
| 포인터로 자료구조 | 3 | 스택 · 공유 버퍼 · 이중 포인터 | 2023-2회 11번 · 12번 · 2024-3회 19번 |
→ 답이 여러 줄인 문항이 4개다(2023-1회 2번 5줄 · 2023-3회 3번 5줄 · 2025-1회 10번 2줄 · 2026-2회 12번 4줄). 한 줄이라도 빠지거나 순서가 바뀌면 그 문항이 통째로 나가므로, 줄 수를 먼저 세고 시작한다.
E01 진단의 C 2문항 중 12번(sizeof 와 배열 매개변수)이 이 장이다. 코드 추적은 머릿속으로 하면 첨자 하나가 밀린다 — 칸을 그리고 화살표를 옮기는 습관이 03절이다.
문항 수는 이 노트의 문제 데이터에서 ch=E02 인 것을 센 값이다(2026-09-14). 기출 코드는 grandlife.co.kr 복원에서 옮겼고, 15문항 전부 gcc(도커 alpine)로 실행해 정답을 확인했다. 빈칸 문제 3개는 답을 넣어 실행하거나 컴파일해 확인했다.
왜 이걸 하나 — 시험 전날 규칙 8개를 다시 본다. 전부 「주소냐 값이냐」의 변주다.
int a[5] 에서 a 는 &a[0]. a[i] 는 *(a + i) 와 같다. 문자열 char w[] = "Art" 는 A · r · t · \0 네 칸.p + 1 은 한 칸(자료형 크기만큼) 옆의 주소. *(p + 1) 은 그 칸의 값, *p + 1 은 첫 칸 값에 1 을 더한 것. p++ 는 포인터를 옮기고, (*p)++ 는 값을 올린다.%s 에 주소를 주면 그 자리부터 \0 전까지 출력. %c 에 값을 주면 글자 하나. %c 에 *p + 4 를 주면 코드가 4 큰 글자(K → O).a[2][3] 은 행 2 열 3, 메모리에는 한 줄로 1 2 3 4 5 6. a[1][2] = *(*(a + 1) + 2). int *p = a[0] 이면 p[4] 는 5(한 줄로 센다).int arr[] 매개변수의 sizeof(arr) 는 포인터 크기(8). 값을 넘기면 복사본, 주소를 넘기면 원본이 바뀐다. 이중 포인터 int **pp 는 포인터의 주소.if (a[i] > a[j]) swap 이 오름차순. 버블은 이웃끼리 a[j] > a[j+1]. 스택은 top 을 올리며 넣고 내리며 뺀다. 순환 첨자는 (i + 1) % n.sizeof(a) / sizeof(a[0]). 배열 포인터 int (*p)[8] 의 *p 는 배열 전체(32).왜 이걸 하나 — 규칙 8개는 메모리를 칸으로 그리면 전부 한 그림에서 나온다. 그림이 있으면 처음 보는 코드도 같은 절차다.
char word[] = "Art"; 는 메모리에 A · r · t · \0 네 칸을 나란히 만들고, word 라는 이름은 그 첫 칸의 주소다. 그래서 printf("%s", word) 는 첫 칸부터 \0 전까지 Art 를 찍고, *word 는 첫 칸의 값 A 다. char *p = word; 로 포인터를 만들어도 같은 칸을 가리키니 *p 도 A 다(2023년 1회 2번).
포인터에 1 을 더하면 한 칸 옆의 주소가 된다. word + 1 은 r 의 주소라 %s 로 찍으면 rt 이고, *(word + 3) 은 넷째 칸 값이다. 2023년 3회 3번은 KOREA 로 이 다섯 가지를 한 문제에 넣었다 — %s word(KOREA), %s word+1(OREA), %c *word(K), %c *(word+3)(E), %c *word+4(K 의 코드 75에 4 를 더한 O).
마지막 것이 가장 자주 틀린다. *(word + 3) 은 「3칸 옆의 값」이고 *word + 3 은 「첫 칸 값에 3 을 더한 것」이다. 괄호가 있으면 주소를 먼저 옮기고, 없으면 값을 먼저 꺼낸다 — * 가 + 보다 먼저이기 때문이다. 2025년 3회 2번도 같은 갈림에서 C 가 답이었다.
int a[2][3] = {{1,2,3},{4,5,6}}; 는 그림으로는 2행 3열이지만 메모리에는 1 2 3 4 5 6 이 한 줄로 놓인다. a[1][2] 는 「둘째 행의 셋째 칸」이고 한 줄로 세면 1 × 3 + 2 = 5번째(0부터)라 6 이다. 그래서 int *p = a[0]; 처럼 첫 행의 주소를 한 줄 포인터에 담으면 p[4] 는 5, p[3] 은 4 다(예상 1회 9번).
포인터 식으로 쓰면 *(*(a + 1) + 2) 다. a + 1 은 둘째 행의 주소, *(a + 1) 은 그 행의 첫 칸 주소, 거기에 2 를 더해 셋째 칸, 마지막 * 로 값. 2024년 2회 15번과 훈련 3번이 이 식을 그대로 묻는다. 행 첨자에는 열 개수를 곱한다는 것만 기억하면 어느 칸이든 한 줄 번호로 바꿀 수 있다.
매개변수 자리의 int arr[] 는 배열이 아니라 포인터다. 그래서 함수 안에서 sizeof(arr) 는 배열 크기가 아니라 포인터 크기(64비트에서 8)이고, 2026년 2회 12번의 function3 이 8 / 4 = 2 를 찍는다. 배열 전체를 가리키는 int (*arr)[8] 로 받으면 *arr 가 배열 자체라 32 / 4 = 8 이 된다(function4).
같은 문제의 앞부분이 값 전달과 주소 전달이다. function1(&value) 는 주소를 받아 *p = 50 으로 원본을 바꾸고, function2(value) 는 복사본만 60 으로 바꿔 원본은 50 그대로다. 훈련 28번(값 전달 vs 주소 전달)이 같은 원리이고, 2024년 3회 19번은 포인터의 주소(int **)를 넘겨 원본 포인터를 바꾼다.
전역 버퍼도 같은 함정이다. 2023년 2회 12번은 scanf 로 읽어 전역 배열 buffer 의 주소를 돌려주는 함수를 세 번 부른다. 세 포인터가 같은 버퍼를 가리키므로 마지막에 읽은 gamma 가 세 번 찍힌다. 「포인터를 세 개 만들었으니 값도 세 개」라고 생각하면 틀린다.
빈칸 문제는 뼈대를 알아야 채운다. 첫 값을 맨 뒤로 보내는 순환 출력은 values[(i + 1) % 5] — i 가 4 일 때 5 % 5 = 0 으로 첫 칸에 돌아온다(2023년 2회 9번, 5 4 3 2 1 을 넣으면 4 3 2 1 5). 선택 정렬의 오름차순은 if (values[i] > values[j]) 에서 바꾸는 것이라 빈칸은 > 다(2023년 2회 14번). 버블 정렬의 swap 은 arr[idx2] = temp 로 끝나고 호출은 bubbleSort(values, size) 다(2023년 1회 14번).
스택은 top 하나로 돌아간다. push 는 top 을 올린 뒤 넣고, pop 은 값을 꺼낸 뒤 top 을 내린다. 2023년 2회 11번은 push 1 · 2, pop → 2, push 3, pop → 3, push 4 · 6, pop → 6, pop → 4, push 5, pop → 5, pop → 1 로 213465 다. pop 이 찍는 것은 가장 최근에 넣은 것이라 순서를 표로 적으면 틀리지 않는다.
%s p · %s p+1 · %c *p · %c *(p+n) · %c *p+n)의 출력을 KOREA 로 안 보고 적는다. 둘째, 2차원 배열의 칸을 한 줄 번호로 바꾼다. 셋째, 값 전달 · 주소 전달 · 배열 매개변수의 sizeof 를 가른다. 넷째, 스택 · 순환 첨자 · 정렬 뼈대를 손으로 한 바퀴 돌린다. 기출 15문항이 이 넷 안에 있다.* 가 + 보다 먼저다. *p + 1 은 첫 칸 값에 1 을 더한 것(K → L), *(p + 1) 은 둘째 칸의 값(O). 2023년 3회 3번의 마지막 줄 O 는 *word + 4 라 K 에 4 를 더한 것이다.int arr[] 는 포인터라 sizeof 가 8 이다. 2026년 2회 12번의 3.2 가 그 결과다. 배열 크기를 함수 안에서 알려면 길이를 따로 넘기거나 배열 포인터 int (*arr)[8] 로 받는다.왜 이걸 하나 — 코드를 종이에 칸으로 그리며 푸는 연습이다. 출력이 여러 줄이면 줄 수를 먼저 센다.
변수마다 칸을 그리고 포인터는 화살표로 그린다. printf 를 만날 때마다 답 칸에 한 줄씩 적고, 정답을 연 뒤 몇째 줄에서 어긋났는지를 보면 규칙 8개 중 무엇이 빠졌는지 나온다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — 다섯 줄: Art / A / A / Art / Art. 배열 이름 word 와 포인터 p 가 같은 자리를 가리키므로 같은 것을 두 번씩 찍는 셈이다.
원리 — C 에서 문자열은 글자를 한 칸에 하나씩 넣은 상자 줄이고 끝에 보이지 않는 끝표('\0')가 붙는다. "Art" 는 A · r · t · 끝표 네 칸이다. 배열 이름 word 는 그 줄의 첫 칸 주소이고, char *p = word 는 그 주소를 종이쪽지 p 에 베껴 적은 것이다. 그래서 word 로 가든 p 로 가든 도착하는 칸은 같다. %s 는 "그 주소부터 끝표 전까지 전부 찍어라", %c 는 "그 칸의 글자 하나만 찍어라"다. 별표 *p 는 "p 가 가리키는 칸의 내용"이라 첫 글자 A 다.
따라가기
printf("%s\n", word) — 첫 칸부터 끝표 전까지 → Art, 줄바꿈.printf("%c\n", *p) — p 가 가리키는 칸의 글자 → A.printf("%c\n", *word) — 배열 이름도 첫 칸 주소라 *word 는 첫 글자 → A.printf("%s\n", p) — p 부터 끝표 전까지 → Art.word[0] 부터 끝표를 만날 때까지 한 글자씩, 줄바꿈 없이 → Art.헷갈리는 자리 — 줄바꿈 수다. 앞 넷은 \n 이 있고 마지막 for 문은 없으니 답은 다섯 줄이고, 마지막 줄 뒤에 빈 줄이 없다. *word 를 "배열 전체"로 읽어 Art 라고 적는 것이 흔한 오답이다 — 별표는 언제나 칸 하나다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램에서 ①과 ②에 들어갈 변수명을 순서대로 쓰시오.
답 — ① idx2 ② size. ① 은 두 값을 맞바꾸는 마지막 단계에서 비어 있는 자리이고, ② 는 정렬 함수에 넘길 배열의 길이다.
원리 — 두 컵의 물을 맞바꾸려면 빈 컵이 하나 더 필요하다. temp = arr[idx1](첫째 컵을 빈 컵에), arr[idx1] = arr[idx2](둘째 컵을 첫째 컵에), 마지막으로 빈 컵의 물을 둘째 컵에 부어야 하니 arr[idx2] = temp 다. 이 세 줄은 순서가 정해져 있어 한 줄만 보여도 나머지가 정해진다. 버블 정렬은 이웃한 두 칸을 비교해 앞이 크면 맞바꾸는 일을 배열 길이만큼 반복하는 것이라, 함수는 배열과 그 길이 두 가지를 알아야 한다.
따라가기
size = 5 하나 → ② size.헷갈리는 자리 — ② 에 숫자 5 를 적는 것. 문제가 "변수명"을 물었으므로 5 는 틀린다. ① 에 idx1 을 적으면 첫째 컵에 두 번 붓는 꼴이라 둘째 컵이 그대로 남는다 — 맞바꾸기가 안 된다.
빈칸에 답을 넣어 gcc(도커 alpine)로 컴파일 · 실행해 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
정수 다섯 개를 배열에 입력한 뒤 첫 번째 값을 맨 뒤로 보내 출력하려고 한다. ①에 들어갈 식을 쓰시오.
답 — (i + 1) % 5. i 가 0 · 1 · 2 · 3 일 때는 다음 칸(1 · 2 · 3 · 4)을, i 가 4 일 때는 5 % 5 = 0 으로 첫 칸을 가리켜 첫 값이 맨 뒤로 간다.
원리 — 나머지 연산 % 는 회전판이다. 어떤 수를 5 로 나눈 나머지는 0 · 1 · 2 · 3 · 4 만 나오고, 5 가 되는 순간 다시 0 으로 돌아간다. 그래서 "첨자 하나 앞으로, 끝에 닿으면 처음으로"라는 움직임은 언제나 (첨자 + 1) % 크기 로 적는다. 원형 큐나 시계의 시침이 같은 규칙이다. 첫 번째 값을 맨 뒤로 보낸다는 말은 출력 순서를 1번 칸부터 시작해 마지막에 0번 칸을 찍는다는 뜻이다.
따라가기 — 입력이 1 2 3 4 5 라 하면 values 는 [1, 2, 3, 4, 5].
헷갈리는 자리 — i + 1 만 적으면 i = 4 에서 values[5] 를 읽어 배열 밖(쓰레기 값)이다. (i % 5) + 1 은 5 가 나올 수 있어 역시 밖으로 나간다. 괄호를 빼고 i + 1 % 5 로 적으면 % 가 먼저 계산돼 i + 1 과 같아진다 — 괄호가 답의 일부다.
빈칸에 답을 넣어 gcc(도커 alpine)로 컴파일 · 실행해 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — 213465. 넣은 순서의 거꾸로 꺼내는 스택을 push · pop 순서대로 그리면 한 자리씩 나온다.
원리 — 스택은 접시 더미다. 접시를 올릴 때(push) 맨 위에 놓고, 꺼낼 때(pop)도 맨 위 것을 집는다. 마지막에 넣은 것이 먼저 나온다(LIFO). 코드의 top 은 맨 위 접시가 놓인 칸 번호이고 처음엔 −1(접시 없음)이다. stack[++top] = value 는 top 을 하나 올린 뒤 그 칸에 넣는 것, stack[top--] 는 맨 위 칸을 읽은 뒤 top 을 하나 내리는 것이다. 읽은 값을 지우지는 않지만 top 이 내려갔으니 다음 push 가 그 칸을 덮는다.
따라가기 — 더미를 아래부터 적는다.
헷갈리는 자리 — 꺼낸 값을 지웠다고 생각해 다음 push 의 자리를 잘못 잡는 것과, 큐(먼저 넣은 것이 먼저)로 착각해 5 부터 적는 것. printf 에 줄바꿈이 없으니 여섯 자리를 붙여 적는다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램에 alpha, beta, gamma를 차례대로 입력했을 때 출력 결과를 줄마다 쓰시오.
답 — gamma / gamma / gamma. 세 포인터가 전부 같은 배열 buffer 를 가리키고, 그 배열엔 마지막 입력만 남아 있다.
원리 — readValue 는 값을 새로 만들어 주는 함수가 아니다. 전역 배열 buffer 한 채에 입력을 써넣고, 그 집의 주소를 돌려줄 뿐이다. 집은 하나인데 주소를 적은 쪽지(first · second · third)가 세 장인 셈이다. 두 번째 입력이 들어오면 같은 집의 내용이 지워지고 beta 로, 세 번째에 gamma 로 바뀐다. 나중에 세 쪽지를 따라가 보면 전부 같은 집이라 같은 글자가 보인다. 값을 따로 보관하려면 strcpy 로 다른 배열에 복사해야 한다.
따라가기
헷갈리는 자리 — alpha / beta / gamma 라고 적는 것. 포인터는 값을 담는 그릇이 아니라 주소를 적은 쪽지라는 것을 잊으면 그렇게 된다. 함수가 지역 배열을 돌려주지 않고 전역 배열을 쓰는 것이 이 코드의 함정 장치다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
선택 정렬로 배열을 오름차순 정렬하려고 한다. ①에 들어갈 비교 연산자를 쓰시오.
답 — >. 오름차순은 앞 칸이 뒤 칸보다 클 때 자리를 바꿔야 한다.
원리 — 선택 정렬의 이 꼴은 i 번째 칸을 고정하고 그 뒤의 모든 칸 j 와 비교해, 조건이 맞으면 두 칸을 맞바꾼다. 안쪽 반복이 끝나면 i 칸에는 뒤쪽 전체에서 가장 작은 값이 남는다. 오름차순(작은 것부터)이 되려면 "앞이 뒤보다 크다"가 교환 조건이어야 하므로 부등호는 > 다. 내림차순이면 반대로 <. 부등호를 "정렬 결과와 반대인 상태를 잡아내는 조건"으로 읽으면 헷갈리지 않는다.
따라가기 — 64 25 12 22 11 에서 i = 0 만 본다.
헷갈리는 자리 — >= 도 결과는 같지만 답은 문제가 준 꼴대로 > 하나를 적는다. < 를 넣으면 64 25 22 12 11 로 내림차순이 된다. 이 코드는 출력문이 없어 화면엔 아무것도 안 찍힌다는 것도 눈여겨본다.
빈칸에 답을 넣어 gcc(도커 alpine)로 컴파일 · 실행해 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 줄바꿈까지 맞춰 쓰시오.
답 — KOREA / OREA / K / E / O. 괄호가 있느냐 없느냐로 넷째 줄과 다섯째 줄이 갈린다.
원리 — char *word = "KOREA" 는 K · O · R · E · A · 끝표 여섯 칸의 첫 칸 주소다. 주소에 1 을 더하면(word + 1) 한 칸 옆의 주소이고, 거기서 %s 로 찍으면 그 칸부터 끝까지 나온다. 별표는 "그 주소의 칸을 열어라"이고, 열어 나온 것은 글자인데 글자는 사실 숫자(문자 코드)라 더하기가 된다. K 는 75, 75 + 4 = 79 는 O 다. *(word + 3) 은 "3칸 옆으로 간 뒤 연다", *word + 4 는 "첫 칸을 연 뒤 그 글자에 4 를 더한다" — 괄호가 순서를 바꾼다.
따라가기
%s, word → 첫 칸부터 → KOREA%s, word + 1 → 둘째 칸부터 → OREA%c, *word → 첫 칸 글자 → K%c, *(word + 3) → 넷째 칸(0 · 1 · 2 · 3) 글자 → E%c, *word + 4 → K(75) + 4 = 79 → O. 마지막 줄엔 줄바꿈이 없다.헷갈리는 자리 — 다섯째 줄을 A(4칸 옆 글자)로 적는 것. 별표가 먼저 붙어 글자를 꺼낸 뒤 4 를 더하므로 자리 이동이 아니라 글자 값 이동이다. 알파벳은 코드가 이어져 있어 K 에서 네 글자 뒤가 O 라고 세도 된다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — 10. "abc" 뒤에 "de" 를 이어 붙여 "abcde" 가 되고, 5 + (e − a) + 1 = 5 + 4 + 1 이다.
원리 — char text[10] = "abc" 는 열 칸짜리 상자 줄에 a · b · c · 끝표를 넣고 나머지는 0 으로 채운 것이다. text + 3 은 넷째 칸(첨자 3, 지금은 끝표가 있는 자리)의 주소이고, strcpy(text + 3, "de") 는 그 자리부터 d · e · 끝표를 써넣는다. 그러면 줄은 a b c d e 끝표가 되어 strlen(끝표 전까지 글자 수)이 5 다. 글자는 코드값이라 text[4] - 'a' 는 e 와 a 의 거리, 알파벳에서 e 는 a 로부터 네 번째이니 4 다.
따라가기
헷갈리는 자리 — strcpy 가 "이어 붙이기"가 아니라 "그 자리부터 덮어쓰기"라는 것. 시작 주소를 text 로 주면 "de" 가 a · b 를 덮어 "de" 만 남아 strlen 이 2 가 된다. 이 문제는 시작을 text + 3 으로 잡아 이어 붙이기처럼 보이게 한 것이다. 배열 크기 10 은 답에 안 쓰인다 — 크기와 길이는 다르다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — 21. p 는 둘째 칸(5)을 가리키고, *p = 5, *(p + 1) = 7, values[3] = 9 를 더하면 21 이다.
원리 — 배열 이름 values 는 첫 칸의 주소다. 주소에 1 을 더하면 "한 칸 옆"이지 "1바이트 옆"이 아니다 — int 한 칸이 4바이트라도 values + 1 은 둘째 칸이다. 그래서 int *p = values + 1 은 p 를 둘째 칸(5)에 세워 두는 것이다. 별표는 그 칸을 여는 것이므로 *p 는 5, *(p + 1) 은 p 에서 한 칸 더 간 셋째 칸 7 이다. values[3] 은 첨자로 직접 넷째 칸을 여는 것이라 9 다.
따라가기
*p = 5*(p + 1) → 첨자 2 → 7values[3] → 9. 합 5 + 7 + 9 = 21헷갈리는 자리 — *p + 1(값 5 에 1 을 더한 6)과 *(p + 1)(한 칸 옆의 값 7)의 차이다. 괄호가 있으면 자리를 옮기고, 없으면 값을 더한다. 또 p 가 첫 칸이 아니라 둘째 칸에서 시작한다는 것을 놓치면 3 + 5 + 9 = 17 로 틀린다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — 1. update 가 배열을 제자리에서 (값 + 첨자) % 5 로 바꾸고, 셋째 칸은 (4 + 2) % 5 = 1 이 된다.
원리 — int *p = values 는 배열 첫 칸의 주소를 적은 쪽지 p, int **pp = &p 는 "쪽지 p 가 놓인 자리"의 주소를 적은 두 번째 쪽지다. 그래서 *values(함수 안 이름)는 쪽지 p 의 내용, 즉 배열 첫 칸의 주소이고, *values + i 는 그 주소에서 i 칸 옆, 앞에 별표를 하나 더 붙인 *(*values + i) 가 그 칸의 값이다. 이중 포인터라 해도 결국 두 번 따라가서 원래 배열의 칸에 도착한다는 것이 전부다. 복사본이 아니라 원래 배열을 고치므로 main 의 values 가 바뀐다.
따라가기 — values = [3, 1, 4, 1, 5], size = 5. 새 값 = (옛 값 + i) % 5.
values[2] → 1헷갈리는 자리 — 별표 두 개를 보고 겁먹어 값을 안 바꾸는 함수라고 여기는 것. 주소를 넘겼으니 원본이 바뀐다. 또 % 를 빼먹고 6 을 적는 것 — 나머지 연산이 마지막에 있다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 두 줄로 쓰시오.
답 — 두 줄: 4 / BACDE. 첫 줄은 글자 코드의 차이, 둘째 줄은 C 를 제자리에 끼워 넣은 결과다.
원리 — 글자는 숫자(코드)라 빼기가 된다. E 는 69, A 는 65 이니 letters[3] - letters[1] 은 4 다. 둘째 부분은 "끼워 넣기"다. 배열 B A D E 에서 target C 보다 큰 첫 글자를 찾아(그 자리가 pos) 그 자리부터 뒤의 글자들을 한 칸씩 뒤로 밀고 빈 자리에 C 를 놓는다. 뒤에서부터 미는 이유는 앞에서부터 밀면 밀린 글자가 다음 글자를 덮어 버리기 때문이다. 다섯째 칸(끝표)이 밀려 사라지지만 출력은 다섯 글자를 그대로 찍는다.
따라가기
헷갈리는 자리 — B A 가 정렬돼 있지 않은데 "정렬된 배열에 끼워 넣기"로 넘겨짚어 ABCDE 라 적는 것. 코드는 정렬하지 않고 C 보다 큰 첫 글자 앞에 끼울 뿐이다. 첫 줄의 4 는 첨자 차이(3 − 1 = 2)가 아니라 글자 값 차이다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — 13. 아홉 값을 3×3 격자에 한 칸 밀린 자리로 채운 뒤 짝수 첨자는 더하고 홀수 첨자는 뺀다.
원리 — 2차원 배열의 칸 번호를 한 줄 번호로 바꾸는 규칙은 행 = 번호 / 3, 열 = 번호 % 3 이다(3열짜리). place 는 값 i 를 번호 i + 1 자리에 넣되 행에 % 3 을 한 번 더 걸어, 번호 9 는 행 3 이 아니라 행 0 으로 돌아간다. 즉 values 를 격자에 순서대로 넣되 한 칸 뒤로 밀고 마지막 값이 맨 앞으로 돈다. 합을 구할 때 i % 2 == 0 ? 1 : -1 은 첨자가 짝수면 +, 홀수면 − 라는 뜻이다.
따라가기
헷갈리는 자리 — i = 8 에서 행이 3 이 되어 배열 밖이라고 보는 것. % 3 때문에 0 행으로 돈다. 그리고 부호는 값의 첨자(i)가 아니라 합칠 때의 i 로 정해진다 — 격자를 한 줄로 편 뒤에 번갈아 붙인다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — C. p 는 둘째 원소 {2, "DC"} 를 가리키고, "DC" 의 주소에서 한 칸 옆부터 끝까지 찍으면 C 다.
원리 — 구조체 배열의 원소 하나는 offset 과 text 두 칸을 가진 묶음이다. &items[1] 은 둘째 묶음의 주소이고, p->text 는 그 묶음 안의 text, 즉 문자열 "DC" 의 첫 글자 주소다. 문자열 주소에 수를 더하면 그만큼 옆 글자부터 시작하는 문자열이 된다. %s 는 시작 주소부터 끝표 전까지 찍으므로 "DC" + 1 은 "C" 다. 화살표 -> 는 "포인터가 가리키는 구조체의 그 칸"이라는 뜻으로 (*p).text 와 같다.
따라가기
헷갈리는 자리 — items[1] 을 "1번째"로 읽어 첫 묶음 {1, "AB"} 로 보는 것(첨자는 0 부터). 그리고 %c 가 아니라 %s 라 글자 하나가 아니라 그 자리부터 끝까지인데, 여기선 남은 글자가 C 하나라 결과가 같아 보일 뿐이다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — 106.00. 두 함수는 같은 배열의 평균 53.0 을 각각 돌려주고, %.2f 가 소수 둘째 자리까지 찍는다.
원리 — 함수 매개변수의 int p[] 와 int *p 는 완전히 같은 것이다. 배열을 넘기면 복사되지 않고 첫 칸 주소만 넘어가므로, 어느 쪽으로 적어도 함수 안의 p 는 포인터다. 따라서 p[i] 와 *(p + i) 도 같은 칸을 읽는다 — 대괄호는 "주소에 i 를 더해 연다"의 다른 표기일 뿐이다. 두 함수는 이름과 표기만 다르고 하는 일이 같아 결과가 같다. (double) 은 정수를 실수로 바꿔 나눗셈에서 소수점이 잘리지 않게 한다.
따라가기
%.2f → 106.00헷갈리는 자리 — 106 이나 106.0 으로 적는 것. 서식 문자열이 답의 일부라 소수점 아래 두 자리까지 적어야 한다. 또 "arr2 가 포인터라 다른 값이 나온다"고 넘겨짚는 것 — 표기가 다를 뿐 같은 칸이다. (double) 을 빼면 av 가 double 이라 어차피 실수 나눗셈이지만, av 까지 int 였다면 53 이 아니라 소수점이 잘린 값이 나온다 — 나눗셈은 두 쪽 중 하나만 실수여도 실수로 계산된다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 줄 단위로 쓰시오. 단, sizeof(int)=4, sizeof(int*)=8이다.
답 — 네 줄: 1.50 / 2.50 / 3.2 / 4.8. 주소를 넘긴 함수만 원본을 바꾸고, 배열 매개변수의 sizeof 는 포인터 크기가 된다.
원리 — 함수에 값을 넘기면 복사본이 만들어져 함수 안에서 아무리 바꿔도 원본은 그대로다(function2). 주소를 넘기면 함수가 그 주소로 찾아가 원본을 고친다(function1). 배열을 매개변수로 받을 때 int arr[] 라고 써도 실제로는 int *arr, 즉 주소 하나만 받는다. 그래서 sizeof(arr) 는 배열 전체(32)가 아니라 포인터 크기 8 이다. 반면 int (*arr)[8] 은 "int 8개짜리 배열을 가리키는 포인터"라 *arr 가 배열 자체이고 sizeof(*arr) 는 4 × 8 = 32 다.
따라가기
헷갈리는 자리 — 둘째 줄을 2.60 으로 적는 것(값 전달은 원본을 못 바꾼다)과 셋째 줄을 3.8 로 적는 것(배열 매개변수는 포인터). "1." "2." 같은 앞 글자는 프로그램이 찍는 것이라 답에 그대로 들어간다. 문제가 sizeof(int) = 4, sizeof(int*) = 8 을 준 이유가 셋째 줄이다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 코드의 출력을 쓰시오.
답 — ATION / F / K (세 줄). 포인터에 더하는 것과 글자에 더하는 것이 다르다는 것을 한 문제에 넣었다.
원리 — s 는 문자열 "INFORMATION" 의 첫 글자 주소를 담은 포인터다. s + 6 은 "여섯 글자 뒤의 주소"이고 %s 는 그 주소부터 널 문자까지 찍으니 7번째 글자부터 끝까지 나온다. *(s + 2) 는 "두 글자 뒤 주소의 내용" = 세 번째 글자 하나다. *s + 2 는 우선순위가 다르다 — * 가 + 보다 먼저라 "첫 글자의 내용"에 2 를 더한 것이고, 문자는 정수(아스키 코드)라 'I' 의 코드 73 + 2 = 75 = 'K' 가 된다. 괄호 위치 하나가 "주소를 옮기나, 글자를 바꾸나"를 가른다.
따라가기
헷갈리는 자리 — *s + 2 를 *(s + 2) 로 읽어 F 라고 적는 것. 괄호가 없으면 * 가 먼저 붙는다. 그리고 %c 로 찍으니 숫자 75 가 아니라 글자 K 다 — %d 였다면 75 가 찍힌다. 번호는 0 부터 세는 것도 늘 확인한다.
이전 자료의 예상 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
다음 코드의 출력을 쓰시오.
답 — 5 4. 2차원 배열도 메모리에는 한 줄로 놓이므로, 첫 칸 주소에서 4칸 뒤는 두 번째 행의 두 번째 원소다.
원리 — int a[2][3] 은 "3칸짜리 행이 2개"이고 메모리에는 1 2 3 4 5 6 이 이어서 놓인다(행 우선). a[0] 은 첫 행의 시작 주소이므로 p = a[0] 은 1 이 있는 칸을 가리킨다. p + 4 는 int 4개 뒤, 곧 통째로 세었을 때 5번째(0부터 4번) 칸이라 값은 5 다. a[1][0] 은 두 번째 행의 첫 원소 4 다. 2차원 첨자 [i][j] 를 1차원 번호로 바꾸면 i × 열 수 + j 이고, 거꾸로 번호 4 는 4 ÷ 3 = 1 행, 4 % 3 = 1 열 → a[1][1] = 5 다.
따라가기
헷갈리는 자리 — p 가 int * 이므로 p + 4 는 4바이트가 아니라 int 4개(16바이트)만큼 간다는 것. 그리고 a + 1 은 "행 하나(int 3개)" 를 건너뛰지만 a[0] + 1 은 "원소 하나"를 건너뛴다 — 같은 + 1 인데 타입에 따라 보폭이 다르다.
이전 자료의 예상 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
다음 코드의 출력을 쓰시오.
답 — 10,15. 짝수 8 + 2 = 10, 홀수 3 + 5 + 7 = 15 다.
원리 — % 는 나머지 연산이고, a[i] % 2 가 0 이면 짝수다. 반복문이 배열 5칸을 차례로 보며 짝수는 s1 에, 홀수는 s2 에 더한다. if 에 중괄호가 없으면 바로 다음 문장 하나만 if 에 속하고, else 는 그 if 의 짝이다 — 한 줄에 적혀 있어도 구조는 if { s1 += } else { s2 += } 다. printf 서식이 "%d,%d" 라 두 수 사이에 쉼표가 공백 없이 붙는다 — 서식 문자열의 글자는 그대로 찍힌다.
따라가기
헷갈리는 자리 — 서식의 쉼표를 빼고 "10 15" 로 적는 것. 시험은 출력을 글자 그대로 채점하니 서식 문자열의 구두점 · 공백을 그대로 옮긴다. 음수가 섞였다면 C 의 % 는 부호가 피제수를 따라 -3 % 2 = -1 이라 "== 0" 판정은 그대로 되지만 "== 1" 판정은 깨진다는 것도 알아 둔다.
이전 자료의 예상 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
왜 이걸 하나 — 코드 추적은 원리를 알아도 표기와 줄에서 깎인다.
| 자리 | 새는 꼴 | 적는 법 | 기출 |
|---|---|---|---|
| 줄 수 | 5줄 출력에서 한 줄을 빼먹는다 | printf 마다 \n 이 있는지 보고 줄 수를 먼저 센다 | 2023-1회 2번 · 2023-3회 3번 |
| 괄호 | *p + 1 을 옆 칸으로 읽는다 | * 가 먼저. 괄호가 있어야 주소가 먼저 움직인다 | 2023-3회 3번 · 2025-3회 2번 |
| 소수점 · 서식 | %.2f 를 정수로, %zu 앞의 「3.」을 소수점으로 | 서식을 그대로 옮긴다. 2026-2회 12번의 3.2 는 「3.」 뒤에 2 | 2026-1회 2번 · 2026-2회 12번 |
| 공유 버퍼 | 세 포인터에 세 값을 적는다 | 같은 전역 배열이면 마지막 값이 전부 | 2023-2회 12번 |
| 순환 첨자 | (i + 1) % 5 를 i + 1 로 | 마지막에 첫 칸으로 돌아가는 % 가 빈칸의 핵심 | 2023-2회 9번 |
| 비교 방향 | 오름차순에 < 를 적는다 | 앞이 뒤보다 크면 바꾼다 → > | 2023-2회 14번 |
| 변수명 | 빈칸에 비슷한 이름(idx1 · length)을 적는다 | 코드에 선언된 이름 그대로. swap 의 마지막은 idx2, 호출은 size | 2023-1회 14번 |
| 공백 · 줄바꿈 | 「4 BACDE」를 한 줄로 | 「두 줄로 쓰시오」면 두 줄. printf 의 \n 을 따른다 | 2025-1회 10번 |
C 출력 문제는 printf 의 서식 문자열이 곧 답의 꼴이다. 답을 적기 전에 서식(%d %c %s %.2f, 공백, \n)을 답 칸 옆에 베껴 두면 표기 감점이 사라진다.
왜 이걸 하나 — 기출과 같은 원리를 짧은 코드 10개로 돌린다. 매일 5문항씩 곁들이는 자리다.
훈련 10문항은 포인터 문자열 3종, 포인터 누적, 2차원 이중 역참조, swap, 최솟값 · 최댓값, 버블 1회전, 선택 정렬, 포인터 순회, 값 · 주소 전달, 인덱스 체인이다. 정답은 전부 gcc 로 실행해 확인했다.
답 — PUTER / O / D (세 줄). P-1-02 와 같은 세 가지 — 주소 이동 · 글자 하나 · 글자 더하기다.
원리 — p 는 "COMPUTER" 의 첫 글자 주소다. p + 3 은 세 글자 뒤 주소이고 %s 는 거기서부터 끝까지 찍는다. *(p + 1) 은 한 글자 뒤의 내용, 곧 두 번째 글자다. *p + 1 은 * 가 먼저 붙어 첫 글자 'C'(67) 에 1 을 더한 68 = 'D' 다. 문자는 정수로 다뤄지므로 더하기가 되고, %c 가 그 정수를 글자로 찍는다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — 18. i 가 0 · 2 · 4 일 때의 원소 2 + 6 + 10 이다.
원리 — 배열 이름 a 는 첫 원소의 주소로 쓰이므로 p = a 는 p 가 a[0] 을 가리키게 한다. *(p + i) 는 a[i] 와 완전히 같은 뜻이다 — 포인터 산술이 곧 첨자다. 반복문은 i += 2 라 0 · 2 · 4 만 돌고 5 에서 멈춘다(5 < 5 거짓). 그래서 짝수 번 칸만 더한다. 조건식이 i < 5 인지 i <= 5 인지에 따라 마지막 칸 포함 여부가 갈리니 반드시 확인한다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — 6 6. *(*(a+1)+2) 는 a[1][2] = 6 이고, a[0][1] + *(a[1]) 은 2 + 4 = 6 이다.
원리 — 2차원 배열에서 a + 1 은 "두 번째 행"의 주소다(행 하나만큼 건너뜀). *(a + 1) 은 그 행 자체, 곧 a[1] 이고 이것은 다시 첫 원소의 주소로 쓰인다. 거기에 + 2 하고 * 를 붙이면 a[1][2] 다. 즉 a[i][j] 는 *(*(a + i) + j) 의 줄임이다. *(a[1]) 은 a[1] 행의 첫 원소 a[1][0] = 4 다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — 7 3. 주소를 넘겼으므로 함수 안에서 바꾼 것이 main 의 a · b 에 그대로 반영된다.
원리 — C 는 값 복사로 인자를 넘긴다. swap(a, b) 로 값을 넘기면 함수 안의 복사본만 바뀌고 main 의 a · b 는 그대로다. 그래서 &a · &b 로 "주소"를 넘기고, 함수는 *x · *y 로 그 주소의 내용을 직접 읽고 쓴다. t 에 *x 를 보관하고 *x 에 *y 를 넣고 *y 에 t 를 넣으면 두 칸의 내용이 맞바뀐다. 이것이 C 에서 함수가 호출자의 변수를 바꾸는 유일한 방법이다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — 1 9 8. 최솟값 1, 최댓값 9, 차 8 이다.
원리 — 최솟값 · 최댓값 찾기의 정석은 "첫 원소로 시작해 나머지를 하나씩 비교"다. min 과 max 를 a[0] = 7 로 두고 i = 1 부터 본다. 더 작으면 min 을 갈아 끼우고, 더 크면 max 를 갈아 끼운다. 두 if 가 독립이라 한 원소가 둘 다 갱신할 수도, 둘 다 안 할 수도 있다. 0 이 아니라 a[0] 으로 시작하는 이유는 전부 음수이거나 전부 큰 수일 때도 맞게 하기 위해서다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — 24135. 버블 정렬을 "한 바퀴만" 돌린 결과라 완전히 정렬되지 않았다.
원리 — 버블 정렬은 이웃한 두 칸을 비교해 앞이 크면 바꾸며 오른쪽으로 간다. 한 바퀴가 끝나면 가장 큰 값이 맨 끝에 가 있다(거품이 떠오르듯). 완전 정렬은 바깥 반복이 n−1 바퀴 필요한데 이 코드는 바깥 반복이 없이 j 반복 한 번뿐이다. 그러니 "가장 큰 5 가 끝으로 간 것" 까지만 보장되고 나머지는 어정쩡하다. 문제는 그 어정쩡한 상태를 정확히 적으라는 것이다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — 1234. 선택 정렬 꼴의 이중 반복이라 끝까지 돌면 오름차순이 된다.
원리 — 바깥 i 가 "지금 채울 자리", 안쪽 j 가 "그 뒤의 모든 칸"이다. a[i] 보다 작은 a[j] 를 만날 때마다 바꾸므로 안쪽 반복이 끝나면 a[i] 에는 i 번부터 끝까지 중 가장 작은 값이 와 있다. i 를 0 · 1 · 2 로 옮기며 반복하면 앞에서부터 차례로 최솟값이 채워져 정렬이 끝난다. 마지막 칸은 남은 하나라 자동으로 맞다(그래서 i < 3).
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — 4. "informatics" 의 모음 i · o · a · i 를 센다.
원리 — while (*p) 는 "p 가 가리키는 글자가 널('\0', 값 0)이 아닌 동안"이다. C 문자열은 끝에 널이 있어 이 조건이 자연스럽게 끝을 찾는다. 안에서 글자를 다섯 모음과 비교해 맞으면 c 를 올리고, p++ 로 다음 글자로 옮긴다. 대문자 모음은 검사에 없으니 소문자만 센다 — 이 문자열은 전부 소문자라 상관없다. || 로 이은 다섯 비교 중 하나라도 참이면 전체가 참이다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — 5 15. 값으로 넘긴 f 는 원본을 못 바꾸고, 주소로 넘긴 g 는 바꾼다.
원리 — f(a) 는 a 의 값 5 를 복사해 n 에 넣는다. n = n + 10 은 그 복사본만 15 로 만들고 함수가 끝나면 사라진다 — main 의 a 는 5 그대로다. g(&a) 는 a 의 주소를 넘긴다. *n = *n + 10 은 "그 주소의 내용"을 바꾸므로 main 의 a 가 15 가 된다. 같은 "+10" 인데 무엇을 넘겼느냐로 결과가 갈린다. 이것이 T-C-04 swap 이 포인터를 쓰는 이유이기도 하다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
답 — 10 30 40 20. 배열 두 개로 흉내 낸 연결 리스트를 next 를 따라 도는 것이다.
원리 — data 는 값, next 는 "다음 칸 번호"다. cur 이 지금 칸이고, 값을 찍은 뒤 cur = next[cur] 로 다음 칸으로 건너뛴다. −1 은 "끝"이라는 약속이라 while (cur != −1) 이 멈춘다. 배열 번호 순서(0 1 2 3)가 아니라 next 가 가리키는 순서(0 → 2 → 3 → 1)로 도는 것이 핵심이다. 포인터 없이 배열 인덱스로 링크를 표현한 연결 리스트다.
따라가기
이 노트에서 만든 변형 문제다. 코드를 손으로 따라가고 docker gcc(alpine 13.2) 실행 결과와 대조했다.
이 컴퓨터에는 gcc 가 없어 도커로 돌렸다. 파워셸에서 코드를 main.c 로 저장한 뒤 아래를 치면 컴파일과 실행이 한 번에 된다(도커 데스크톱이 떠 있어야 한다).
이 장의 기출 15개 · 훈련 10개는 위와 같은 방법(alpine 3.20 의 gcc)으로 실행해 답을 확인했다. sizeof(int)=4 · sizeof(int*)=8 인 64비트 환경이라 2026-2회 12번의 전제와 같다.
왜 이걸 하나 — 아래를 안 보고 적을 수 있어야 포인터 문제가 끝난다.
%s p · %s p+1 · %c *p · %c *(p+3) · %c *p+4 의 출력 다섯 줄.a[2][3] 에서 a[1][2] 가 한 줄 몇 번째 칸인지, 포인터 식으로 어떻게 쓰는지.int arr[] 의 sizeof 가 왜 8 인지, int (*arr)[8] 과의 차이.(i + 1) % n, 선택 정렬의 비교 방향, 스택 push · pop 의 순서.* 가 + 보다 먼저다. 괄호가 주소와 값을 가른다.