본문 바로가기
면접 준비

기술면접 list - C/C++

by 힐무새 2017. 12. 6.

C와 C++의 차이

http://jjoreg.tistory.com/entry/C-%EA%B3%BC-C%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90


malloc, new 차이점

- malloc()는 C의 <stdlib.h> 헤더 파일에서 지원하는 함수로, 인자로 할당할 size를 받는다. 기본적으로 void * 형태의 포인터를 return 하기 때문에 할당할 포인터 자료형에 맞게 casting이 필요하다. 메모리 해제는 free()를 사용한다.

- new 는 C++ 자체에서 지원하는 키워드로 따로 헤더 파일이 필요없다. malloc과는 다르게 할당할 객체의 크기를 알아서 계산하여 heap에 할당하기 때문에 size를 입력할 필요가 없다. 또한 객체 생성시 생성자를 자동으로 호출하기 때문에 생성과 초기화가 동시에 이루어진다. 메모리 해제는 delete 키워드를 사용한다.


차이점

  • malloc는 헤더파일이 필요하지만, new는 그렇지 않다.
  • malloc은 size를 인자로 받고 자료형 포인터에 따라 캐스팅을 필요로 하지만, new는 할당할 타입과 같은 포인터 변수로 받기만 하면 된다.
  • malloc과 달리 new는 생성자를 자동으로 호출하게 된다. 따라서 new는 생성과 동시에 초기화가 이루어진다. 반면에 malloc는 메모리 공간만 확보할 뿐이다.
해시테이블 vs STL map
- 해시테이블
해시테이블의 값(value)는 키(key)에 대한 해시 함수를 호출하여 저장한다. 값은 정렬된 순서로 보관되지 않으며, 값을 저장한 인덱스를 찾기 위해 키를 사용한다. 삽입 및 삭제 연산은 충돌이 적다는 가정하에 O(1)에 수행된다. 충돌되는 경우에는 보통은 체이닝(chaining)을 통해 문제를 해결한다. 
-STL map
STL의 map은 키를 기준으로 만든 이진 탐색 트리에 key/value 쌍을 보관한다. 충돌을 처리할 필요가 없고, 트리의 균형이 유지되므로 삽입 및 탐색시간이 O(log N)이 보장된다.

입력되는 항목의 수가 적다면?
둘다 사용할 수 있다. map은 O(log N)이지만, 입력 데이터의 수가 적다면 성능 저하는 무시할 만 하다.

가상 함수(virtual)의 동작 원리
기존의 함수는 정적 바인딩 형태로, 컴파일 시간에 호출된다. 이미 호출되어야 하는 함수의 주소를 알고 있기 때문이다. 하지만 가상 함수와 같이 런타임 시점에서 동적바인딩을 통해 호출될 함수의 주소를 결정해야 하는 경우가 있다. 그런 경우에 사용하는 키워드가 virtual이다. 

1. 어떤 클래스의 함수가 virtual로 선언되어 있다면, 해당 클래스의 가상 함수 주소를 보관하는 vtable이 만들어진다. 가상함수 테이블은 객체가 아닌, 클래스에 생성됨을 주의하라.

2. 객체를 생성하게 되면 가상함수 테이블을 가리키는 포인터 변수가 생성된다. 이 포인터는 각 클래스에 해당하는 가상함수 테이블을 가리키기 때문에, 포인터를 통해 각 타입에 맞는 함수의 주소를 동적으로 찾을 수 있는 것이다.

얕은 복사(Shallow copy) vs 깊은 복사(Deep copy)
얕은 복사는 한 객체의 모든 멤버 변수의 값을 복사한다. 깊은 복사의 경우에는 그 뿐 아니라 포인터 변수가 가리키는 모든 객체에 대해서도 시행한다.
예를 들면 같은 클래스의 객체 A, B가 있다고 할 때, A에는 int형 멤버 변수 a1, a2가 존재하고, 다른 객체를 참조하는 포인터 ptr이 있다고 할 때, 얕은 복사는 새로 생성한 객체에 a1, a2를 각각 복사하되, 포인터 ptr가 가리키는 객체는 동일하게 유지한다. 즉 원본과 복사본이 가리키는 ptr은 같은 객체를 가리키게 되는 것이다. 이러한 방식이 얕은 복사이다.
반면 ptr이 가리키는 객체의 모든 멤버 변수를 복사해서 새로이 복사된 객체의 포인터에 새로 할당하면, 원본, 복사본의 ptr이 가리키는 주소는 다르지만, 객체의 구성은 동일하게 된다. 이러한 방식을 깊은 복사라 한다.

volatile이란?
volatile이란 컴파일러에게 해당 변수의 값이 외부에 의해 바뀔 수 있음을 알려주어 최적화를 방지한다. 해당 변수는 운영체제, 하드웨어, 혹은 다른 스레드에 의해 변경될 수 있음을 컴파일러에게 알려주어 프로그래머라 작성한 방식 그대로 동작하도록 만든다.

*(unsigned int *)0x8C0F = 0x8001

*(unsigned int *)0x8C0F = 0x8002;

*(unsigned int *)0x8C0F = 0x8003;

*(unsigned int *)0x8C0F = 0x8004;

*(unsigned int *)0x8C0F = 0x8005;


위의 코드를 보면 같은 포인터 변수에 값을 중복 할당한다. 그 과정에서 컴파일러가 중복된 과정을 제거하여 마지막 줄의 선언만을 실행할 가능성이 있다. 하지만 위와 같은 중복 할당이 로직 상 중요한 요소가 될 때(다른 하드웨어, 운영체제, 스레드가 참조하는 경우) 일련의 과정이 생략된다면 큰 문제를 일으킬 수 있다. 이렇듯 최적화를 수행하지 못하도록 강제하는 것이 volatile이다.


참조: http://skyul.tistory.com/337


스마트포인터

특정 스코프 내에서 선언한 객체는 스코프 범위를 벗어나게 되면 메모리가 해제되는 반면, 동적 할당으로 선언한 객체는 스택이 아닌 힙영역에 할당되기 때문에, 스코프를 벗어나더라도 계속 유지된다. 프로그래머가 명시적으로 동적 할당한 객체에 대해 메모리 해제를 하지 않을 경우 메모리 누수로 인한 심각한 문제를 야기할 수 있다. 


프로그래머가 일일이 모든 동적할당된 객체를 해제하는 것 또한 번거로운 일이 아닐 수 없다. 스마트포인터는 일반 포인터와 같지만 자동적으로 메모리를 관리할 수 있는 기능덕에 더 안전하다.





'면접 준비' 카테고리의 다른 글

기술면접 list- 자료구조  (0) 2017.11.14
기술 면접 list - 운영체제  (0) 2017.10.27