포인터를 사용하는 이유?
포인터를 사용하므로써 다른 변수에 더 쉽게 접근할 수 있기 때문이다.
나누는 이유는?
->각각의 메모리 영역은 담당하는 역할이 다르기 때문 보안을 위해서도 필요한데, 영역을 나눠 중요한 부분은 읽기전용으로 만든다던가 프로그램에서 문제가 생겼을 때 어디서 문제가 생겼는지 구역을 보면 쉽게 알 수 있다.
코드 영역 (Code / Text 영역)
main()같은 코드들이 저장되는 공간 //읽기전용(함수 내용을 바꾸는 것X)
데이터 영역 (Data 영역)
프로그램 시작 전에 값이 정해진 변수들이 들어가는 곳 ex)int sum = 7;
힙 영역 (Heap)
직접 메모리를 만들어서 쓰는 공간 //malloc이나 new 같은 걸로 필요할 때 만들어 씀. 크기 상관X
스택 영역 (Stack)
함수가 실행될 때, 임시로 필요한 변수들이 들어가는 곳 ex) 지역변수, 함수의 매개변수
예제를 알아보자
#include <stdio.h>
#include <stdlib.h>
int global = 10; // 데이터 영역
int main() {
int local = 5; // 스택 영역
int *heapVar = malloc(sizeof(int)); // 힙 영역
*heapVar = 20;
printf("global: %d\n", global); // 10
printf("local: %d\n", local); // 5
printf("heapVar: %d\n", *heapVar); // 20
free(heapVar); // 힙은 꼭 정리해줘야 함
return 0;
}
이 코드를 보면서 느낀 점은 main함수 안 전체가 코드영역인데 그러면 코드영역에 다른 영역들이 다 있는거니까 코드영역이 더 큰 개념 아닌가? 라고 생각했다.
근데 그게 아니라 코드 영역에서 하는 역할은 코드 안에서 한줄 한줄 읽으면서 어떤 영역에서 실행해야 할지 지시해주는 역할을 한다.
메모리 구조
전역변수 -> 프로그램 어디서든 접근 가능한 변수
지역변수 -> 프로그램에서 특정한 블록에서만 접근할 수 있는 변수
주소 연산자 (&): 그 변수의 메모리 주소를 얻는다.
역참조 연산자 ( ): 포인터가 가리키는 주소에 저장된 실제 값을 가져온다.
간접 참조 연산자 ( ) : 포인터가 가리키는 값에 접근한다.
-> 여기서 선언할 때와 선언 이후의 포인터 연산자는 다르다.
이중 포인터
->포인터를 가리키는 포인터의 값을 저장
#include <stdio.h>
int main() {
int num = 100;
int *p = #
int **pp = &p;
printf("num의 값 : %d\n", num); // 100
printf("*p의 값 : %d\n", *p); // 100
printf("**pp의 값 : %d\n", **pp); // 100
return 0;
}
문자열 포인터
char * p = "apple"; 의 sizeof값은 8이 나온다.
apple 5글자 + null 1글자 + 주소값 2글자
char * p = "apple" ;
printf(" %p", "apple");
여기서 "apple"은 char 형 배열인데, 첫 번째 문자의 주소로 동작함
즉, "apple"은 곧 &"apple"[0] 이므로 포인터임
동적으로 메모리를 할당할 때 힙영역에서 할당을 한다.
프로토타입에는 malloc함수가 있다
int * ptr = (int*)malloc(sizeof(int) * 10);
지정한 바이트(byte) 수만큼 메모리를 할당하며 할당된 메모리의 시작 주소를 반환한다.
free(ptr);
동적 메모리 할당을 해주게 되면 반드시 free를 통해 메모리 해제를 해줘야 한다.
동적 메모리 할당 해제를 하는 이유
-> 힙 영역에 할당된 메모리가 프로그램이 꺼져도 지속되서 메모리 누수위험이 있기 때문이다.
문제설명 :
int a; int *ptr = &a; int **ptr2 = &ptr; int ***ptr3 = &ptr2; int ****ptr4 = &ptr3;
각 포인터 변수의 이름은 "ptr", "ptr2", ..., "ptrN" (N은 수)이 되어야 하고, 코드 형식은 위 예시와 동일해야 한다.
문제풀이 :#include <stdio.h> int main(){ int n; scanf("%d",&n); printf("int a;\n"); printf("int *ptr = &a;\n"); for (int i=2; i<=n;i++){ printf("int "); for (int j = 1; j<=i ; j++){ printf("*"); } if (i == 2) { printf("ptr%d = &ptr;\n", i); } else { printf("ptr%d = &ptr%d;\n", i, i - 1); } } }
두번째 줄 까지는 예외라 그냥 출력 해 줬다..
별찍는 갯수랑 int뒤에 숫자는 개수가 똑같고 마지막 숫자는 -1해주면 된다
for문을 통해서 2부터n까지 돌게한다. 여기서 int를 출력해주고 그다음 for문에서 최소 2가 출력되면서 i값만큼 돌며 별을 출력한다.
별을 다 출력해줬으면 별 출력 만큼(i) 첫번째에다 i ,두번째엔 i-1 을 출력한다.
여기서 i가 2일때는 뒤에 숫자가 없어서 예외처리를 해준다.
세 개의 장대가 있고 첫 번째 장대에는 반경이 서로 다른 n개의 원판이 쌓여 있다. 각 원판은 반경이 큰 순서대로 쌓여있다. 이제 수도승들이 다음 규칙에 따라 첫 번째 장대에서 세 번째 장대로 옮기려 한다.
한 번에 한 개의 원판만을 다른 탑으로 옮길 수 있다.
쌓아 놓은 원판은 항상 위의 것이 아래의 것보다 작아야 한다.
이 작업을 수행하는데 필요한 이동 순서를 출력하는 프로그램을 작성하라. 단, 이동 횟수는 최소가 되어야 한다.#include <stdio.h> void hanoi(int n, int first, int second, int third) { if (n == 1) { printf("%d %d \n", first, third); } else { hanoi(n - 1, first, third, second); printf("%d %d\n", first, third); hanoi(n - 1, second, first, third); } } int main() { int input; scanf("%d", &input); printf("%d \n", (1 << input) - 1); hanoi(input, 1, 2, 3); return 0; }
이 문제를 이해하기 위해서는 일단 어떻게 하노이 탑이 돌아가는지 이해해야 했다. 일단 3개의 원반이 있다고 생각하자. 그 원반을 옮기기 위해서는 탑2번에 위에 2개를 옮기고 마지막에 남은 가장 큰 원반을 탑3에 직접 옮길 수 있다. 이 부분을 재귀함수를 통해 여러번 실행해주고 있다. 일단 main에서는 input 변수를 입력받는다. 이 변수는 원반이 몇개 있는지 입력받는 변수이다. 여기서 printf("%d \n", (1 << input) - 1);
이 코드는 총 이동횟수를 계산하는 부분이다. 그 다음에는 하노이 함수를 통해서 탑 이동 순서를 출력해준다. 하노이 함수에 이동하게 되면 우선 hanoi(n - 1, first, third, second);
여기서 위에 있는 n-1개의 원반을 탑으로 옮기기 위해서 재귀호출을 해주는 부분이다. 만약에 원반이 하나이면 그냥 탑3로 바로 이동하면 되니까 printf를 통해 출력해줬다. 그게 아니면 hanoi(n - 1, first, third, second);
여기부분에서 가장 아래 있는 원판만 남기고 다 탑2로 옮겨주는 부분이다 이제 마지막 원반을 탑3으로 옮겨주는 코드가 바로 printf("%d %d\n", first, third);
이거다. 그리고 임시 탑에 있는 것도 탑3으로 옮겨야 하니까 hanoi(n - 1, second, first, third);
이 코드를 통해서 반복해서 모두 탑3로 이동시킨다.
오늘은 신승원의 생일이다.
박승원은 생일을 맞아 신승원에게 인천국제공항을 선물로 줬다.
공항에는 G개의 게이트가 있으며 각각은 1에서 G까지의 번호를 가지고 있다.
공항에는 P개의 비행기가 순서대로 도착할 예정이며, 당신은 i번째 비행기를 1번부터 gi (1 ≤ gi ≤ G) 번째 게이트중 하나에 영구적으로 도킹하려 한다. 비행기가 어느 게이트에도 도킹할 수 없다면 공항이 폐쇄되고, 이후 어떤 비행기도 도착할 수 없다.
신승원은 가장 많은 비행기를 공항에 도킹시켜서 박승원을 행복하게 하고 싶어한다. 승원이는 비행기를 최대 몇 대 도킹시킬 수 있는가?#include <stdio.h> int parent[100001]; int find(int x) { if (parent[x] != x) { parent[x] = find(parent[x]); } return parent[x]; } void set(int a, int b) { parent[find(a)] = find(b); } int main() { int G, P; scanf("%d %d", &G, &P); for (int i = 1; i <= G; i++) { parent[i] = i; } int cnt = 0; for (int i = 0; i < P; i++) { int plane; scanf("%d", &plane); int docking = find(plane); if (docking == 0) break; set(docking, docking - 1); cnt++; } printf("%d\n", cnt); return 0; }
parent 배열을 1~G번 게이트를 자신으로 초기화하여 각 게이트를 독립된 집합으로 설정힌다.
find(x)는 경로 압축을 통해 x의 대표(가장 큰 사용 가능 게이트)를 찾아 반
set(a, b)는 a 집합의 대표를 b 집합의 대표에 연결해 두 집합을 합친다.
각 비행기마다 요청 게이트 plane에서 find(plane)을 호출해 최대 사용 가능 게이트를 찾는다.
반환값이 0이면 더 이상 도킹 불가해 반복 중단, 아니면 그 게이트를 이전 게이트(docking-1)와 합치고 카운트 증가시킨다.
문제설명 :
어떤 문자열에서 부분문자열을 추출하여 출력하는 프로그램을 작성하시오.
단 배열 대신 동적메모리 할당방법을 사용하시오.
입력 예시
abcdefg
1 3
출력 예시
abc
문제풀이 :#include <stdio.h> #include <stdlib.h> int main(){ int a,b; char *p =malloc(sizeof(char) * 100); scanf("%s",p); scanf("%d %d",&a,&b); for(int i =a-1;i<b;i++){ printf("%c",p[i]); } free(p); return 0; }
p라는 문자열을 동적 메모리 할당을 통해 입력받는다.
a,b를 입력받는다.
배열은 0부터 시작하므로 for문을 통해 a-1에서부터 b까지 해당하는 문자열을 출력한다. free를 통해 메모리 할당을 끝낸다.
문제설명 : 이 문제는 두 변수의 값을 바꾸는 함수를 구현하는 문제입니다.
다음 조건을 참고해서 함수 본체만 작성해서 제출하시기 바랍니다.
함수명 : myswap
매개 변수(parameter) : 정수형 포인터 변수 변수 2개(매개변수를 반드시 int∗ 로 사용)
반환 형(return type) : 없음(void)
함수 내용 : 첫 번째 포인터가 가리키는 변수의 값이 두 번째 포인터가 가리키는 변수의 값보다 클 경우 두 값을 서로 바꾼다.
문제풀이 :#include <stdio.h> void myswap(int *a , int *b){ int swap = *a; if (*a > *b){ *a = *b; *b = swap; } } int main(){ int a, b; scanf("%d %d", &a, &b); myswap(&a, &b); printf("%d %d", a, b); }
main에서 a,b를 입력받는다. myswap함수에 a랑b의 주소를 전달한다.
myswap함수에선 a와 b를 포인터 변수로 선언된다. swap 변수에 a의 값을 입력받는다. if문을 통해서 a의 값이 b의 값보다 크면 a에 b를 저장하고 b의 swap을 저장해서 바꾸도록 한다.
#include <stdio.h> #include <stdlib.h> int main() { int n; scanf("%d", &n); int *arr = (int *) malloc(n * sizeof(int)); // arr값 입력 for (int i = 0; i < n; i++) { scanf("%d", arr + i); } // 앞뒤 비교 반복 for문 for (int i = 0; i < n - 1; i++) { // 배열 앞뒤 비교 for문 for (int j = 0; j < n - i - 1; j++) { if (*(arr + j) > *(arr + j + 1)) { int temp = *(arr + j); *(arr + j) = *(arr + j + 1); *(arr + j + 1) = temp; } } } //배열에 값이 있을 때만 작동 if (n > 0) { //맨 처음 값 출력 printf("%d", *arr); //1번값부터 앞값과 비교하면서 다르면 출력 for (int i = 1; i < n; i++) { if (*(arr + i) != *(arr + i - 1)) { printf(" %d", *(arr + i)); } } } printf("\n"); free(arr); return 0; }
malloc을 통해 동적 메모리 할당을 받고있다. for문을 통해서 arr에 값을 입력받는다. 다 입력을 받으면 for문에서 배열의 크기만큼 돌면서 그 안에서 for문을 돌면서 앞값이랑 뒷값이랑 비교해서 앞 값이 더 크면 temp변수를 만들어서 두 값을 바꿔준다. 이 반복을 통해서 for문을 빠져나오면 오름차순 정렬이 되어있을거다. 여기서 arr[0]번 값을 일단 출력해준다. 여기서 for문을 돌리면서 앞 값과 뒷 값이 다르면 출력해준다.