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;
}

설명:

  1. 변수 선언 및 초기화

    • 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과 동일한 주소를 가리킵니다.
  2. 값 수정

    • *p2 = 20;: p2는 n의 주소를 가리키고 있으므로, *p2는 n에 해당합니다. 따라서 *p2 = 20;은 n의 값을 20으로 변경합니다. 이제 n은 20을 가집니다.
  3. 출력

    • 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;
}

설명:

  1. 변수 선언 및 초기화

    • 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와 동일한 주소를 가리킵니다.
  2. 출력

    • 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;
    포인터 pn의 주소를 저장하게 되며, 이제 pn을 가리키게 된다.

  • *p
    p가 가리키는 주소의 값을 의미한다. pn의 주소를 가지고 있으므로 *pn의 값과 같다.

출력 코드

printf("%d %d\n", n, *p);
  • 첫 번째 %d: n의 값 → 10
  • 두 번째 %d: *pp가 가리키는 주소의 값 → 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 = &amp;c;       // p1은 c의 주소를 저장하는 char형 포인터
    double* p2 = &amp;d;     // p2는 d의 주소를 저장하는 double형 포인터

    printf("%d %g\n", c, d);        // 변수 자체 출력
    printf("%d %g\n", *p1, *p2);    // 포인터를 역참조해서 출력
    printf("%d %g\n", *&amp;c, *&amp;d);    // 주소 연산자(&amp;)와 역참조(*) 조합
}
✅ 개념 요약

표현 | 설명 | 결과값
-- | -- | --
c | 변수 자체 값 | 10
d | 변수 자체 값 | 5.6
*p1 | c를 가리키는 포인터의 역참조 | 10
*p2 | d를 가리키는 포인터의 역참조 | 5.6
*&c | 주소를 취한 후 다시 역참조 (=&) | 10
*&d | 주소를 취한 후 다시 역참조 (=&) | 5.6

📘 C 포인터 & 배열 예제 상세 설명

✅ 예제 1: 포인터로 배열 요소에 역순 접근

#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`

✅ 예제 2: 포인터로 배열 순회 및 다양한 방식의 접근

#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`

✅ 예제 3: 반복문을 사용한 배열 초기화 및 출력

#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 대입

- 출력 루프에서는 각 요소를 공백으로 구분해서 출력

✅ 예제 4: 함수 호출을 통한 변수 조작

#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


✅ 예제 5: 다양한 타입에 대한 포인터 연산

#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`의 값을 변경

- 다양한 자료형에서도 포인터를 사용해 직접 값을 수정 가능

⚠️ **GitHub.com Fallback** ⚠️