c
포인터 : (메모리 상에 위치한) 데이터의 주소값을 저장하는 변수
/* 사용방법 */
int* p; // (주소값이 저장되는 데이터의 형태)* (포인터의 이름)
int *p; // (주소값이 저장되는 데이터의 형태) *(포인터의 이름)
포인터의 값을 집어넣기 위한 데이터의 주소가 필요
&a // &(주소값을 계산할 데이터)
위와 같이 사용
&연산자로 특정 데이터의 메모리 주소를 알아낼 수 있다.
#include <stdio.h>
int main() {
int *p; // 정수형 포인터 p 와
int a; // 정수형 a를 지정
p = &a; // 포인터 p값을 a의 주소로 지정
a = 2;
printf("%d \n", a);
printf("%d", *p); // *p를 이용하여 p에 저장된 주소의 데이터를 가져오는 역할 >>>
//p = &a 를 통해 포인터p를 a 주소값으로 지정하였으므로
// 주소 a의 데이터인 2를 가져옴
return 0;
}
>>>2
>>>2
위에서 사용되는 *은 주소값에 대응하는 데이터를 가져오는 역할을 함
*p 를 통해 p 에 저장된 주소(변수 a 의 주소)에 해당하는 데이터, 즉 변수 a 그 자체를 의미할 수 있게 됩니다.
출처 : https://modoocode.com/23
#include <stdio.h>
int main() {
int *p;
int a;
p = &a; // (1)포인터p를 a의 주솟값으로 지정
*p = 3; // (2)*p를 통해 포인터 p의 주소의 데이터를 3으로 생각
// (3)*p는 p에 저장된 데이터 값을 가져오라는 의미
// (4)p에 저장된 주소는 a
// (5) => (2)에 의해 a의 값이 3이 됨
printf("%d \n", a);
printf("%d \n", *p);
return 0;
}
>>>3
>>>3
a의 데이터를 가져오지 않았는데 a의 데이터를 가져온 결과가 출력되었다.
const int a =3; 과 같이 자료형 앞에 const가 붙는다면 a값은 절대 변하지 않음.
강제적으로 a=5라고 설정해도 오류메시지가 뜨게 됨
평소에 쓰던 arr[3], *(arr + 3), 3[arr] 은 같은 표현
포인터에 대한 const 사용
https://starfish22.tistory.com/13
https://timing-bravery.tistory.com/49
https://ansan-survivor.tistory.com/1260
const에 대한 대략적인 의미는 알겠는데,
const int* a1 = &aa // 주소변경만 가능
int const* a2 = &aa // 주소변경만 가능
int *const a3 = &aa // 정수변경만 가능
위의 세 가지가 헷갈립니다.
정확히는 1, 3번째는 이해를 했는데, 2번째를 볼 때마다 어떻게 해야할지 고민인데 일단 넘어가고 헷갈릴 때 다시 보는것이 좋을 것 같습니다.
일단 위 식 3개는 통째로 외웠습니다. 시간은 걸리겠지만 헷갈리지는 않겠네요
**ppa = *(*ppa)
arr[][], arr[0], arr[0][0]은 주소는 서로 동일하지만 같은 값은 아님
주소값(&)을 사용하지 않거나 sizeof를 사용하지 않는 경우에는 arr[0], arr[1] 은 암묵적으로 arr[0][0], arr[1][0] 을 가리키는 포인터로 변환됨
int main() {
int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};
printf("전체 크기 : %d \n", sizeof(arr));
// 24
printf("총 열의 개수 : %d \n", sizeof(arr[0]) / sizeof(arr[0][0]));
//3
printf("%d \n", sizeof(arr[0]));
//12
//sizeof(arr[0]) = 0번째 행의 길이 = 열의 갯수
//int 사이즈인 4를 곱해서 12가 나오는 것으로 추정
printf("%d \n", sizeof(arr[0][0]));
//4
//sizeof(arr[0][0]) = int의 크기 4를 리턴
//[0][0]으로 한 개의 값만을 가져오는데, 이 값의 크기는 4바이트
printf("총 행의 개수 : %d \n", sizeof(arr) / sizeof(arr[0]));
//2
//전체 크기를 열의 크기로 나눈 값
}
2차원 배열을 포인터로 표현할 경우
(배열의 형) (*포인터 이름) [2차원 배열의 열 개수 = 2차원 배열의 행의 길이];
int (*parr)[3]; // 예시
parr[1] = *(parr +1)
parr[1][1]= *(*(parr +1) +1)
#include <stdio.h>
int main() {
int *arr[3]; // 배열 arr을 포인터로 지정
// arr[0] arr[1] arr[2]를 포인터로하여 주소지정이 가능해짐
int a = 1, b = 2, c = 3;
arr[0] = &a;
arr[1] = &b;
arr[2] = &c;
printf("a : %d, *arr[0] : %d \n", a, *arr[0]);
printf("b : %d, *arr[1] : %d \n", b, *arr[1]);
printf("b : %d, *arr[2] : %d \n", c, *arr[2]);
printf("&a : %p, arr[0] : %p \n", &a, arr[0]);
return 0;
}
함수를 호출할 때에는 &를 이용한 주솟값을 적고, 함수를 정의할 때에는 *를 이용하여 포인트로 지정하여야 함.
예시
#include <stdio.h>
int change_val(int *i) { // 함수 정의 시 *를 이용한 포인터 사용
i = 3;
return 0;
}
int main() {
int i = 0;
printf("호출 이전 i 의 값 : %d \n", i);
change_val(&i); // 함수 호출시 &를 이용한 주솟값 사용
printf("호출 이후 i 의 값 : %d \n", i);
return 0;
}
함수를 사용할 때 main() 함수를 올리고 싶으면 위에 함수의 정의를 적어줘야 함.
#include <stdio.h>
int swap(int *a, int *b); // 함수의 원형부분
int main() {
int i, j;
i = 3;
j = 5;
printf("SWAP 이전 : i : %d, j : %d \n", i, j);
swap(&i, &j);
printf("SWAP 이후 : i : %d, j : %d \n", i, j);
return 0;
}
int swap(int *a, int*b) { // 함수의 정의부분
int temp = *a;
*a = *b; // 외부인 main()에서 가져오기 때문에 *는 필수적으로 붙어야함
*b = temp; // temp에 *을 붙이지 않은 이유는 함수 외부에서 가져오는 값이 없기때문
}