C언어 - 포인터의 기초

2022. 11. 20. 01:31·C프로그래밍/개인 공부

포인터

 

point에 er을 붙인 것이다. pointer을 직역하면 '가르키는 것'이 되는데, 변수의 주소를 가지고 있는 변수이다. 즉, int i = 4이렇게 변수에 데이터를 저장했다고 가정했을때, 포인터는 변수i가 저장되어있는 메모리상 주소를 가진다.


 

주소 연산자 &

 

그렇다면 변수의 주소를 어떻게 알 수 있을까?

주소 연산자인 &를 사용하면된다. 간단한 예제를 살펴 보자.

 

1
2
3
4
5
6
7
8
9
#include<stdio.h>
 
int main(void)
{
    int a = 10;
    printf("%u", &a);//%u는 주소를 십진수로 출력
 
    return 0;
}
cs

 

이 예제에선, 변수 a를 선언하고 10을 저장했다. 그렇다면 이 변수 a가 저장되어 있는 메모리상 주소가 있을 것이다. &는 주소 연산자로써 &a를 하면 a가 저장된 메모리의 주소를 알 수 있다.

 

메모리 주소는 1836660552이다

변수 a가 저장되어있는 주소가 나왔다!

 

 

 


 

포인터의 선언

 

그렇다면 포인터 변수의 선언은 어떻게 할까?

일단 포인터 선언은 int *p; 이렇게 한다. 이것도 예제를 통해서 알아보자.

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
 
int main(void)
{
    int a = 10;
    int *p;//int형의 변수를 가르키는 포인터변수 p의 생성
    p = &a;
 
    printf("%u", p);
    return 0;
}
Colored by Color Scripter
cs

 

설명) 일단 변수 a를 선언하고 10을 저장한다. 그리고 포인터 변수p를 선언한다. 여기서 int형으로 포인터 변수를 선언했는데, 이 포인터가 가르킬 변수가 int형이기 때문이다.

p = &a를 보면 포인터 변수 p에 a의 주소를 저장한 것이다. 포인터는 주소를 가르키는 것이고, &는 주소 연산자이기 때문이다. 즉, 주소를 저장하는 변수p에 &a의 변수를 넣은 것이라고 보면된다.

 

이것도 변수 a의 주소가 출력된다!

 

 

 


 

간접 참조 연산자 *

 

 포인터는 주소만 저장할 수 있는게 아니라, 주소로 가서 데이터를 가져올 수 있다. 그러려면 포인터변수 p앞에 *를 붙여서 *p를 하면 된다. 그러면 포인터 변수 p가 가르키고 있는 변수의 데이터를 가져온다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
 
int main(void)
{
    int i = 3000;
    int *p = NULL;
 
    p = &i;
 
    printf("i = %d\n", i);//변수 i의 데이터
    printf("&i = %u\n", &i);//변수 i의 주소
 
    printf("*p = %d\n", *p);//포인터 변수 p가 가르키고 있는 변수의 데이터
    printf("p = %d\n", p);//포인터 변수에 저장되어있는 주소
 
    return 0;
}
Colored by Color Scripter
cs

설명)

i=3000이고 *p는 i가 저장되어있는 주소로 가서 데이터인 3000을 가져온다. &i는 i의 주소이고 포인터변수인 p도 i의 주소이다. 따라서 i와 *p는 같으며, &i와 p는 같다.

결과 확인

 

 


 

포인터 연산

 

포인터에서도 사칙 연산이 적용 될까? 덧셈과 뺄셈만 가능하다! 만약 포인터 p의 값이 1000이다. 여기서 p를 하나 증가시키면 1001이 될 것만 같다. 즉, p++를 하면 1001이 될 것 같지만, 포인터p가 어떤 자료형을 가르키는지에 따라서 다르다. 포인터p가 int자료형을 가르키고 있다면 4씩 증가한다. 즉 p++을 하면 1000에서 1004가 된다. int 자료형은 4byte이고, 포인터는 4byte씩 읽어들인다. 뺄셈도 마찬가지다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <Stdio.h>
 
int main(void)
{
    char *pc;
    int *pi;
    double *pd;
 
    pc = (char *)10000; //이렇게 포인터에 직접 값을 대입하는건 좋지 않다
    pi = (int *)20000;  //정확학 설명을 위해 하는 것임.
    pd = (double *)30000;
 
    printf("증가 전 : pc = %u pi = %u pd = %u\n", pc, pi, pd);
 
    pc++;
    pi++;
    pd++;
 
    printf("증가 후 : pc = %u pi = %u pd = %u\n", pc, pi, pd);
    return 0;
}
Colored by Color Scripter
cs

이 코드는 포인터를 증가시키면 얼마씩 증가되는지 알아보기 위해서 작성한 코드이다. char형 포인터는 1씩, int는 4씩, double은 8씩 증가 한 것을 볼 수 있다.

각각의 증가 결과

 

포인터에서 쓰이는 간접 참조 연산자와 증감 연산자를 알아보자.

*p++와 (*p)++의 차이가 뭘까?

*p++ : p가 가르키는 위치에서 값을 가져온 다음에, p를 증가시킨다.

(*p)++ : p가 가르키는 값을 증가시킨다.

예제로 확인해 보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
 
int main(void)
{
    int i = 10;
    int *pi = &i;
 
    printf("i = %d   pi = %u\n", i, pi);
    (*pi)++; //pi가 가르키는 곳에서 가져온 값을 증가한다.
    printf("i = %d   pi = %u\n", i, pi);
 
    printf("i = %d   pi = %u\n", i, pi);
    *pi++; //pi가 가르키는 곳에서 가져온다음 pi를 증가한다.
    printf("i = %d   pi = %u\n", i, pi);
 
    return 0;
}
Colored by Color Scripter
cs
결과

 

