공든탑앱 열기

C 배열·문자열·포인터

정보처리기사 · 프로그래밍 언어 · 약 16분

쉽게 말하면

배열은 같은 종류의 값을 줄지어 담는 상자 묶음이고, 첫 칸 번호는 0이에요. 포인터는 값이 아니라 '값이 있는 주소'를 담는 변수예요. &x는 x의 주소, *p는 p가 가리키는 곳의 값이에요. 배열 이름은 첫 칸의 주소라서 *(a + 2)는 a[2]와 같아요. 문자열은 글자 배열이고 끝에 보이지 않는 '\0'(널 문자)이 하나 더 붙어요.

시험용 정의

배열은 같은 자료형 값을 연속된 메모리에 저장하며 인덱스는 0부터 시작한다. 배열 이름은 첫 요소의 주소이므로 a[i]와 *(a + i)는 같다. 포인터는 주소를 저장하는 변수로, &변수는 주소, *포인터는 가리키는 곳의 값(간접 참조)이다. 포인터에 1을 더하면 자료형 크기만큼 다음 요소로 이동한다(int면 4바이트). 포인터의 포인터(**pp)는 포인터의 주소를 담는다. 문자열은 char 배열이며 끝에 널 문자 '\0'이 붙어 char s[] = "KOREA"의 sizeof는 6, strlen은 5다. 2차원 배열 b[i][j]는 *(*(b + i) + j)와 같다. 구조체는 서로 다른 자료형을 묶은 사용자 정의형으로, 변수는 .(점), 포인터는 ->로 멤버에 접근한다.

비유로 이해하기

아파트로 비유하면 배열은 같은 평형 집이 0호부터 줄지은 동, 포인터는 '302호'라고 적힌 쪽지다. 쪽지를 따라가면(*) 집 안의 물건(값)을 볼 수 있고, 쪽지 번호에 1을 더하면 옆집이다.

자세히

먼저 알아 둘 말

말뜻
인덱스배열 칸 번호. 0부터 시작
주소메모리 위치를 가리키는 번호
& (주소 연산자)변수의 주소를 구한다
* (간접 참조 연산자)포인터가 가리키는 곳의 값
널 문자 '\0'문자열 끝을 알리는 값 0
구조체여러 자료형을 하나로 묶은 형 (struct)

예제 1: 배열과 포인터

int a[5] = {10, 20, 30, 40, 50};
int *p = a;
printf("%d %d %d\n", *p, *(p + 2), *p + 2); // 10 30 12
p++;                                        // 이제 a[1]을 가리킴
printf("%d %d\n", *p, p[2]);                // 20 40

int x = 10, *px = &x, **ppx = &px;
*px = 20;
**ppx += 5;
printf("%d\n", x);                          // 25

예제 2: 문자열

char s[] = "KOREA";
printf("%d %d %c %s\n", strlen(s), sizeof(s), s[2], s + 3);
// 5 6 R EA
char w[] = "ABCDE";
for (int i = 0; i < 2; i++) {      // 앞뒤 바꾸기
  char tmp = w[i]; w[i] = w[4 - i]; w[4 - i] = tmp;
}
printf("%s\n", w);                // EDCBA
  • s + 3은 'E'부터 시작하는 문자열이라 %s로 찍으면 EA
  • sizeof는 '\0'까지 6, strlen은 글자 수 5

예제 3: 2차원 배열과 구조체

int b[2][3] = {{1, 2, 3}, {4, 5, 6}};
printf("%d %d\n", b[1][0], *(*(b + 1) + 2));  // 4 6

struct st { char name[10]; int age; };
struct st t = {"kim", 20};
struct st *pt = &t;
pt->age += 1;
printf("%s %d\n", pt->name, t.age);         // kim 21

기출에서 더 나온 것

말뜻
strcmp(s1, s2)두 문자열을 비교한다. 같으면 0. 연결하는 함수는 strcat
strcat(s1, s2)s1 뒤에 s2를 이어 붙인다
문자열 함수 (string.h)strlen 길이, strcpy 복사, strcat 이어 붙이기, strcmp 비교 (같으면 0)

시험에 이렇게 나와요

확인 문제

Q1. int a[5] = {10, 20, 30, 40, 50}; int *p = a; 일 때 *(p + 2)의 값은?

  1. 20
  2. 12
  3. 30
  4. 주소값
정답 보기

3번 30

p는 a[0]을 가리킨다. p + 2는 두 칸 뒤 a[2]의 주소이고, *를 붙이면 그 값 30. 반면 *p + 2는 10 + 2 = 12다. 괄호 위치에 주의.

Q2. int a[] = {1, 2, 3, 4}; int *p = a + 3; printf("%d", *p - *(p - 2));의 출력은?

  1. 1
  2. 2
  3. 3
  4. 4
정답 보기

2번 2

*p = a[3] = 4, *(p − 2) = a[1] = 2. 4 − 2 = 2.

Q3. char s[] = "HELLO";에서 sizeof(s)의 값은?

  1. 4
  2. 5
  3. 6
  4. 8
정답 보기

3번 6

글자 5개 + 널 문자 1개 = 6.

Q4. int a[5] = {10, 20, 30, 40, 50}; int s = 0; for (int i = 0; i < 5; i += 2) s += a[i]; 실행 후 s는?

  1. 50
  2. 60
  3. 90
  4. 150
정답 보기

3번 90

a[0] + a[2] + a[4] = 10 + 30 + 50 = 90.

Q5. 구조체 포인터 pt로 멤버 age에 접근하는 올바른 표현은?

  1. pt.age
  2. pt->age
  3. *pt.age
  4. &pt.age
정답 보기

2번 pt->age

포인터는 ->, (*pt).age도 같다. *pt.age는 우선순위 때문에 다른 뜻이다.

헷갈리기 쉬운 O·X

C에서 배열의 첫 번째 요소 인덱스는 1이다.

정답 보기

X 0부터 시작한다.

배열 이름 a는 a[0]의 주소와 같다.

정답 보기

O

int형 포인터 p에 1을 더하면 주소가 1바이트 늘어난다.

정답 보기

X int 크기(보통 4바이트)만큼 다음 요소로 이동한다.

함께 보면 좋은 개념