10장 보충 - 포인터
10.1. 포인터의 기본 개념
C 언어에서 포인터는 메모리의 주소를 저장하는 변수이다. 포인터 변수는 메모리 내의 다른 변수들이 저장된 위치를 가리키는 데 사용된다.
포인터의 선언은 다음과 같다.
int *pt; // 정수형 포인터 선언
변수의 주소를 가져오려면 & 연산자를 사용하고, 포인터를 통해 가리키는 변수의 값을 얻으려면 * 연산자를 사용한다.
int a = 5; pt = &a; // pt에 a의 주소 저장 int y = *pt; // pt가 가리키는 값(5)을 y에 저장
예제 10.1
#include <stdio.h>
int main(void) {
int a;
double b;
char c;
printf("%p\n", &a);
printf("%p\n", &b);
printf("%p\n", &c);
return 0;
}실행 결과
0x7fff6b3ab84c 0x7fff6b3ab840 0x7fff6b3ab83f
예제 10.2
#include <stdio.h>
int main(void) {
int a;
int *pa;
pa = &a;
*pa = 10;
printf("%d\n", *pa);
printf("%d\n", a);
return 0;
}실행 결과
10 10
예제 10.3
#include <stdio.h>
int main(void) {
int a = 10, b = 15, tot;
double avg;
int *pa, *pb;
int *pt = &tot;
double *pg = &avg;
pa = &a;
pb = &b;
*pt = *pa + *pb;
*pg = *pt / 2.0;
printf("%d, %d\n", *pa, *pb);
printf("%d\n", *pt);
printf("%.1lf\n", *pg);
return 0;
}실행 결과
10, 15 25 12.5
예제 10.4
#include <stdio.h>
int main(void) {
char ch;
int in;
double db;
char *pc = &ch;
int *pi = ∈
double *pd = &db;
printf("&ch : %zu\n", sizeof(&ch));
printf("&in : %zu\n", sizeof(&in));
printf("&db : %zu\n", sizeof(&db));
printf("pc : %zu\n", sizeof(pc));
printf("pi : %zu\n", sizeof(pi));
printf("pd : %zu\n", sizeof(pd));
printf("*pc : %zu\n", sizeof(*pc));
printf("*pi : %zu\n", sizeof(*pi));
printf("*pd : %zu\n", sizeof(*pd));
return 0;
}실행 결과
&ch : 8 &in : 8 &db : 8 pc : 8 pi : 8 pd : 8 *pc : 1 *pi : 4 *pd : 8
예제 10.5
#include <stdio.h>
int main() {
int i = 10;
int j = 20;
int *k = &i;
scanf("%d", k);
printf("%d, %d, %d\n", i, j, *k);
return 0;
}실행 결과
90, 20, 90
예제 10.6
#include <stdio.h>
int main() {
int a = 3, b = 4, *p, *q;
p = &a;
q = &b;
*p = *p + 1;
*q = *q + *p;
printf("%d %d\n", a, b);
}실행 결과
4 8
예제 10.7
#include <stdio.h>
void main() {
int a = 10;
int b;
int *c = &b;
b = a++;
b += 10;
printf("a=%d \n", a);
printf("b=%d \n", b);
printf("c=%d \n", *c);
}실행 결과
a=11 b=20 c=20
10.2. 포인터와 함수
포인터는 함수의 매개 변수 전달에 사용된다. '값에 의한 전달(pass by value)'과 '참조에 의한 전달(pass by reference)'의 개념을 이해해야 한다.
값에 의한 전달
함수에 값을 직접 전달하는 방식이다. 원본 데이터의 복사본이 함수로 전달되므로, 함수 내부에서 매개변수를 변경하더라도 원본 데이터에는 영향을 미치지 않는다.
void change(int a) {
a = 10;
}
int main() {
int x = 5;
change(x);
printf("%d\n", x); // x의 값은 여전히 5이다.
return 0;
}참조에 의한 전달
값이 저장된 메모리의 주소를 전달하는 방식이다. 함수에 매개변수로 포인터를 전달하여 원본 데이터를 직접 변경할 수 있다.
void change(int *a) {
*a = 10;
}
int main() {
int x = 5;
change(&x);
printf("%d\n", x); // x의 값은 10으로 바뀌었다.
return 0;
}예제 10.8
#include <stdio.h>
void swap(int x, int y);
int main(void) {
int a = 10, b = 20;
swap(a, b);
printf("a: %d, b: %d\n", a, b);
return 0;
}
void swap(int x, int y) {
int temp;
temp = x;
x = y;
y = temp;
}실행 결과
a: 10, b: 20
예제 10.9
#include <stdio.h>
void swap(int *pa, int *pb);
int main(void) {
int a = 10, b = 20;
swap(&a, &b);
printf("a: %d, b: %d\n", a, b);
return 0;
}
void swap(int *pa, int *pb) {
int temp;
temp = *pa;
*pa = *pb;
*pb = temp;
}실행 결과
a: 20, b: 10
10.3. 포인터와 배열
포인터와 배열은 C 언어에서 매우 밀접한 관계를 가지고 있다. 배열의 이름은 배열의 첫 번째 요소의 주소를 나타낸다.
배열 이름은 주소
int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr; // 이것은 &arr[0]과 같다.배열 요소 접근
int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr;
printf("%d", *(ptr + 2)); // 3을 출력한다. 이는 arr[2]와 같다.포인터 연산과 배열
int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr;
for(int i=0; i<5; i++) {
printf("%d ", *(ptr + i)); // 1 2 3 4 5를 출력한다.
}[참고] 배열 이름과 포인터의 차이점
배열 이름은 포인터처럼 작동하지만, 일반 포인터와는 달리 그 값을 변경할 수 없다. 배열 이름은 상수 포인터이기 때문이다.
int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr;
ptr++; // 가능: 포인터를 증가시키면 가리키는 요소가 바뀐다.
// arr++; // 불가능: 컴파일 에러 발생예제 10.10
#include <stdio.h>
int main() {
int a[5] = {10, 20, 30, 40, 50};
int i;
int *p;
p = a;
for (i = 0; i < 5; i++)
printf("a[%d] == %d\n", i, *(p + i));
return 0;
}실행 결과
a[0] == 10 a[1] == 20 a[2] == 30 a[3] == 40 a[4] == 50
예제 10.11
#include <stdio.h>
int main() {
int aa[5] = {10, 20, 30, 40};
printf("%p\n", &aa[0]);
printf("%p\n", &aa[1]);
printf("%p\n\n", &aa[2]);
printf("%p\n", aa);
printf("%p\n", aa + 1);
printf("%p\n", aa + 2);
printf("%p\n\n", aa + 3);
printf("%d\n", *aa);
printf("%d\n", *(aa + 1));
printf("%d\n", *(aa + 2));
printf("%d\n", *(aa + 3));
return 0;
}실행 결과
0x7ffcdc8e59b0 0x7ffcdc8e59b4 0x7ffcdc8e59b8 0x7ffcdc8e59b0 0x7ffcdc8e59b4 0x7ffcdc8e59b8 0x7ffcdc8e59bc 10 20 30 40
예제 10.12
#include <stdio.h>
void main() {
int a[2][3] = {
{11, 12, 13},
{21, 22, 23}
};
int i, *p;
p = &a[0][0];
for (i = 0; i < 6; i++)
printf("a[][] == %d\n", *(p + i));
}실행 결과
a[][] == 11 a[][] == 12 a[][] == 13 a[][] == 21 a[][] == 22 a[][] == 23
예제 10.13
#include <stdio.h>
void main() {
int array[] = {100, 200, 300, 400, 500};
int *ptr;
ptr = array;
printf("%d\n", *(ptr+2)+10);
}실행 결과
310
예제 10.14
#include <stdio.h>
void main() {
int a[4] = {10, 20, 30};
int *p = a;
p++;
*p++ = 100;
*++p = 200;
printf("a[0]=%d a[1]=%d a[2]=%d a[3]=%d\n", a[0], a[1], a[2], a[3]);}
실행 결과
a[0]=10 a[1]=100 a[2]=30 a[3]=200
예제 10.15
#include <stdio.h>
int main(void) {
int a[] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
int *ptr = a+3;
for (i=0; i<5;++i) {
printf("%d", *(ptr+i) - 3);
}
}실행 결과
37 47 57 67 77
예제 10.16
#include <stdio.h>
void main() {
int nums[5] = {11, 22, 33, 44, 55};
int *ptr = nums+1;
int i;
for (i=0; i<4; i++)
printf("%d", *ptr++);
}실행 결과
22 33 44 55
예제 10.17
#include <stdio.h>
int main() {
int arr[] = {8, 5, 3, 1, 2, 7, 9};
int *p = arr+2, a = 0, b = 0;
a = *++p;
b = (*p)++;
printf("%d, %d\n", a, b);
return 0;
}실행 결과
1, 1
10.4. 포인터와 문자열
C 언어에서 문자열과 포인터의 관계는 매우 밀접하다. 문자열은 기본적으로 문자형(char) 배열로 정의되며, 문자열의 시작 주소를 가리키는 포인터를 통해 문자열에 접근할 수 있다.
char str[] = "Hello"; // 'H', 'e', 'l', 'l', 'o', '\0'로 구성된 문자 배열 char *p = str; // str의 시작 주소(여기서는 'H'의 주소)를 가리키는 포인터
문자열 포인터 선언
char *p = "Hello";
char *p: p는 문자에 대한 포인터이다.= "Hello": "Hello"는 문자열 리터럴로, 실제로는{'H', 'e', 'l', 'l', 'o', '\0'}이라는 문자 배열이다.- 이렇게 선언된 문자열 "Hello"는 상수이며 변경할 수 없다. 즉,
p[0] = 'h';와 같은 코드는 오류를 발생시킨다. - 변경 가능한 문자열을 원하면
char str[] = "Hello";를 사용해야 한다.
예제 10.18
#include <stdio.h>
void main() {
char aa[6] = "KOREA";
char *p;
int i;
p = &aa[0];
printf("%x\n", &aa[0]);
printf("%x\n", &p);
printf("%c\n\n", *p);
for (i = 0; i <= 4; i++)
printf("aa[%d] = %c, %p\n", i, *(p + i), &aa[i]);
}실행 결과
aa[0] = K, 0x7ffdb5736d12 aa[1] = O, 0x7ffdb5736d13 aa[2] = R, 0x7ffdb5736d14 aa[3] = E, 0x7ffdb5736d15 aa[4] = A, 0x7ffdb5736d16
댓글 없음:
댓글 쓰기