C의 꽃: 포인터

이정연·2023년 10월 16일
0

Embedded

목록 보기
2/5

개념

#include <stdio.h>

int main() {
    int n = 10;
    int *ptr = &n;
    printf("address of n: %d\n", &n);
    printf("address of n: %d\n", ptr);
    printf("value of pointer: %d\n", *ptr);
    return 0;
}
address of a: 6422296
address of a: 6422296
value of pointer: 10

선언

포인터도 일종의 자료형이다. int와 char 같은.

포인터 타입의 선언은 [자료형]* [포인터 변수명] = [주소값]으로 한다.

이 때, *의 위치는 상관없다.

Ex)

int ptr: int형 자료가 들어있는 주소값
char
ptr: char형 자료가 들어있는 주소값

위 그림에서 변수 n은 10이 할당되어 있고 이는 메모리 어딘가에 저장된다.

int는 4바이트를 차지하므로 00120B14~00120B17까지 주소를 할당받는데 포인터가 가리키는 주소값은 가장 첫 번째다.

(변수의 주소값은 코드를 실행할 때마다 항상 바뀌므로 위 코드의 주소값과 그림의 주소값이 다르다고 의아해할 필요 없다.)

다시 본론으로 돌아와서 위 코드를 해석해보자면

나는 n에 10을 담았고 ptr에 n의 주소를 담았다.

&[변수]

&은 변수의 주소값을 반환하는 문법이다.

따라서 첫번째와 두번째 printf는 n의 현재 주소값인 6422296를 출력한다.

*[주소값]

*는 주소값에 들어있는 데이터를 반환하는 문법이다.

위 예시를 보면, ptr에 n의 주소값이 담겨있으므로

*ptr을 하면 n의 데이터인 정수형 10이 반환되는 것이다.

또 다른 예시

#include <stdio.h>

int main() {
    double num = 3.1415;
    double* numAddress = &num;
    printf("%d\n", sizeof(numAddress));
    printf("%d\n", sizeof(num));

    printf("num: %.4f\n", num);
    printf("&num: %d\n", &num);
    printf("numAddress: %d\n", numAddress);
    printf("&numAddress: %d\n", &numAddress);
    printf("*numAddress: %.4f\n", *numAddress);
    return 0;
}

배열

배열도 일종의 포인터다.

#include <stdio.h>

int main() {
    int ary[] = {1,2,3};
    printf("array: %d\n", ary);
    printf("array0: %d\n", ary[0]);
    printf("array1: %d\n", ary[1]);
    printf("array2: %d\n", ary[2]);
	printf("*array: %d\n", *ary);
    return 0;
}
array: 6422292
array0: 1
array1: 2
array2: 3
*array: 1

ary를 출력해보면 주소값인 6422292가 나온다.

즉, 배열도 일종의 포인터 자료형이라고 볼 수 있다.

배열은 포인터 상수

#include <stdio.h>

int main() {
    int ary[] = {1,2,3};

    // 포인터는 가변
    int* ptr = NULL;
    printf("%d\n", ptr);

    ptr = ary;
    printf("%d\n", ptr);

    // 배열은 불변
    int num = 5;
    ary = &num;
    return 0;
}
expression must be a modifiable lvalue

포인터의 값은 바꿀 수 있지만 배열의 값은 바꿀 수 없다.

따라서, 배열은 포인터 성격을 띠고 있지만 값을 바꿀 수 없다는 점에서 "포인터 상수"라고 볼 수 있다.

포인터로 배열 쓰기

#include <stdio.h>

int main() {
    int ary[] = {1,2,3};
    printf("array: %d\n", ary);
    printf("array+1: %d\n", ary+1);
    printf("array+2: %d\n", ary+2);
    printf("array+3: %d\n", ary+3);
    printf("&array: %d\n", &ary);
    printf("&array+1: %d\n", &ary+1);
    printf("&array+2: %d\n", &ary+2);
    printf("&array+3: %d\n", &ary+3);
    return 0;
}
array: 6422292
array+1: 6422296
array+2: 6422300
array+3: 6422304
&array: 6422292
&array+1: 6422304
&array+2: 6422316
&array+3: 6422328

포인터+1 연산을 하면 주소값+1이 아니다.
주소값+[자료형 크기]가 된다.

예를 들어, 위 코드의 array는 정수 배열이므로 4바이트다.

따라서, 포인터에 +1을 할때마다 4씩 주소가 커진다.

반면에 &array는 배열 자체의 주소를 의미하기 때문에 4바이트(정수형)*3(길이가 3인 배열이므로) = 12바이트씩 주소가 커진다.

이를 활용하면 아래처럼 배열의 원소값에 접근 가능하다.

#include <stdio.h>

int main() {
    int ary[] = {1,2,3};
    
    for (int i=0;i<3;i++) {
        printf("%d\n", *(ary+i));
    }
    return 0;
}
1
2
3

Reference

https://jhnyang.tistory.com/100

profile
0x68656C6C6F21

0개의 댓글