자료구조와 알고리즘
자료구조란
자료의 정의 - 자료는 관찰이나 측정을 통해 발생한 값으로, 문자열, 정수, 실수 등 다양한 형태로 표현할 수 있으며, 컴퓨터에 입력 및 저장을 할 수 있어야 하고, 이를 처리하여 정보로 활용할 수 있다.
자료구조의 정의 - 자료구조는 자료가 어떠한 형태로 저장되어 있고, 이를 어떻게 사용하는지를 나타낸다. 가장 대표적인 자료구조로는 변수 배열 등이 있다.
자료구조의 종류 - 자료구조의 종류는 기본 자료구조, 파생 자료구조, 사용자 정의 자료구조가 있다.
기본 자료구조 | 파생 자료구조 - 기본 자료형을 사용해 만듬 |
사용자 정의 자료구조 - 개발자가 특정한 목적에 맞게 정의해서 사용하는 자료구조 |
|
선형 | 비선형 | ||
숫자(정수, 실수) 문자 |
문자열 배열 * 구조체 * 포인터 |
연결리스트 스택 배열 큐 테이블의 레코드 |
트리 그래프 |
// 배열은 파생 자료구조이면서 선형 구조이다.
* 구조체 - C언어에서 사용되는 데이터 구조의 하나로, 여러 개의 변수를 하나의 자료형으로 묶어서 관리하는 데 사용된다.
* 포인터 - 메모리 주소를 저장하는 변수로, 다른 변수나 데이터 구조에 대한 참조를 가리키는 데 사용된다.
자료에 대한 기본 작업
초기화(initialization) - 자료를 생성할 때 특정 값으로 설정
조회(retrieval) - 자료구조 또는 데이터베이스에서 조건에 맞는 자료원소 또는 * 튜플들을 찾아 가져와서 이를 출력장치에 나타냄
순회(traversal) - 자료구조에서 모든 원소를 한 번만 방문하면서 전체 자료를 처리
탐색(searching) -자료구조에서 목표 원소 또는 탐색키를 갖고 있는 자료를 찾는 작업
삽입(insertion) - 자료구조에 새로운 원소 삽입
삭제(deletion) - 자료구조에서 기존의 원소 삭제. (기억장소가 유지된다는 점에서 소멸과 차이가 있음)
소멸(destruction) - 자료가 사용했던 기억장소를 다른 목적으로 재사용할 수 있게 점유를 해제함
정렬(sorting) - 자료구조에서 자료 원소를 순서대로 나열하는 작업
합병 / 병합(merging) - 두 개 이상의 자료 집합을 하나로 합치는 작업
* 튜플(tuple) - 데이터베이스에서 튜플은 테이블의 한 행(row)에 해당하며, 각각의 열(column)에 대한 값의 조합으로 구성된다.
* 가비지 컬렉션(Garbage Collection) - 프로그래밍 언어에서 동적으로 할당된 메모리 중에서 더 이상 사용되지 않는 객체들을 자동으로 감지하고 해제하는 메모리 관리 기법이다.
* 오름차순 정렬 - 주어진 데이터를 작은 값부터 큰 값으로 정렬하는 것을 의미한다.
* 내림차순 정렬 - 주어진 데이터를 큰 값부터 작은 값으로 정렬하는 것을 의미한다.
알고리즘이란
알고리즘의 정의 - 알고리즘은 '어떤 문제를 해결하기 위한 확실한 방법'을 뜻한다. 즉 어떤 문제를 해결하기 위해 입력된 다양한 자료를 토대로 원하는 결과를 만들어 내기 위한 규칙의 집합이라고 정의할 수 있다.
알고리즘 충족 요건
- 유한성 - 언젠가는 종료되어야 함
- 명확성 - 각 단계별로 무엇을 하여야 하는지를 구체적으로 표현하여야 함
- 입력 - 처리를 위하여 0개 이상 필요함
- 출력 - 1개 이상의 출력을 얻기 위해 알고리즘은 존재함
- 효과성 - 효과적인 방법으로 결과를 만들어 내야 함
알고리즘 분석 기준
구분 | 내용 |
작업 시간 | 수행 시간. *시간 복잡도로 정량적 평가 |
기억장소 사용량 | 주기억장치 사용량. *공간 복잡도로 정량적 평가 |
단순성 | 수행 과정의 단순성. 정성적 평가 |
* 알고리즘 - 어떠한 상황에 주어진 문제를 효율적으로 해결하기 위해 설계된 것을 의미한다. 알고리즘은 일상생활에서도 길 찾기, 여행 일정계획, 음악 추천, 상품 광고 등에 다양하게 활용되고 있다.
시간복잡도 - 특정 알고리즘이 어떤 문제를 해결하는 데 걸리는 시간. Big-O 표기법 사용
경우의 수 | 내용 | 표기법 |
최선의 경우 | 한 번에 찾음 | Big-Ω |
최악의 경우 | 배열의 길이만큼 걸림 | Big-O |
평균의 경우 | 배열의 길이 중간만큼 걸림 | Big-θ |
배열의 시간 복잡도
종류 | 설명 | 대표적 사례 |
O(1) | 상수형. 데이터 수에 관계 없음 | 해시 테이블 |
O(log₂ n) | 로그형. 데이터 수에 따라 조금씩 증가함 | 이분 검색 |
O(n) | 선형. 데이터 수에 따라 산술급수적으로 증가함 | 트리 운행 |
O(n * log₂ n) | 선형 로그형. 로그형과 선형의 곱 | 퀵 정렬 |
O(n²) | 평방형. 데이터 수에 따랄 기하급수적으로 증가함 | 삽입 정렬 |
O(n³) | 입방형. 평방형보다 더 기하급수적으로 증가함 | 3차원 처리 |
O(2ⁿ) | 지수형. 입방형보다 더 기하급수적으로 증가함 | 하노이 타워 |
O(n!) | 계승형. 지수형보다 더 기하급수적으로 증가함 | 순열 |
// 수행 시간이 짧은 시간 복잡도
-> O(1) < O(log₂ n) < O(n) < O(n * log₂ n) < O(n²) < O(n³) < O(2ⁿ) < O(n!)
알고리즘에 따른 시간 복잡도의 예
공간 복잡도 - 입력 크기에 대해 어떠한 알고리즘이 실행되는 데 필요한 메모리 공간의 양. Big-O 표기법 사용
// 1차원 배열 = O(n), 2차원 배열 = O(n²)
// n개의 int(4byte)형의 데이터 = n * 4byte = O(n)
알고리즘 표현 방법
서술적 표현 - 사람이 사용하는 자연어로 표현
순서도 표현 - 약속된 기호로 작업 과정을 나타내는 순서도로 표현
// 순서도 기호(교과서 22p), 순서도 예시(교과서 23p - 유클리드 호제법으로 최대공약수 구하기)
- 직선형 - 처리과정이 순차적으로 나열되는 순차 구조
// 세 값을 입력받아 차례로 누적하여 출력하기 - 분기형 - 조건에 따라 처리를 달리하는 선택 구조
- 반복형 - 조건을 만족하는 경우에 처리 작업을 반복하는 반복 구조
의사코드 표현 - 일반적인 언어로 코드를 흉내 내어 표현
의사코드를 사용하는 이유
- 전체 흐름을 사전에 파악하고, 논리적인 오류를 초기에 발견할 수 있다.
- 나중에 프로그램 코드를 읽고 디버깅하거나 수정해야 하는 개발자에게 도움이 된다.
- 컴퓨터 프로그램 알고리즘이 어떻게 실행되어야 할지, 또는 어떻게 실행될 수 있는지 보여준다.
- 코드 입력, 테스트, 디버그 단계에서 수정하는 것보다 의사코드 설계 단계에서 미리 작업하는 것이 훨씬 경제적이다.
- 프로그래믜 문제를 해결하기 위한 도구로, 또는 다른 사람과 프로그램의 흐름에 대해 소통하는 방법으로 활용한다.
- 순차적 명령문
1. 주문 목록 확인()
2. 결제 내역 확인()
3. 영수증 발행()
4. 상품 포장()
5. 상품 발송() - 조건문(선택구조) - if, then, else, endif 등
if 현재시각 < 12시 then
현재시각 앞에 AM을 붙인다.
else
현재시각 앞에 PM을 붙인다.
endif - 반복문
- for문 - 'for i = 숫자 1 to 숫자 2 do'명령의 형식으로 작성한다.
for i = 1 to 100 do
sum = sum + i
endfor - while문 - while로 시작, endwhile로 종료, 조건이 만족될 때만 반복문이 실행된다.
- for문 - 'for i = 숫자 1 to 숫자 2 do'명령의 형식으로 작성한다.
- 의사코드 예제
- 로그인 처리 과정
"사용자로부터 필요한 정보(아이디, 비밀번호)를 입력받는다.
데이터베이스에서 필요한 내용을 가져온다.
아이디가 일치하는지 확인한다.
비밀번호가 일치하는지 확인한다.
비교 결과에 따라 로그인 처리를 하여 해당 페이지로 이동한다."
- 의사코드 수정하기
장점 - 수정하거나 추가해야 하는 부분을 나중에 채울 수 있다.
컴퓨팅 언어를 사용한 코딩 - 프로그래밍 언어로 직접적으로 표현
- 알고리즘 자체가 코드가 됨 = 알고리즘을 구체화할 필요 x
- 특정 프로그래밍 언어로 작성 -> 해당 언어 알지 못하면 이해 어려움. / 보편성 떨어짐.
알고리즘 작성에 사용되는 제어 구조
순차 구조 - 시작부터 끝까지 차례대로 작업이 진행되면서 명령 실행
선택 구조 - 조건에 따라 실행 흐름이 달라지는 것
반복 구조 - 작업이 진행되다가 어느 시점에서 반복하는 부분이 포함된 것
재귀 구조 - 함수 내부에서 함수가 자기 자신을 또다시 호출하는 구조
점프 구조 - 프로그램의 흐름을 도중에 건너뛰는 것
알고리즘 작성의 예
유클리드 호제법 / 유클리드 알고리즘 - 2개의 자연수 또는 방정식의 최대공약수를 구하는 알고리즘의 하나이다.
1. 임의의 두 자연수 num1, num2가 주어졌을 때, 둘 중 큰 값을 num1으로 지정
2. num1을 num2로 나누고 그 나머지를 n이라고 할 때, (num1% num2 = n)
3. n이 0일 때, num2가 최대 공약수이다.
4. 만약 n이 0이 아니라면, num1에 num2값을, num2에 n값을 다시 대입한 후 2. 의 과정을 반복한다.
#includ <stdio.h>
int euclidean(int num1, int num2){
while(1){
int temp = num2;
num2 = num1 % num2;
num1 = temp;
if(num2 == 0) break;
}
return num1;
}
void main(){
int answer = euclidean(78, 66);
printf("%d \n", answer); // 최대공약수 6 출력
}
매직카드
- 0~31 중 숫자 하나를 마음속으로 정하고 다음 카드를 보며 순서대로 '있다', '없다'를 답한다.
- 순서대로 +1, +2, +4, +8, +16을 있다고 답했을 때 더한다. -> 마음속으로 정한 0~31 중 숫자 하나가 나온다.
첫 번째 | 두 번째 | 세 번째 | 네 번째 | 다섯 번째 | |||||||||||||||
1 | 3 | 5 | 7 | 2 | 3 | 6 | 7 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 16 | 17 | 18 | 19 |
9 | 11 | 13 | 15 | 10 | 11 | 14 | 15 | 12 | 13 | 14 | 15 | 12 | 13 | 14 | 15 | 20 | 21 | 22 | 23 |
17 | 19 | 21 | 23 | 18 | 19 | 22 | 23 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 24 | 25 | 26 | 27 |
25 | 27 | 29 | 31 | 26 | 27 | 30 | 31 | 28 | 29 | 30 | 31 | 28 | 29 | 30 | 31 | 28 | 29 | 30 | 31 |
하노이 타워 - 재귀함수를 배울 때 나오는 대표적인 알고리즘 중의 하나로, 재귀함수의 하향식 계산 방식의 강력함을 볼 수 있다.
P(A) = B // A : 원판의 수, B : 이동 횟수
// P(1) = 1
// P(2) = 1+1+1 = 3
// P(3) = 3+1+3 = 7
-> P(n) = P(n-1) + 1 + P(n-1) = 2P(n-1)+1 = 2ⁿ-1
=> 시간복잡도 = O(2ⁿ)
#include <stdio.h>
// a는 출발지, b는 경유지, c는 도착지 변수
void HanoiTower(int n, char a, char b, char c){
if(n==1) printf("원판 %d, %c -> %c\n", n, a, c);
else{
HanoiTower(n-1, a, c, b); // (n-1)개를 출발지 -> 경유지
printf("원판 %d, %c -> %c\n", n, a, c); // n번 원판 이동
HanoiTower(n-1, b, a, c); // (n-1)개를 경유지 -> 도착지
}
}
int main(void){
int n = 4; // 원판의 개수
HanoiTower(n, 'A', 'B', 'C');
return 0;
}
배열이란
배열 - 배열은 같은 타입(type)의 자료를 연속된 공간에 저장하기 위해 사용하는 선형 구조이다.
// 배열 삽입 - 삽입 위치 뒤로 전부 한 칸씩 이동, 마지막 데이터 있으면 삭제됨.
// 배열 삭제 - 삭제 데이터 뒤에 모든 값 앞으로 한 칸씩 이동
배열의 장점 | 배열의 단점 |
데이터의 접근이 빠르다. (직접 접근) 읽기, 쓰기 같은 참조에는 성능이 O(1)이다. 기억 장소를 효율적으로 사용할 수 있다. (데이터 저장을 위한 추가 공간 필요 없음) |
크기 예측이 힘들기 때문에 메모리 낭비가 발생할 수 있다. (실행속도 감소) 특정 위치에 데이터 삽입/삭제 시 자료이 이동이 많다. (배열 데이터가 연속된 메모리 공간에 배치되어 있으므로, 중간에 데이터를 삽입하거나 삭제할 때의 성능은 좋지 않다.) 배열 크기를 충분한 크기로 준비할 때, 사용하지 않는 공간은 낭비를 초래한다. |
#include <stdio.h>
int main(void){
int i, j, b[5][3];
int a[3][5] = {{5, 41, 24, 6, 10}, {50, 33, 20, 15, 11}, {7, 17, 35, 21, 16}};
for(i=0; i<3; i++)
for(j=0; j<5; j++)
b[j][i] = a[i][j];
return 0;
}
구조체란
구조체의 정의 - 배열보다 발전된 개념으로, 서로 다른 타입의 데이터도 하나로 묶어서 사용할 수 있다.
구조체의 선언 -구조체를 사용하려면 먼저 정의를 해야 한다. struct 명령어와 함께 구조체의 이름을 쓰고, {} 안에 하나의 구조체로 묶으려는 변수나 배열의 타입과 이름을 하나 이상 나열한다.
// 구조체 정의와 선언을 따로
struct book{
char title[30];
char writer[20];
int value;
char publisher[30];
};
struct book book1, book2, book3;
// 구조체 정의와 선언 동시에
struct book{
char title[30];
char writer[20];
int value;
char publisher[30];
} book1, book2, book3;
구조체의 초기값 설정
- 하나의 구조체 변수에 초기값 설정
struct book book1 = {"유몰로 읽는 역사", "이덕일 외", 15000, "세종서적"}
// book1의 데이터 타입 = struct book
// book1.title = "유물로 읽는 역사"
// book1.writer = "이덕일 외"
// book1.value = 15000
// book1.publisher = "세종서적"
- 구조체 배열에 초기값 설정
struct book books[] = {
{"김병호의 문화체험", "김병호", 10000, "푸른숲"},
{"인류의 기원", "아서 니호프", 12000, "푸른숲"},
{"0교시 문학시간", "이낭희", 14000, "나라말"}
};
// books[] = 배열로 선언 -> books[]배열 내애서 struct book 타입의 데이터 가질 수 있다.
// 배열의 인덱스는 0부터 시작
// books[1].title = "인류의 기원"
// books[1].value = 12000
// books[2].title = "0교시 문학시간"
// books[2].value = 14000
중첩 구조체 - 구조체의 멤버로 또다시 구조체를 내포하고 있는 구조체
// 구조체의 멤버(member) / 필드(field) = 구조체 안에 선언된 변수나 배열
struct personal_info{
char name[20];
char address[50];
char tel_no[16];
char e_meil[50];
};
struct book{
char title[30];
struct personal_info writer;
int value;
char publisher[30];
} b1;
b1 | title | |
writer | name | |
address | ||
tel_no | ||
e_mail | ||
value | ||
publisher |
b1.title = "0교시 문학시간";
b1.writer.name = "이낭희";
b1.writer.address = "관악구 호암로 546";
b1.writer.tel_no = "872-4072";
b1.writer.e_mail = "mirim1@e-mirim.hs.kr";
b1.value = 14000;
b1.publisher = "나라말";
구조체의 패딩(Padding) 현상 - 구조체의 멤버 사이에 빈 공간 생길 수 있다.
// 구조체는 구성원 중 가장 큰 데이터 타입을 기준으로 크기 정해진다.
- 메모리를 효율적으로 접근하기 위해 사용한다.
- 구조체를 정의할 때 패딩 현상을 고려해 멤버 변수의 순서와 데이터 유형을 조정한다.
포인터
포인터의 정의 - 실제 변수의 값이 저장되어 있는 메모리의 주솟값을 저장하는 변수로, 포인터 변수라고도 한다. 데이터를 간접 소유하게 되므로 한 번 이상의 접근으로 데이터를 조작할 수 있다.
int k = 23;
int *ptr = &k;
단순 포인터 - 단순 포인터는 포인터 변수에 데이터의 주소가 주어지고, 한 번의 접근으로 데이터를 조작할 수 있다. 포인터라고 하면 보통은 단순 포인터를 의미한다.
int k = 23;
int* ptr = &k;
printf("k = %d\n", k); // k = 23
printf("&k = %p\n", &k); // k = k의 주소
printf("ptr = %p\n", k); // ptr = k의 주소
printf("*ptr = %d\n", *ptr); // *ptr = 23
printf("&ptr = %p\n", &ptr); // &ptr = ptr의 주소
이중 포인터 - 이중 포인터 변수는 단순 포인터 변수의 주소를 값으로 갖고, 두 번의 접근으로 실제 데이터에 접근할 수 있다.
int k = 23;
int *ptr = &k; // 단순 포인터
int **pptr = &ptr; // 이중 포인터
배열과 포인터 - 배열명은 배열의 시작 주소를 갖고 있으므로 일종의 포인터라고 할 수 있다.
* 배열명 - 배열의 시작 주소를 갖고 있으므로 포인터는 맞지만, 주소값을 변경할 수 없으므로 포인터 변수는 아니다.
int arr[5] = {5, 10, 15, 20, 25};
int* ptr = &arr[0];
printf("arr[0] = %d\n", arr[0]); // arr의 0번째 데이터 5 츨력
printf("*ptr = %d\n", *ptr); // ptr에 있는 arr의 0번째 주소의 값 5 출력
printf("arr[0] = %p\n", &arr[0]); // arr[0] 주소 출력
printf("ptr = %p\n", ptr); // ptr이 가진 arr[0]의 주소 출력
printf("arr[1] = %d\n", arr[1]); // 10
printf("*(ptr+1) = %d\n", *(ptr+1)); // 10
printf("arr[2] = %d\n", arr[2]); // 15
printf("*(ptr+2) = %d\n", *(ptr+2)); // 15
#include <stdio.h>
int main(void){
int i, k=5, *p1=&k, **p2=&p1;
int a[5] = {5, 10, 15, 20, 25};
*(a+3)=**p2+100; // a[3] = 5+100;
p1 = 1; // p1 = a[0];
p1 += 2; // p1 = a[2];
**p2=30; // a[2] = 30;
for(i=0; i<5; i++) printf("%d ", a[i]);
// 5 10 30 105 25
printf("\n");
return 0;
}
구조체 포인터 - 구조체 변수 역시 포인터로 다룰 수 있는데, 포인터 변수가 구조체의 주소를 갖는다.
struct book book1 = {"0교시 문학시간", "이낭희", 14000, "나라말"};
structbook *ptr = &book1;
// 포인터로 구조체 배열 접근할 때 * 과 . 연산자 사용
// book1.value = 14000
// = (*ptr).value = 14000
// = ptr -> value = 14000
// 연결리스트 구현
#include<stdio.h>
void main(void){
struct node{
char data;
struct node* link;
} a, b, c, *p;
p = &a;
a.data = 'A';
a.link = &b;
b.data = 'B';
b.link = &c;
c.data = 'C';
c.link = NULL;
}
정적 할당과 동적 할당
메모리 영역(C프로그램) - 프로그램을 실행하면 운영체제는 실행에 필요한 메모리 공간을 할당한다. 메모리 공간 간은 프로그램을 실행할 때마다 운영체제에 의해 주기억 장치 RAM의 빈 공간에 할당된다.
정적 할당 영역으로 컴파일할 때 점유할 메모리 크기가 결정됨. 실행코드, 전역변수, 지역변수 |
CODE - 함수 실행 코드 |
DATA - 초기화된 전역변수, static 변수 할당 - 프로그램 시작과 동시에 할당 되고 프로그램이 종료되면 메모리에서 소멸 |
|
BSS(Blocked STated Symbol) - 초기화가 되지 않은 전역변수 |
|
STACK - 지역변수 -> 함수 호출하면 점유 ( 지역변수, 매개변수 저장 ) -> 함수 종료되면 소멸 ( 지역변수와 매개변수 소멸) - 연속 공간 사용 -> 설정 크기 이상으로 요구되면 프로그램 실행 중단 |
|
실행 중에 함수를 사용하여 메모리를 할당 또는 해제하며, 기본 제공 크기 이상의 할당이 가능함. | HEAP - 동적 할당 ( 필요할 때마다 동적으로 메모리를 할당하여 사용가능 ) -> 할당함수 - malloc(), callock() -> 소멸 함수 - free() - 불연속 공간 사용 -> 설정 크기 이상으로 요구하여도 다른 사용할 수 있는 공간을 확보하여 할당 |
* 정적 할당 - 프로그램 실행 전에 컴파일러에 의해 메모리 크기가 결정되는 방식
* 동적 할당 - 프로그램 실행 중에 필요한 만큼의 메모리를 동적으로 할당하는 방식
정적 메모리 할당
- 프로그램에서 선언된 지역변수의 메모리 할당에 해당하며, 실행할 때 그 크기가 정해져 있고, STACK영역을 사용한다.
- 사용할 메모리의 크기와 할당부터 해제까지의 저장 기간이 고정적이다.
- 프로그램의 시작부터 종료까지 오랫동안 유지되므로 사용을 최소화하는 것이 좋다.
// 만약 메모리가 stack영역의 기본 크기보다 크다면 stack영역의 기본 크기를 필요한 만큼 늘린다.
// 만약 메모리가 너무 크고, 컴파일 시까지 그 크기를 결정하기 힘든 경우 동적으로 할당한다.
#include <stdio.h>
#define SIZE 1000000 // 1MB
// Visual Studio에서 STACK, HEAP영역의 기본 크기 = 1MB
int main(void){
int a[SIZE] = { 10, }; // 배열 a는 4MB 크기를 요구함.
// stack 영역에 할당된 크기보다 더 많은 크기를 요구 -> 프로그램이 정상적으로 실행되지 않음.
// 해결 방법 = stack 영역을 늘리거나 동적할당으로 처리
printf("%d\n", a[0]);
return 0;
}
* 정적으로 할당된 변수 - 프로그램이 실행되는 동안 메모리에 상주하므로 빠른 액세스와 효율적인 사용이 가능하다. 하지만 변수의 크기가 컴파일 시점에 결정되므로, 실행 중에 크기를 동적으로 조정할 수 없는 제약이 있다.
동적 메모리 할당
- 프로그램 실행 중에 필요한 만큼의 메모리를 HEAP영역에 할당하고 원하는 기간에 사용할 수 있으므로 메모리를 가장 효율적으로 사용하는 방법이다.
- stack영역에서 공간이 부족하면 프로그램 실행이 중지되지만, heap영역에서는 메모리 내 다른 곳에서 공간을 확보해 할당한다.
- 메모리를 요청하고 할당받는 과정에서 시간이 지연되는 성능 저하 현상이 발생한다.
- 개발자가 직접 메모리를 할당(malloc() 호출)하고, 해제(free() 호출) 해야 하므로 * 메모리 누수현상이 발생할 수 있다.
// 일시적으로 메모리가 필요하거나 큰 기억공간이 필요한 경우 동적 메모리 할당이 효율적이다.
// heap영역은 연속된 공간을 사용하지 않아도 되기 때문에 추가적으로 필요한 공간만큼 다른 장소에 메모리를 확보해 프로그램이 계속 실행되도록 한다.
#include <stdio.h>
#include <stdlib.h>
#define SIZE 1000000
int main(void){
int* a = (int*)mallock(sizeof(int) * SIZE);
a[0] = 10;
printf("%d\n", a[0]);
free(a); // 동적 할당은 사용 후, 항상 할당 해제(소멸)해야 함.
return 0;
}
* 동적으로 할당된 메모리 - 적절하게 관리하지 않으면 메모리 누수(Memory leak)와 같은 문제가 발생할 수 있다. 따라서 동적으로 할당된 메모리는 반드시 해제해야 한다.
* 메모리 누수 - 동적으로 할당된 메모리가 프로그램에서 더 이상 필요하지 않은데도 해제되지 않고 계속 유지되고 있는 상태를 말한다.
'전공' 카테고리의 다른 글
Java_컬렉션 제네릭 (7) | 2024.10.08 |
---|---|
파이썬_변수, 자료형 / 제어문, 반복문 / 함수 (2) | 2024.07.10 |
자료구조_비선형 구조 (1) | 2024.07.09 |
자료구조_선형 구조 (4) | 2024.07.09 |
java (0) | 2023.07.06 |