
포인터 배열의 배열명을 저장할 땐 이중 포인터가, 이차원 배열의 배열명을 저장할 땐 배열 포인터가 필요합니다. 특히 매개변수로 배열명을 보낼 때 중요해요.
#include <stdio.h>, int main(void), return 0; 등 구문은 특별히 필요하지 않은 경우 생략합니다.자료형 **포인터와 같이 선언int **ppi로 int *형 포인터를 가리키는 포인터 ppi 선언int a = 33;
int *pi = &a; // int형 변수 a의 주소를 저장
int **ppi = π // int*형 포인터 pi의 주소를 저장
printf("a: 값 %d\n", a);
printf("pi: 값 %p, &연산 %p, *연산 %d\n", pi, &pi, *pi);
printf("ppi: 값 %p, &연산 %p, *연산 %p, **연산 %d\n", ppi, &ppi, *ppi, **ppi);
// (주소값은 편의상 16자리 중 마지막 6자리만 명시)
// a: 값 33
// pi: 값 5FFE8C, &연산 5FFE80, *연산 33
// ppi: 값 5FFE80, &연산 5FFE78, *연산 5FFE8C, **연산 33

ppi는 포인터 pi를 가리킴pi는 변수 a를 가리킴ppi로 변수 a의 값을 사용하려면, **ppi와 같이 * 연산자를 2회 사용해야 함*ppi -> 단일 포인터 pi 반환*pi -> 변수 a 반환pi가 int형 변수의 주소를 저장할 때pi는 (int *)형double k = 13.37; // double형 변수
double *pk = &k; // pk는 (double)형을 가리킴
double **ppk = &pk; // ppk는 (double *)형을 가리킴
pk는 (double *)형ppk는 (double *)형의 pk의 주소를 저장함ppk는 (double *)*... 즉 double **형두 변수의 값을 바꾸는 함수를 만들 땐
* 연산자를 사용해 값을 바꿔야 함두 포인터의 값을 바꾸는 경우
e.g., 두 char *형 포인터의 값 바꾸기
#include <stdio.h>
void swap_ptr(char **ppa, char **ppb);
int main(void){
char *pa = "무적 LG 박용택";
char *pb = "오오 오오오오오 오 오오오오오";
printf("%s %s\n", pa, pb);
// [출력] 무적 LG 박용택 오오 오오오오오 오 오오오오오
swap_ptr(&pa, &pb);
// char*형 포인터의 주소를 매개변수로 보냄
printf("%s %s\n", pa, pb);
// [출력] 오오 오오오오오 오 오오오오오 무적 LG 박용택
}
void swap_ptr(char **ppa, char **ppb){
// ppa엔 pa의 주소, ppb엔 pb의 주소가 저장됨
char *temp;
// pa와 pb에 저장된 주소를 바꿈
temp = *ppa;
*ppa = *ppb;
*ppb = temp;
}

// 포인터 배열을 매개변수로 받기
#include <stdio.h>
void print_str(char **str, int count);
int main(void){
// char *형 포인터를 요소로 갖는 배열
char *dinner[] = {"군만두", "찐만두", "물만두", "딤섬"};
// 배열 요소의 수
int count = sizeof(dinner) / sizeof(dinner[0]);
print_str(dinner, count);
return 0;
}
// 매개변수로 이중 포인터 사용
// char *형인 배열명을 넘기므로 이중 포인터를 사용
void print_str(char **str, int count){
for (int i = 0; i < count; i++){
// 배열 요소 (char *형 포인터) 순회하며 각 문자열 출력
printf("%s ", str[i]);
}
}
// [출력] 군만두 찐만두 물만두 딤섬

int arr[5]를 선언했을 때arr은 배열 첫 번째 요소의 주소로 해석됨&arr 사용 시, 배열 전체를 하나의 변수로 간주하고 주소를 구함arr과 &arr은 전혀 다른 주소// 편의상 주소를 16진수가 아니라 10진수로 표현
int arr[5];
printf("arr: %u\n", arr);
printf("arr + 1: %u\n", arr + 1);
printf("&arr: %u\n", &arr);
printf("&arr + 1: %u\n", &arr + 1);
// [출력]
// arr: 6291056
// arr + 1: 6291060
// &arr: 6291056
// &arr + 1: 6291076

