C 언어 pointer - Hwanghyewon06/c- GitHub Wiki
#include <stdio.h>
int main()
{
int n = 10; // 변수 n을 10으로 초기화
int n2 = n; // 변수 n2에 n의 값을 복사
int* p = &n; // 포인터 p가 n의 주소를 가리킴
int* p2 = p; // 포인터 p2도 p가 가리키는 주소를 가리킴
*p2 = 20; // p2가 가리키는 주소에 있는 값을 20으로 변경
printf("%d %d %d\n", n, *p, *p2); // n, p가 가리키는 값, p2가 가리키는 값 출력
return 0;
}
-
변수 선언 및 초기화
-
int n = 10;
: 변수 n은 10으로 초기화됩니다. -
int n2 = n;
: 변수 n2는 n의 값을 복사하여 10이 저장됩니다. n2는 n과 별개로 독립적인 값을 가지게 됩니다. -
int* p = &n;
: 포인터 p는 n의 주소를 가리키게 됩니다. 즉, p는 n의 메모리 주소를 저장하고 있습니다. -
int* p2 = p;
: 포인터 p2는 p의 값(즉, n의 주소)을 복사하여 n의 주소를 가리킵니다. 결과적으로 p2는 n과 동일한 주소를 가리킵니다.
-
-
값 수정
-
*p2 = 20;
: p2는 n의 주소를 가리키고 있으므로, *p2는 n에 해당합니다. 따라서*p2 = 20;
은 n의 값을 20으로 변경합니다. 이제 n은 20을 가집니다.
-
-
출력
-
printf("%d %d %d\n", n, *p, *p2);
:- n의 값은 20입니다.
- *p는 p가 가리키는 값인데, p는 n의 주소를 가리키므로 *p는 n의 값, 즉 20입니다.
- *p2도 마찬가지로 p2가 가리키는 값이고, p2도 n의 주소를 가리키므로 *p2는 n의 값, 즉 20입니다.
-
20 20 20
- 변수 n의 값을 10에서 20으로 변경하고, 이를 포인터 p와 p2를 통해 확인합니다.
- n, *p, *p2 모두 동일한 메모리 주소를 가리키고 있으며, 값이 20로 변경된 후 출력됩니다.
#include <stdio.h>
int main()
{
int n = 10; // 변수 n을 10으로 초기화
int n2 = n; // 변수 n2에 n의 값을 복사
int* p = &n; // 포인터 p가 n의 주소를 가리킴
int* p2 = p; // 포인터 p2가 p의 주소를 가리킴
printf("%d %d %d\n", n, *p, *p2); // n, p가 가리키는 값, p2가 가리키는 값 출력
return 0;
}
-
변수 선언 및 초기화
-
int n = 10;
: 정수형 변수 n을 선언하고, 값을 10으로 초기화합니다. -
int n2 = n;
: 변수 n2를 선언하고, n의 값을 복사하여 10을 저장합니다. n2는 n과 별개로 독립적인 값인 10을 가지게 됩니다. -
int* p = &n;
: 포인터 p는 n의 주소를 저장합니다. &n은 n의 메모리 주소를 의미하며, p는 이제 n의 주소를 가리킵니다. -
int* p2 = p;
: 포인터 p2는 p의 값을 복사하여 p가 가리키는 주소(즉, n의 주소)를 가리킵니다. 결과적으로 p2는 p와 동일한 주소를 가리킵니다.
-
-
출력
-
printf("%d %d %d\n", n, *p, *p2);
:- 첫 번째
%d
는 변수 n의 값을 출력합니다. n의 값은 10입니다. - 두 번째
%d
는 *p의 값을 출력합니다. p는 n의 주소를 가리키므로 *p는 n의 값, 즉 10입니다. - 세 번째
%d
는 *p2의 값을 출력합니다. p2는 p와 동일한 주소를 가리키므로 *p2 역시 n의 값, 즉 10입니다.
- 첫 번째
-
10 10 10
- 변수 n의 값은 10입니다.
- 포인터 p와 p2는 각각 n의 주소를 가리키고 있기 때문에, *p와 *p2는 모두 n의 값인 10을 출력합니다.
- 출력된 값은 10 10 10이며, 이는 n, *p, *p2의 값이 모두 동일하기 때문입니다.
#include <stdio.h>
int main()
{
int n = 10;
int n2 = n;
int* p = &n;
int* p2 = p;
printf("%d %d\n", n, *p);
printf("%p %p\n", &n, &*p);
printf("%p %p\n", &n, p);
}
-
int n = 10;
변수 n은 정수형으로 선언되며 값 10이 저장된다. -
int n2 = n;
변수 n2는 n의 값을 복사하여 저장하며, n과는 별개의 메모리 공간을 가진다. -
int* p = &n;
포인터 p는 변수 n의 주소를 저장하며, n을 간접적으로 참조할 수 있다. -
int* p2 = p;
포인터 p2는 p가 가리키는 주소(n의 주소)를 그대로 복사하여 동일한 주소를 가리킨다.
-
printf("%d %d\n", n, *p);
n은 10이며, *p는 포인터 p가 가리키는 n의 값을 출력하므로 10이 출력된다. -
printf("%p %p\n", &n, &*p);
&n은 n의 주소이고, &*p는 p가 가리키는 값을 다시 주소로 바꾼 것이므로 결과는 같다. -
printf("%p %p\n", &n, p);
&n은 n의 주소이고, p는 n의 주소를 저장하므로 같은 값이 출력된다.
10 10
0x7ffeeb4c3a4c 0x7ffeeb4c3a4c
0x7ffeeb4c3a4c 0x7ffeeb4c3a4c
※ 주소는 시스템 환경에 따라 달라질 수 있습니다.
변수 n의 값을 직접 출력한 것과 포인터 p를 통해 간접적으로 참조한 값이 동일하게 출력된다.
&*p는 결국 &n과 동일하며, 포인터 p 자체도 n의 주소를 가지고 있기 때문에 모두 동일한 주소가 출력된다.
포인터와 변수의 관계, 그리고 간접 참조와 주소 연산의 상호 작용을 확인할 수 있는 코드이다.
아주 좋습니다. 아래는 해당 내용을 **GitHub Wiki에 저장하기 좋은 Markdown 형식**으로 정리한 버전입니다. 그대로 복사하여 `.md` 파일로 저장하거나 GitHub Wiki 페이지에 붙여넣기 하시면 됩니다.
```markdown
## printf("%d %d\n", n, *p);에서 왜 둘 다 10이 출력되는가?
### 코드 예시
```c
int n = 10;
int* p = &n;
printf("%d %d\n", n, *p);
-
int n = 10;
변수n
은 정수형으로 선언되고, 값 10을 저장한다. -
int* p = &n;
포인터p
는n
의 주소를 저장하게 되며, 이제p
는n
을 가리키게 된다. -
*p
p
가 가리키는 주소의 값을 의미한다.p
는n
의 주소를 가지고 있으므로*p
는n
의 값과 같다.
printf("%d %d\n", n, *p);
- 첫 번째
%d
:n
의 값 → 10 - 두 번째
%d
:*p
→p
가 가리키는 주소의 값 →n
의 값 → 10
n: 10 // n이라는 변수에 저장된 값
p: &n // 포인터 p는 변수 n의 주소를 저장
*p: 10 // p가 가리키는 주소에 들어 있는 값, 즉 n의 값
포인터 p
는 변수 n
의 주소를 가리키고 있고, *p
는 그 주소에 있는 값을 의미하므로 n
과 *p
는 같은 값을 가지게 된다. 따라서 printf("%d %d\n", n, *p);
는 10 10
을 출력한다.
int main()
{
char c = 10; // 변수 c에 10 저장 (char는 1바이트)
double d = 5.6; // 변수 d에 5.6 저장 (double은 8바이트)
char* p1 = &c; // p1은 c의 주소를 저장하는 char형 포인터
double* p2 = &d; // p2는 d의 주소를 저장하는 double형 포인터
printf("%d %g\n", c, d); // 변수 자체 출력
printf("%d %g\n", *p1, *p2); // 포인터를 역참조해서 출력
printf("%d %g\n", *&c, *&d); // 주소 연산자(&)와 역참조(*) 조합
}
✅ 개념 요약
표현 | 설명 | 결과값
-- | -- | --
c | 변수 자체 값 | 10
d | 변수 자체 값 | 5.6
*p1 | c를 가리키는 포인터의 역참조 | 10
*p2 | d를 가리키는 포인터의 역참조 | 5.6
*&c | 주소를 취한 후 다시 역참조 (=&) | 10
*&d | 주소를 취한 후 다시 역참조 (=&) | 5.6
#include <stdio.h>
int main()
{
int arr[4] = {10, 20, 30, 40};
int* p = NULL;
p = &arr[3];
printf("%p %p %p %p\n", p, p + 1, p + 2, p + 3);
printf("%d %d %d %d\n", p[-3], p[-2], p[-1], p[0]);
}
- `int arr[4] = {10, 20, 30, 40};`
→ 크기가 4인 정수 배열을 선언하고, 초기값으로 각각 10, 20, 30, 40을 저장한다.
→ 메모리 상에는 `arr[0]`, `arr[1]`, `arr[2]`, `arr[3]` 순서대로 연속 저장된다.
- `int* p = NULL;`
→ 정수형 포인터 `p`를 선언하고, NULL(아무것도 가리키지 않음)로 초기화한다.
- `p = &arr[3];`
→ 포인터 `p`에 배열의 마지막 요소 `arr[3]`의 주소를 저장한다.
→ 즉, `p`는 현재 40을 가리키고 있다.
- `printf("%p %p %p %p\n", p, p + 1, p + 2, p + 3);`
→ `p`는 현재 `arr[3]`을 가리킨다.
→ `p + 1`, `p + 2`, `p + 3`은 각각 이후 메모리 주소를 가리킨다.
→ **주의**: 배열을 벗어난 영역을 가리키므로 접근은 금물! (주소 출력은 가능)
- `printf("%d %d %d %d\n", p[-3], p[-2], p[-1], p[0]);`
→ `p[-3]` = `arr[0]`, `p[-2]` = `arr[1]`, `p[-1]` = `arr[2]`, `p[0]` = `arr[3]`
→ `[]` 연산자에서 음수를 사용하면 포인터 기준으로 앞쪽 요소에 접근할 수 있다.
→ 실제 출력은: `10 20 30 40`
#include <stdio.h>
int main()
{
int arr[4] = {10, 20, 30, 40};
int* p = arr;
printf("%p %p %p %p\n", p, p + 1, p + 2, p + 3);
printf("%d %d %d %d\n", *p, *(p + 1), *(p + 2), *(p + 3));
printf("%d %d %d %d\n", p[0], p[1], p[2], p[3]);
}
- `int* p = arr;`
→ 배열 이름 `arr`은 배열의 첫 번째 요소 `&arr[0]`의 주소값이다.
→ `p`는 이제 `arr[0]`을 가리킨다.
- `printf("%p %p %p %p\n", p, p + 1, p + 2, p + 3);`
→ 포인터 연산으로 배열의 각 요소 주소 출력
→ `p + i`는 `arr[i]`의 주소와 동일
- `printf("%d %d %d %d\n", *p, *(p + 1), *(p + 2), *(p + 3));`
→ 포인터 역참조로 각 값 출력: `10 20 30 40`
- `printf("%d %d %d %d\n", p[0], p[1], p[2], p[3]);`
→ `p[i]`는 `*(p + i)`의 축약형
→ 동일한 결과 출력: `10 20 30 40`
#include <stdio.h>
int main()
{
int arr[4];
for (int i = 0; i < 4; ++i)
{
arr[i] = (i + 1) * 10;
}
for (int i = 0; i < 4; ++i)
{
printf("%d ", arr[i]);
}
printf("\n");
}
- `int arr[4];`
→ 초기화되지 않은 크기 4의 정수 배열 선언
- `arr[i] = (i + 1) * 10;`
→ `i = 0`일 때 10, `i = 1`일 때 20, ... `i = 3`일 때 40 대입
- 출력 루프에서는 각 요소를 공백으로 구분해서 출력
#include <stdio.h>
void ResetData(int* p)
{
*p = 0;
}
void PrintData(int data)
{
printf("data : %d\n", data);
}
void IncrementData(int* p)
{
*p = *p + 1;
}
int main()
{
int n;
ResetData(&n);
PrintData(n);
IncrementData(&n);
PrintData(n);
}
### 설명
- `ResetData(&n);`
→ 포인터로 `n`을 전달해서 값을 0으로 초기화
- `PrintData(n);`
→ 값 자체를 전달해서 출력
- `IncrementData(&n);`
→ 포인터로 값을 1 증가시킴
- 출력 결과:
data : 0 data : 1
#include <stdio.h>
int main()
{
int n = 10;
int* p = &n;
*p = 20;
char c = 10;
char* p2 = &c;
*p2 = 5;
double d = 9.99;
double* p3 = &d;
*p3 = 3.141592;
}
- `int* p = &n;` → 정수형 변수의 주소 저장
`*p = 20;` → `n`의 값을 20으로 변경
- `char* p2 = &c;` → 문자형 변수의 주소 저장
`*p2 = 5;` → `c`의 값을 5로 변경
- `double* p3 = &d;` → 실수형 변수의 주소 저장
`*p3 = 3.141592;` → `d`의 값을 변경
- 다양한 자료형에서도 포인터를 사용해 직접 값을 수정 가능