1. 필수 기반 지식

더보기

 

필수 기반 지식

 

  • 2진수, bit, Byte, 16진수
  • 프로그래밍) 빌드, 컴파일, 링킹(함수) 
  • 컴퓨터) 실행 개념과 메모리, CPU 동작구조
  • 프로그래밍 언어, 어셈블리, 기계어
  • C 언어의 자료형과 함수
  • 스텍 메모리 동작 구조

 

배열과 포인터는 연산자 &  *  [ ] 만 이해하면 된다.
그리고, 배열과 포인터는 다르다.
하지만, 학습 초기에는 "같다" 고 가정하고 접근하여 익숙해지는게 먼저다.

 

 

연산자 우선순위

우선순위 연산자 유형 연산자 결합방향
높다 1 괄호, 배열, 구조체 ( )     [ ]    .     →  좌 → 우
  2 단항연산 -    !    ~    ++    --    (type)    &       sizeof 좌  우
3 산술 연산 승제 *    /    % 좌 → 우
4 가감 +    -
5 비트 이동 연산 >>    <<    
6 관계 연산 비교 <    <=    >    =>
7 등가 ==    !=
8 비트 논리 연산 &    |    ^
9 논리 연산 &&    ||
10 삼항(조건) 연산 ? : 좌  우
11 대입 연산 대입 =
복합 대입 +=    -=    /=    %=
축약 비트 대입 >>==    <<==
낮다 12 나열 연산     좌 → 우

 

 

2. 포인터 연산자 사용법

 

더보기

 

2.1 포인터 변수 선언, 메모리 주소값 할당

 

 

#include <stdio.h>

void main()
{
	int iNum = 90;

	printf("iNum 변수의 정수값: %d\n",  iNum);  // num 변수에 담긴 "정수 값 90" 출력
	printf("iNum 변수의 주소값: %p\n", &iNum);  // num 변수가 참조하는 첫번째 Byte "메모리 주소" 출력

    int* p_iNum = &iNum;                  // 실제로 p_iNum 같은 형태로 선언하지 않는다. 하나의 예시다.

	printf("p_iNum 포인터 변수 값: %p\n",  p_iNum);  // num 변수에 담긴 "정수 값 90" 출력
	printf("p_iNum 포인터 변수 역참조 값: %d\n", *p_iNum);  // num 변수가 참조하는 첫번째 Byte "메모리 주소 값" 출력
 }

 

 

 

 

2.2 포인터는 포인터다.

메모리 주소값은 주소값일 뿐이다. 변수는 변수다.

#include <stdio.h>

int main(void)
{
    int iNum2 = 89;                    // int형 변수를 선언
    int* p_iNum2 = &iNum2;             // &iNum2 int형 포인터 주소값을, char형 포인터로 변환 
    printf("p_iNum: %p\n",  p_iNum2);  // 포인터 변수명 p_iNum 만 사용한다. "변수명"만 사용한다. 
    printf("p_iNum: %d\n", *p_iNum2);  // 변수명 p_iNum 에 *역참조 연산자를 사용한다. -1, +10 

    return 0;
}

 

 

 

2.3 포인터 관련 연산자 상관관계 정리

 

포인터는 역참조를 위해 존재한다. 포인터의 역참조는 변수의 사용과 동일한 의미다.   

 

개념 예시 포인터는 "가르킨다"는 의미다.
변수 → 데이터 iNum → 90  일반 변수 사용 방법
변수 + & → 포인터 + * → 데이터 iNum + & → p_iNum + * → 90  
&변수 → 포인터 (&iNum) → p_iNum 메모리 주소
*포인터 → 데이터 *p_iNum → 90 메모리 주소의 데이터를 포인터한다.
*(&변수) → 데이터 *(&iNum) → 90 포인터 역참조는
변수의 사용과 동일한 방법이다.
변수 → 데이터 iNum → 90

 

 

3. "변수의 포인터 연산"과 메모리 주소

 

더보기

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

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

 

 

3.1 예시 1

#include <stdio.h>

int main(void)
{
    char    cNum1 = 70,        cNum2 = 71,        cNum3 = 72;
    char *p_cNum1 = &cNum1, *p_cNum2 = &cNum2, *p_cNum3 = &cNum3;

    printf("cNum1 : %p %d\n", p_cNum1, *p_cNum1); //cNum1  : 0x7fff6813cbad 70
    printf("cNum2 : %p %d\n", p_cNum2, *p_cNum2); //cNum2  : 0x7fff6813cbae 71
    printf("cNum3 : %p %d\n", p_cNum3, *p_cNum3); //cNum3  : 0x7fff6813cbaf 72
    printf("\n");

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

    return 0;
}

 

 

 


