C언어_9

gimmicks_u·2022년 3월 31일
0

C언어

목록 보기
9/13
post-thumbnail

포인터

특정 메모리의 주소를 저장하는 변수

메모리는 주소를 통해 메모리에 접근하여 값을 읽고 쓸 수 있다. 포인터란 메모리의 주소값을 가리키는 변수이다.
무거운 데이터를 다룰 때 그 데이터를 가져다 쓰는 것 보다 주소값을 통해 참조하는 방법으로 사용하면 더욱 효율적으로 사용할 수 있다는 장점이 있다.

포인터 선언

char *pA;
int *pB;
double *C;

포인터 변수 선언시에는 변수명 앞에 *기호를 붙여준다.

int b = 100;
int *pB = &b;

&를 통해 변수의 주소값을 얻어올 수 있다.

#include <stdio.h>

int main(void)
{
    int b = 100;
    int *pB = &b;
    
    printf("b = %d\n", b);
    printf("&b = %d\n", &b);
    printf("*pB = %d\n", *pB);
    printf("pB = %d\n", pB);
}
b = 100
&b = 1862201964
*pB = 100
pB = 1862201964

포인터 변수를 선언할 때의 *기호와 출력할 때 *값은 서로 다른 기능인 것을 주의하자.

포인터 연산

  • 포인터끼리는 더할 수 없다.
  • 포인터끼리 뺀 값은 두 요소간의 상대적인 거리이다.(but 큰 의미는 없다...)

포인터에 정수를 더하거나 뺄 수 있다.

기준 포인터의 위치로부터 이동한 주소의 위치를 나타낸다.

#include <stdio.h>

int main(void)
{
    char str[] = "Programming";
    char *ptr1;

    ptr1 = &str[0];

    printf("%x\n", ptr1);
    printf("%x\n", ptr1 + 1);
    printf("%c\n", *(ptr1 + 1));
    printf("%x\n", ptr1 + 3);
    printf("%c\n", *(ptr1 + 3));
}
6b3fb258
6b3fb259
r
6b3fb25b
g
  • 배열을 직접 접근 : 직접 접근
  • 포인터를 통해 접근 : 간접 접근

홀수개수를 가지고있는 배열의 중간값을 포인터를 통해 출력하는 예제

#include <stdio.h>

int main(void)
{
    int arr[5] = {1, 2, 3, 4, 5};
    int *ptr = &arr[0];
    int len_arr = sizeof(arr) / sizeof(int);

	printf("%d\n", *ptr + (len_arr / 2));
}

포인터 주소값 뒤에 연산을 하는 수의 단위는byte가 아닌, 요소이다.
예를 들어, 문자열의 경우 1byte, 정수 배열의 경우 4byte이다.

포인터의 자료형

#include <stdio.h>

int main(void)
{
    char a = 'A';
    char *pA = &a;
    
    int b = 100;
    int *pB = &b;
    
    double c = 3.14;
    double *pC = &c;

    printf("pA의 크기 : %dbyte\n", sizeof(pA));
    printf("pB의 크기 : %dbyte\n", sizeof(pB));
    printf("pC의 크기 : %dbyte\n", sizeof(pC));
    printf("*pA의 크기 : %dbyte\n", sizeof(*pA));
    printf("*pB의 크기 : %dbyte\n", sizeof(*pB));
    printf("*pC의 크기 : %dbyte\n", sizeof(*pC));
}
pA의 크기 : 8byte
pB의 크기 : 8byte
pC의 크기 : 8byte
*pA의 크기 : 1byte
*pB의 크기 : 4byte
*pC의 크기 : 8byte

저장 공간이 같은 포인터 변수에 자료형을 나누어 놓은 이유는, 각각의 포인터 변수가 가르키는 변수들의 실제값을 참조하기 위함이다.

동적 메모리

동적 메모리 할당하는 이유

메모리 할당은 컴파일 타임에 이루어진다. 유동적인 자료형식을 고정하지 않고 실행시 결정하기 위해 동적으로 메모리를 할당해야 한다.

동적 메모리 할당과 해제

동적 메모리 할당 함수의 원형

void malloc(size_t size);

전달인자 size는 바이트 단위로 입력하고, 메모리 할당이 되면 메모리의 주소값을 리턴한다. 메모리 부족 시 null을 리턴한다. 리턴형이 void인데, 타입이 지정되어 있지 않는 포인터를 리턴해준다.(원하는 메모리 크기만큼 할당해주고, 메모리는 사용자가 원하는 형태로 정해서 사용)

동적 메모리 해제 함수의 원형

void free(void* memblock);

메모리 사용 후 반드시 해제해주어야 하고, 전달인자로 메모리를 가르키는 포인터를 대입한다. 해제하지 않을경우 메모리 누수가 일어난다.

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int num;
    int *student;

    printf("학생 수를 입력하세요 : ");
    scanf("%d", &num);

    student = (int*)malloc(sizeof(int) * num); // 할당한 메모리를 int형으로 형변환

 	// 동적 메모리 할당 뒤 국룰
    if(student == NULL) // null 포인터 검사
        {
            printf("메모리가 부족하여 메모리를 할당할 수 없습니다.\n");
            return 0;
        }
    //

        printf("할당된 메모리의 크기는 %d 입니다.\n", sizeof(int) * num);

        free(student);

        return 0;
}

메모리 재할당

실시간 메모리를 할당하여 사용하더라도 사용 중에 메모리 크기를 더 늘려야 하는 경우가 발생한다. malloc 함수로 할당된 메모리를 remalloc다시 동적으로 재할당해줄 수 있다.

void = remalloc(void* memblock, size_t size);

기존 동적 메모리의 값을 모두 가지면서 크기만 변경된 동적 메모리를 만들어낸다. 기존 메모리와 새로 확장할 메모리를 모두 포함한 크기로 설정한다.

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int i;
    int *arr = (int*)malloc(sizeof(int) * 5);
    int *rearr;

    for(i = 0; i < 5; i++)
    {
        arr[i] = i + 1;
    }
    rearr = (int*)realloc(arr, sizeof(int) * 10);
    for (i = 5; i < 10; i++)
    {
        rearr[i] = i + 1;
    }
    for (i = 0; i < 10; i++)
    {
        printf("%d\n", rearr[i]);
    }

    free(rearr);
}
1
2
3
4
5
6
7
8
9
10
profile
Done is better than perfect

0개의 댓글