주소를 통한 변경
출력은?
int x=5; int *p=&x;
*p += 4;
printf("%d %d", x, *p);정답과 풀이 확인
정답 9 9
p가 x를 가리킨다. *p에 4를 더하면 x가 9가 되어 두 출력 모두 9다.
이 브라우저에서 다음 학습에도 적용됩니다.
정보처리 실무 · 학습 노트
주소와 값을 나누면 포인터가 보인다
C는 이 자료에서 가장 먼저 시간을 투자할 영역이다. JavaScript 객체 참조와 비슷한 직관은 도움이 되지만, 주소 산술·배열·문자열 종료 문자는 별도로 배워야 한다. 예제는 C11의 정의된 동작을 기준으로 작성했다.
기호와 용어가 낯설면 기초·상세 보강을 먼저 읽고, 기존 핵심 정리로 연결하세요. 예제의 값을 손으로 계산한 뒤 확인 질문을 답하고 마지막에 문제를 풉니다.
핵심 규칙을 설명하고, 연습문제의 답과 이유를 해설 없이 적을 수 있으면 체크하세요. 이해 체크와 정답 기록은 별도로 저장됩니다.
int는 정수, double은 실수, char는 문자 코드 하나를 저장한다. printf의 %d는 int, %c는 문자, %s는 널 종료 문자열, %.2f는 소수 둘째 자리까지 표시한다.
“자료형과 출력”의 핵심 규칙과 헷갈리는 지점을 설명해 보세요.
문자 하나는 'A', 문자열은 "A". char s[]="WEB"는 W,E,B,\0의 4칸이다. int의 바이트 수를 무조건 4라고 단정하지 말 것. sizeof 결과는 문제에서 주어진 환경을 따른다.
문자 하나는 'A', 문자열은 "A". char s[]="WEB"는 W,E,B,\0의 4칸이다.
헷갈리는 지점 int의 바이트 수를 무조건 4라고 단정하지 말 것. sizeof 결과는 문제에서 주어진 환경을 따른다.
변수는 값이 놓인 칸, &x는 그 칸의 주소, int *p는 정수 칸의 주소를 저장하는 변수다. *p는 p가 가리키는 칸의 값이다. *p를 변경하면 원본 x가 바뀐다.
int x = 7;
int *p = &x;
*p += 3; // x가 10이 된다p=&x 뒤 *p=9를 실행하면 x는?
9. p는 같은 x 칸을 가리킨다.
선언의 *는 포인터 선언, 식의 *는 역참조다. p와 *p는 전혀 다르다.
헷갈리는 지점 int *p, x;에서 p만 포인터다. x는 정수다.
a[i]는 *(a+i)와 같은 원소 접근이다. p+1은 1바이트가 아니라 가리키는 자료형 원소 1개만큼 이동한다. 배열 이름은 많은 식에서 첫 원소 주소로 변환되지만 배열 자체와 포인터 변수는 같지 않다.
“배열과 포인터 산술”의 핵심 규칙과 헷갈리는 지점을 설명해 보세요.
int a[3]={4,8,12}; p=a; → *p=4, *(p+2)=12. sizeof(a)는 실제 배열 선언이 보이는 곳에서 전체 배열 크기지만 함수의 int a[] 매개변수는 포인터로 조정된다.
int a[3]={4,8,12}; p=a; → *p=4, *(p+2)=12.
헷갈리는 지점 sizeof(a)는 실제 배열 선언이 보이는 곳에서 전체 배열 크기지만 함수의 int a[] 매개변수는 포인터로 조정된다.
*p++는 *(p++)이므로 기존 위치의 값을 사용한 후 포인터가 이동한다. (*p)++는 가리키는 값 자체를 증가시킨다. *++p는 먼저 포인터 이동, ++*p는 먼저 가리키는 값 증가다.
“증감식 읽는 법”의 핵심 규칙과 헷갈리는 지점을 설명해 보세요.
p 변화와 배열 원소 변화를 별도 열에 기록한다. printf("%d %d", i++, i++)처럼 같은 변수의 순서 없는 변경은 C에서 정의되지 않은 동작이다. 임의의 정답을 암기하지 않는다.
p 변화와 배열 원소 변화를 별도 열에 기록한다.
헷갈리는 지점 printf("%d %d", i++, i++)처럼 같은 변수의 순서 없는 변경은 C에서 정의되지 않은 동작이다. 임의의 정답을 암기하지 않는다.
strlen은 종료 문자 전까지의 길이를 센다. sizeof는 저장 공간을 센다. char s[]는 수정 가능한 배열, 문자열 리터럴을 가리키는 char *를 통한 리터럴 수정은 허용되지 않는다. 이차원 배열은 행 단위로 연속 저장한다.
“문자열과 이차원 배열”의 핵심 규칙과 헷갈리는 지점을 설명해 보세요.
int a[2][3]에서 a+1은 다음 행, *(*(a+1)+2)는 a[1][2]. C 문자열은 +로 이어 붙일 수 없다. 문자열 비교는 strcmp 결과가 0인지 확인한다.
int a[2][3]에서 a+1은 다음 행, *(*(a+1)+2)는 a[1][2].
헷갈리는 지점 C 문자열은 +로 이어 붙일 수 없다. 문자열 비교는 strcmp 결과가 0인지 확인한다.
모든 함수 인자는 값으로 전달된다. 정수 복사본을 바꿔도 호출자의 정수는 그대로다. 주소의 복사본을 받으면 *p로 호출자의 칸을 바꿀 수 있다. 지역 static은 한 번 초기화하고 호출 사이 값을 유지한다.
“함수 인자와 static”의 핵심 규칙과 헷갈리는 지점을 설명해 보세요.
일반 지역변수는 호출마다 별개, 지역 static은 생존 기간이 프로그램 전체다. 주소를 전달해 원본을 바꾸는 관용 표현을 보고 C 자체가 참조 전달이라고 쓰지 않는다.
일반 지역변수는 호출마다 별개, 지역 static은 생존 기간이 프로그램 전체다.
헷갈리는 지점 주소를 전달해 원본을 바꾸는 관용 표현을 보고 C 자체가 참조 전달이라고 쓰지 않는다.
struct는 여러 필드를 하나로 묶는다. 변수 n의 필드는 n.value, 구조체 포인터 p의 필드는 p->value로 접근한다. p->value는 (*p).value와 같다.
“구조체와 연결 자료구조”의 핵심 규칙과 헷갈리는 지점을 설명해 보세요.
연결 리스트에서는 선언 순서가 아니라 next 화살표를 따른다. 트리는 left/right와 재귀 호출 순서를 그린다. 노드의 값을 교환하는 것과 next 포인터를 바꿔 노드의 순서를 교환하는 것은 다르다.
연결 리스트에서는 선언 순서가 아니라 next 화살표를 따른다. 트리는 left/right와 재귀 호출 순서를 그린다.
헷갈리는 지점 노드의 값을 교환하는 것과 next 포인터를 바꿔 노드의 순서를 교환하는 것은 다르다.
&는 둘 다 1, |는 하나라도 1, ^는 서로 다르면 1이다. 부호 없는 작은 양수의 <<는 범위 안에서 2의 거듭제곱을 곱하는 효과다. switch는 일치한 case부터 시작한다.
“비트 연산과 switch”의 핵심 규칙과 헷갈리는 지점을 설명해 보세요.
break가 없으면 다음 case까지 계속 실행되는 fall-through를 확인한다. 음수 시프트·오버플로·잘못된 시프트 크기는 단순한 산술 규칙으로 풀지 않는다. signed 정수 오버플로는 C에서 정의되지 않는다.
break가 없으면 다음 case까지 계속 실행되는 fall-through를 확인한다.
헷갈리는 지점 음수 시프트·오버플로·잘못된 시프트 크기는 단순한 산술 규칙으로 풀지 않는다. signed 정수 오버플로는 C에서 정의되지 않는다.
strcpy(dest,src)는 dest에 src를 널 문자까지 복사한다. strcat(dest,src)는 dest 문자열의 끝에 src를 이어붙인다. strcmp(a,b)는 사전순으로 a가 작으면 음수, 같으면 0, 크면 양수를 반환한다.
“문자열 처리 함수”의 핵심 규칙과 헷갈리는 지점을 설명해 보세요.
dest 버퍼는 복사·연결 후 결과를 담을 만큼 충분히 커야 한다. strcmp의 반환값이 항상 -1,0,1이라고 단정하지 않는다. 부호만 의미가 있다.
dest 버퍼는 복사·연결 후 결과를 담을 만큼 충분히 커야 한다.
헷갈리는 지점 strcmp의 반환값이 항상 -1,0,1이라고 단정하지 않는다. 부호만 의미가 있다.
C 프로그램은 main에서 시작하고 중괄호로 블록, 세미콜론으로 대부분의 문장 끝을 표시한다. #include는 헤더의 선언을 사용하게 한다. //와 /* ... */는 주석이어서 출력되지 않는다. 변수는 사용 전에 자료형을 선언한다.
int a=3;은 정수 변수 생성·초기화, a=5;는 변경, a==5는 비교다. &&는 논리 AND, ||는 논리 OR, !는 논리 NOT이다. 조건에서는 0이 거짓이고 0이 아닌 값이 참이다.
#include <stdio.h>
int main(void) {
int x = 3;
if (x != 0) { printf("%d", x); }
return 0;
}| 기호 | 의미 |
|---|---|
| &x | x의 주소 |
| *p | p가 가리키는 값 |
| a[i] | i번 원소 |
| p->v | 구조체 포인터의 필드 |
| ?: | 조건에 따라 값 선택 |
| % | 나머지(printf 문자열 안에서는 형식 시작) |
int *p에서 *와 x*y에서 *는 같은 뜻인가?
포인터 선언과 곱셈으로 문맥이 다르다. *p가 식이면 역참조.
printf 사용에는 stdio.h, strlen·strcmp에는 string.h를 포함한다.
헷갈리는 지점 C의 //는 주석이다. Python의 //와 다르다. =를 비교 기호로 착각하지 않는다.
정수끼리 /는 소수 부분을 0 방향으로 버린다. (double)a/b는 a를 먼저 실수로 바꿔 실수 나눗셈을 하고 (double)(a/b)는 정수 나눗셈 후 이미 잘린 결과를 실수로 바꾼다. 작은 정수형 char·short는 많은 연산에서 int로 승격된다.
char는 문자 코드를 저장하는 정수형이다. 문제에서 ASCII를 가정한다면 '0'은 48, 'A'는 65다. 숫자 문자 '7'에서 '0'을 빼면 정수 7을 얻는다.
int a=7, b=2;
printf("%.1f %.1f %d", (double)a/b, (double)(a/b), '7'-'0');C의 -7/3, -7%3은?
-2, -1. -7=(-2)×3+(-1).
변환을 언제 했는지 괄호로 확인한다. 실수 저장 변수라고 계산도 실수인 것은 아니다.
헷갈리는 지점 char의 signed 여부와 int 크기는 구현에 따라 다를 수 있다. 문제 조건을 따른다.
++i는 증가한 새 값을 식에서 사용하고 i++는 이전 값을 식에서 사용하면서 i를 증가시킨다. 독립 문장 i++;와 ++i;는 둘 다 i를 1 증가시킨다. +=, -=, *=는 계산과 대입을 함께 하는 복합 대입이다.
for(초기화;조건;증감)은 초기화를 한 번 한 뒤 조건·본문·증감을 반복한다. while은 먼저 조건 검사, do-while은 본문을 한 번 실행한 뒤 조건 검사한다. switch의 case에서 break가 없으면 뒤 case 본문으로 계속 흐른다.
int i=2;
int a=i++;
int b=++i;
printf("%d %d %d",a,b,i);for에서 continue를 만나면 증감식은 실행되는가?
실행된다. 현재 본문의 나머지만 건너뛴다.
각 문장이 끝난 뒤 i와 대입된 변수를 따로 적는다.
헷갈리는 지점 C에서 같은 스칼라를 순서 없이 여러 번 변경하는 식은 정답을 임의로 추적하지 않는다.
int a[4]={1,2};는 나머지 원소를 0으로 초기화한다. 지역 배열을 초기화하지 않으면 값을 보장할 수 없다. int *p=a;는 p가 a[0]의 주소를 가리키게 한다. a[i]와 *(a+i)는 같은 원소다.
int **pp=&p;는 포인터 변수 p의 주소를 저장한다. *pp는 p, **pp는 p가 가리키는 int 값이다. 주소를 한 단계 따라갈 때마다 *가 하나 필요하다. 배열 범위 밖을 역참조하면 정의된 출력이 없다.
int x=3;
int *p=&x;
int **pp=&p;
**pp=8;
printf("%d %d", x, *p);int a[4]={1,2};의 a[3]은?
0. 일부만 초기화한 나머지 원소는 0으로 초기화된다.
주소 화살표 pp → p → x. **pp를 바꾸면 x가 바뀐다.
헷갈리는 지점 배열 바로 뒤의 포인터를 만들 수 있어도 그 위치를 역참조할 수는 없다.
문자열은 char 배열에 문자들과 마지막 \0을 저장한다. strlen은 \0 전까지 문자 개수, strcpy는 종료 문자까지 복사, strcat는 끝에 붙이고 strcmp는 사전순 비교 결과가 음수·0·양수인지 알려준다. 목적지에는 충분한 공간이 필요하다.
scanf("%d", &x)는 읽은 값을 x에 저장하려고 주소를 받는다. char s[20]에 scanf("%19s",s)는 첫 원소 주소를 전달한다. %s는 공백 전까지 읽으므로 한 줄 전체 입력과 다르다.
char s[10]="AB";
strcat(s,"CD");
printf("%s %zu",s,strlen(s));char s[]="A";의 sizeof(s)와 strlen(s)는?
2와 1. sizeof에는 종료 문자 공간이 포함된다.
strcmp(a,b)==0이면 내용이 같다. strcmp가 반드시 -1 또는 1을 반환하는 것은 아니다.
헷갈리는 지점 문자열 리터럴 수정, 작은 버퍼에 복사, 종료 문자 없는 배열의 strlen은 안전한 출력 문제가 아니다.
지역 자동 변수는 블록 실행 동안 존재하고 초기화하지 않은 값은 보장하지 않는다. 전역 변수와 정적 저장 기간 변수는 명시적 초기화가 없으면 0으로 초기화된다. 지역 static은 블록 안에서 이름을 사용하지만 호출 사이 값을 유지한다.
malloc은 동적 저장 공간을 할당하고 실패하면 NULL을 반환한다. calloc은 할당 공간을 모두 0비트로 초기화한다. free는 할당한 공간을 해제한다. 함수 지역 자동 변수의 주소를 반환하면 함수 종료 후 그 객체를 사용할 수 없다.
int f(void) {
int a=0;
static int b=0;
a++; b++;
return a+b;
}
// f()를 순서대로 두 번 호출하면 2, 3static 지역변수는 전역에서 이름으로 접근할 수 있는가?
아니다. 수명은 프로그램 전체지만 이름의 범위는 해당 블록이다.
이름의 보이는 범위(scope)와 객체의 생존 기간(lifetime)은 별개다.
헷갈리는 지점 free 후 접근·중복 해제·초기화 안 된 지역 변수 읽기의 결과를 고정 숫자로 외우지 않는다.
int (*p)[3]은 정수 3개짜리 배열을 가리키는 포인터다. int *p[3]은 정수 포인터 3개를 담는 배열이다. 선언의 괄호를 먼저 읽는다. 2차원 배열 a를 가리키는 p에서 p+1은 다음 행, (*p)+1은 현재 행의 다음 원소다.
int a[2][3]={{1,2,3},{4,5,6}};
int (*p)[3]=a;
printf("%d", *(*(p+1)+1));a={{1,2,3},{4,5,6}}에서 *(*(p+1)+1)은?
5. p+1은 두 번째 행, +1은 그 행의 두 번째 원소다.
2026.10.14 재확인: C11 위원회 초안 N1570 §6.5.6·6.7.6.2
int a[2][3]; int (*p)[3]=a; p[1][2]는 a[1][2].
헷갈리는 지점 sizeof(int)를 4바이트로 고정하지 않는다. 문자열 끝의 널 문자와 숫자 0도 구별한다.
모두 유형 연습을 위해 직접 만든 문제입니다. C 예제의 printf·strlen은 필요한 표준 헤더가 포함된 상황을 가정합니다. Java는 표시된 클래스·main 위치에서 실행합니다. 단답은 동의어가 있을 수 있어 자동 판정 대신 자기 채점을 사용합니다.
출력은?
int x=5; int *p=&x;
*p += 4;
printf("%d %d", x, *p);정답 9 9
p가 x를 가리킨다. *p에 4를 더하면 x가 9가 되어 두 출력 모두 9다.
출력은?
int a[]={2,6,9,11};
int *p=a+1;
printf("%d %d", *p, *(p+2));정답 6 11
p는 처음 a[1]. 첫 출력은 6. p+2는 a[3]이라 11이다.
출력은?
int a[]={3,8,12};
int *p=a;
int x=*p++;
(*p)++;
printf("%d %d", x, a[1]);정답 3 9
x=*p++는 첫 값 3을 x에 넣고 p를 두 번째 칸으로 이동한다. (*p)++가 8을 9로 바꾼다.
main의 출력은?
void change(int a, int *b) { a+=2; *b+=2; }
int main(void) {
int x=4,y=5;
change(x,&y);
printf("%d %d",x,y);
}정답 4 7
a는 x의 복사본이라 x는 4다. b는 y 주소의 복사본이므로 *b+=2가 y를 7로 만든다.
세 번 호출한 반환값의 합은?
int next(void) { static int n=2; n+=2; return n; }
int main(void) {
int a=next(); int b=next(); int c=next();
printf("%d",a+b+c);
}정답 18
static n은 2부터 시작해 4,6,8을 차례로 반환한다. 합은 18.
출력은?
char s[]="CODE";
printf("%zu %zu", strlen(s), sizeof(s));정답 4 5
CODE는 문자 4개, 배열은 마지막 널 문자까지 5바이트다. %zu는 size_t 출력이다.
출력은?
int a[2][3]={{2,4,6},{8,10,12}};
printf("%d", *(*(a+1)+2));정답 12
a+1은 두 번째 행, *(a+1)+2는 그 행의 세 번째 원소다.
공백 없이 출력하면?
struct N { int v; struct N *next; };
struct N n1={2,NULL},n2={4,NULL},n3={7,NULL};
n1.next=&n3; n3.next=&n2;
for(struct N *p=&n1;p!=NULL;p=p->next)
printf("%d",p->v);정답 274
n1→n3→n2 순으로 방문하므로 2,7,4다. 선언 순서로 읽으면 틀린다.
출력은?
unsigned int a=10,b=6;
printf("%u %u",a&b,a^b);정답 2 12
10=1010, 6=0110. AND는 0010=2, XOR는 1100=12.
출력은?
int x=2,s=6;
switch(x) {
case 1: s+=1; break;
case 2: s+=2;
case 3: s+=3; break;
default: s=0;
}
printf("%d",s);정답 11
case 2에서 2를 더하고 break가 없어 case 3에서 3을 더한다. 총 6+2+3=11.
출력은?
void f(int n) {
if(n==0) return;
f(n-1);
printf("%d",n);
}
// f(3);정답 123
f(3)→f(2)→f(1)→f(0). f(0) 종료 뒤 돌아오며 1,2,3을 출력한다.
walk(&a)의 출력은?
struct N {int v; struct N *l,*r;};
void walk(struct N *p) {
if(!p) return;
walk(p->l); walk(p->r); printf("%d",p->v);
}
// 함수 안에서 아래 노드를 만든 뒤 walk(&a) 호출
struct N b={4,NULL,NULL},c={9,NULL,NULL};
struct N a={6,&b,&c};정답 496
왼쪽 노드 4, 오른쪽 노드 9, 루트 6 순으로 출력하는 후위 순회다.
출력은?
char dest[20]="AB";
strcat(dest,"CD");
printf("%s", dest);정답 ABCD
strcat은 dest 문자열의 끝에 src를 이어붙인다.
strcmp("apple","banana")의 결과는 양수·음수·0 중 무엇인가?
정답 음수
사전순으로 apple이 banana보다 작으므로 음수를 반환한다.
출력은?
int a=5,b=2;
printf("%.1f %.1f",(double)a/b,(double)(a/b));정답 2.5 2.0
첫 식은 실수 나눗셈, 둘째 식은 정수 나눗셈 후 변환.
출력은?
int x=2; int *p=&x; int **pp=&p;
**pp+=5;
printf("%d",x);정답 7
pp→p→x로 두 단계 따라가 x를 7로 바꾼다.
출력은?
int a[3]={4};
printf("%d %d %d",a[0],a[1],a[2]);정답 4 0 0
배열의 나머지 원소는 0으로 초기화된다.
출력 결과를 쓰시오.
int a[2][3]={{1,2,3},{4,5,6}};
int (*p)[3]=a;
printf("%d", *(*(p+1)+1));정답 5
p+1은 다음 행, 그 행에서 +1한 원소는 5다.
널 종료 문자열 s의 sizeof s와 strlen(s)를 순서대로 쓰시오.
char s[]="ABC";
printf("%zu %zu", sizeof s, strlen(s));정답 4 3
배열은 A,B,C,널 문자 4칸이고 strlen은 널 앞의 문자 3개를 센다. sizeof(char)는 1이다.
2024년 1회 · Java 객체 공유·C 비트 연산·응집도
2024년 3회 · 문자열 비교·Python 슬라이싱·LRU·상속·C 연결 구조
2025년 2회 · 인덱스 접근·속성 용어·언어 실행 추적
2025년 3회 · 패키지 다이어그램·조건 커버리지·C/Java·SQL
2026년 2회 · 구조체·상속·딕셔너리·외부 조인·상관 서브쿼리·SRT·서브넷