• 복합구문&콤마연산자

여러구문을 하나의 구문처럼 간주하는 것

 

중괄호를 사용해 블럭을 생성하는 방법

 

콤마연산자를 이용한 방법이 있다

 

복합구문의 예로 for의 Loop Body는 하나의 구문이어야 하는데

복합구문을 이용해 여러 구문을 실행하게 하는것이였다

콤마연산자도 마찬가지로 복합구문을 만들 수 있다

다만 밑에 처럼 선언과 같이 사용하면 변수 이름을 분리시킨다 하여 분리자 라고 한다

위에 출력값이 20 과 40이다

콤마 연산자는 왼쪽의 구문을 먼저 실행하고 오른쪽의 구문을 실행하는 시퀀스 포인트라고 한다

그래서 a = 20이 들어가고 b = 20 * 2이 되어 40이 출력이 되었다

 


  • 관계표현식

각 연산의 결과가 bool형으로 나온다

 


  • tpyedef ( define & using )

typedef는 기존 데이터형의 별명을 만드는 방법중 하나다( 그외 define, using)

 

구성이다

typedef typeName 식별자

사용하는 방식은 내가 경험하면서 알야겠지만

일단 복잡한 자료형을 간단히 나타내는데 괜찮을거 같고 자료형의 크기가 중요할때 사용해도 괜찮을거 같다

 

define으로도 가능하다

 

#define 을 한 줄에 다 쓸수 없을 때

\ 문자를 이용하여 다중 줄로 선언할 수 있다.

단, 다중 줄로 선언할 경우 마지막 줄 에는 \ 문자를 붙이지 않는다.

 

언리얼엔진 헤더파일중 일부분

 

다만 define을 사용하면 이런문제가 있다고 한다

myDatatype으로 생성한 변수 b는 왜 오류가 나지 않을까?

이유는 int*가 아닌 int형으로 생성되었기 때문이다

 

myDatatype a, b 를 전처리기에서 변환하면

int *a, b 로 변환되기에

a는 int * 으로 생성되고

b는 int 로 생성 되었기 때문이다

 

그렇기에 자료형의 별칭을 만드려면 define은 비추다

 

그리고 typedef말고 using을 사용해서도 정의할 수 있다

 

그럼 typedef와 using의 차이는 무엇인가?

templete의 사용 유무다

using 같은 경우 템플릿을 사용가능하나

typedef 같은 경우 템플릿을 사용하지 못한다


  • 문자열 비교

c 스타일 - strcmp( const char * 1, const char * 2) 사용

 

훨씬 편한 string은 == 사용하여 비교 가능

 


  • while

루프 몸체와 조건 검사부분으로 이루어진 반복문

 

for과 같이 조건이 true면 루프몸체를 실행한다

 


  • do while

while로직이 "조건검사 ─> 루프몸체 실행" 이라면

 

do while은 "루프몸체 실행 ─> 조건검사" 으로 실행부터하고 검사한다

 

조건이 true면 다시 몸체 실행을 하는 것 도 같다

 


  • Range based for loop

C+11에서 추가된 for의 형태

조건부 구성이다

for( range_declaration : range_expression )

 

range_declaration - 변수의 선언, range_expression의 배열 원소 타입으로 지정한다

range_expression - begin( ), end( ) 함수가 정의된 객체 혹은 braced init list

 

 

braced init list는 중괄호를 사용한 초기화 문법인데 아마 이걸 사용한 데이터를 뜻하지 않나 싶다

단순 동적배열에 begin이나 end가 내부적으로 정의 되어 있는지 모르겠지만

(아마 안되는 듯 싶은데.. 검증해야한다)

일단 braced init list내에 속해 있기에 가능한거같다

 

밑의 링크는 braced init list

https://en.cppreference.com/w/cpp/language/list_initialization

 

range_declartion은 range_expression원소와 자료형이 달라도 자동적으로 캐스팅을 해줌으로

같지는 않더라도 최소 캐스팅이 가능한 자료형이여야한다

 

밑의 링크는 ranged based for이 설명된 사이트

https://en.cppreference.com/w/cpp/language/range-for

밑의 Explanation은 위의 사이트에서 나온 설명이다

