본문 바로가기

 

배열과 포인터는 연산자 & * [ ] 만 이해하면 된다.
그리고, 배열과 포인터는 다르다.

 

1. 필수 기반 지식

 

  • 프로그래밍과 빌드, 실행의 이해
  • bit, Byte, 2진수, 16진수, 기본 자료형 이해
  • 컴퓨터 실행의 기본 동작과 장치(cpu, memory, storage) 이해
  • 함수와 스텍 메모리 이해

 

 

2. 포인터의 선언, 변수 사용, 역참조 구분 

 

코딩 컨벤션(네이밍 룰)

 

#include <stdio.h>

int main(void)
{
    char cNum = 65;                   // char형 변수 cNum 선언
    char *pVar1 = &cNum;              // 포인터 변수 pVar 선언, char형 포인터 연산가능한  
    printf(" pVar1: %p\n", pVar1);    // 포인터 사용, 변수명만 사용, 주소값 의미
    printf("*pVar1: %d\n", *pVar1);   // 포인터 역참조, 포인터(주소)가 가르키는 공간에 저장된 값 의미

    int iNum = 90;
    int *pVar2 = &iNum;
    printf(" pVar2: %p\n", pVar2);
    printf("*pVar2: %d\n", *pVar2);

    return 0;
}

 

2.1 변수 선언 이해

 

 

  • char 자료형 크기만큼 메모리를 사용하고, 65 라는 값을 저장하여, cNum이라는 변수명으로 참조하겠습니다.
  • int 자료형 크기만큼 메모리를 사용하고, 90 라는 값을 저장하여, iNum이라는 변수명으로 참조하겠습니다.
  • 컴파일러는 변수명이 필요없다.

 

2.2 포인터의 자료형 선언 부분 이해

 

 

  • 포인터가 의미하는 값, 모든 메모리 주소 크기는 일정하다. == 메모리 주소 저장에 필요한 크기는 일정하다.
    기본 자료형을 사용할때 처럼, 데이터 타입을 명시할 이유가 없다.

    Q. 자료형을 명시하여 사용하는 이유는?
    Q. 포인터 선언시, 자료형을 명시하여 사용하는 이유는?

 

  • 포인터 변수의 사용은, 포인터 변수가 가지는 공간의 값, 메모리 주소값을 의미한다.
    printf(" pVar1: %p\n", pVar1);    // 포인터 사용, 변수명만 사용, 포인터 변수가 저장한 주소값 의미한다.

 

  • 표인터 변수 선언
    int *pVar = &iNum; // 주소값을 담는 포인터 선언, 변수명 앞에 * 에스터리스크 사용한다.

 

  • 표인터 변수 사용, 역참조 구분
    pVar // 포인터 변수를 사용한 때는 변수만 사용한다.
    *pVar // 포인터 변수에, 역참조 연산자가 추가되면, 주소값을 참조하여 포인터 변수 선언시 사용한 자료형의 크기만큼 참조한다. 

 

 

2.3 정리

 

변수 → & → 포인터(주소) → * → 데이터

