C언어/참고서: C언어 콘서트

C언어 45차시 포인터, 메모리, 변수, 포인터 연산자 &, *, %p, 간접참조연산자

Olivia-BlackCherry 2023. 4. 5. 18:55

목차

    1. 메모리

    메모리는 바이트로 구성되고, 각 바이트마다 고유한 주소를 가진다. 

    출처: c언어 콘서트

     

     

    2. 변수

    변수부터 살펴보자. 

    변수는 만들어지면 컴파일러에 의해 메모리 공간에 배치된다.

    즉, 변수는 컴퓨터 메모리에 만들어진다. 

    변수의 자료형에 따라 차지하는 메모리 공간이 달라진다. 

    int, float 4 byte

    char 1 byte

    short 2 byte

    double 8 byte 

     

     

    3. 변수의 주소 계산하는  연산자 &

    변수의 주소를 계산하는 연산자 &를 쓰면 된다. 

    scanf 함수를 썼을 때, 입력하는 것을 변수의 주소에 담았던 것을 기억할 것이다. 

    scanf("%d", &x); 

    c 언어 콘서트 (출처)

     

     

    4. 변수의 주소를 출력할 때는 형식 지정자 %p

    &은 변수의 이름을 받아서, 그 변수에 주소를 저장한다. 

    해당 주소를 출력하고 싶다면, 형식 지정자 %p를 쓰면 된다. 

    printf("%p", &x);

     

     

    5. 포인터

    1) 포인터를 알아야하는 이유

    포인터는 어려운 개념이지만, 제대로 알아둔다면 컴퓨터를 이해하고 고차원적인 기술을 접목하는데 도움이 될 것이다. 

     

     

    2) 포인터를 사용하는 이유

    메모리의 낭비를 줄인다.

    변수를 지정하면 변수는 컴퓨터의 어떤 메모리에 저장이된다. 

    변수를 생성하는 것을 아기가 태어나는 것이라고 가정하자. 

    아기(변수)는 해운데에 살고 있다. 아기의 주민등록상 주소는 해운대이다. 

     

    그런데 아기는 한 곳에만 있지 않는다.

    아기의 신원을 파악하기 위해, 정부는 아기가 어디있는지 확인하기 위해서 아기가 있는 위치를 모두 기록한다.

    아기의 원래 주소는 해운대이지만, 

    어린이집에 갈 때는 어린이집의 주소가 하나 더 생기고, 마트에 갈 때도 마트 주소가 생기고, 돌잔치에 갈 때는 연회장의 주소가 생긴다. (사본이 생겨나고, 사본의 주소가 생겨남)

     

    그렇다고 원래 주소인 해운대가 변하지는 않는다.(원본은 변함없음)

     

    그런데 이렇게 아기가 왔다갔다하면, 주소가 너무 많아져서 아기의 위치를 저장하는 공간이 가득 차게 된다. 

    즉, 메모리가 가득 차는 것이다.

    그러면..어쨌든 문제가 생길 것이 분명하다!

     

    그래서 포인터를 쓰는 이유가 있다.

     

    왜냐하면 포인터는 아기의 새로운 위치를 만드는 것이 아니라,

    원본의 위치를 가리켜서 그 주소값을 전달하기 때문이다.

    더이상 사본을 만들어 내지 않는다.

    포인터는 메모리의 낭비를 줄인다!!

     

     

    3) 포인터의 정의

    변수는 저마다 자기의 주소를 가진다. 

    포인터는 이 변수가 어떤 위치에 있는지 가리킨다.

     

    즉, 변수가 저장되는 주소와 깊은 관계가 있다. 

     

     

    4) 포인터 선언

    포인터도 변수이기 때문에 사용하기 전에 선언해야 한다. 

    *은 곱셈 연산자와는 아무 관련이 없다. 

    포인터를 뜻하는 의미이다.

    포인터가 가리키는 자료형 + * + 이름
    int *p;

     

     

     5) 포인터 초기화

    반드시 초기화해야 한다. 

    포인터에는 변수의 주소가 저장되어야 하므로 &연산자를 이용한다.

    int number =10'
    int *p;         ---> 포인터 선언
    p=&number;---->포인터 초기화

     

     

    6) NULL(0) 

    포인터가 아무것도 가리키지 않을 때는 NULL으로 설정한다. 

    안전한 코드를 만들기 위해 필요하다. 

    int *p= NULL;

     

     

    6. 간접 참조 연산자 *

    포인터가 유용한 이유는, 포인터가 가리키는 위치의 값을 읽어오거나 변경할 수 있기 때문이다. 

    포인터 p가 가리키는 위치에 저장된 내용을 가져오려면 p앞에 *기호를 붙인다. 

    *p

    p의 값 

    이라고 해석하면 편리하다.

    간접 참조 dereferencing, indrection 연산자는 단항 연산자로 연산 우선순위가 높다.

    int number =10'int *p;         ---> 포인터 선언p=&number;---->포인터 초기화

    printf("%d", *p); -->10출력

     

     

    7. 정리: 포인터 연산자

    포인터 연산자는 두 개가 있다. 

    첫 번째는 주소 연산자 &

    두 번째는 간접 참조 연산자 *

     

     

    8. 예제 확인

    <변수가 가지는 주소, 변수 값을 뽑아보자>

    #define _CRT_SECURE_NO_WARNINGS
    #include <stdio.h>
    #include <math.h>
    int main(void)
    {
    	int number = 10;
    	int* p;
    	p= &number;
    
    	printf("number변수가 가지는 주소:\n");
    	printf("%p\n", &number);
    	printf("%p\n\n", p);
    
    	printf("number값:\n ");
    	printf("%d\n", number);
    	printf("%d\n", *p);
    	
    	return 0;
    }

     

     

    <간접 참조 연산자 *을 이용해서 포인터가 가리키는 변수 값 변경하기>

    #define _CRT_SECURE_NO_WARNINGS
    #include <stdio.h>
    #include <math.h>
    int main(void)
    {
    	int number = 10;
    	int* p;
    	p= &number;
    
    	printf("number값:\n");
    	printf("%d\n", number);
    
    	*p = 30;
    	printf("%d\n", *p);
    	
    	return 0;
    }