배열(Array) : 동일한 자료형의 변수를 메모리에 연속으로 할당한 것
각 배열 요소는 일정한 간격으로 주소를 가짐 ( 자료형의 크기 만큼 )

' int형 변수 ' 는 4byte 이므로, 각 배열 요소의 주소는 100, 104, 108, 112가 됨
즉, 첫 번째 요소의 주소를 알면 나머지 요소의 주소도 쉽게 유추 가능
= 컴파일러는 배열의 이름을 배열의 시작 주소 값(첫 번째 요소의 주소)으로 함
= arr + i = &a[i]
= *(arr + i) = a[i]
단, 배열의 이름은 값의 저장이 불가능하고 (대입 연산자의 피연산자도 불가능), 주소 값의 변경이 불가능
= 포인터 상수, 상수 형태의 포인터
#include <stdio.h>
int main(void)
{
int arr[3] = {1, 2, 3};
printf("배열의 이름 : %p\n", arr);
printf("첫 번째 요소 : %p\n", &arr[0]);
printf("두 번째 요소 : %p\n", &arr[1]);
printf("세 번째 요소 : %p\n", &arr[2]);
return 0;
}
// >>> output <<<
// 배열의 이름 : 005AFA14 << 배열의 이름 = 포인터 주소
// 첫 번째 요소 : 005AFA14 << 배열의 첫번째 주소값과 배열의 이름의 출력값이 같음
// 두 번째 요소 : 005AFA18
// 세 번째 요소 : 005AFA1C
포인터 연산 : 곱셈, 나눗셈을 제외한 ' + , - , ++ , -- ' 연산자를 사용
- + 연산자는 초기값 자체를 변경시키지 않음
- ++ 연산자는 초기값을 변경시킴
#include <stdio.h>
int main(void) {
int * ptr = 0x00;
printf("+ : %p %p \n", ptr + 1, ptr);
printf("++ : %p %p \n", ++ptr, ptr);
return 0;
}
// >>> output <<<
// + : 0x4 0x0
// ++ : 0x4 0x4
#include <stdio.h>
int main(void)
{ // 자료형(타입)의 크기
char * ptr1 = 0; // 1 Byte
int * ptr2 = 0; // 4 Byte
double * ptr3 = 0; // 8 Byte
printf("%d번지, %d번지, %d번지\n", ptr1, ptr2, ptr3);
ptr1++;
ptr2++;
ptr3++;
printf("%d번지, %d번지, %d번지\n", ptr1, ptr2, ptr3);
return 0;
}
// >>> output <<<
// 0번지, 0번지, 0번지
// 1번지, 4번지, 8번지 // main 함수에서 정의한 타입의 크기에 맞게 증가
> - - - - - - - - - - - - - - - 배열의 이름 == 포인터 변수 - - - - - - - - - - - - - - - - <
#include <stdio.h>
int main(void)
{
int arr[3] = {1, 2, 3};
int * ptr = arr;
printf("%d %d %d\n", *ptr, *(ptr + 1), *(ptr + 2));
printf("%d %d %d\n", ptr[0], ptr[1], ptr[2]);
printf("%d %d %d\n", *arr, *(arr + 1), *(arr + 2));
printf("%d %d %d\n", arr[0], arr[1], arr[2]);
return 0;
}
// >>> output <<<
// 1 2 3
// 1 2 3
// 1 2 3
// 1 2 3
결론
arr[i]==*(arr + i)==*(ptr + i)
= ptr 에 저장된 값이 arr의 주소값이기 때문
int* p = a[i]
/* 아래는 모두 같다 */
a[i++] = j;
*p++ = j;
*(p++) = j;
| 표현식 | 의미 |
|---|---|
*p++ 혹은 *(p++) | 증가되기 이전의 표현식의 값은 *p; 그리고 p 가 증가 |
(*p)++ | 증가되기 이전의 표현식의 값은 *p; 그리고 *p 가 증가 |
*++p 혹은 *(++p) | p 가 증가; 증가된 이후의 표현식의 값은 *p |
++*p 혹은 ++(*p) | *p 가 증가; 증가된 이후의 표현식의 값은 *p |
/* 배열 a 의 원소들의 합 구하기 */
for (p = &a[0]; p < &a[N]; ++p) {
sum += *p;
}
p = &a[0];
while (p < &a[N]) {
sum += *p++;
}
포인터 변수로 이루어진 '배열'
포인터 배열을 선언할 땐 배열 요소의 자료형이 '포인터'이므로 배열이름 앞에 * 을 붙임
#include <stdio.h>
int main(void)
{ // 포인터 배열 선언 및 초기화
int num1 = 1, num2 = 2, num3 = 3;
int * arr[3] = { &num1, &num2, &num3 };
printf("주소값 : %p %p %p\n", arr[0], arr[1], arr[2]);
printf("값 : %d %d %d\n", *arr[0], *arr[1], *arr[2]);
return 0;
}
// >>> output <<<
// 주소값 : 00EFFB24 00EFFB18 00EFFB0C // '포인터 배열'은 메모리에 연속해서 위치
// 값 : 1 2 3 // But, 포인터 배열에 저장된 '주소값'은 연속성 X
#include <stdio.h>
int main(void)
{ // 문자열 배열 선언 및 초기화
char * strarr[3] = {"Krafton", "Jungle", "Compass"};
printf("%s %s %s\n", strarr[0], strarr[1], strarr[2]);
return 0;
}
// >>> output
// Krafton Jungle Compass
포인터 배열은 문자열을 저장 가능
문자열 배열은 문자열의 주소값을 저장하는 배열 ( char 형 포인터 배열 )
= 문자열의 주소값 = 문자열 첫 번째 문자의 주소값
( 변환 문자 %s -> null 이 나올 때까지 모든 문자를 차례로 출력 = 하나의 문자열 출력 )
배열을 가리킬 수 있는 '포인터'
2차원 이상의 배열을 가리킬 때, 포인터를 배열처럼 사용하기 위함 ( 1차원은 배열은 이름 자체가 포인터 )
>> 배열 포인터 선언 <<<
자료형 (*포인터이름)[가로(행) 길이]
> - - - - - - - - - - - - - - - - - - - Example - - - - - - - - - - - - - - - - - - - <
#include <stdio.h>
int main(void)
{
int arr2d[2][3] = {
{10, 20, 30},
{40, 50, 60},
};
printf("%d %d\n", *arr2d[0], *arr2d[1]);
return 0;
}
// >> output
// 10 40
> - - - - - - - - - - - - - - - - - - 인덱싱 Example - - - - - - - - - - - - - - - - - - <
#include <stdio.h>
int main(void)
{
int arr2d[2][3] = {
{10, 20, 30},
{40, 50, 60},
};
int i, j;
int (*ptr)[3] = arr2d; // 배열 포인터 선언
for (i = 0; i < 2; i++)
{
for (j = 0; j < 3; j++)
printf("%d ", ptr[i][j]); // 배열 참조
printf("%d ", arr2d[i][j]); // 배열 포인터로 참조
printf("%d ", (*(arr2d + i))[j]);
printf("%d ", *(arr2d[i] + j));
printf("%d\n", *(*(arr2d + i) + j)); // 모두 같은 값을 나타냄
}
return 0;
}
// >>> output <<<
// 10 10 10 10 10
// 20 20 20 20 20
// 30 30 30 30 30
// 40 40 40 40 40
// 50 50 50 50 50
// 60 60 60 60 60
포인터 배열 (Array of Pointer) VS
배열 포인터 (Pointer to Array)
- 포인터 배열 = 주소값을 저장하는 '배열(Array)'
- 배열 포인터 = 배열의 시작주소 값을 저장할 수 있는 '포인터(Pointer)'
| int *ptr[3]; | int (*ptr)[3]` |
왼쪽 : int형 변수로 이루어진 int형 포인터의 배열
오른쪽 : 가로길이가 3인 int형 2차원 배열을 가리키는 포인터 변수
' ( ) ' 괄호의 유무가 중요