10/18
보고 또 보고 또 봐도 제대로 이해를 하지 못했다. (12-3 중후반 부분)
가슴이 답답하고 마음 한 구석에 응어리가 있다.
내일 다시 처음(12-1)부터 읽어봐야 겠다.
10/19
이 문장에선 parr 이라는 포인터변수를 선언하고 arr의 주소를 가리키게 했고
parr++ 를 했을때 int형 포인트 이므로 1*4 를해서 주소값에 4바이트 만큼 증가시키고 정수는 1 증가가 가능하다고 한다
그런데 어째서 arr 배열을 선언하고 arr++ 를 하면 오류가 나는지 이해가 안된다
배열의 이름이 첫 번째 원소를 가리키는 포인터로 타입 변경 된다고 했을 때, 이는 단순히 배열의 첫 번째 원소를 가리키는 주소값 자체가 될 뿐입니다. 따라서 arr++ 문장은 C 컴파일러 입장에서 다음을 수행한 것과 같습니다.
첫 번째 원소를 가리키는 주소값 이 된다면 ++ 를 했을때 어째서 오류가 나는 것일까?
그저 정말 딱 저 문장만 약속으로 해둬서 그런걸까?
parr 은 int* 를 가리키는 포인터이고, int*의 크기는 8바이트 이기 때문에 parr+1 은 주소값이 8 증가해서 세번째 원소의 주소값을 갖게되어서 3이 된다는건 이해를 했다.
그런데 *(parr+1)+1 부분에서 int 크기만큼 주소값이 4가 늘어낫는데 주소값이 총 12가 늘었다는 뜻 아닌가?
4가 아닌 7이 되었다는게 이해가 안된다.
그렇다면 이 코드는 무슨 일을 했었을 까요? << 에서의 예제와 내용중에 int*가 64bit이기때문에 parr+1을 했을 경우 8byte가 증가한다는건 이해가 됩니다. 그런데 그다음에 *(parr + 1) + 1 에서 int 크기 만큼 증가를 하신다고 하셨는데 왜 3의 다음인 4가 아니라 index가 4만큼 증가인 7이 나오는건가요 제가 어느부분이 모잘라서 그런지 모르겠습니다. 혹시 여기에 관해서 설명이 가능할까요 int * 타입이라고 하셨는데 왜 int 크기 만큼 증가인지 잘모르겠습니다. 정말 너무 궁금합니다
*
:
1. 단행 연산자로 쓰일 때에는 주소값에 저장되어있는 값을 불러오게 됩니다.
2. 피연산자가 두 개일 때는, 두 값을 곱해주는 산술 연산자로 역할하게 됩니다.
&
:
1. 단행 연산자로 쓰일 때에는 해당 값이 자장되어있는 주소값을 불러오게 됩니다.
2. 피연산자가 두 개일 때는 AND를 의미하는 논리 연산자로 역할합니다.
포인터는 변수의 주소값을 저장합니다.
포인터도 변수입니다.
포인터도 주소값을 가집니다.
이중포인터는 포인터의 주소값을 가리킵니다.
const int =
1. 가리키는 대상의 값을 바꿀 수 없다.
2. 가리키는 대상(주소)은 바꿀 수 있다.
int const =
1. 가리키는 대상의 값을 바꿀수 있다.
2. 가리키는 대상(주소)은 바꿀 수 없다.
암기 팁 : 앞에 있는 수식어를 생각 하자
*(*(arr+3)+3)
처음에 정답을 보고 위에 사람처럼 의문이 생겼다
그리고서 아래의 글과 코드를 보고 이해가 됐다.
arr +1 라는 코드의 의미는 배열의 원소가 가진 크기만큼 1번 더하라 라는 의미입니다.
arr의 크기는 arr[x]의 경우엔 16, arr[x][y]의 경우에는 4가 나옵니다.
여기서 arr은 arr[x]의 첫번째 원소를 가르키는 주소값을 나타내죠. 따라서 첫번째 원소의 크기만큼 16의 주소값이 이동하게 됩니다. arr + 1은 결국 arr[x+1]의 주소값이 되는 셈이죠. 이후에도 마찬가지로 arr[3][0]의 값을 나타내는 *(a+3)에 3을 더하는 행위는 arr[3][y]의 크기인 4만큼 3번을 더하라는 소리가 되어 12만큼의 주소값이 이동하게 됩니다.
+1이라는것이 배열의 한칸 한칸을 이동하라는 의미가 아닌 배열의 원소의 크기(메모리적인)만큼 이동하라는 의미라고 생각하시면 됩니다.
#include <iostream>
int main() {
int arr[4][4] = { 0 };
for (int i = 0; i <4; i++)
for (int j = 0; j < 4; j++)
printf_s("arr[%d][%d]의 주소값 = %p\n", i, j, &arr[i][j]);
printf_s("*(arr+3)의 주소값 = %p\n", arr + 3);
printf_s("*arr 의 크기 = %d\n", sizeof(*arr));
printf_s("*(*(arr+3)+3)의 주소값 = %p\n", *(arr + 3)+3);
return 0;
}
위 코드를 돌려보면 아래와 같은 결과값이 나옵니다.
arr[0][0]의 주소값 = 0019FC24
arr[0][1]의 주소값 = 0019FC28
arr[0][2]의 주소값 = 0019FC2C
arr[0][3]의 주소값 = 0019FC30
arr[1][0]의 주소값 = 0019FC34
arr[1][1]의 주소값 = 0019FC38
arr[1][2]의 주소값 = 0019FC3C
arr[1][3]의 주소값 = 0019FC40
arr[2][0]의 주소값 = 0019FC44
arr[2][1]의 주소값 = 0019FC48
arr[2][2]의 주소값 = 0019FC4C
arr[2][3]의 주소값 = 0019FC50
arr[3][0]의 주소값 = 0019FC54
arr[3][1]의 주소값 = 0019FC58
arr[3][2]의 주소값 = 0019FC5C
arr[3][3]의 주소값 = 0019FC60
*(arr + 3)의 주소값 = 0019FC54
*arr 의 크기 = 16
* (*(arr + 3) + 3)의 주소값 = 0019FC60
int* 변수 3 개를 가지는 배열
따라서 아무리 차원이 높아져도 결국 메모리에는 1차원으로 죽 이어서 나열하게 되는 것이고, 포인터는 그 배열의 시작 주소를 가리키면 됩니다.
즉, 배열의 차원이 아무리 높아져도 포인터의 차원에는 아무런 영향이 없다는 뜻이고, 다시 말해, 배열의 차원이 높아진다고 포인터가 이중 포인터가 되거나 하는 것과는 전혀 연관이 없다는 것 입니다.
따라서, 배열의 차원이 높아질 때마다 포인터의 정의에 그 차원에 따른 부가적인 정보만 더해주면 될 것 같습니다.
배열의 차원이 높아지더라도 실제 메모리에서는 1차원이고, 포인터는 단지 그 배열의 시작주소를 가리키는 것이라고 생각하면 헷갈리지 않는 것 같습니다.
포인터 간의 형변환은 포인터가 가리키는 시작 주소는 같으나 그 시작 주소로 부터 읽어오는 크기가 다르기 때문에, 참조되지 않은 메모리 값을 참조할 수 있기 때문에 위험할 것 같다.
포인터 간의 형변환은 큰 크기 타입(double,int) 을 작은 타입(char)로 나눔으로써 데이터 값을 정교하게 바꿀 수 있다는 것을 의미. 작은 값(char형)을 큰 값(ex.int형)으로 바꾸는 것은 위험하지 않지만, 그 반대는 값을 손실 할 수 있어 위험하다.