열렬히.뛰기

배열과 포인터

Language > 프로그래밍 언어 > C > 배열과 포인터

배열

배열 다루기 1

c
// 선언하기
int s[10];
float cost[12];
char src[10];


// 인덱스에 접근
s[1] = 10;
cost[2] = 1.234;

배열 다루기 2

c
// 배열 초기화
int scores[5] = {0};
int scores[5] = {10, 20, 30};

// 배열 크기 계산
int size = sizeof(scores) / sizeof(scores[0])

// 배열의 복사
int a[SIZE] = {1, 2, 3, 4, 5};
int b[SIZE];
for(int i = 0; i < SIZE; i++) {
				b[i] = a[i];
}

배열 다루기 3

c
// 배열을 인수로
int get_average(int scores[], int size){
	for (int i = 0; i < sizeof(scores), i++) {
		sum += scores[i];
	}
}

// 2차원 배열
int arr[3][3];
int arr2[3][3] = {{0}, {0}, {0}}

포인터

  • 메모리의 주소를 가지고 있는 변수
  • 동적 메모리, 참조에 의한 호출, 자료구조 구현에 사용된다.
    • C언어로 완벽한 참조에 의한 호출은 불가능하다.
    • 그러나, 포인터를 이용해 이를 흉내내는 것은 가능.
    • 포인터를 활용한 대표적인 자료구조로 트리, 연결 리스트가 있다.

포인터 다루기 (1)

c
// 변수의 주소 다루기
int i = 10;
printf("i의 주소 : %u", &i);


// 포인터의 선언
int *p;
int *a1, *a2, *a3;


// 포인터의 초기화
int i = 10; // 정수 변수 i를 10으로 초기화
int *p; // 포인터 p 선언
p = &i; // 포인터 p에 i의 주소를 저장한다.


// 포인터 형변환
double *pd = &f;
int *pi;
pi = (int *)pd;

포인터와 간접참조

* 기호를 앞에 붙인다. 이것을 포인터를 통해 메모리를 간접참조한다고 한다.

c
int i = 10;
int *p;
p = &i;
printf("%d", *p)

// p는 i의 주소(&i)를 따라간다.
// *p는 i의 값을 따라간다.

정리하자면, 다음과 같다.

  • & 연산자는 변수의 주소를 포인터에 대입할 때 사용한다.
    • 연산자는 포인터를 통해 변수를 간접 참조할 때 사용한다.

또 포인터에 정수를 더하면 다음과 같다.

c
int numArr[5] = {11, 22, 33, 44, 55};
int *numPtrA;
int *numPtrB;
int *numPtrC;

numPtrB = numPtrA + 1;
numPtrC = numPtrC + 2;

printf("%p\n", numPtrA);
printf("%p\n", numPtrB); // sizeof(int) * 1이므로 4 증가
printf("%p\n", numPtrC); // sizeof(int) * 2이므로 8 증가

/* 결과
0x560c1e43f2dd
0x560c1e43f2e1
0x560c1e43f298 */

간접 참조 연산자와 증감 연산자

c
v = *p++;   // p가 가리키는 값을 가져온 후 포인터 p를 증가
v = (*p)++; // 포인터가 가리키는 대상의 값을 증가.

포인터, 함수, 배열

  • 값에 의한 호출 : 복사본이 전달된다.
  • 참조에 의한 호출 : 원본이 전달된다.
c
void swap(int x, int y){
        int tmp;

        printf("a = %d, b = %d\n", x, y);
        tmp = x;
        x = y;
        y = tmp;
        printf("a = %d, b = %d\n", x, y);
}

void swap2(int *px, int *py) {
        int tmp;
        tmp = *px;
        *px = *py;
        *py = tmp;
}

int main() {
        int a = 100, b = 200;
        printf("값에 의한 호출\n");
        printf("a = %d, b = %d\n", a, b);
        swap(a, b);
        printf("a = %d, b = %d\n", a, b);
				// 실제 a와 b의 값이 바뀌지는 않음.

        printf("\n\n========================\n");
        printf("참조에 의한 호출\n");
        printf("a = %d, b = %d\n", a, b);
        swap2(&a, &b);
        printf("a = %d, b = %d\n", a, b);
				// 실제 a와 b의 값이 바뀜.
}
c
값에 의한 호출 (원본 값이 바뀌지는 않음)
a = 100, b = 200
a = 100, b = 200
a = 200, b = 100
a = 100, b = 200

========================
참조에 의한 호출 (제대로 값이 바뀜)
a = 100, b = 200
a = 200, b = 100

단, 앞에 const를 붙이면 포인터로 값을 바꿀 수 없다.

포인터와 배열

  • 배열의 이름이 포인터
c
#include <stdio.h>

int main() {
        int arr[3] = {10, 20, 30};
        int* ptr_arr = arr; // 포인터에 배열의 이름 대입

        printf("배열 이름으로 각 요소 접근: %d %d %d\n", arr[0], arr[1], arr[2]);
        printf("포인터로 각 요소 접근 : %d %d %d\n", ptr_arr[0], ptr_arr[1], ptr_arr[2]);

        printf("배열의 크기 : %ld\n", sizeof(arr));
        printf("포인터의 크기 : %ld\n", sizeof(ptr_arr));

}

/*
결과 : 
배열 이름으로 각 요소 접근: 10 20 30
포인터로 각 요소 접근 : 10 20 30
배열의 크기 : 12
포인터의 크기 : 8
*/
  • 포인터를 배열처럼 쓰기
c
#include <stdio.h>

int main() {
        int a[] = {10, 20, 30, 40, 50};
        printf("a = %u\n", a);
        printf("a + 1 = %u\n", a+1);
        printf("*a = %d\n", *a);
        printf("*(a+1) = %d\n", *(a+1));
}

/*
결과 : 
a = 613384960
a + 1 = 613384964
*a = 10            => *a = a[0]
*(a+1) = 20        => *(a+1) = a[1]
*/

단, 배열의 이름 그 자체의 값은 바꿀 수 없음.

c
int a[] = {10, 20, 30, 40, 50};
++a; // 문법 오류

포인터를 배열처럼

c
// 포인터를 배열처럼 사용해보자.
#include <stdio.h>

int main() {
        int a[] = {10, 20, 30, 40, 50};
        int *p;

        p = a;
        printf("%d", p[1]);

}
c
// 배열을 전달하는 함수
#include <stdio.h>
void sub(int b[], int size){
        // 매개변수 b는 전달된 배열을 가르키는 포인터.
        b[0] = 1;
        b[1] = 2;
        b[2] = 3;
}

int main() {
        int a[] = {10, 20, 30};
        printf("%d %d %d\n", a[0], a[1], a[2]);
        sub(a, 3); // 배열의 이름 = 배열주소
                   // 따라서 배열의 주소가 전달.
        printf("%d %d %d\n", a[0], a[1], a[2]);
}
  • 포인터가 배열의 시작주소를 가리킬 수 있다.