ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [C] 포인터②
    C 2023. 5. 9. 00:05

     

     

     

    04 포인터를 사용한 배열 활용


     

    일차원 배열과 포인터

     

     

    배열이름을 이용한 참조

    • 배열 score
      • 배열이름 score 자체가 배열 첫 원소의 주소값인 상수이다.
      • 배열이름 score를 이용하여 모든 배열원소의 주소와 저장값을 참조할 수 있다.
      • 배열이름 score는 배열 첫 번째 원소의 주소를 나타내는 상수로 &score[0]와 같으며 배열을 대표한다. 그러므로 간접연산자를 이용한 *score는 변수 score[0]와 같다.
      • 배열이름 score가 포인터 상수로 연산식 (score+1)이 가능하다. 즉 연산식 (score+1)은 score의 다음 배열원소의 주소값을 의미한다. 즉 (score+1)은 &score[1]이다.
      • (score+i) == &score[i]
      • *(score+i) == score[i]
      • 연산식 *(score+1)과 (*score+1)은 다르므로 주의한다. (*score+1)은 배열 첫 번째 원소에 1을 더하는 연산식이다.
    int score[ ] = { 10, 20, 30 };
    주소값 참조 &score[0]
    score
    &score[1]
    score+1
    &score[2]
    score+2
    배열 score 10 20 30
    저장 값 참조 score[0]
    *score
    score[1]
    *(score+1)
    score[2]
    *(score+2)
    • 배열의 주소값(배열 첫 번째 원소의 주소값) : score, &score[0]
    • 배열 첫 번째 원소 저장 값 : *score, score[0]
    • 배열 (i+1)번째 원소 주소값 : (score+i), &score[i]
    • 배열 (i+1)번재 원소 저장 값 : *(score+i), score[i]

     

    배열원소의 주소와 내용 값의 다양한 접근 방법

    배열 초기화 문장 int score[ ] = { 10, 20, 30 };
    원소 값 10 20 30
    배열원소 접근 방법 score[i] score[0] score[1] score[2]
    *(score+i) *score *(score+1) *(score+2)
    주소값 (첫 주소 + 배열원소 크기 * i ) 100 104
    (100 + 1 * 4)
    108
    (100 + 2 * 4)
    주소값 접근 방법 &score[i] &score[0] &score[1] &score[2]
    score+i score score+1 score+2
    int a[3] = { 10,20,30 };
    int* p = a; # a = &a[0]
    
    # 포인터 변수 p 사용, 배열 원소 값 참조
    printf("%d %d %d\n", *(p), *(p + 1), *(p + 2));
    
    # 위 포인터 변수 p에서 배열처럼 첨자를 사용 가능
    printf("%d %d %d", p[0], p[1], p[2]);
    10 20 30
    10 20 30
    • 포인터 p에 &a[0]를 저장하면 연산식 *(p+i)로 배열원소를 참조할 수 있다.
    • 특히 포인터 p로도 배열처럼 첨자를 이용해 p[i]로 배열원소를 참조할 수 있다.

     

     

    • 참조연산자 *의 우선순위는 ++p의 전위 증감연산자와 같고, 괄호나 p++의 후위 증감연산자보다 낮다. 
    • 연산식 *p++는 *(p++)를 의미한다.
    • *p++는 포인터 p가 가리키는 변수를 참조하고 p의 주소를 1 증가시킨다.
    • (*p)++는 포인터 p가 가리키는 변수를 참조하고 그 값을 1 증가시키는 연산식이다.
    • 연산식 *++p는 *(++p)으로 포인터 p를 1 증가시킨 후 가리키는 변수를 참조한다.
    • 연산식 ++*p는 ++(*p)으로 포인터 p가 가리키는 값을 1 증가시킨 후 참조한다.

     


     

    char 배열을 int 자료형으로 인식

     

    명시적 형변환

    • *pi로 수행하는 간접참조는 pi가 가리키는 주소에서부터 4byte 크기의 int 형 자료를 참조한다는 것을 의미한다.
    • 변환된 포인터 변수는 지정된 주소값을 시작하여 그 변수 자료형의 크기만큼 저장공간을 참조한다.
    • 동일한 메모리의 내용과 주소로부터 참조하는 값이 포인터의 자료형에 따라 달라진다.
    #include <stdio.h>
    
    int main(void)
    {
    	char c[4] = { 'A', '\0', '\0', '\0' };	# 문자 'A' 코드값: 65
    	# int *pi = &c[0]; //경고 발생
    	int* pi = (int*)&c[0];
    
    	printf("%d %c\n", (int)c[0], c[0]);
    	printf("%d %c", *pi, (char)*pi);
    
    	return 0;
    }
    65 A
    65 A

     


     

    이차원 배열과 포인터

     

    배열이름과 행이름으로 참조

    • 이차원 배열에서 배열이름인 td는 포인터 상수 td[0]를 가리키는 포인터 상수이다.

     

    • td[0]는 무엇일까?   
      • 배열의 첫 행을 대표
      • 배열의 첫 번째 원소 td[0][0]의 주소값 &td[0][0]을 갖는 포인터 상수이다.
      • 그러므로 배열이름인 td는 포인터의 포인터인 이중 포인터이다.

     

    • 배열이름 td는 이차원 배열을 대표하는 이중 포인터이다.
    • sizeof(td)는 배열전체의 byte 크기를 반환한다.
    • 배열이름 td를 이용하여 변수 td[0][0]의 값을 20으로 수정하려면 **td = 20; 문장을 이용할 수 있다. td가 이중 포인터이므로 간접연산자 *이 2개 필요하다.
    • td[i]는 (i+1)번째 행을 대표하며, (i+1)번째 행의 처음을 가리키는 포인터 상수이다. 그리고 sizeof(td[0])와 sizeof(td[1])은 각각 첫 번째 행의 바이트 크기와 두 번째 행의 바이트 크기를 반환한다.
    • 마찬가지로 td[1]은 두 번째 행의 첫 원소의 주소이므로 *td[1]로 td[1][0]를 참조할 수 있다.
    int td[ ][3] = {{1, 2, 3}, {4, 5, 6}};
    1 td[0][0] *(*(td + 0) + 0) *(*td + 0)
    2 td[0][1] *(*(td + 0) + 1) *(*td + 1)
    3 td[0][2] *(*(td + 0) + 2) *(*td + 2)
    4 td[1][0] *(*(td + 1) + 0) *(*td + 3)
    5 td[1][1] *(*(td + 1) + 1) *(*td + 4)
    6 td[1][2] *(*(td + 1) + 2) *(*td + 5)
    • 연산식 (*td+n)은 배열의 (n+1)번째 원소의 주소값이다. 그러므로 역참조 연산자를 이용한 연산식 *(*td+n)은 배열의 (n+1)번째 원소 자체를 나타낸다.
    • td[i]는 (i+1)번째 행의 주소이다. 그러므로 연산식(td[i]+j)는 &td[i][j]이다. 여기서 역참조 연산자를 이용한 연산식 *(td[i]+j)는 배열의 td[i][j] 원소자체를 나타낸다.
    • a[i] == *(a+i)
    • td[i][j] == (td[i])[j] == *(td[i]+j) == *(*(td+i)+j)
    • 연산식 **td++는 연산 우선순위에 따라 **(td++)와 같으며 현재 포인터가 가리키는 원소를 참조하고 ptr을 하나 증가시켜 다음 원소를 가리키게 하는 연산식이다.
    • **td === td[0][0] == *(*td+0)

     


     

     

    포인터 배열과 배열 포인터

     

     

    포인터 배열(array of pointer)

    • 주소값을 저장하는 포인터를 배열 원소로 하는 배열이다.
    • 포인터 변수를 선언하는 포인터 배열 
    int a = 5, b = 7, c = 9;
    int *pa[3];
    
    pa[0] = &a;
    pa[1] = &b;
    pa[2] = &c;

     

     

    포인터 배열 선언

    자료형 *변수이름[배열크기];
    
    int *p[5];
    char *ptr[4];
    float a, b, c;
    double *dary[5] = { NULL };
    float *ptr[3] = {&a, &b, &c};

     

     

    배열 포인터(pointer to array)

    # 일차원 배열 포인터의 변수 선언
    
    원소자료형 *변수이름;
    변수이름 = 배열이름;
    or
    원소자료형 *변수이름 = 배열이름;
    
    int a[] = {1, 2, 3, 4, 5};
    int *p = a;
    # 이차원 배열 포인터의 변수 선언
    
    원소자료형 (*변수이름)[배열크기];
    변수이름 = 배열이름;
    or
    원소자료형 (*변수이름)[배열크기] = 배열이름;
    
    int ary[][4] = {{1, 2, 3, 4, 5}, {5, 6, 7, 8, 9, 10}};
    int (*ptr)[4] = ary;    # 열이 4인 배열을 가리키는 포인터
    int *ptr[4] = ary; # 포인터 배열
    • 괄호가 없는 int *ptr[4];은 바로 전에 배운 int형 포인터 변수 4개를 선언하는 포인터 배열 선언문장이다.
    • int (*ptr)[4];는 열이 4인 이차원 배열 포인터 선언문장이다.

     

     

     

     

     

     

    'C' 카테고리의 다른 글

    [C] 문자열와 명령행 인자②  (1) 2023.05.16
    [C] 문자와 문자열①  (0) 2023.05.11
    [C] 포인터①  (1) 2023.05.04
    [C] 변수 유효범위②  (0) 2023.05.02
    [C] 변수 유효범위①  (0) 2023.04.26
Designed by Tistory.