정말 기존 for문에서 새로운 코드가 아니라 내부적으로는 위처럼 기존 for문이 작동하나 보다

 

 

보통 밑의 코드처럼 사용하는데

auto를 이용해 자료형을 받는데 편리함을 취하고

&를 이용해 복사비용을 줄이면서 값까지 변경 할 수 있는 방식을 많이 사용하는 듯 하다

 

조건부 배열 부분에 배열이름을 사용했다

처음에는 배열이름은 곧 주소이기도 하니까 포인터를 사용 할 수 있지 않을까 생각을 했지만

그렇게 되면 for문은 그 주소가 가진 배열의 크기를 알지 못하기에 사용 할 수 없다

그렇기 때문에 range_expression부분에 들어오는 데이터에 크기를 알수있는 데이터만 가능한가보다

시도했는데 안된다

그러다 함수내에서 매개변수 받아  ㅅㅂ 어떻게 사용하지? 하다가 이렇게 자료형을 구체적으로 적어주는 걸 생각했다

*가 아닌 &를 사용한건 배열 그 자체의 자료형을 가져오려 사용했다

 

근데 이렇게 사용하다가는 너무 불편할거 같아 템플릿을 이용했다

편안..

 

braced init list 에 있는것중 이런것도 있어 가능한지 확인했다

 

  • stl vector & stl array

기존 정적배열의 관리를 쉽게해주는 템플릿 클래스

 

에서 가변적으로 크기를 쉽게 조정 할 수 있게 만든 템플릿 클래스

 

 

vector의 경우 배열의 크기를 런타임중에도 계속해서 변경 할 수 있는 특징이 있다

내부적으로 new delete를 사용한다

 

array의 경우 크기는 컴파일타임시 초기화를 해야 해 크기가 정적이나

대입연산자의 가능, 배열 크기 이상의 값을 참조했을 때 예외를 반환하는등 좀 더 편하게 다룰 수 있다

 


  • 표현식

값, 또는 값 + 연산자 의 조합으로 이루어진 명백한 하나의 값을 가지는 식

 

일단 지금까지 공부한걸로는 세미콜론을 뺄때 값이 있는 것들은 표현식이 되는거 같다

 

선언, 반복문 등은 표현식이 아니다

리턴문도 표현식이 아니라고 하는데 이건 좀 더 봐야할듯

 


  • for

구성

// 세 개 표현식(expression)으로 이루어진 제어부분
for( Loop Initialization ; Loop Test         ; Loop Update ) 
    =init-expression 	   =cond-expression    =loop-expression 
{
      Loop Body;
}

 

순서

Loop Init ─> Loop Test  ─True─> Loop Body ─> Loop Update ─> Loop Test ....

                           │

                           └──False─> 종료

 

 

제어 부분의 세가지 부분은 모두 생략 가능하다 ( 모두 생략시 무한루프 )

 

 

init-expression, loop-expression은 ' , ' 으로 여러 구문을 사용할 수 있다

※' , '를 cond-expression에 사용을 해도 오류는 나지 않으나 아마 정상 작동 안될 확률99%다

 

 

init-expression에 선언한 변수는 for문 안의 지역변수다

for문이 종료되면 사라진다

※단 구형c++ 경우 루프 앞에 선언한 것으로 인식해 삭제하지 않는 경우도 있다

 

 

책보다 문서가 더 정리가 잘되어있다

https://docs.microsoft.com/ko-kr/cpp/cpp/for-statement-cpp?view=msvc-160#remarks 

 

for 문 (c + +)

Microsoft Visual Studio c + +의 표준 c + +에 대 한 참조입니다.

docs.microsoft.com

 


  • 증가 연산자 & 감소연산자

두개 모두 접두(++a), 접미(a++) 방식으로 사용 가능

 

접두식으로 했을 경우와 접미로 사용했을 경우 연산자 순서가 차이가 많이 나니 주의

 

 

 

한 구문에 너무 많이 사용하면 한대 맞을 수 도있다

int a = 3 * a++ - (34 - --a)/++a;

 

포인터와 함께 사용할 수 있다

접두형 끼리 붙었을때 (++*a) 오른쪽에서 왼쪽으로 실행하면 된다고 생각하면 된다

 

