C - 포인터 & 배열

lsjoon·2024년 1월 30일

C

목록 보기
2/8

포인터와 배열의 관계

배열(Array) : 동일한 자료형의 변수를 메모리에 연속으로 할당한 것
각 배열 요소는 일정한 간격으로 주소를 가짐 ( 자료형의 크기 만큼 )

' int형 변수 ' 는 4byte 이므로, 각 배열 요소의 주소는 100, 104, 108, 112가 됨
즉, 첫 번째 요소의 주소를 알면 나머지 요소의 주소도 쉽게 유추 가능
= 컴파일러는 배열의 이름을 배열의 시작 주소 값(첫 번째 요소의 주소)으로 함
= arr + i = &a[i]
= *(arr + i) = a[i]

단, 배열의 이름은 값의 저장이 불가능하고 (대입 연산자의 피연산자도 불가능), 주소 값의 변경이 불가능
= 포인터 상수, 상수 형태의 포인터

[ 예제 ]

#include <stdio.h>
 
int main(void)
{
    int arr[3] = {1, 2, 3};
 
    printf("배열의 이름 : %p\n", arr);
 
    printf("첫 번째 요소 : %p\n", &arr[0]);
    printf("두 번째 요소 : %p\n", &arr[1]);
    printf("세 번째 요소 : %p\n", &arr[2]);
 
    return 0;
}
 
// >>> output <<<
// 배열의 이름 : 005AFA14			<< 배열의 이름 = 포인터 주소
// 첫 번째 요소 : 005AFA14			<< 배열의 첫번째 주소값과 배열의 이름의 출력값이 같음
// 두 번째 요소 : 005AFA18
// 세 번째 요소 : 005AFA1C


포인터 연산

포인터 연산 : 곱셈, 나눗셈을 제외한 ' + , - , ++ , -- ' 연산자를 사용

+, ++ 의 차이점

- + 연산자는 초기값 자체를 변경시키지 않음
- ++ 연산자는 초기값을 변경시킴

#include <stdio.h>

int main(void) {
  int * ptr = 0x00;
  
  printf("+ : %p %p \n", ptr + 1, ptr);
  printf("++ : %p %p \n", ++ptr, ptr);
  
  return 0;
}

// >>> output <<<
// + : 0x4 0x0 
// ++ : 0x4 0x4

[ 예제 ]

#include <stdio.h>
 
int main(void)
{							// 자료형(타입)의 크기
    char * ptr1 = 0; 		// 1 Byte
    int * ptr2 = 0;			// 4 Byte
    double * ptr3 = 0;		// 8 Byte
 
    printf("%d번지, %d번지, %d번지\n", ptr1, ptr2, ptr3);
 
    ptr1++;
    ptr2++;
    ptr3++;
 
    printf("%d번지, %d번지, %d번지\n", ptr1, ptr2, ptr3);
 
    return 0;
}

// >>> output <<<
// 0번지, 0번지, 0번지
// 1번지, 4번지, 8번지			// main 함수에서 정의한 타입의 크기에 맞게 증가
> - - - - - - - - - - - - - - - 배열의 이름 == 포인터 변수  - - - - - - - - - - - - - - - - <
#include <stdio.h>
 
int main(void)
{
    int arr[3] = {1, 2, 3};
 
    int * ptr = arr;
 
    printf("%d %d %d\n", *ptr, *(ptr + 1), *(ptr + 2));
    printf("%d %d %d\n", ptr[0], ptr[1], ptr[2]);
    printf("%d %d %d\n", *arr, *(arr + 1), *(arr + 2));
    printf("%d %d %d\n", arr[0], arr[1], arr[2]);
 
    return 0;
}

// >>> output <<<
// 1 2 3
// 1 2 3
// 1 2 3
// 1 2 3

결론

arr[i] == *(arr + i) == *(ptr + i)
= ptr 에 저장된 값이 arr의 주소값이기 때문



+, ++ 섞어쓰기

int* p = a[i]

/* 아래는 모두 같다 */
a[i++] 	= j;
*p++ 	= j;
*(p++) 	= j;
표현식의미
*p++ 혹은 *(p++)증가되기 이전의 표현식의 값은 *p; 그리고 p 가 증가
(*p)++증가되기 이전의 표현식의 값은 *p; 그리고 *p 가 증가
*++p 혹은 *(++p)p 가 증가; 증가된 이후의 표현식의 값은 *p
++*p 혹은 ++(*p)*p 가 증가; 증가된 이후의 표현식의 값은 *p

