

배열은 정적 자료구조라고 불린다. 그래서 배열을 만들기 위해서는 미리 크기를 정해놓게 되는데, 그렇게 되면 해당 크기만큼의 연속된 메모리 주소를 할당 받게 된다.
연속된 메모리 주소를 갖게되기 때문에 데이터는 인덱스라는 것을 갖게된다. 인덱스를 통해 임의 접근이 가능하게 된다. 따라서 접근과 탐색에 용이하다는 장점이 있다.
하지만 미리 크기를 정해 놓았기 때문에 수정하는 것이 불가능하고, 이미 크기가 정해져 있기때문에 해당 배열 크기 이상의 데이터를 저장할 수 없다는 단점이 있다.
연결 리스트(링크드 리스트)는 동적 자료구조라고 불린다. 그러므로 크기를 미리 정할 필요가 없다. 또한 배열처럼 연속된 메모리 주소를 할당 받지도 않는다.
대신 노드라는 것이 존재하며, 그 노드안에 데이터가 있고 다음 데이터를 가리키고 있는 주소를 가지고 있다.
연결리스트는 크기를 정해 놓지 않았기 때문에 크기의제한이 없고, 그로인해 데이터 추가, 삭제가 자유롭다.
반면에 배열처럼 메모리 주소를 할당 받지 않았기 때문에 임의로 접근하는 것이 불가능하므로, 데이터를 탐색할 때 순차적으로 접근해야 한다.
운영체제(리눅스)가 프로그램(a.out)이 시작되면 메모리 x번지 ~ x번지까지 할당해줌. 프로그램 하나 당 갖게되는 메모리 공간이 있다. 프로그램끼리 서로 메모리 접근할 수 없음(운영체제에서 보호해줌).

프로그램에 설정된 메모리공간은 스택(stack)과 힙(heap) 공간으로 나누어짐.
stack영역은 지역변수, 함수의 매개변수, ... 등이 저장됨. 함수 호출이 끝나면 지역변수 등은 자동으로 스택영역에서 사라짐.
heap영역은 malloc 함수로 선언한 애가 저장됨. 함수가 끝나도 자동으로 사라지지 않음. free를 꼭 해줘야 함. 안 그러면 heap 메모리 공간이 넘쳐나서 메모리 누수가 발생한다.
자바에서는 가비지 컬렉터가 알아서 heap영역에 안쓰는것들을 free시켜줌.
따라서 malloc 함수는 메모리를 동적할당을 해주는 것이다
#include <stdlib.h>
malloc 함수를 사용하기 위해서는 malloc 함수가 포함되어 있는<stdlib.h> 헤더를 포함시켜야 한다.
#include <stdio.h>
#include <stdlib.h>
void main()
{
int* arr;
arr = (int*)malloc(sizeof(int) * 4); // 16바이트(int(4) * 4) 동적할당
arr[0] = 100;
arr[1] = 200;
arr[2] = 300;
arr[3] = 400;
for (int i = 0; i < 4; i++) {
printf("arr[%d] : %d\n", i, arr[i]);
}
free(arr); //동적할당 해제
}
1. 힙(heap)영역에 4바이트 할당(int)
malloc(sizeof(int))
2. void* -> int*
(int*)
malloc은 리턴 값으로 void형 포인터를 리턴한다. malloc은 메모리만 할당하는 함수이기 때문에 어떠한 데이터 형을 사용하는지 알 수 없기 때문이다. 따라서 void포인터를 반환하고 개발자가 알맞게 변환하여 사용할 수 있도록 함수가 설계되어 있다. 그러므로 리턴된 void*을 int*로 캐스팅 한 것이다.
3. *arr 에 대입
arr = (int*)malloc(sizeof(int));
malloc 함수를 사용한뒤 꼭 메모리를 해제 시켜줘야 한다.
#include <stdio.h>
#include <string.h>
#define MAX 200
int g_h_total = 0;
typedef struct human{
int num;
char name[20];
human * next;
}human;
human * head = (human *)malloc(sizeof(human));
void add_h(human * h_num);
void print_all(human * h_num);
int main(){
human h_num[MAX];
for(int i = 0;i < MAX;i++){
add_h(h_num);
}
print_all(h_num);
return 1;
}
void add_h(human * h_num){
h_num[g_h_total].num = (g_h_total + 1) * 2;
sprintf(h_num[g_h_total++].name,"test%d",g_h_total+1);
}
void print_all(human * h_num){
int i = 0;
while(h_num[i].num){
printf("---------\n");
printf("[%d]번지: %d\n",i,h_num[i].num);
printf("[%d]번지이름 : %s\n",i,h_num[i].name);
i++;
if(i >= MAX){
break;
}
}
}
다음시간에 위 코드를 가지고 링크드리스트 구현할 예정...
calloc과 realloc도 malloc함수와 마찬가지로 메모리 동적할당을 해준다.
#include <stdlib.h>
void *calloc(size_t nmemb, size_t size);
calloc 함수는 malloc함수와 마찬가지로 원하는 크기의 메모리를 동적으로 할당받는 역할을 한다.
하지만 malloc 과 차이점이 있다.
1. 할당받을 byte 크기만큼 한번에 할당하는 것이아닌 요소의 크기와 개수로 나누어 매개변수를 받는다.
2. 메모리 할당과 동시에 값을 0으로 초기화 한다.
예제)
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *pMint;
int *pCint;
int count = 5;
pMint = (int *) malloc(sizeof(int) * count);
pCint = (int *)calloc(count, sizeof(int));
...
free(pMint);
free(pCint);
return 0;
}
#include <stdlib.h>
void *realloc(void *ptr, size_t size);
realloc 함수는 할당받은 메모리를 원하는 사이즈로 다시 할당받는 기능을 한다. 여기서 size는 malloc을 사용할 때처럼 할당받을 메모리의 크기 전체를 입력하면 된다.
1. realloc을 통해 다시 할당받은 메모리는 주소 값이 이전과 같을 수도 다를 수도 있다
2. malloc과 마찬가지로 초기화하지 않고 할당한다.
3. 메모리 크기를 줄이는 것도 가능하다
예제)
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *pMint;
int *pRint;
int count = 5;
pMint = (int *)malloc(sizeof(int) * count);
pRint = (int *)realloc(pMint, sizeof(int) * (count +2));
...
free(pRint);
return 0;
}