++*a를 예로 *가 ++보다 오른쪽에 있으니 먼저 실행한다.

= a포인터에 들어있는 값( a[0]의 값  )

 

그 후에 왼쪽에 있는 ++가 왼쪽에 있었으니 다음으로 실행된다

여기서 ++가 되는 대상은 단순 a가 아닌 ' * ' 를 실행시킨 *a라는 점

= *a의 값에 ++ (a[0]은 1이며 ++하면 2가 된다)

 


  • 부수 효과 & 시퀀스 포인트

간단하게 부수효과는 수식이 진행될 때 변수에 값이 변경되는 효과

 

 

시퀀스 포인트는 부수효과,특히 접미어 방식이 일어나는 시점을 명확히 알 수 있게 해주는 시점을 나타낸다고 보면 된다

포인트로는 수식의 끝, 세미콜론, While루프의 검사 조건 ...등이 있다

 

위의 코드중 접미에 붙은 ++ 가 일어나는 순서와 시점은 구체적으로 알 수 없다

 

다만 시퀀스 포인트(위의 코드에서 ' ; ' )에서 모두 실행이 되었다고 알수있다

 

이 지점에 왔을 때는 모든 부수효과가 실행 완료 됐다 라고 알려주는 것 이게 시퀀스 포인트의 의미

 


  • 접두어 & 접미어 방식

모두 부수효과가 나타난다 가정시에

 

접두어 방식은 기본값에 부수효과를 적용하고 리턴한다

 

접미어 방식은 기본값을 복사하고 복사한 값에 부수효과를 적용하고 리턴한다

 

이 차이가 있으므로 접두어 방식이 조~~~~~~~~금 낫다고 한다

 

 

나중에 클래스사용시 ++나 -- 를 오버로딩하여 사용할 수 있는데

 

크기가 큰 클래스는 복사비용이 꽤 들테니 둘다 사용해서 상관없다면 접두어 방식을 사용하는 습관을 가지자

 

 

  • 도트 멤버 연산자 & 화살표 멤버 연산자

둘 다 멤버데이터를 참조 할 때 사용한다

 

차이점이라면

 

도트 멤버연산자 - 객체에 사용

 

화살표 멤버연산자 - 객체의 주소에 사용

pttrA 같은 경우

(*pptrA) = 객체를 가르키는 주소

이니까 ->만 붙이면 되겠다

 

 


  • 데이터의 저장공간

Stack(자동공간)

지역변수가 저장되는 영역 LIFO 구조로 되어있다

해당 변수가 속한 스코프가 끝나면 자동으로 메모리 해제된다

 

Code&Data(정적공간)

전역변수가 저장되는 영역 프로그램이 종료될 때 메모리 해제된다

 

Heap(동적공간)

책에서는 Free store와 같다고 한다

근데 new로 할당하면 free store이고 malloc으로 할당하면 heap 뭐 이런 소리도 있던데

일단 내가 사용하고 있는 VC++에서의 new는 내부적으로 malloc이 실행되기에 그냥 같은 말이라고 생각한다

 

이 책 포인터부분에서 이 저장공간을 작성했다는건

사용자가 만든 함수 내부에 지역변수로 포인터써서 동적할당하고 해제 안했을때의 메모리 릭 문제를 강조하는거 같다

 

※메모리에 대해 좀 더 공부


  • 변수형의 조합(포인터 장난)

파트 이름은 변수형의 조합.. 이지만 그냥 배열, 구조체에 포인터를 이용할 수 있다 라는 내용이다

 

예제 비슷하게 장난 같은걸 쳐봤다

3번은 왼쪽부터 쭉 읽으면 논리적으로는 완벽해보인다만 오류가 나온다

 

그 이유는 연산자 실행 순서 때문인데

 

모든 식에서(괄호없는 수식) * 보다 . 가 먼저 실행되기 때문에 

 

(arr+1).member 가 실행되는것이다

 

그렇기에 괄호를 한번 더 쳐주어서 *가 먼저 실행되게 하면 정상 실행된다

 

안쓰던 더블포인터랑 포인터 배열 사용 했는데 장난치다보니까 나도 헷갈리더라ㅋㅋㅋㅋㅋ