포인터와 배열

배열이름이 포인터라면 포인터도 배열처럼 사용할 수 있다. 간단한 예제를 보자.

1
2
3
4
int a[] = {10, 20, 30, 40, 50};
int *p
 
p = a;
cs

배열 a를 선언, 포인터 p를 선언하고 포인터 p가 배열 a가르키도록 만든다.(배열의 이름은 배열의 주소) 그리고, 배열 a와 포인터 p를 배열처럼 사용해서 출력해보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
 
int main(void)
{
    int a[] = {10, 20, 30, 40, 50};
    int *p;
 
    p = a;
 
    printf("a[] = ");
    for(int i=0; i < 5;i++){ //배열 a를 출력
        printf("%d ", a[i]);
    }
    printf("\n");
 
    printf("p[] = ");
    for(int i=0; i < 5; i++){ //포인터 p를 배열처럼 출력
        printf("%d ", p[i]);
    }
 
    return 0;
}
Colored by Color Scripter
cs
결과

포인터도 배열처럼 사용해서 출력했을때, 배열 a와 동일하다는 것을 알 수 있다. 즉, 포인터도 배열처럼 사용가능하다.

 

1
2
p[0] = 60;
p[1] = 70;
cs

p를 이용해서 배열 a를 수정해보자. 마찬가지로 포인터 p가 배열a의 주소를 가르키고있기때문에, p를 수정하면 배열 a도 수정되게 된다.

1
2
3
4
p[0] = 60;
p[1] = 70;
 
printf("%d %d", a[0], a[1]);
cs
p를 수정하니 a도 수정됨

 

포인터와 함수(값에 의한 호출, 참조에 의한 호출)

함수에서 배열을 매개변수로 할 때, 장소를 할당하는게 아니라 주소를 저장하는 포인터로 생성됨. why? 배열은 크기가 크면 문제가 생길 수 있음.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdio.h>
 
void func(int b[]);
 
int main(void)
{
    int a[3] = {1, 2, 3};
 
    for(int i=0; i < 3; i++){
        printf("%d ", a[i]);
    }
    printf("\n");
 
    func(a); //인수로 배열 a의 주소를 전달
 
    for(int i=0; i < 3; i++){
        printf("%d ", a[i]);
    }
    printf("\n");
 
    return 0;
}
 
void func(int b[]) //배열을 가르키는 포인터가 생성된다.
{
    b[0] = 5;
    b[1] = 6;
    b[2] = 7;
}
Colored by Color Scripter
cs

설명) func함수에서 배열 a의 주소가 인수로 전달된다. func함수에서는 받은 매개변수(배열 a의 주소)로 가서 값을 수정한다. 주소로 가서 값을 수정하는 것이기 때문에, 배열 a의 값을 출력해보면 변경된 것을 알 수 있다.


 

포인터를 사용하는 반환값

함수의 인수로 포인터를 받는 형태도 있지만, 함수의 반환값으로 포인터를 사용할 수 있다. 주의!! 함수가 종료되더라도 남아 있는 주소를 반환해야 한다. why? 지역변수의 경우 함수가 종료되면 변수가 사라지기 때문에 그 사라진 변수의 주소를 반환하면 안된다.!

 

'C프로그래밍 > 개인 공부' 카테고리의 다른 글

C언어 - 구조체와 포인터  (0) 2022.12.10
C언어 - 문자열을 정수로, 정수를 문자열로 바꾸기  (0) 2022.12.10
C언어 - 스트림과 파일 입출력 기초(쓰기와 삭제)  (0) 2022.11.02
C언어 - 10진수를 2진수로 바꾸기(재귀함수)  (1) 2022.10.13
C언어 - 구조체와 포인터  (0) 2022.08.09
'C프로그래밍/개인 공부' 카테고리의 다른 글
  • C언어 - 구조체와 포인터
  • C언어 - 문자열을 정수로, 정수를 문자열로 바꾸기
  • C언어 - 스트림과 파일 입출력 기초(쓰기와 삭제)
  • C언어 - 10진수를 2진수로 바꾸기(재귀함수)
Jminu
Jminu
  • Jminu
    뇌 구조가 바이너리
    Jminu
  • 전체
    오늘
    어제
    • 분류 전체보기
      • C프로그래밍
        • 오류해결
        • 개인 공부
        • Programming Lab(학교수업)
        • MemoryTracker
      • C++
        • 개인 공부
      • 자료구조(Data Structure)
      • ARM arch
        • Cortex-M
        • FreeRTOS
      • 컴퓨터 공학(Computer Science)
        • OS
        • 컴퓨터 구조
      • Qualcomm 기업과제
      • Linux
      • Web
      • 똥글
      • 백준
      • Git 학습
        • 오류해결
        • 학습중
      • Python
        • 오류해결
        • 개인 공부
  • 블로그 메뉴

    • 태그
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    버퍼
    포인터
    토발즈
    파일 입출력
    arm
    yolo
    커널
    Branch
    피보나치
    Qualcomm
    C++
    백준
    순환
    시스템콜
    커널 기여
    Git
    소수
    c언어
    스택
    앤드류모튼
    이진 트리
    동적메모리
    commit
    파이썬
    rubikpi3
    자료구조
    INIT
    rubik pi
    리눅스
    드라이버 분석
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Jminu
C언어 - 포인터의 기초
상단으로

티스토리툴바