안녕하세요, 어서 오세요 이제 동적 메모리 할당을 이해했습니다
구현해야 하고 C# 코드에서 어떻게 하는지 알아야 하죠
아주 중요한 기능 세 가지를 배울 거예요 멍텅구리,
굳은살, 재구성
이름이 있는 게 보이시죠 메모리 할당된
콜록과 재분포
메모리를 할당하는 가장 간단하고 일반적인 방법은 맬록이라는
표준 라이브러리 기능을 이용하는 거죠
런타임에 동적 메모리를 할당하죠
이 함수를 호출하려면 표준 lib 헤더 파일을 포함해야 해요
인수로 할당하고 싶은 바이트의 메모리를 명시하죠
이 함수에서 반환되는 것은 할당된 첫 바이트 메모리의 주소인데요
주소가 반환되면 포인터에만 주소를 넣을 수 있어요
이것이 동적 메모리 할당이 포인터를 통해서만 가능한
이유입니다 포인터는 주소를 반환하기 때문이죠
포인터에 주소만 입력하면 돼요 포인터는 주소를 저장하거든요
간단한 구문은 이렇게 하는 거예요
보통 포인터를 만들 때는 그럴 필요가 없어요
포인터를 만들어 null로 설정할 수 있어요
그리고 다음 대사에서 멍텅구리 소리를 내죠
표준 구문이 있어요 int 포인터를 만드는 거죠 int
형식에 대한 포인터요
그리고 멍텅구리를 호출하는 게 보이시죠
그리고 쇼핑몰을 선택합니다 쇼핑몰은 100 바이트를 생성합니다
그리고 int 포인터에 캐스팅을 할 거예요
몰록은 주소만 반환하기 때문에 엔드 포인터로 캐스트해야
합니다 주소가 int 포인터를 저장하기
때문이죠
이게 표준 방식이에요
100 바이트의 메모리를 요청하고
메모리 블록의 주소를 p로 할당하는 거죠
할당된 100 바이트의 첫 번째 int 위치를 가리키죠
한 조각에 정수가 4 바이트니까 25 int
값을 담을 수 있죠
4 바이트라고 가정해 보죠
여러분이 실행하는 시스템에 따라 클 수도, 작을 수도 있죠
뭐가 문제인지 아시겠죠? 이 코드는 다른 시스템에선 작동하지
않아요 왜냐하면 가정에 근거해 할당하니까요 int 크기에 대한
가정에 근거해서요
숫자가 100인 청어를 이런 식으로
사용하는 건 좋지 않아요
여러분이 원하는 건 사이즈의 연산자를 이용하는 거죠
int가 4 바이트라는 가정을 제거하는 것이 낫겠군요
쇼핑몰 인수 안에 25개의 정수를 위한 공간을 할당하고 싶다면 할당하고
싶은 정수 개수를 지정합니다
그런 다음 그 정수들의 크기에 곱하는 거죠
이렇게 하면 코드가 훨씬 더 이동하기 쉬워지죠
이 코드는 이제 다양한 시스템 다양한 운영 체제 다양한 아키텍처에서 작동하죠
반환 값과 주소를 여전히 캐스팅해야죠 형식 int를 가리켜야
하니까요 int*라고 하세요 유일한 차이점은 크기of연산자를 쓴다는 거죠
크기가 큰 연산자는 메모리를 할당할 때 아주 중요합니다 멜록이나 캘록
혹은 재갤록을 사용할 때요
항상 사이즈오프연산자를 사용합니다
유형을 할당하기 위해서요 그리고 그걸 몇 개의 특정
숫자로 곱합니다 25 int를 저장하고 싶다면
25라고 하죠
위에 있는 몰록 인수는 25개의 타입 int 값을 수용할 충분한 바이트를
나타냅니다 사용 가능해야 하죠
배우들 좀 보세요 함수로 반환된 주소를 변환합니다
type-pinter로 int와 int-pinter로요
말로크는 void 타입의 포인터를 반환해요 그래서 유용하죠
주소를 반환하지만 void 포인터예요
void 포인터에 관해 얘기한 거 기억하시죠? void 포인터가
왜 유용한지는 함수를 통해 다양한 매개 변수를 받아 void 포인터를 리턴할 수
있기 때문이죠 void 포인터를
리턴하는 능력도 보셨죠
하지만 데이터를 할당하고 참조를 해제하려면 캐스트를 해야
해요
캐스팅하기 싫으면 보이드 스타 P 넘버라고 하죠
캐스팅을 안 하면 나중에 다시 캐스팅을
해야 했어요
그래서 말로크를 캐스팅해야 해요 주소를 반환하고 int 유형을 가리키길
원하죠 void 유형을 반환해요
어떤 바이트든 요청할 수 있어요
하지만 시스템에 따라 달라요 시스템에 메모리가 얼마나 있느냐에 따라서요
따라서 엄청난 바이트를 생성하거나 어떤 한계가
있다면 실패할 수도 있죠
실패하면 null 값을 반환해요,몰록은 null을 반환하죠
이게 좋은 이유는 포인터가 null을 가리키면 어떤 메모리도 가리키지
않는다는 겁니다 따라서 무심코
메모리를 손상하거나 바꿀 수 없죠
그래서 몰록을 사용한 후에는 사용하기
전에 바로 null을 확인하는 것이
좋습니다 데이터를 할당할
때나 포인터를 참조 해제할 때처럼요
뭔가를 가리키고 있다는 걸 확실히 해야 해요
P 넘버에 대한 메모리를 할당했어요 포인터요 P 넘버가
아니면이라고 하는 거죠
null은 0이라는 걸 기억하세요
그냥 No를 사용하면 돼요 그걸 null에 비교할 필요는 없어요
null과 비교할 수 있어요 가독성과 명시성을 더 높일 수 있죠
그냥 p가 아니라고 하면 돼요 그럼 1이 아니고 Null은
0이 되죠 Null인지 확인할 거예요
Null이면 메모리가 할당될 수
없다는 걸 의미하죠 프로그램에서 메모리를 할당하지 못하면 문제가 생기죠
메모리 할당 오류를 해결하기 위해 보통 이 코드에서
해야 하는 일은 중단하거나 종료 호출을 하거나
프로그램에서 나오는 거죠 프로그램이 메모리를 할당 못 하면 끝장이죠
보통 메모리를 할당 못 하면 사고 중단이라고 하죠
적어도 이렇게 하면 메시지를 표시하고 프로그램을
종료할 수 있죠 프로그램이 계속되도록
하는 것보다 훨씬 낫죠 메모리를 할당할 수 없으니까요
그 메모리를 사용하려고 할 수도 있지만 Null이
될 수도 있기 때문에 프로그램이 중단될 수 있어요 하지만
그 이유는 알 필요가 없죠
콜 스택을 봐야 해요 그 오류를 디버그하는 데 훨씬 더 오래 걸릴 거예요
기억을 버리는 거죠 여러분이 프로그래머이기 때문에
메모리를 할당할 책임이 있습니다 더 이상 사용하지 않을 때는
메모리를 지워야 합니다 메모리는 중요한 자원입니다 특히 내장형
시스템에서는요
필요 없으면 메모리를 쓰지 말아야죠 그 기억을 놓아줘야 해요
더 이상 필요 없는 기억을 놓아주고 싶어하죠
힙에 할당된 메모리는 프로그램이 존재할 때 자동으로 공개됩니다 좋은
거죠 정리 작업이 되니까요
하지만 사용이 끝났을 때 메모리를 공개하는 게 훨씬
좋아요 나가기 직전이라도요
더 깔끔하죠, 항상
무료로 하거나 할당된 후에 항상 메모리를 릴리즈합니다
이 규칙을 따르는 게 좋죠 이건 엄격한 규칙이에요
할당된 메모리는 항상 릴리즈하고요
메모리 누출은 어떤 메모리를 동적으로 할당하고 참조를
보유하지 않으면 발생합니다 그래서 방출할 수 없죠
그걸 참조할 범위를 벗어났을지도 몰라요 풀면 안 돼요
그걸 메모리 유출이라고 하죠 할당된 메모리는 더 이상 사용되지 않아요
이건 루프에서 자주 발생합니다 루프에서 메모리를 할당하면서요
보고할 게 있어요 이 메모리를 할당하죠 루프 안에서 사용하고
루프 밖으로 점프한 다음 더는 풀지 않는 거죠
각 반복문은 그걸 할당하죠
동적으로 할당된 무료 메모리입니다
주소 접근이 가능해야 하죠
사용이 끝나면 보통 무료 메모리를 원하고 할당된
메서드에서 사용하죠
하지만 메모리를 다른 함수에 넘기면 그 함수의
책임이지만 보통은 메모리와 할당된 함수를
방출해야 하죠
동적 할당 메모리 블록을 위해 메모리를 배포하려면
포인터에 주소가 저장된 메모리 블록이요 free 기능을
호출하기만 하면 되죠
이것도 표준 해방어예요 자유 기능에 포인터를 전달하면 돼요
보통 포인터를 넘긴 후에는 null로 설정합니다
왜냐하면 할당된 메모리가 없기 때문이죠
자유 함수는 형식 void star의 공식 매개
변수를 갖고 있어서 어떤 포인터 형식도
넘길 수 있어요
캐스팅 같은 건 안 해도 돼요
p 번호에 메모리가 할당됐을 때 반환된 주소가 포함되어 있는 한 전체
메모리 블록은 추후 사용이 가능하죠 다른 프로그램도 그 메모리를 사용할 수 있죠 여러분의
프로그램도 이제 그 메모리를 사용할 수 있어요
임베디드 시스템에 있을 때는 중요한 거죠
그리고 말씀드린 것처럼 포인터를 null로 설정하세요
포인터가 더는 아무것도 가리키지 않는다는 뜻이니까요
그 기억이 자유로워졌어요
칼록이라는 기능도 있어요
말코손바닥사슴보다 유리한 점이 몇 가지 있죠 몰록과 아주 유사하지만 하는
일은 그 메모리를 주어진 크기에서 다수의 요소로 할당하는 거죠 또한
메모리를 초기화해요
그게 차이점이죠 초기화요 초기화의 중요성에 대해 말씀드렸죠
그래서 항상 데이터를
초기화해서 여러분이 기대하는 데이터가 거기 있다는 걸 이해하려고
하는 거죠
데이터를 구체화하지 않으면 그 안에 어떤 단서도 없는 데이터가 있을 수 있어요
데이터를 항상 무언가로 초기화하세요
칼슘이 좀 더 나아요 효과가 있거든요
인수는 2개 매개 변수는 2개예요
어떤 공간에 필요한 데이터 아이템의 수와 각 데이터 아이템의 크기죠
표준 lib 헤더에서 선언되죠
말코손바닥사슴이라고 부르는 것처럼요 거의 똑같아요
이 예제에서는 정수 포인터를 만들었어요
int 크기의 정수 75개를 할당했죠
두 가지 매개 변수가 필요해요
좀 더 깔끔하죠 곱셈을 할 필요가 없으니까요
말록에서는 75번의 시간제한 종목을 해야 했어요
75개의 int를 생성하는데
각각 4 바이트이고 운영자 크기로 시스템이
반환하는 것이죠
이게 의미하는 건 모든 데이터도 초기화한다는 겁니다 해당 메모리를 할당하지
못하면 반환 값은 null이 될 수 있어요 따라서 중단해선 안 되죠
하지만 말로크와 아주 유사해요 큰 장점은 초기화라는 거죠
모든 int는 0으로 초기화 되고 그건 정말 큰
장점이죠
매개 변수가 둘이라 사용하기가 좀 더 쉬워요
realloc이라는 다른 함수에 대해 얘기해보죠
realloc 함수를 이용하면 이전에 할당했던 메모리를
재사용하거나 확장할 수 있죠
실행하는 동안 메모리가 얼마나 할당되는지를 동적으로
바꾸는 방법이죠
처음에는 많은 메모리를 생성할 수 있지만 나중에는 충분한 메모리가
아니라는 것을 알게 되죠 여기서 할 수 있는 건 재정리록을 호출하는
겁니다 그럼 메모리가 재분배되죠
2개의 인수 값을 기대하죠 초소형 음성 호출로 이전에
전환된 주소를 포함하는 포인터를요
할당된 메모리나 캘록을 가진 포인터를 가지고 있고 크기와 바이트를
할당하고자 하는 새 메모리를 가지고 있죠
두 번째 인수로 명시된 메모리의 양을 할당합니다
두 번째 인수죠 이전에 할당된 메모리의 내용을 전송하고
포인터에 의해 참조되어 자동적으로 할당된 메모리의 양을 알게
됩니다 포인터를 전달하기 때문이죠
그런 다음 새로 할당된 메모리를 추가하죠
텅 빈 포인터를 새 기억으로 돌려보내죠
다른 영화처럼 캐스팅을 다시 해야 해요
재확인을 못 하면 Null을 반환합니다
치명적인 오류일 테니 중단해야 해요
이 작업의 가장 중요한 특징은 원래 메모리
영역의 내용물을 저장한다는 겁니다 메모리를 확장하는 거죠
순서대로 할 수 없기 때문에 조각날 수도 있지만 현재 데이터에
할당할 수 있는 메모리는 여전히 있어요
예를 들어보죠
이 예제에서는 meloc을 사용하고 그 메모리를 재alloc 한 다음
자유롭게 할 거예요.
여기서 캐릭터 포인터를 만들어요
Null로 초기화하지 않을 거예요 그래야겠죠
하지만 가리키는 것에 대해 할당된 메모리는 없어요
포인터를 저장하기 위해 메모리를
할당합니다, 주소죠 그 주소로 가려고 하면 프로그램이 진행될 거예요
이제 무명갈전갱이를 불러요
이건 무명갈전갱이 15마리예요
문자 포인터를 위해 15 바이트를 생성하죠
빈 공간 포인터를 돌려주거든요 str은 포인터로 무엇을 가리키는지에
대해 할당된 메모리를 가지고 있어요.
그 다음 str 복사본을 써서 그것이 가리키는 것에 데이터를 전달할 수
있어요 문자열이요 그리고
주소의 문자열을 인쇄하죠
그럼 15바이트짜리 바이트는 너무 작다는
걸 알게 되죠
다음엔 realloc을 호출하고 str이라는
포인터를 전달합니다 25 바이트를 더 활용하고요 이건 void point를
반환합니다 다시 cast할게요
메모리 제이슨도 있죠
이제 문자열 연결을 호출할 수 있고 문자열 컴에 연결할 수 있죠 이제
제이슨이라 부를게요 출력할 수 있어요
그리고 마지막으로 이 슬라이드에서
가장 중요한 건 메모리 누출이 없도록 프리를 호출하는 거죠
무명갈전갱이에게 전화할 땐 항상 프리 콜을 하세요
코드블록 내부의 예제를 살펴보죠
코드블록 에디터 내의
코드 예제가 있네요
가장 먼저 보셔야 할 것은 표준 lib 헤더 파일을
포함하고 있다는 겁니다 이 파일에 단어형 함수와 realloc
함수 자유 함수가 들어있기 때문이죠
또한 str 함수와 연결, 복사를 사용하기 때문에
문자열도 포함할 거예요 H요
8번째 라인에서 캐릭터 포인터를 만들 거예요
할당된 메모리가 없어요
이걸 null로 초기화해야 해요 아직
아무것도 가리키지 않으니까요 11번 라인에 무명갈전갱이예요
그리고 char의 15배 크기로 설정합니다.
바이트의 char가 다를 수 있으니까요. 그리고
문자 포인터로 설정합니다. blah는 void를 반환하니까요.
그대로 베끼는 거죠
이걸 복사하려 하는데 라인 11에서 아무것도 안 하면 프로그램이
중단될 겁니다 스트링이 지적할 것에 대해 할당된 메모리가 없기 때문이죠
그런 다음 문자열과 주소를 인쇄하죠
이제 재건축해야죠
데이터는 15바이트 이상 저장합니다
25바이트의 realloc도
사용하고요 그리고 char의 크기도 일관성을 위해서 사용하죠
이걸 캐스트하고 제이슨을 포함하는 기존 메모리
위치에 연결하죠 jason을 출력할 거예요 컴이요
마지막으로 20번째 라인에서 아주 중요한 메모리를
풀어주죠
그럼 이걸 실행해보죠 두 번째로 프린트했을
때 보실 수 있는 건 연결이에요
첫 번째 문자열은
메모리를 할당받았고 주소는 000C2918이에요
그리고 새 주소를 만들었어요 인수로 통과한 포인터의 기존 크기를
재분배해서요
000C0CD8은 더 많은 데이터를 할당합니다
기존 json 데이터와 25
바이트가 더 있죠
보시다시피 연결은 작동해요
왜냐하면 콘텐츠를 재설정할
때 jason JSON을 메모리에 두고 확장을 했거든요
그래서 이 녹음을 사용하는 장점이 많아요 녹음과 자유로운 녹음을 사용하죠
이것들을 사용하고 이해하고 싶어하죠 아주 간단한 기능이죠
마지막 슬라이드에서 가이드라인을 살펴보죠
많은 양의 소량의 메모리를 할당하는 것을 피해야 합니다 효율적이지 않으니까요
메모리를 힙에 할당할 때
약간의 오버헤드가 있어요
작은 메모리 블록을 할당하면 큰 블록을 적게 할당하는 것보다 훨씬
많은 오버헤드가 생겨요
필요한 메모리를 할당하세요
하지만 재분배로 두 문장마다 하진 마세요 큰 덩어리로 하세요
필요할 때까지만 기억을 붙잡고 있어요 메모리는 귀한 자원이에요
산더미처럼 쌓이면 더 드물죠
메모리 블록이 끝나면 전화 프리예요
할당된 메모리를 배포하기 위해 항상 메모리를 제공해야 합니다 코드 어디에
할당된 코드를 작성할 때 메모리를 배포할지 결정하세요
포인터에 접근하도록 하세요
포인터를 글로벌로 만들어야 한다면 그렇게 하세요
하지만 보통 함수에서 할당하면 그 함수에서 릴리스해야 해요
다른 기능이 메모리를 방출한다면
그건 좋지 않다고 가정하는 거죠 결합과 종속성이 너무 많아요
만든 사람이 지우는 거죠
그 책임을 다른 일에 떠넘기지 마세요
메모리를 방출하기 전에 할당된 메모리의 주소를 부주의하게 덮어쓰지
않도록 하세요 그럼 메모리 누출이 발생하니까요
따라서 너무 많은 바이트를 입력하거나 넘쳐흐르면 이슈가 발생할
수 있죠
루프 내에서 메모리를 할당할 때 특히 주의해야 합니다
버퍼 오버플로에서 문제가 생길 수 있기 때문이죠
도움이 됐으면 좋겠네요 동적 메모리 할당은 아주 중요하죠
더 친숙해지는 데 도움이 될 과제를 드릴 거예요 하지만
이 개념을 이해하셔야 해요 고마워요