미래의 나에게 알려준다....

 

 

  • 문자열 상수

배열의 식별자   =    배열의 첫번째 데이터의 주소

(밑에서는 a)

문자열 상수      = 문자열의 첫번째 문자 주소

(밑에서는 "ABCDEFG" , "Is english")

 

문자열은 첫번째 문자의 주소부터 null값 까지 데이터를 찾는 방식으로 사용이 된다

 

그렇기에 저 "Is english"도 문자열이기에 메모리 어딘가에 저장이 되고

첫번째 문자의 주소가 있을 것이고 null값 또한 있을 것 이다

 

첫번째 주소는 "Is english" 이 자체로 첫번째 문자의 주소를 나타낸다

 


 

쉽게 "ABCDEFG"로 확인한다

위에 말처럼 "ABCDEFG" 는 문자열의 첫번째 문자 주소가 될수도있다.

 

(int*) 을 붙여준 이유는 안붙이면 cout가 문자열주소 로 파악하고 문자열을 출력하기때문에

주소를 출력하려고 변환했다

 

"ABCDEFG"가 가진 주소는 00B0AB30, 그 주소로 가 무슨 데이터가 있는지 확인한다

 

41이 들어있다, 메모리는 16진수형태로 나타나며 41은 10진수로 65다

 

65는 아스키 코드로 'A' 이므로

 

"ABCDEFG" 가 'A'의 주소를 가지고 있다고 볼 수 있다


 

컴파일러마다 다르지만 같은 내용이 담긴 문자열 상수가 여러개가 사용되면

 

하나로 취급하여 하나의 주소로 사용 하는 경우도 있다고 한다

[메모리에 하나만 저장하여 쓰인다는 말]

계속해서 작성중 입니다.


 

Malloc & new

 


  • malloc은 초기값을 설정할 수 없다, new는 가능하다

 


  • malloc은 생성자가 호출되지 않는다, new는 생성자가 호출된다
더보기

 

 

eh vector constructor iterator에서 생성자 호출?

 

 


  • malloc은 Realloc으로 메모리블럭의 재할당이 가능하다, new도 실행하다?
더보기

구글링을 하면 new는 realloc이 되지 않는다는 글이 많다.

 

물론 사용안하는게 정신건강에 좋겠지만

 

그래도 실행은 되지 않을까? 하는 마음에 테스트 해봤다

 

밑의 코드로 malloc에서 realloc을 하였을 때, new에서 realloc을 하였을 때 를 메모리 디버깅으로 확인해 볼것이다

 

먼저 malloc에서 realloc일때다

 

realloc 실행 전
realloc 실행 후

 

realloc이 다른 주소를 뱉어내는 바람에 원래 들어 있었던 값 9가 다른 주소로 옮겨지는건 확인했지만

우리가 원한 16바이트 만큼 할당이 된건지 알 수 없다

쥰내 안나와서 코드좀 덧붙였다

위의 사진에서 realloc으로 재할당 받는걸 볼 수 있다

 

저 일정하게 채워져 있는 cd와 fd가 무슨 뜻이 있을거 같아서 검색해봤는데 힙에서 넣어주는 값이라고 한다

앞뒤의 fd는 가드 바이트라 하고 cd는 초기화가 되지 않았다는 뜻이라한다

이 글에 자세히 나와있다

https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=ruvendix&logNo=220905335341 

 

 

아무튼 이제 new로 확인해보겠다

진짜 같은 주소 안나와서 가챠하는 기분이였다

마찬가지로 원래 있던 값 9가 있으며 앞뒤로 가드바이트가 있으며 빈 영역에 cd로 채워져있다

 

이건 realloc이 실행됬다고 생각을 한다

 

new도 realloc이 되기는 한다

 


  • mallock과 new의 반환형
더보기

malloc은 void * 를 반환한다

 

new는 자료형을 추가로 입력받아 자동으로 캐스팅하여 반환해준다

 

근데 사실 차이까지라고 해야 하나 싶다 그럴거면 그냥 이름도 차이난다고 하지


  • new는 내부적으로 malloc을 사용한다
더보기

 

위에 있는 코드를 어셈블리어로 F11을 눌러서 계속 들어가 확인해 보겠다

 