arr을 주소로 사용할 때: 첫 요소를 가리킴4int의 크기인 4가 더해짐&arr을 주소로 사용할 때: 배열 전체를 가리킴4 * 5 = 2020이 더해짐int arr[3][4] = {{5, 7, 3, 1}, {2, 8, 10, 4}, {9, 6, 4, 11}}; // 2차원 배열 초기화, 선언
int (*pa)[4]; // int형 변수 4개의 배열을 가리키는 포인터 선언
pa = arr;
// pa를 2차원 배열처럼 사용
for (int i = 0; i < 3; i++){
for (int j = 0; j < 4; j++){
printf("%4d", pa[i][j]);
}
printf("\n");
}
// 5 7 3 1
// 2 8 10 4
// 9 6 4 11
int형 원소가 4개인 1차원 배열을 가리키는 경우int (*parr)[4]와 같이 선언int *parr[4]처럼 선언하면, 배열 포인터가 아닌 포인터 배열이 되므로 주의할 것parr은 int (*)[4] 형 포인터라고 부름
#include <stdio.h>
// 2차원 배열을 출력하는 함수
void print_array(int (*)[4]);
int main(void){
int arr[3][4] = {{1, 5, 7, 7}, {8, 2, 8, 2}, {2, 5, 8, 8}};
print_array(arr);
return 0;
}
// 매개변수는 배열 포인터
void print_array(int (*pa)[4]){
for (int i = 0; i < 3; i++){
for (int j = 0; j < 4; j++){
printf("%3d", pa[i][j]);
}
printf("\n");
}
}
// [출력]
// 1 5 7 7
// 8 2 8 2
// 2 5 8 8
pa[i][j]는 arr[i][j]와 동일한 결과 반환
int arr[3][4]로 배열을 선언했을 때, pa[1][2], 즉 arr[1][2]의 값은?array[1][2] 는 *(*(arr + 1) + 2)와 같은 연산arr + 1 계산arr은 arr[0]의 주소, 덧셈 연산 시 sizeof(arr[0]) = 4 * 4 = 16만큼 증가arr + 1 -> 100 + 1 * 16 = 116*(arr + 1) 계산*(arr + 1)은 주소 116에 있는 부분배열 arr[1]의 시작 주소*(arr + 1) 역시 116arr[1][2]의 위치 확인*(arr + 1)은 arr[1][0]의 주소, 덧셈 연산 시 sizeof(arr[1][0]) = 4만큼 증가*(arr + 1) + 2 -> 116 + 2 * 4 = 124void 포인터void *포인터명으로 선언void 포인터의 자료형은 void * 형int a = 35;
double b = 10.5;
void *vp; // void 포인터 선언
vp = &a; // int형 변수의 주소 저장
// 단, vp를 (int *)형으로 변환한 다음 사용해야 함
printf("a: %d\n", *(int *)vp);
vp = &b;
// 단, vp를 (double *)형으로 변환한 다음 사용해야 함
printf("b: %.1lf\n", *(double *)vp);
vp = "포인터 너무 어려워 ㅠㅠ";
// 단, vp를 (char *)형으로 변환한 다음 사용해야 함
printf("%s\n", (char *)vp);
// [출력]
// a: 35
// b: 10.5
// 포인터 너무 어려워 ㅠㅠ
void 포인터에 바로 간접참조 연산(*)이나 포인터 연산을 수행할 수 없음(int *), (double *))로 변환해 사용해야 함void 포인터를 대입할 수 있으나, 형 변환 후 대입하는 것을 권장int *pi = (int *)vp와 같이다음과 같이 배열이 선언되어 있을 때, 각 값을 저장할 포인터를 선언하세요.
변수 선언은p로 합니다.
char *ps[5] = {"baseball", "football", "volleyball", "swimming", "golf"}; // 포인터 배열
int arr[2][3] = {{1, 2, 3}, {4, 5, 6}}; // 2차원 배열
ps: char **p로 선언ps는 char *형 포인터 배열ps는 배열의 첫 요소인 char *형 포인터를 가리킴char **형 이중 포인터로 저장arr: int (*p)[3]으로 선언arr은 int형 2차원 배열arr은 배열의 첫 요소인, 원소가 3개인 int형 배열을 가리킴int (*)[3]형 배열 포인터로 저장arr[0]: int *p로 선언arr[0]은 int형 1차원 배열arr[0]은 배열의 첫 요소인, int형 원소를 가리킴int *형 포인터로 저장&ps[2]: char **p로 선언ps[2]는 포인터 배열의 원소로, char *형 포인터char **형 이중 포인터로 저장&arr: int (*p)[2][3]으로 선언&arr은 2행 3열의 배열 전체를 나타내는 주소int (*)[2][3]형 배열 포인터로 저장2명의 나이와 키를 입력한 후 바꾸어 출력합니다.
단, 나이와 키를 바꾸는 함수는int형과double형을 모두 교환할 수 있도록 하나의 함수로 구현하세요.
void 포인터를 매개변수로 두어, 인수로 주소를 우선 입력받음(int *)형 또는 (double *) 형으로 형변환strcmp(문자열A, 문자열B)를 이용해 두 문자열 비교#include <stdio.h>
#include <string.h>
void swap(char* mode, void *pa, void *pb);
int main(void){
int age_a, age_b;
double height_a, height_b;
printf("첫 번째 사람의 나이와 키 입력: ");
scanf("%d %lf", &age_a, &height_a);
printf("두 번째 사람의 나이와 키 입력: ");
scanf("%d %lf", &age_b, &height_b);
swap("int", &age_a, &age_b);
swap("double", &height_a, &height_b);
printf("첫 번째 사람의 나이와 키 : %d, %.1lf\n", age_a, height_a);
printf("두 번째 사람의 나이와 키 : %d, %.1lf\n", age_b, height_b);
return 0;
}
void swap(char* mode, void *pa, void *pb){
// strcmp 이용해서 "int"인지 "double"인지 확인
// 이후 void 포인터 형변환을 통해, 값을 서로 바꿈
if (strcmp(mode, "int") == 0){
int temp;
temp = *(int *)pa;
*(int *)pa = *(int *)pb;
*(int *)pb = temp;
} else if (strcmp(mode, "double") == 0){
double temp;
temp = *(double *)pa;
*(double *)pa = *(double *)pb;
*(double *)pb = temp;
}
}