예제

/* 배열 a 의 원소들의 합 구하기 */
for (p = &a[0]; p < &a[N]; ++p) {
	sum += *p;
}

p = &a[0];
while (p < &a[N]) {
	sum += *p++;
}


포인터 배열

포인터 변수로 이루어진 '배열'
포인터 배열을 선언할 땐 배열 요소의 자료형이 '포인터'이므로 배열이름 앞에 * 을 붙임

[ 예제 ]

#include <stdio.h>
 
int main(void)
{    // 포인터 배열 선언 및 초기화
    int num1 = 1, num2 = 2, num3 = 3;
    int * arr[3] = { &num1, &num2, &num3 };
    
    printf("주소값 : %p %p %p\n", arr[0], arr[1], arr[2]);
    printf("값 : %d %d %d\n", *arr[0], *arr[1], *arr[2]);
 
    return 0;
}
// >>> output <<<
// 주소값 : 00EFFB24 00EFFB18 00EFFB0C		// '포인터 배열'은 메모리에 연속해서 위치
// 값 : 1 2 3								// But, 포인터 배열에 저장된 '주소값'은 연속성 X


#include <stdio.h>
 
int main(void)
{	// 문자열 배열 선언 및 초기화
    char * strarr[3] = {"Krafton", "Jungle", "Compass"};
 
    printf("%s %s %s\n", strarr[0], strarr[1], strarr[2]);
 
    return 0;
}
// >>> output
// Krafton Jungle Compass

포인터 배열은 문자열을 저장 가능
문자열 배열은 문자열의 주소값을 저장하는 배열 ( char 형 포인터 배열 )
= 문자열의 주소값 = 문자열 첫 번째 문자의 주소값
( 변환 문자 %s -> null 이 나올 때까지 모든 문자를 차례로 출력 = 하나의 문자열 출력 )



배열 포인터

배열을 가리킬 수 있는 '포인터'
2차원 이상의 배열을 가리킬 때, 포인터를 배열처럼 사용하기 위함 ( 1차원은 배열은 이름 자체가 포인터 )

[ 예제 ]


>> 배열 포인터 선언 <<<
자료형 (*포인터이름)[가로() 길이]


> - - - - - - - - - - - - - - - - - - - Example - - - - - - - - - - - - - - - - - - - <
#include <stdio.h>
 
int main(void)
{
    int arr2d[2][3] = {
    {10, 20, 30},
    {40, 50, 60},
    };
 
    printf("%d %d\n", *arr2d[0], *arr2d[1]);
 
    return 0;
}
// >> output
// 10 40

> - - - - - - - - - - - - - - - - - - 인덱싱 Example - - - - - - - - - - - - - - - - - - <
#include <stdio.h>
 
int main(void)
{
    int arr2d[2][3] = {
    {10, 20, 30},
    {40, 50, 60},
    };
 
    int i, j;
    int (*ptr)[3] = arr2d;    						// 배열 포인터 선언
 
    for (i = 0; i < 2; i++)
    {
        for (j = 0; j < 3; j++)
            printf("%d ", ptr[i][j]);    			// 배열 참조
            printf("%d ", arr2d[i][j]);				// 배열 포인터로 참조 
            printf("%d ", (*(arr2d + i))[j]);
            printf("%d ", *(arr2d[i] + j));
            printf("%d\n", *(*(arr2d + i) + j));	// 모두 같은 값을 나타냄
    }
    return 0;
}

// >>> output <<<
// 10 10 10 10 10
// 20 20 20 20 20 
// 30 30 30 30 30
// 40 40 40 40 40 
// 50 50 50 50 50 
// 60 60 60 60 60 


포인터 배열 vs 배열 포인터

포인터 배열 (Array of Pointer) VS
배열 포인터 (Pointer to Array)

- 포인터 배열 = 주소값을 저장하는 '배열(Array)'
- 배열 포인터 = 배열의 시작주소 값을 저장할 수 있는 '포인터(Pointer)'

				|		int *ptr[3];		|		int (*ptr)[3]`		|

왼쪽 : int형 변수로 이루어진 int형 포인터의 배열
오른쪽 : 가로길이가 3인 int형 2차원 배열을 가리키는 포인터 변수
' ( ) ' 괄호의 유무가 중요



사진 클릭 시 출처 이동
출처 , 출처2

profile
중요한 것은 꺾여도 그냥 하는 마음

0개의 댓글