일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 등록금0원
- 배윤슬
- 제거된값 첨부하기
- 직선의방정식
- 윤파고
- 허스켈그래프
- 2023채용박람회
- 숫타니파아타
- playground배열
- 최단경로문제
- 청년도배사 이야기
- 정보처리기사공부방법
- 나르시스트
- 티스토리챌린지
- 데이터베이스시스템
- 쌍대성원리
- 그래프2
- 이런 사람에게 "절대" 돈과 시간 쓰지 마세요. (이헌주 교수 3부)
- 아이엔이야기
- wxMaxima install for mac os
- 오블완
- 다자녀장학금
- 무소의뿔
- kgol
- 합의정리
- 이분그래프
- 오일러투어
- 집착형
- 맥북에서 wxMaxima 설치
- wxmaxima
- Today
- Total
사적공간
홍정모C++(섹션 5~ 섹션 17 6.11 메모리 동적할당 new 와 delete) 본문
지역변수의 범위와 지속 기간 (scope,duration)
동적 할당을 하면 범위와 지속 기간이 분리됨.
선언은 여기저기 가능. 정의는 한 곳에서 나와야 함.
scope resolution operation = '::'
c++ 17 에선 아래와 같은 문법사용 가능
전역변수, 정적변수, 내부연결, 외부연결
전역변수는 가급적 수를 줄여야 함.
전역변수는 잘 안 쓰게 되는데, 다른 파일에 전역변수가 값을 바꾼다면 감당이 안됨.
이름으로 구분짓거나 설계를 잘 하거나 객체지향으로 전역변수를 안쓰거나
이렇게 외부파일에 정의되어 있어
해결은?
정의된 파일에 가서 변수를 초기화를 해주면 됨.
만약 익스턴이 정의된 파일에서 한 번 더 초기화를 해주면 에러가 뜸.
Using문과 모호성
my_var가 두 네임스페이스의 영향을 받아서 애매모호함.
using namespace는 큰 영역에 넣으면 큰 오류를 초래할 수 있다. 좁은 영역에 넣고 쓰는게 좋음.
auto 키워드와 자료형 추론
함수의 매개변수에는 auto를 못 씀. 내가 넣는 실 매개변수에 따라 함수에 들어가는 자료형이 결정되게끔 하려면 auto가 아니라 템플릿을 써야 함.
임시형 형변환(coersion)과 명시적 형변환(casting)
C++에서 static_cast<int>(c)와 (int)c는 둘 다 형 변환을 수행하지만, 작동 방식과 의미에는 차이가 있습니다.
1. (int)c (C 스타일 캐스트)
- C 스타일 형 변환으로, C++에서도 사용할 수 있습니다.
- 모호하고 위험합니다.
- 여러 종류의 캐스트(static_cast, reinterpret_cast, const_cast, dynamic_cast)를 모두 포함할 수 있으며, 컴파일러가 적절한 변환을 선택합니다.
- 코드에서 의도를 명확히 알기 어렵습니다.
- 변환 과정에서 예기치 않은 동작이 발생할 수 있습니다.
- 용법:
char c = 'A'; int i = (int)c; // C 스타일 캐스트
2. static_cast<int>(c) (C++ 스타일 캐스트)
- C++에서 도입된 명시적 형 변환 방식입니다.
- 안전하고 명확합니다.
- 변환이 명시적으로 컴파일 타임에 검증됩니다.
- 불필요하거나 위험한 변환은 컴파일러가 경고하거나 오류를 발생시킬 수 있습니다.
- 어떤 종류의 캐스트인지 명확히 드러나므로, 코드의 가독성과 유지보수가 더 쉽습니다.
- 용법:
char c = 'A'; int i = static_cast<int>(c); // C++ 스타일 캐스트
차이점 비교
특성 (int)c static_cast<int>(c)
역할 | 모든 형 변환 수행 가능 | 컴파일 타임 검증된 형 변환 |
안전성 | 낮음 | 높음 |
명시성 | 낮음 | 높음 |
사용 권장 | C 스타일 코드에서 사용 | C++ 스타일 코드에서 사용 |
가독성 | 낮음 | 높음 |
결론
C++ 코드에서는 **static_cast**를 사용하는 것이 권장됩니다. 이는 코드의 의도를 명확히 하고, 예상치 못한 동작을 방지하는 데 도움이 됩니다.
(int)c는 여전히 동작하지만, 모호하고 덜 안전하기 때문에 가급적 사용하지 않는 것이 좋습니다.
문자열 소개 std::string
열거형 enumerated types
enum은 integer와 일부 호환된다. 그리고 casting을 활용한다.
영역 제한 열거형 (열거형 클래스) scoped Enumerations (Enum Class)
자료형에게 가명 붙여주기
읽기 쉬우니 유지보수 하기 쉽고, 고정너비 정수에서 사용?
구조체 struct
#include <iostream>
#include<iomanip>
#include<limits>
#include<string>
#include<cstdint>
#include<vector>
using namespace std;
struct person
{
double height;
float weight;
int age;
string name;
};
void printPerson(person ps) {
cout << ps.height << " " << ps.name <<" " << ps.weight <<" "<< ps.age;
}
int main()
{
person me;
me.age = 20;
me.name = "Jack";
me.weight = 50;
me.height = 177;
person mom{ 170,50,23,"udi" }; // uniform 초기화랑 똑같네
person dad;
printPerson(me);
return 0;
}
. 은 멤버선택 오퍼레이터 연산자
구조체 안에 함수를 넣고
#include <iostream>
#include<iomanip>
#include<limits>
#include<string>
#include<cstdint>
#include<vector>
using namespace std;
struct person
{
double height;
float weight;
int age;
string name;
void print() {
cout << height << " " << name << " " << weight << " " << age;
}
};
int main()
{
person me;
me.age = 20;
me.name = "Jack";
me.weight = 50;
me.height = 177;
person mom{ 170,50,23,"udi" }; // uniform 초기화랑 똑같네
person dad;
//printPerson(me);
me.p
return 0;
}
= 어싸인먼트가 생각대로 동작 안할 수도 ..
구조체 안에 구조체를 넣을 수도 있음.
함수를 호출해서 구조체 변수에 리턴값으로 받은 구조체를 넣을 수도 있음.
구조체에 있는 초깃값으로 초기화를 할 수도 있음.
최적화: 구조체 안에 데이터 변수의 순서나 기타 다른 것들을 바꿔서 컴퓨터가 더 빠르게 처리하게 좋게 만드는 것.
제어 흐름 소개
exit(0)은 디버깅할 때 많이 씀.
여기서 강의 점프함.
배열 기초[1 of 2] array
배열 초기화
enum과 함께 쓰기 .
이렇게 쓰면 학생수와 딱 맞게 됨.
#include <iostream>
using namespace std;
enum studentName {
JACK,
DASH,
VIO,
NUM_STDUDENTS,
};
int main()
{
int student_scores[NUM_STDUDENTS];
student_scores[JACK] = 0;
student_scores[DASH] = 100;
return 0;
}
컴파일 -> 런타임
런타임의 배열의 개수가 결정되어서 아래처럼 하며 안됨. 컴파일 시점에서 결정되도록 해야 함.
const를 쓴다는 건 컴파일 타임 전에 5가 들어가는 것이 결정된다는 의미
배열의 기초적인 사용법 [1/2]
메인함수에서 찍은 배열의 시작주소와 함수호출로 찍은 배열의 시작주소가 다름
-> 배열의 이름은 그 자체가 주소이기 때문에 앞에 &를 붙이지 않아도 주소를 구할 수 있음. // 그래서 배열의 시작주소의 경우 &를 붙인것과 뺀것의 결과는 같음.
함수의 () 안에 들어가는 형식매개변수는 배열 모양을 하고 있지만 배열이 아님, 배열이 아니라 포인터임.
그리고 마찬가지로 함수 안에 있는 배열의 변수처럼 보이는 것들도 배열 자체가 아니라 배열을 가리키고 있는 포인터임.
그래서 위 '사진1'의 캡처본과 같은 결과가 나오는 것임.
시작주소가 다르게
그래서 함수 안에 있는 포인터 변수에 다시 &를 취해서
주소를 가리키게 하면 메인함수와 호출하는 함수의 배열의 시작주소가 찍히게 되어 똑같은 값이 보이게 됨.
그리고 배열과 포인터의 차이로 인해 사이즈를 찍어보아도 다르게 나오는 걸 알수 있음.
그러나 x64에선 포인터 변수의 사이즈가 8바이트
배열과 포인터는 땔 수 없는 관계
배열과 반복문
나누기를 하기전과 한 후의 캐스팅은 값이 다를 수 있어
함수로 구할 경우 포인터 변수로 구하는 것 주의 (위 내용)
가장 큰값 구하기 삼항연산자
배열과 선택정렬
가볍게 보고 넘어감
정적 다차원 배열
2차원 배열은 동적 할당을 하게 됨.
행렬x행렬, 행렬x벡터를 2차원 배열로 구현해보기 (숙제)
C언어 스타일의 배열 문자열
#include<cstring>
source에 있는 문자열을 const 포인터로 받아서 dest에 붙여넣기
//strcat() 문자열 붙이기
// strcmp() 같은지 비교
포인터의 기본적인 사용법
나에게 연락하려면 이분에게 연락하세요.
이분이 포인터변수,
*&x == x // *와&가 만나서면 서로 소멸되는 것처럼 동작함.
이렇게 할 수도 있음.
구지 왜 포인터를 쓸까?
-> 가장 기본이 되는 이유는 배열 때문에 그렇음. 함수 파라미터로 넣으면 전부 복사가 되어서 부담됨. 그래서 포인터로 포인터 주소 시작위치와 개수를 던져줘서 찾아가게 함. // 이후 추가 설명
이렇게 아예 안되진 않지만, 이게 또 해킹의 원리
타입아이디로 데이터의 타입 찍어보기 .
포인터 자체 사이즈는 고정,
구조체에 대한 포인터
실제 작업할 때는 WARNING이 많아서 초기화 안된 변수는 안보일 수 있음.
디버거로 잡음.
널 포인터
포인터 변수에 이상한 주소값이 가리켜 있으면 문제되어서 있음.
C스타일로 0을 넣기도 함.
포인터와 정적배열
메모리 동적할당과 관련있음
함수 매개변수에 int array[ ] 와 int *array는 사실 같음.
함수로도 역참조 해서 잘 나오는 거 확인
함수로 배열을 전달받고, 함수에서 역참조로 배열의 시작주소에 있는 공간에 100을 넣음
그리고 메인함수에서 다시 배열을 찍어봄
바뀐 걸 확인할 수 있다.
*(ptr+1) 이 7인것을 확인
구조체 안에 배열을 넣고, 구조체를 보내버림.
구조체에 함수를 보내보고, 구조체 안에 배열의 사이즈를 찍음
이번에는 주소를 던져주고 포인터로 받아서 했지만 결과는 위와 동일
포인터 연산과 배열 인덱싱
집을 찾을 때, 301호의 옆집, 302호의 앞집 이런식의 개념임.
uintptr_t 는 언사인드인티저포인트 타입으로 더 정확한 형변환 방식
포인터로 구현하면
문자열
C언어 스타일의 문자열 심볼릭(기호적) 상수
자료형 앞에 const 가 붙어야지 '기호적 상수'처럼 쓸 수 있음.
컴파일러가 너희 문자열이 같으니까 메모리를 같이 써라.
글자를 바꾸면 주소도 달라짐.
리턴타입에도 쓸 수 있다.
문자포인터의 특성
cout 에서 문자열은 특별하게 처리한다고 생각해야 함.
문자배열의 시작주소가 COUT을 만나면 주소를 찍지 않고, 문자열이 아닐까해서 안에 값을 NULL이 나올때까지 출력함.
메모리 동적할당 new 와 delete
1.스테틱 메모리 얼로케이션, 전역, 스테틱.. 프로그램이 끝날때까지 가진것
2.자동메모리 할당: 변수 선언, 정적 배열 선언했을때, 블록 바깥에 나가면 사라지는 것
3. 동적 메모리 할당 : 포인터와 관련지어
정적 메모리 할당은 스택으로 가고 스택은 크기가 작고
동적 메모리 할당은 힙에 들어가고 힙은 크기가 큼.
할당받은 메모리를 os에게 다시 돌려줘야 함.
-> 컴퓨터 메모리를 효율적으로 쓰기 위해
주의할 점
딜리트 ptr 이 없어도, 오에스가 메모리를 엄마만큼 줄 걸 기억하고 있어서 자동으로 메모리를 걷어가서 문제가 안생김.
딜리트 ptr은 os가 걷어가기 전에 미리 반납하겠다는 의미
메모리는 이미 반납했는데, 주소는 변수에 따로 저장되는 거라서 그대로 따랐갔는데, 알수 없는 값이 나오게 됨.
하지만.. 실제로 해보면..
달랐음. ide가 업뎃되면서 바뀐게 있나봄
#include <iostream>
#include <typeinfo>
using namespace std;
int main()
{
int* ptr = new int{7}; // os에게 4바이트 공간을 받고 주소를 받음.
cout << ptr << endl;
cout << *ptr << endl;
delete ptr; // os에게 메모리 반납
ptr = nullptr; // 아무런 의미도 없는 공간이에요. 기록
cout << "After delete" << endl;
if (ptr != nullptr) // ptr이 의미가 있을 때만 역참조를 할 수 있게 함.
{
cout << ptr << endl;
cout << *ptr << endl;
}
return 0;
}
다른 프로그램이 메모리를 차지하고 있어서 메모리를 할당 받지 못하는 경우가 있음.
그때 그냥 프로그램을 죽이거나
기다렸다가 다시 할당받는
메모리 할당에서 에러가 있는 경우 견디는 법
nothrow (예외처리 방법 중 하나 )
ptr2도 반납해야 하는데, 안하면 에러 날 수 있어서 꼼꼼하게 하거나 안전장치 이용
메모리 누수
메모리를 받아서 만들기만 하고 쓰질 않음. 어디 있는지도 알 수 없음.
이런 실수를 많이 함. (지우는 것을 깜빡함)
<확인방법>
작업관리자에서 메모리 사용량이 Peak 를 찍으면서 느려짐.. 어딘가 메모리가 세고 있음
debug > show windows > diagnostic tools..
메모리 사용량이 끝없이 올라가는 것이 보임.
delete ptr; 을 넣으니 메모리를 반납하고 다시 받기를 반복해서 메모리 사용량이 수평을 그리는 것을 볼 수 있음
new와 delete는 os를 다녀와야 해서 느리기 때문에 가능한 적게 사용하는게 프로그래밍을 잘 하는 것임.
다른 언어들은 이걸 사용자가 통제할 수 없어서 느려지는 걸 관리할 수 없는 문제가 있음. c++ 은 통제할 수 있어서 최적화에 좋음. 단 실수하기 쉽고, 어려운 단점이 있음.
동적 할당 배열
'KNOU_CS > C++' 카테고리의 다른 글
문자 포인터 출력 (0) | 2024.12.13 |
---|---|
for each 배열 값 출력 (0) | 2024.12.12 |
홍정모 C++(섹션 1~3) (0) | 2024.11.27 |
3x3 배열에 문자 주석 아래 행 순서부터 출력 (0) | 2024.11.01 |
3행 10열 문자배열 각 행에 문자를 입력받고, VECT 배열에 저장된 문자가 있는지 확인(행마다 다른 길이로 탐색) (0) | 2024.11.01 |