1. new의 실체인 operator new가 call이 된다

1

 

2. operator new가 있는 곳으로 간다

2

 

3. 들어가보면 malloc이 나와있다

3

 

 

4. 과연 같은 malloc일까? 하여 malloc의 실행 주소가 같은지 확인해본다

4

 

5. 먼저 new의 malloc이다

5

 

 

6. malloc의 malloc이다

6

 

7. 두 함수 모두 0172E340 부터 malloc이 실행된다 이를 통해 같은 malloc이라고 생각을 하고

new의 구현에 있어서 다르겠지만 현재 사용하는 VC++의 new는 내부에서 malloc이 실행된다고 생각한다

 


  • __declspec(allocator) [진행중]
더보기

먼저 New가 실행시에 실행되는 함수 operator new이다

new에 F12를 눌러 확인할 수 있다 // _VCTRT_ALLOCATOR에 F12를 눌러 확인할 수 있다

_VCRT_ALLOCATOR 이 __declspec(allocator) 으로 define되어 있다

 

 

이번엔 malloc의 실 함수이다

여기도 비슷하게 생긴 _CRTALLOCATOR 이란게 있다

여기도 __declspec(allocator)이 나온다!

 

두개에 모두 들어있기도 하고 ALLOCATOR라는 단어가 들어있어서

메모리 할당 요청에 근접한 기능이 있는가 해서 알아보았다

 

 

https://docs.microsoft.com/ko-kr/cpp/cpp/declspec?view=msvc-160 

 

__declspec 이란 대강 뒤에 붙는(ex 위에서 allocator) 특성? 같은걸 저장소 클래스에 지정할 수 있게 해주는 키워드 같다

 

그럼 이 allocator가 특성이라 하니 살펴봤다

 

 

https://docs.microsoft.com/ko-kr/cpp/cpp/allocator?view=msvc-160 

allocator 선언 지정자는 사용자 지정 메모리 할당 함수에 적용 되어 ETW(Windows용 이벤트 추적) (ETW)를 통해 할당을 표시할 수 있습니다.

 

잘 모르겠지만 allocator라는 특성을 설정하고 ETW로 무언가 디버깅?? 같은걸 할수 있다는 말 같은데

ETW 문서도 보았다

 

 

 

https://docs.microsoft.com/ko-kr/windows-hardware/drivers/devtest/event-tracing-for-windows--etw-

https://docs.microsoft.com/ko-kr/visualstudio/profiling/custom-native-etw-heap-events?view=vs-2019 

ETW (Windows 용 이벤트 추적)는 사용자 모드 응용 프로그램 및 커널 모드 드라이버에서 발생하는 이벤트를 추적하고 기록하는 메커니즘을 제공합니다. ETW는 Windows 운영 체제에서 구현되며 개발자에게 빠르고 안정적이며 다양한 이벤트 추적 기능 세트를 제공합니다.
Add the __declspec(allocator)
 decorator to any function in your custom heap manager that returns a pointer to newly allocated heap memory. This decorator allows the tool to correctly identify the type of the memory being returned. For example:

최종적으로 보아하니 __declspec(allocator)는 직접적인 할당의 요청 이런게 아니라 그냥 단순 속성을 정하고

 

디버깅을 할때? 그런 용도로 사용되는거 같다..

 

V가 붙고 안붙고의 차이는 모르겠다..

 


 

delete [ ]

 

 

 

new로 할당 받은 배열 포인터의 해제다

 

delete [ ] 포인터   로 해제를 한다

근데 사실 delete만 사용해도 해제가 된다

[객체 배열 같은 경우에는 소멸자 문제가 있음]

delete 전 // array를 동적 할당 받아옴 각 1, 2, 3 이 들어오는걸 볼수있다
delete 후 // int * 형을 해제 시켰을 뿐인데 모두 해제가 되는 기적을 본다

 

근데 우리가 몇개의 배열을 할당 받은 줄 알고 시작주소만 넘겨주어도 모두 해제가 이루어지는가?? 궁금했다

 

 

일단 사전 지식을 알아야 이해할 수 있었다

 

