[선언]
자료형* 포인터변수명
ex)
int* pInt = nullptr;
short* pShort;
//nullptr은 아무것도 가리키지 않는 걸 의미함
int a = 10;
float b = 1.23;
(O)
int* pInt1 = &a;
float* pfloat2 = &b;
(X)
int* pInt2 = &b; //Error
pInt1 = &b; //Error
int *pInt = 3; //Error
int* pInt1, *pInt2;
int* pInt3, pInt4;
-> 포인터 변수 O : pInt1, pInt2, Pint3
포인터 변수 X : pInt4 (int형 변수)
//정수 i의 주솟값을 포인터 변수 pInt에 저장
int i = 100;
int* pInt = &i;
//위 코드에서 이어짐
(*pInt) = 100; //i를 참조하여 i에 100을 대입
cout << *pInt; // pInt가 가리키는 주소의 값을 출력
포인터 변수의 자료형은 해당 포인터가 전달받는 주소를 해석하는 단위이다.
가리키는 주소에 들어있는 값이 그대로여도, 보는 관점(자료형)에 따라 다르게 표현된다.
포인터 변수 입장에서는 실제 메모리 공간에 들어있는 데이터 값은 중요하지 않다.
포인터 변수의 증감 단위는 가리키는 자료형의 크기에 따라 달라진다.
포인터 변수의 주솟값을 1 증가시키면
sizeof(자료형)과 같이 자료형의 크기 단위로 증가한다.
ex)
int형 포인터 pInt의 주소가 100번지일 때,
pInt+=1; 을 하면 주솟값은 101번지가 아닌 104번지로 바뀐다. (int형의 크기는 4btye)
#include <stdio.h>
using namespace std;
void swap(int* x, int* y)
{
int temp;
temp = *x;
*x = *y;
*y = temp;
}
int main()
{
int x = 1;
int y = 2;
swap(&x, &y);
printf("x = %d\ny = %d\n", x, y);
return 0;
}
[출력]
x = 2
y = 1
-> 포인터를 사용하지 않으면, 매개변수의 값들이 함수 내에서만 처리되고, 함수가 종료되면서 사라지기 때문에 두 변수의 값이 바뀌지 않게 된다.
//포인터 변수를 사용하지 않은 경우
#include <stdio.h>
using namespace std;
void swap(int x, int y)
{
int temp;
temp = x;
x = y;
y = temp;
}
int main()
{
int x = 1;
int y = 2;
swap(x, y);
printf("x = %d\ny = %d\n", x, y);
return 0;
}
[출력] //두 변수의 값이 바뀌지 않았다.
x = 1
y = 2
배열 포인터 : 배열을 가리키는 "포인터"
포인터 배열 : 배열 요소로 포인터를 가지는 "배열"
[선언]
int(*ptr)[4]; //배열 포인터,
int* ptr[4]; //포인터 배열
int a = 10;
int b = 20;
int c = 30;
int d = 40;
int* ptr[4];
ptr[0] = &a;
ptr[1] = &b;
ptr[2] = &c;
ptr[3] = &d;
printf("%d %d %d %d\n", *ptr[0], *ptr[1], *ptr[2], *ptr[3]);
[출력]
10 20 30 40
char str[] = "Hello";
printf("%s", str);
//printf("%s", &str[0]); 과 같음
[출력]
Hello
-> 배열의 이름 str이 배열의 시작 주소를 가리킨다. 이 때 %s를 사용했으므로 시작 주소부터 널 문자(\0)가 나올 때까지 문자들을 출력해 준다,
char strings[3][10] = { "Hello", "World", "Doodle"};
for (int i = 0; i < 3; i++) {
printf("%s\n", strings[i]);
//strings[i] 는 &strings[i][0] 과 같다.
}
-> 이 때 strings[i] 자체가 포인터가 된다.
그리고 위의 '참고'처럼, i 행의 문자를 \0까지 모두 출력하게 된다.
[출력]
Hello
World
Doodle
*(iArr+0) = 10;
-> 배열의 첫 번째 데이터에 10을 대입한다.
배열의 이름이 이미 배열의 시작 주소이므로, 시작 주소를 그대로 사용(0을 더하는 것과 같음)해도 된다.
*(iArr+1) = 10;
-> 배열의 두 번째 데이터에 10을 대입한다.
(위와 같은 원리가 배열의 인덱스가 0부터 시작하는 이유)
//문제 1.
short sArr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int* pI = (int*)sArr;
int iData = *((short*)(pI + 2));
printf("1번 문제 정답 : %d\n", iData);
int* pI = (int*)sArr;
-> short 배열 sArr를 int형 포인터 pI가 가리키기 위해, sArr를 int 타입으로 강제 캐스팅(형변환)함
int iData = *((short*)(pI + 2));
-> sArr는 short형 배열로, 각 데이터 요소 크기 2바이트
-> int 포인터 pI의 주솟값 2를 증가시킴. 즉 8바이트 증가함.(int는 4바이트) 이 때 이상한 값 나올 것을 방지하기 위해, 접근하기 직전에 포인터를 short형으로 형변환해줌
답 5
//문제 2.
char cArr[2] = { 1, 1 };
short* pS = (short*)cArr;
iData = *pS;
printf("2번 문제 정답 : %d\n", iData);
-> 각 데이터가 1바이트인 char형 배열을 short형 포인터 pS가 가리킬 때, short형의 크기(2btye)로 접근함.
-> (하단 그림) 8비트(1바이트)씩 두 칸(맨 마지막 비트가 1로 채워짐)
-> 1바이트로 표현할 수 있는 최대치 : 255 (8비트가 전부 1로 채워질 경우)
(2^8 라 256가지 표현 가능. 0~255)
cArr을 char형으로 바라보면
[ 0 0 0 0 0 0 0 1 ][ 0 0 0 0 0 0 0 1 ]
와 같은 상태이고,
이걸 다시 short형으로 보고, *pS로 값에 접근하기로 했다. 따라서
[ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 ] 가 된다.
즉 257
답 257
void Test(int a)
{
a = 500;
}
int main()
{
int a = 100;
Test(a);
printf("출력 : %d", a);
return 0;
}
[출력}
출력 : 100
💡 Test 함수를 호출하면서 main 함수의 변수 a의 값을 바꾸고 싶으면?
👉 Test 함수에게 a의 주소를 넘겨준다.
void Test(int* a)
{
*a = 500;
}
int main()
{
int a = 100;
Test(&a);
printf("출력 : %d", a);
return 0;
}
[출력}
출력 : 500
scanf_S("%d", &a);
[참고]
https://youtu.be/dnU6Rqj8DFU
https://boycoding.tistory.com/199
https://www.ijemin.com/blog/c-%ED%8F%AC%EC%9D%B8%ED%84%B0-%EC%B0%B8%EC%A1%B0-%EC%97%B0%EC%82%B0%EC%9E%90%EB%8A%94-%EC%AA%BC%EA%B0%9C%EC%84%9C-%EC%9D%B4%ED%95%B4%ED%95%B4%EC%95%BC-%EC%89%BD%EB%8B%A4/
https://boycoding.tistory.com/201
https://youtu.be/JsS1A0xwozo
https://youtu.be/Y-0KlEy6yxs
https://velog.io/@starkshn/CPP어소29포인터-문제-풀이-해답