WIL: Week 5

서인·2023년 5월 7일
0

포인터, 배열

정리는 나중에 ..^^

const int *pa = &a;

const = 절대적으로 바뀌지 않는 값을 의미함
그래서 pa가 가리키는 변수 a의 값은 절대 바뀌면 안됨
*pa = 3; // 올바르지 않은 문장
pa = &b; // 올바른 문장

int const *pa = &a;

const의 위치가 바뀌었음. 이러면 const는 pa 자체를 바뀌면 안되는 값으로 지정함. pa가 가리키는 것은 a여야만 하는것임.
고로 아까랑 상황이 달라짐
pa = 3; // 올바른 문장
pa = &b; // 올바르지 않은 문장

const int* const pa = &a;

이렇게 되면 pa가 가리키는 값, 그리고 a의 값 또한 바뀔 수 없음.

배열 / 포인터

#include <stdio.h>
int main() {
  int arr[3] = {1, 2, 3};

  printf("arr 의 정체 : %p \n", arr);
  printf("arr[0] 의 주소값 : %p \n", &arr[0]);

  return 0;
}

컴파일 시 나오는 결과 :
arr 의 정체 : 0x7fff1e868b1c
arr[0] 의 주소값 : 0x7fff1e868b1c

배열의 이름과 첫번째 원소의 주소값은 다름. 근데 결과값이 같게 나온 이유는 배열의 이름이 sizeof 연산자나 주소값 연산자 &와 사용될 때가 아니라면, 배열의 이름을 사용시 암묵적으로 첫 번째 원소를 가리키는 포인터로 타입 변환됨. 그래서 arr이라고 입력했을 때 arr[0]의 주소값이 프린트 되는 것임.

arr은 sizeof를 사용하지 않았고 &도 사용하지 않았기 떄문에 첫번째 원소를 가리키는 포인터로 타입 변환되었음.

/* 신기한 [] 사용 */
#include <stdio.h>
int main() {
  int arr[5] = {1, 2, 3, 4, 5};

  printf("3[arr] : %d \n", 3 [arr]);
  printf("*(3+a) : %d \n", *(arr + 3));
  return 0;
}

arr[3] = *(arr+3)
둘다 출력값은 4임

[]는 연산자임. []를 사용할 시 위와 같이 사용됨. 그리고 arr은 + 연산자와 사용되기 때문에 첫번째 원소를 가리키는 포인터로 변환되어서 arr+3이 포인터 덧셈을 수행하게 되는거임.

그리고 3 [arr]같은 경우는 arr[3]과 같음. 왜냐하면 *(3+arr)로 바꿔주기 떄문에 arr[3]과 같은 값으로 출력되는 거임.

그렇다면 arr[3][3]과 같은 경우에는 어떤 식으로 바꿔줘야할까?

*(*(arr + 3) + 3)

위와 같음.
arr[3][3] = {1,2,3,4,5,6,7,8,9}라고 가정하겠음.

arr[x]는 크기가 12임. arr[x][y]는 크기가 4임. arr[3][3]의 경우에는 크기가 36이고 주소값은 48이 됨. (int 기준)
arr[3] = (arr + 3) = 크기 36
arr[3][3] =
(arr + 3)에 +3을 해주면 36 + 3가 아니고 36 + 4 3이 됨. 왜냐면 arr[x][y]크기가 4이므로 4만큼 3번을 더하라는 소리가 돼서 43인거임.

+1은 배열의 원소 크기(메모리적인)만큼 이동하라는 의미임.

2차원 배열을 가리키는 포인터를 통해서 원소에 접근하기 위해서는
1. 가리키는 원소의 크기
2. y의 값을 알아야함

그래서 이렇게 써줌

int arr[2][3];
int (*ptr)[3]; // << 크기가 3인 배열을 가리키는 포인터
ptr = arr; 

1차원 배열에서 배열의 이름이 첫번째 원소를 가리키는 포인터로 타입 변환이 된 것처럼(e.g. arr), 2차원 배열에서 배열의 이름이 첫번째 행을 가리키는 포인터로 타입 변환이 되어야함.

int* arr[3]은 int형 포인터를 요소로 가지는 배열이기 때문에 arr안에 있는 내용은 모두 주소값임. 걍 쉽게 주소값 담을 배열이란거임 ..

malloc

arr = (int *) malloc(sizeof(int) * sizeofarray);

int로 malloc 사이즈 할당/ array 만들거기 때문에 sizeof(int) * 배열 크기만큼의 메모리를 malloc으로 할당해줄거임

즉 arr[] = arr[sizeofarray]

free(arr);를 통해 다 쓰고 난 후에 메모리 영역을 다시 리턴함.

2차원 배열 동적할당
포인터 배열을 동적으로 할당한 뒤에 다시 포인터 배열의 원소들이 가리키는 일차원 배열을 다시 동적으로 할당해줌 >> 실질적으로 따지면 2차원 배열은 아닌데 2차원 배열처럼 사용할 수 있음.

이거 정리는 나중에!

/* 2 차원 배열의 동적 할당 */
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
  int i;
  int x, y;
  int **arr;  // 우리는 arr[x][y] 를 만들 것이다.

  printf("arr[x][y] 를 만들 것입니다.\n");
  scanf("%d %d", &x, &y);

  arr = (int **)malloc(sizeof(int *) * x);
  // int* 형의 원소를 x 개 가지는 1 차원 배열 생성

  for (i = 0; i < x; i++) {
    arr[i] = (int *)malloc(sizeof(int) * y);
  }

  printf("생성 완료! \n");

  for (i = 0; i < x; i++) {
    free(arr[i]);
  }
  free(arr);

  return 0;
}

*(newnode).data = newnode -> data

malloc / calloc / realloc

arr = (int *)malloc(sizeof(int) * 200)
arr = (int *)calloc(200, sizeof(int))

사용방법이 다름
그리고 malloc은 배열 안에 값이 쓰레기값으로 채워지는데 calloc은 값이 0으로 채워짐

realloc - 할당된 배열 크기 재조정

arr = realloc(arr, 300 * sizeof(int))
profile
> ㅁ <

0개의 댓글