1. 일단 하나의 프로그램이 시작되면 그 프로그램에게 하나의 힙메모리가 주어진다 이는 Default Heap이라 한다

   (Default Heap, Default process heap 이렇게 부르는 듯 하다)

 

2. Default Heap은 다양한 메모리크기의 요청에 응답하려 여러 메모리의 크기로 나누어져있다

   이 나누어진 메모리들을 메모리 블럭 이라 한다

 

3. Windows에서 이 Default Heap을 관리하는 Heap manager라는 시스템이 있다

 

4. 우리가 힙에 메모리할당을 요청하면 이 HeapManager가 Default Heap에서

   요청한 크기에 알맞는 메모리블럭을 찾으면 그 첫번째 주소를 반환한다

 

5. 이때 Heap manager에 지금 할당해 준 크기를 저장한다

우리가 free나 delete로 시작주소만 넘겨도 모두 해제가 될 수 있었던 이유는
저 Heap manager에 할당해 준 크기가 저장되어 있기 때문이였다
[ 힙매니저에 저장되는 방식이라던지, 어디에있고 어떻게 관리되는 부분은 아직 내게 필요하지 않은 부분같다 ]

 

6. 여기까지 malloc 의 대략적인 할당 과정이다.

 

※ new의 동적할당과 new의 배열동적할당 어셈블리 차이 확인하기

 


 

작성시 많은 도움이 된 글

https://kfgd.tistory.com/18?category=974115 

 

검증이 어렵고 어려운 내용이 많아 틀린부분이 많을거 같습니다.

 

잘못된 부분이 있다면 알려주시면 감사드립니다.

  • 포인터

주소 저장 목적의 변수

 

&[주소연산자] - 해당 변수의 주소값을 반환


*[간접 참조 연산자] - 포인터 앞에 붙을시에 포인터가 가진 주소에 데이터를 반환

 

int * a 가 있다면 a는 int형 포인터다

 

이 말은 int가 이 주소의 데이터형 단위 라는 것이며

 

이 데이터형 단위로 읽는다는 것이다

 

 

 


 

  • NULL , nullptr

NULL 은 상수 0 이라고 define되어 있다

그렇기에 포인터외의 자료형도 사용할수가 있다

 

 

nullptr C++에서 생겼으며 말 그대로 NULL값을 가진 포인터를 의미하여 포인터끼리만 연산이 가능하다

 

모두 포인터에 사용했을시에 핵심은 데이터가 0인지 판단하는것이지 정상적으로 할당받은 데이터를 판단할수는 없다

                                                                                          [ex) new로 할당 받은 주소]

 


 

  •  New

new 자료형 - 운영체제에서 자료형만큼의 데이터공간의 주소를 반환

저렇게 new만 써도 메모리가 할당된다

그렇기에 저 반환하는 주소를 포인터에 대입시키는 것이다

 

저 new의 실체는 operator new 라는 함수이다

 

배열형식으로 선언은

new 자료형 [num]

 


 

  • Delete

new가 메모리를 운영체제에서 받아왔다면 이건 운영체제에 받아온 메모리를 반환한다

 

이것도 마찬가지로 operator delete 가 본체이다

 

array형식을 delete할때는 " delelte [ ] 식별자  " 로 해줘야한다

그 이유는 소멸자 문제가 발생하기 때문이다.

[ 위에는 소멸자가 딱히 관련이 없기에 delete[ ] 를 delete로 바꾸어도 정상으로 돌아가긴한다 ]

소멸자가 한번 호출후 에러가 난다

 

 

이러한 주소하나만 delete에 넘겨주어도 주소가 가지고있는 할당된 메모리가 해제되는 이유같은 내용은

다른 글에 다시 정리한다

[ 작성중인 글 ]

https://ddidding.tistory.com/23

 


 

  • 배열 포인터

[ ] 를 사용하여 해당 인덱스의 배열 값을 나타내듯이 사용할 수 있다

 

+ 와 - 를 이용하여 해당 인덱스의 주소를 알아낼 수 있다

여기서의 0, 1, 2, 3 이 의미하는것은 정수 0, 1 이 아니라 a 포인터가 담는 자료형(int) 의 크기만큼 주소를 더한다는 뜻

 

그렇기에 int형의 크기 4 BYTE 만큼 주소가 증가한걸 볼 수 있다

 