3.2 예시 2

#include <stdio.h>

int main(void)
{
    int    iNum1 = 81,        iNum2 = 82,        iNum3 = 83;
    int *p_iNum1 = &iNum1, *p_iNum2 = &iNum2, *p_iNum3 = &iNum3;

    printf("p_iNum1: %p %d\n", p_iNum1, *p_iNum1);  // p_iNum1: 0x7ffd68a660b4 81
    printf("p_iNum2: %p %d\n", p_iNum2, *p_iNum2);  // p_iNum2: 0x7ffd68a660b8 82
    printf("p_iNum3: %p %d\n", p_iNum3, *p_iNum3);  // p_iNum3: 0x7ffd68a660bc 83
    printf("\n");

    // 메모리에 변수 값이 위 주석처럼, 순차적으로 저장된다고 가정할 때
    // (참고) 위의 메모리 주소값을 확인해서 연산을 수정해야 할 수 있다.
    printf("p_iNum1  : %p %d\n", p_iNum1,   *p_iNum1);      // p_iNum1  : 0x7ffd68a660b4 81
    printf("p_iNum1+1: %p %d\n", p_iNum1+1, *(p_iNum1+1));  // p_iNum1+1: 0x7ffd68a660b8 82
    printf("p_iNum1+2: %p %d\n", p_iNum1+2, *(p_iNum1+2));  // p_iNum1+2: 0x7ffd68a660bc 83

    return 0;
}

 

 

 

4. 배열과 메모리 주소

 

더보기

 

4.1 "변수의 포인터 연산"과 배열 비교

 

#include <stdio.h>

int main(void)
{
    char    cNum1 = 70,        cNum2 = 71,        cNum3 = 72;
    char *p_cNum1 = &cNum1, *p_cNum2 = &cNum2, *p_cNum3 = &cNum3;

    printf("cNum1  : %p %d\n", p_cNum1, *p_cNum1); //cNum1  : 0x7fff6813cbad 70
    printf("cNum2  : %p %d\n", p_cNum2, *p_cNum2); //cNum2  : 0x7fff6813cbae 71
    printf("cNum3  : %p %d\n", p_cNum3, *p_cNum3); //cNum3  : 0x7fff6813cbaf 72
    printf("\n");

    char arr[3]  = {70, 71, 72};
    printf("arr[0] : %p %d\n", arr,   arr[0]);  // arr[0] : 0x7ffe463f02a5 70
    printf("arr[1] : %p %d\n", arr+1, arr[1]);  // arr[1] : 0x7ffe463f02a6 71
    printf("arr[2] : %p %d\n", arr+2, arr[2]);  // arr[2] : 0x7ffe463f02a7 72
    printf("\n");

    return 0;
}

 

 

 

 

4.2 배열의 주소값 연산

 

#include <stdio.h>

int main(void)
{
    char arr[3]  = {70, 71, 72};
    printf("arr[0] : %p %d\n", arr+0, arr[0]);  // arr[0] : 0x7ffe463f02a5 70
    printf("arr[1] : %p %d\n", arr+1, arr[1]);  // arr[1] : 0x7ffe463f02a6 71
    printf("arr[2] : %p %d\n", arr+2, arr[2]);  // arr[2] : 0x7ffe463f02a7 72
    printf("\n");

    printf("arr+0 : %p %d\n", arr+0, *(arr + 0));  // arr[0] : 0x7ffe463f02a5 70
    printf("arr+1 : %p %d\n", arr+1, *(arr + 1));  // arr[1] : 0x7ffe463f02a6 71
    printf("arr+2 : %p %d\n", arr+2, *(arr + 2));  // arr[2] : 0x7ffe463f02a7 72

    return 0;
}

 

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

 

arr  <<<< 포인터, 주소값이 들어있는 배열명인 주소 값은 변경이 불가능한, 상수다.
arr 포인터 상수, 즉 포인터 변수처럼 메모리 주소가 들어있다.
arr[0] 의 주소값(첫번째 바이트 메모리 주소)이다.

 

 

5. 다차원 배열

더보기

 

#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;
}

 

 

 

 

6. 함수와 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;
}