배열
배열 다루기 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]);
}
- 포인터가 배열의 시작주소를 가리킬 수 있다.