위에 연산이 주소를 나타내는 것이기에

주소의 값을 나타내는 간접 참조 연산자 ( * ) 를 같이 사용하면 그 주소가 가지고있는 값을 확인할 수 있다

 

여기서 해당값의 주소를 알려주는 주소연산자( & )를 사용하면

다시 주소가 나오겠지ㅋㅋㅋ

 

배열과 포인터의 차이점이라면

 

1. 포인터는 변수이고

배열의 식별자는 상수라는 점이다

 

2. Sizeof를 사용했을 때

a 와 b 모두 첫번째 값의 주소를 나타내지만

 

포인터는 주소의 크기 ( 자료형의 크기가 아님 )

배열은 배열의 크기가 출력된다

 

 

  • 구조체

배열에 여러 데이터형을 넣고 싶다 -> 구조체

 

각 항목을 멤버

 

구조체 태그를 식별자로 사용가능

 

태그를 생략할 수 있는데 태그가 없으니 변수를 생성할 수 없다, 그렇기에 변수 정의와 함께 사용

앞으로 MyStruct밖에 사용 불가

 

멤버들이 저장되는 메모리크기는 가장 큰 자료형의 크기로 저장됨

 

이러한게 많이 비효율적이라 생각이 들면 비트필드 이용

 

지정한 비트만큼만 데이터가 저장된다 ( 컴파일러에 따라 다르지만 VsC++에서는 정수형 & bool형 으로만 사용가능 )

단 자료형보다 큰 비트제어는 불가능하다

 

Signed 일경우 맨 앞자리는 부호비트로보고 나머지를 계산

ex)

1) b에 13를 넣는다

2) 13 = 1101 (이진수)

3) b는 3비트만 사용하여 "101"로 데이터가 잘림

4) 맨앞은 부호비트로 채용, 음수가 됨

5) 나머지 데이터 "01"이 음수이므로 음수형으로 2의 보수를 취한다 [ 십진수를 음수 이진수로 표현 2의 보수 취하기]

6) 그럼 "10" 이 되므로  3이다

6) 최종적으로 -3 데이터 가 들어가있는게 된다 

 

unsigned는 부호비트가 없으므로 어디서 잘리는지만 보면 된다

ex)

1) c에 5를 넣는다

2) c = 101 (이진수)

3) c는 2비트만 사용하여 "01" 로 잘림

4) 최종적으로 1저장

 

※ 구조체와 클래스 차이 공부 필요

 


  • 공용체 (Union)

가장 큰 변수의 메모리를 모든 변수가 공유함

 

 

공용체 , 익명공용체

 

유니온의 크기는 가장 큰값이여도 각자 사이즈는 다르다
같은 주소

이런식으로 const도 바꿀수있나보다

 


  • 열거형

상수형에 이름붙인 나열된 자료형

 

경험상 어떠한 카테고리안의 항목을 다룰 때 편한거 같다

 

예를들어 플레이어의 상태 카테고리라면

이런식으로 쓸수있다

태그명(위에서 State)는 변수를 만들지 않을거면 사용하지 않아도 된다 , 상수값 중복가능

 

데이터형이 Enum형일수도있고 int형으로 될수도있다 그렇기에 산술연산이 가능한데

 

산술연산 가능은 컴파일러마다 다르다 (하지만 이식성을 위해 쓰지말자), 대입연산과 비교연산 가능

 

따로 초기화 해주지 않는 이상 계속 0부터 1씩 증가되어 값이 대입된다

[ 중간에 딱 한값만 100으로 넣어도 그뒤에는 101, 102 .... 이런식이다 ]

 

변수에 값 대입시에 무조건 해당 Enum에 정의된 열거자(식별자)를 넣어줘야하는데 

ex) playerState = Idle;

 

명시적인 데이터형 변환을 사용하면 가능하다

ex) playerState = State(99) // "99"라는 int형을 State형으로 강제 형변환

 

저렇게 99라는 없는 상수도 넣을수 있는데 최대값 범위가 공식으로 있다고 하는데 사실 잘 모르겠다 해봤는데 

그 공식에서 나온 값을 넘어서도 출력이 잘 된다

 

