2022. 3. 8. 14:28ㆍ강의 내용 정리/자료구조
객체지향프로그래밍 Remind
1. 객체 지향 언어 Basic
1) 변수를 구성하는 세 가지 요소
(1) 변수명(Identifier)
(2) 변수를 저장하기 위한 공간
(3) 변수를 저장하는 메모리의 시작 주소: 포인터는 이를 저장하는 변수이다.
- 32비트로 동작시킨다. -> 이는 하나의 메모리 주소에 32비트를 전달하는 것이다. -> 속도에 대한 효율을 위해 효율적으로 하기 위해 한번에 불러올 수 있는 크기가 32비트이다. -> 이는 하드웨어가 지원하는 버스 크기를 의미한다. 기본적으로 32비트를 가진다.
- operation system이 지원할 수 있는 범위를 고려해야한다. 기존 윈도우 xp 운영체제에서는 4G를 제한으로 만들었었다. 이에 따라 2의 32승이 최대였고, 32비트를 기준으로 만들었다.
- 프로그램 x86: 호환성을 위해 빌드가 될 때 위의 단계더라도 32비트로 될 수 있다.
* 상수가 저장되어있는 메모리 공간과 변수가 저장되어있는 메모리 공간이 다름 -> 상수를 변경하고자 하면 에러가 발생한다.
2) 포인터
- 복합자료형의 일종
- 변수를 정의하기 위해서 변수명(identifier), 데이터 저장공간, 메모리의 시작주소가 있어야한다.
- 데이터타입과 * 식별자가 있어야함 ex) int* ptr; // int* ptr != *ptr; // &a != int& a;
- 여러 개의 포인터로 동일한 주소값을 가리킬 경우, 그 값을 바꿀 때 포인터로 가리킨 모든 값이 변경됨
- 함수에서 포인터를 사용할 때 지역변수의 주소값을 가리키는 포인터를 반환하면 에러 발생할 수 있음
cf) 레퍼런스의 경우 실체의 메모리 번지도 동일하게 사용하기에 선언과 동시에 초기화해야함
- 데이터 타입이 있는 경우와 데이터 타입이 없는 경우의 *, &는 서로 다른 동작을 의미한다.
- &를 끌고오면 변수의 시작 주소가 반환된다.
char
- int 데이터 타입이지만 1바이트이기에 정수형과는 데이터가 다르다. 또한 이는 아스키 코드 값으로 나오는 문자로 인식해서 나오기에 int와는 차이가 존재한다.
- 동일한 메모리를 가리키는 포인터가 있다면 하나만 값을 바꾸더라도 다른 것이 같이 값이 바뀐다.
- 포인터도 선언 후 초기화를 하지 않으면 알수없는 값이나 널을 가리키고 있게된다.
- call by pointer를 할 경우에도 함수 내부에는 지역변수가 생긴다. 그럼에도 포인터를 통해 값을 바꿀수는 있다.
Function returning pointers
- 메모리를 저장하는 부분이 다를 뿐이지 포인터도 변수이기에 변수를 사용할 때와 동일하다.
- 삼항 연산자와 if else의 다른 점은 삼항 연산자는 연산의 수행결과가 해당 위치에 반환된다. 이때 return을 사용한다면 해당 결과값의 복사된 값이 반환된다.
- 지역 변수의 포인터를 리턴할 경우에는 내부 지역변수는 함수가 종료될 때 사라지기 때문에 이를 사용하려면 에러가 발생할 수 있다.
- 2차원 포인터에도 각 포인터에 맞는 데이터 타입을 가리키도록 해야한다.
pointer to array
- 같은 데이터를 연속되는 주소에 하나의 식별자 이름으로 묶어놨다.
- 식별자명은 첫번째 원소의 주소값과 동일한 이름을 가진다.
- 배열은 연속되어있기에 a의 인덱스 기호를 통해 접근하거나 포인터 기호를 사용해 접근할 수 있다.
- 위의 예제에선 p가 &a[1]로 선언되었기에 p[-1]이 가능하다.
- 주소값에 +1, -1을 하는 것은 포인터가 가리키고 있는 요소의 메모리 한 단위만큼 +1, -1을 하는 것을 의미한다. 따라서 각각의 데이터 타입에 따라 실제 움직이는 값은 다르게된다.
float과 double의 정밀도 차이(시험문제는 x)
- 십진수를 이진수로 표현하기 위해선 소수단에서 오차가 발생할 수 있다. 이러한 부분에 대해 float은 소수점 데이터가 부동 소수점(소수가 둥둥 떠다닌다.) 으로 표현된다. double형은 유효 숫자부분이 float보다 훨씬 많게 된다.
이차원 배열
- 메모리 구조 상에서는 행 단위로 이차원 배열이 저장된다.
- 함수의 인자로 전달할 때는 사이즈를 넘겨야지 다음 행에 대한 내용을 알려줄 수 있기에 이를 지정해줘야한다. 실제로는 포인터로 전달할 수 있따.
ex) void doIt(int ary[][20]) -> 한 행에 몇 개가 있는지 확인해야지 메모리 주소에 접근할 수 있기 위해
cf) 배열 포인터: int (*p)[20], (*p)[10][20]
2. 메모리
1) 동적 메모리 할당(Memory allocation)
컴파일 타임에 메모리 사용하는 것을 결정할 때는 정적, 프로그램의 실행 단계(running time)에 데이터타입과 메모리 크기가 결정되는 경우는 동적으로 구분한다.
- Static(정적): 선언과 정의를 사용하는 것 -> 대표적인 예시는 배열
- Dynamic(동적): 주로 포인터를 이용해서 동적 메모리 할당을 함 -> 대표적인 예시는 벡터
2) 메모리의 개념적 분류
(1) Program Memory: 프로그램 내부에 코드로 작성되어있는 부분
ex) 메모장의 경우 작성하고 있는 내용을 화면에 띄워주거나, 작성하는 부분에서 커서가 깜빡거리는 등의 동작 구현
cf) main과 called and standard functions -> main은 시작부분
(2) Data Memory: (데이터가 저장되는 공간?)
(1) system stack: 재귀함수를 잘못 작성했을 때 tack overflow가 뜬다.
(2) program heap: 실행시간 중에 저장되는 공간이어서 delete하지 않으면 점점 느려지거나 함
(3) global: 수정은 가능한 값, 상수 등
cf) 프로그램을 열어서 여러개의 프로세스를 열 수 있다.
ex) 메모장 프로그램을 열면 메모장 프로세스를 여러개 열 수 있다.
3. 동적 메모리 할당과 배열
(1) 동적 메모리 할당을 하는 경우 변수를 구성하는 3가지 요소 중 하나인 식별자가 없다.
- 동적 메모리 할당 시 포인터를 통해 대입한다.
- Memory leak: 접근 못하게된 메모리에 대해 할당 해제를 하지 못하면 메모리가 계속 소모된다.
- 자바의 경우에는 가비지 콜렉터가 있어 memory 해제를 해주는 기능이 있음
- 배열 형태로 메모리를 할당할 수도 있다. 하지만 메모리 누수가 발생할 수 있다.
ex) int* ptr = new int[200]; // 동적 배열 할당
ex) delete[] ptr; // 동적 배열을 삭제할 때
- int** table은 1차원 포인터형 int를 각각에 저장할 수 있다.
(2) 배열의 경우
- index를 통한 접근도 가능하고 프로그래밍이 편하지만 고정된 메모리 사용으로 낭비가 될 수 있다.
- 배열의 포인터나 인덱스를 통해 접근이 가능함
- 포인터에서 +1이나 -1은 배열에서 인덱스를 더하고 빼는 것처럼 생각하자.
- 이차원배열의 경우 한 행에 몇 개의 원소가 들어가는지 초기화해줘야함 -> C++에서는 2차원 이상의 배열을 저장할 때는 선형적으로 저장하기 때문에 각 열별로 어느 주소로 접근해야하는지 알기위해
(3) 동적 메모리 할당의 경우
- 메모리 최적화가 가능하지만 index를 통한 접근이 어렵다.
- 실제 프로그램에서 배열의 최대 길이를 미리 예측할 수 없는 경우에는 동적 배열을 사용하는 것이 좋다.
'강의 내용 정리 > 자료구조' 카테고리의 다른 글
자료구조 (6), Linked Structured (0) | 2022.05.02 |
---|---|
자료구조 (5), Stack and Queue (0) | 2022.04.19 |
자료구조 (4) ADTs Unsorted List and Sorted List (0) | 2022.03.17 |
자료구조 (3) 데이터 디자인과 구현 (0) | 2022.03.17 |
자료구조 (2) 소프트웨어 공학 원리 (0) | 2022.03.17 |