(&변수  (* 포인터(주소)) → 데이터

*(&변수  데이터

*&변수  데이터

변수 → 데이터

 

iNum → & → pVar → * → 90

(&iNum  (* pVar) → 90

*(&iNum  90

*&iNum  90

iNum → 데이터

 

 

3. 주소값은 주소값일 뿐이다.

 

포인터는 포인터다.

 

#include <stdio.h>

int main(void)
{
    int iNum2 = 89;                   // int형 변수를 선언
    char* pVar3 = (char*)&iNum2;      // &iNum2 int형 포인터 주소값을, char형 포인터로 변환 
    printf(" pVar3: %d\n", *pVar3);   // char형 크기만큼만 연산한다. 주소값은 주소값일 뿐이다. 

    return 0;
}

 

 

4. 포인터 연산

 

포인터 선언시 사용한 자료형의 크기만큼, (자료형*숫자)Byte 연산한다.

예시의 변수는 순차적으로 저장된다는 가정이지만, 배열은 연속되고 순차적인 특성을 가진다.

 

#include <stdio.h>

int main(void)
{
    char cNum2 = 70, cNum3 = 71, cNum4 = 72;
    char *pVar2 = &cNum2, *pVar3 = &cNum3, *pVar4 = &cNum4;

    printf(" pVar2: %p %d\n", pVar2, *pVar2);  // pVar2: 0061FF13 70
    printf(" pVar3: %p %d\n", pVar3, *pVar3);  // pVar3: 0061FF12 71
    printf(" pVar4: %p %d\n", pVar4, *pVar4);  // pVar4: 0061FF11 72

    // 메모리에 값이 위 주석처럼, 순차적으로 저장된다고 가정할 때
    // (참고) 위의 메모리 주소값을 확인해서 연산을 수정해야 할 수 있다.
    // printf(" pVar4+2: %p %d\n", pVar4+2, *(pVar4+2));  // pVar4+2: 0061FF13 70
    // printf(" pVar4+1: %p %d\n", pVar4+1, *(pVar4+1));  // pVar4+1: 0061FF12 71
    // printf(" pVar4  : %p %d\n", pVar4, *pVar4);        // pVar4  : 0061FF11 72

    return 0;
}

 

#include <stdio.h>

int main(void)
{
    int iNum2 = 81, iNum3 = 82, iNum4 = 83;
    int *pVar2 = &iNum2, *pVar3 = &iNum3,*pVar4 = &iNum4;

    printf(" pVar2: %p %d\n", pVar2, *pVar2);  // pVar2: 0061FF10 81
    printf(" pVar3: %p %d\n", pVar3, *pVar3);  // pVar3: 0061FF0C 82
    printf(" pVar4: %p %d\n", pVar4, *pVar4);  // pVar4: 0061FF08 83

    // 메모리에 값이 저장될 때, 위 주석처럼 순차적으로 저장되었다고 가정할 때
    // (참고) 위의 메모리 주소값을 확인해서 연산을 수정해야 할 수 있다.
    // printf(" pVar4+2: %p %d\n", pVar4+2, *(pVar4+2));  // pVar4+2: 0061FF10 81
    // printf(" pVar4+1: %p %d\n", pVar4+1, *(pVar4+1));  // pVar4+1: 0061FF0C 82
    // printf(" pVar4  : %p %d\n", pVar4, *pVar4);        // pVar4  : 0061FF08 83

    return 0;
}

 

 

5. 포인터와 1차원 배열

 

같다며?
 
*(ptr_num + 0) == ptr_arr[0]
*(ptr_num + 1) == ptr_arr[0+1]
*(ptr_num + 2) == ptr_arr[0+2]  // 배열로 사용하면 * 역참조 연산자가 생략되고, [ ] 연산자가 사용된 형태다.
 
ptr_num + 0
ptr_num + 1
ptr_num + 2
ptr_num + 3

char ptr_arr[5] = {'A', 'B', 'C', 'D', 'E'};

#include <stdio.h>

int main(void)
{
    char arr[5]  = {'A', 'B', 'C', 'D', 'E'};
    printf(" arr+0 : %p %c\n", arr, *arr);
    printf(" arr+1 : %p %c\n", arr+1, *arr+1);
    printf(" arr+2 : %p %c\n", arr+2, *arr+2);
    printf(" arr+3 : %p %c\n", arr+3, *arr+3);
    printf(" arr+4 : %p %c\n", arr+4, *arr+4);

    char *pVar = arr;
    printf(" pVar+0 : %p %c\n", pVar, *pVar);
    printf(" pVar+1 : %p %c\n", pVar+1, *pVar+1);
    printf(" pVar+2 : %p %c\n", pVar+2, *pVar+2);
    printf(" pVar+3 : %p %c\n", pVar+3, *pVar+3);
    printf(" pVar+4 : %p %c\n", pVar+4, *pVar+4);

    return 0;
}

 

arr  <<<< 포인터, 주소값이 들어있는, 포인터 변수, 값인 주소는 변경이 불가능한, 상수 포인터
arr 포인터 상수, 즉 포인터 변수처럼 메모리 주소가 들어있다.
arr[0] 의 주소값이다.

 

 

6. 포인터와 다차원 배열, 그리고 자료형 연산

 

 

#include <stdio.h>

int main(void)
{
    char arr[6]  = {'A', 'B', 'C', 'D'};
    printf(" arr+1 : %p %c\n", arr, *arr);
    printf(" arr+2 : %p %c\n", arr+1, *arr+1);
    printf(" arr+3 : %p %c\n", arr+2, *arr+2);
    printf(" arr+4 : %p %c\n", arr+3, *arr+3);

    char *pVar = arr;
    printf(" pVar+1 : %p %c\n", pVar, *pVar);
    printf(" pVar+2 : %p %c\n", pVar+1, *pVar+1);
    printf(" pVar+3 : %p %c\n", pVar+2, *pVar+2);
    printf(" pVar+4 : %p %c\n", pVar+3, *pVar+3);


    char arr2D[3][2]  = {'A', 'B', 'C', 'D', 'E', 'F'};
    printf(" *arr2D+0 : %p %c\n", *arr2D, **arr2D);
    printf(" *arr2D+1 : %p %c\n", *arr2D+1, **arr2D+1);
    printf(" *arr2D+2 : %p %c\n", *arr2D+2, *(*arr2D)+2);
    printf(" *arr2D+3 : %p %c\n", *arr2D+3, *(*arr2D)+3);
    printf(" *arr2D+4 : %p %c\n", *arr2D+4, *(*arr2D)+4);
    printf(" *arr2D+5 : %p %c\n", *arr2D+5, *(*arr2D)+5);

    // char *pVar = *arr2D;
    // char *pVar = arr2D[0];
    pVar = &(arr2D[0][0]);
    printf(" pVar+0 : %p %c\n", pVar, *pVar);
    printf(" pVar+1 : %p %c\n", pVar+1, *pVar+1);
    printf(" pVar+2 : %p %c\n", pVar+2, *pVar+2);
    printf(" pVar+3 : %p %c\n", pVar+3, *pVar+3);
    printf(" pVar+4 : %p %c\n", pVar+4, *pVar+4);
    printf(" pVar+5 : %p %c\n", pVar+5, *pVar+5);
    

    char arr3D[2][2][2]  = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'};
    printf(" *arr3D+0 : %p %c\n", **arr3D, ***arr3D);
    printf(" *arr3D+1 : %p %c\n", **arr3D+1, ***arr3D+1);
    printf(" *arr3D+2 : %p %c\n", **arr3D+2, *(**arr3D)+2);
    printf(" *arr3D+3 : %p %c\n", **arr3D+3, *(**arr3D)+3);
    printf(" *arr3D+4 : %p %c\n", **arr3D+4, *(**arr3D)+4);
    printf(" *arr3D+5 : %p %c\n", **arr3D+5, *(**arr3D)+5);
    printf(" *arr3D+6 : %p %c\n", **arr3D+6, *(**arr3D)+6);
    printf(" *arr3D+7 : %p %c\n", **arr3D+7, *(**arr3D)+7);

    // char *pVar = **arr3D;
    // char *pVar = arr3D[0][0];
    pVar = &(arr3D[0][0][0]);
    printf(" pVar+0 : %p %c\n", pVar, *pVar);
    printf(" pVar+1 : %p %c\n", pVar+1, *pVar+1);
    printf(" pVar+2 : %p %c\n", pVar+2, *pVar+2);
    printf(" pVar+3 : %p %c\n", pVar+3, *pVar+3);
    printf(" pVar+4 : %p %c\n", pVar+4, *pVar+4);
    printf(" pVar+5 : %p %c\n", pVar+5, *pVar+5);
    printf(" pVar+6 : %p %c\n", pVar+6, *pVar+6);
    printf(" pVar+7 : %p %c\n", pVar+7, *pVar+7);


    return 0;
}



7. 함수와 1차원 배열

 

#include <stdio.h>

int main(void)
{
    int arr_1d[4] = {
        0,
    };

    //1 
    printf("arr_1d     : %p\n",  arr_1d);
    printf("arr_1d     : %p\n", *arr_1d);

    //2
    printf("sizeof(arr): %d\n", sizeof(arr_1d));

    //3
    // int *ptr = *arr_1d;
    int *ptr = &(arr_1d[0]);
    printf("*ptr = &(arr1d[0]): %p\n", ptr);

    return 0;
}

 

#include <stdio.h>

int change_Arr_1d(int *arr)
{
    printf("%p\n", arr);
    printf("입력하세요 >> ");
    scanf("%d", arr +0);  // arr[0]
    printf("입력하세요 >> ");
    scanf("%d", arr + 1); // arr[1]
    printf("입력하세요 >> ");
    scanf("%d", arr + 2); // arr[2]
    printf("입력하세요 >> ");
    scanf("%d", arr + 3); // arr[3]

    return 0;
}

int print_Arr_1d(int *arr_1d)
{
    for (size_t j = 0; j < 4; j++)
    {
        printf("%d ", arr_1d[j]);
    }   
    printf("\n");

    return 0;
}

int main(void)
{
    int arr_1d[4] = {
        0,
    };
    
    printf("%p\n", arr_1d);

    change_Arr_1d(arr_1d);
    print_Arr_1d(arr_1d);

    return 0;
}

 

 

8. 함수와 다차원 배열

 

#include <stdio.h>

int main(void)
{
    int arr_2d[4][4] = {
        0,
    };

    //1
    unsigned char ucSize = sizeof(arr_2d);  // arr_2d 메모리 크기 Byte
    unsigned char ucRow = sizeof(*arr_2d);  // arr_2d[0] 1차원 크기 Byte
    unsigned char ucCol = ucSize/ucRow; // arr_2d 메모리 크기 전체를 1차원 크기로 나누면 컬럼 개수

    printf("%d %d %d\n", ucSize, ucRow, ucCol);

    //2
    printf("  arr_2d: %p %2d\n",   arr_2d, sizeof(arr_2d));   //arr_2d[0][0] 의 포인터의 포인터
    printf(" *arr_2d: %p %2d\n",  *arr_2d, sizeof(*arr_2d));  //arr_2d[0][0] 의 포인터
    printf("**arr_2d: %d %2d\n", **arr_2d, sizeof(**arr_2d)); //arr_2d[0][0]

    return 0;
}

 

#include <stdio.h>

int change_Arr_2d(int *arr)
{
    printf("%p\n", arr);
    printf("입력하세요 >> ");
    scanf("%d", arr + 0); // arr[0]
    printf("입력하세요 >> ");
    scanf("%d", arr + 1); // arr[1]
    printf("입력하세요 >> ");
    scanf("%d", arr + 2); // arr[2]
    printf("입력하세요 >> ");
    scanf("%d", arr + 3); // arr[3]

    return 0;
}

int print_Arr_2d(int *arr_2d)
{
    unsigned char ucSize = sizeof(arr_2d);
    unsigned char ucRow = sizeof(*arr_2d);
    unsigned char ucCol = ucSize/ucRow;

    printf("%d %d %d\n", ucSize, ucRow, ucCol);

    unsigned char cnt = 0;

    for (size_t i = 0; i < 4; i++)
    {
        for (size_t j = 0; j < 4; j++)
        {
            printf("%d ", *(arr_2d+cnt));
            // printf("%d ", (*arr_2d)[j]);
            cnt+=1;
        }
        printf("\n");
    }

    return 0;
}

int main(void)
{
    int arr_2d[4][4] = {
        0,
    };

    //3
    int *ptr = &(arr_2d[0][0]);

    change_Arr_2d(*arr_2d);
    
    //4
    // print_Arr_2d(*arr_2d);
    print_Arr_2d(ptr);

    return 0;
}

 


-- 
 
2차원 배열
 
char arr[2][3]
char arr[6]
 
함수 원형에서, 매개변수 자리는 그냥 주소값만 넘기는거다.
int func(int *arr){
}
 
&(arr_1d[0]) // == arr_1d // int *arr 크기만큼의 주소값을 넘긴다는 의미다,
&(arr_2d[0][0]) // == arr_2d[0] // int *arr 크기 연산 가능한 주소값
 

배열의 대표 주소와
행의 대표 주소 carr2[0][0] carr2[1][0]
 
 

 

BasicLike

어? 나 프로그래밍 좋아하네?