추가+

enum은 몇가지 정수형에 의해 표현되는데

C++98 이하 버전에서는 실행하는 방식에 따라 달랐지만 C++11이후로 선택할수있는 문법이 생겼다

 

  • 배열

선언 - typename Name [Size];

 

0부터 시작

 

 

배열의 이름은 수식에 사용시 자료형의 포인터 형으로 사용된다

자료형의 포인터 형으로 사용될 때 배열의 전체 주소가 아닌 첫번째 원소의 주소이다

arr1에 마우스를 가저다 대면 나오는 창, int* 라고 한다

 

이 때문에 배열과 배열의 대입이 이루어지지 않는다

 

그리고 여기에 얹어서 두가지 특징이 더 있는데

 

첫번째. 배열의 이름은값을 바꿀수 없는 상수(r-value)라는 점이다

 

두번째.  [0]번째 데이터의 주소와 배열 전체를 의미하는 주소는 같다

 


 

  • 문자열

연속되어 저장되어 있는 문자들

 

char text [10] = { 'a', 'b', 'c' }; // 는 a,b,c가 각 배열 인덱스에 복사되어 들어간다

char text [10] = "abc"          // 는 abc가 한번에 들어간다

 

char text [ ] = "abc" // 가 되는 이유는 초기 값을 정해주었기 때문

 

상수표현 " ~ "  -> 자료형이 const char *

 

문자열을 다룰때 끝을 알아야 그만큼 데이터를 사용할텐데 Null을 끝으로 인식하는 방법으로 사용한다

그렇기에 문자열상수( " ~ " )는 우리가 별도로 Null을 넣지 않아도 마지막에 Null이 자동으로 붙는다

그래서 Null이 붙은 크기가 고정되어야 문자열상수의 데이터를 온전히 사용할 수 있기 때문에

( " ~ " )는 const형이 붙어 문자열 상수라 한다

 ' ~ ' 와는 다를 수 밖에 없다

 

cout에서 char * 을 출력할때 다음주소를 한글자씩 출력하면서 Null을 찾는다

Null을 붙여주지 않아서 Null을 찾을때까지 출력하여 이상한 값이 나온다

 

 

char e = "a"; //불가능

char e = "abcd"; //불가능

char * e = "abcd"; //불가능

 

모두 대입하는 문자열 상수의 자료형[ const char * ]과 맞지 않다

마지막 불가능 코드는 "abcd"는 수정이 되지 않는 자료형인데 char * 은 수정이 가능한 자료형이다 그렇기에 대입 불가

 

입력 함수

cin = 화이트스페이스를 끝으로 간주 & 개행문자를 남김

※ 단 화이트스페이스, 개행문자가 제일 처음나오면 멀쩡한 문자가 나올때까지 무시

 

cin.get( ) = 개행문자를 끝으로 간주 & 개행문자를 남김 

cin.getline( ) = 개행문자를 끝으로 간주 & 개행문자를 읽고 폐기

 

strcpy = 문자열 복사

strcat = 문자열 추가

strlen = 데이터형의 길이가 아닌 문자열의 길이 반환

 

 


 

  • String

기존 C에서 Null 으로 마지막을 알아내는 방법과 달리

문자의 길이를 따로 저장하기에 Null관련 이슈가 없다

 

다만 실제로는 null로 끝나는 문자열과의 호환성을 위해 메모리상에 null을 포함하긴 한다

 

문자열 다루는 더 나은 방법의 클래스

 

들어오는 데이터에 따라 크기 자동 조절

 

배열처럼 인덱스 참조 가능

 

==, = , + , += 연산 가능

 

 

strncpy

strncat

.size( )

std::getline( ) - string용 getline


 

  • raw 문자열

문자열 하나하나가 모두 독립적인 문자열 (특수문자까지도)

 

R"~(   로 시작해서

)~"로 끝나야한다

 

 


 

많은 도움이 된 글

https://blog.naver.com/tipsware/221018307213

 

'문자열 상수'의 잘못된 사용에 대하여

C 언어 관련 전체 목차 : http://blog.naver.com/tipsware/221010831969 1. 배열로 선언된 변수의 초기화 ...

blog.naver.com

 

+ Recent posts