문자열
💡 문자 : ‘a’
문자열 : ‘abc’
→ 문자 배열(배열도 자료구조이다.)
- 항상 모든 문장에는 Null 포인터(”\0” == null)가 포함된다.
❗ Null 포인터가 포함되는 이유
- 문장이 종료되었음을 알림.
- C언어에서는 달리 방법이 없음.
- 변수에는 값을 1개만 넣을 수 있기 때문에(주소값을 1개만 넣을 수 있다.)
- Null 포인터가 없으면 계속 출력된다.
공공재
- 공공재는 재활용된다.
- 수정이 따로 불가능하다.
char* str = "문자열상수"; // 8byte(char*) + 15byte
// 공공재의 첫번째 문자를 가리킨다.
// 수정이 불가능하다.
char str[100] = "문자열변수"; // 100byte
// stack부분에 해당한다.
// 수정 가능
char* arr1 = "abc"; // 배열에 a, b, c, null 포함, 공공재이다.
// 포인터이기 때문에 8바이트
char* arr2 = "abc"; // 값이 같으면 같은 주소를 갖는다.(공공재를 재활용한다.)
// 가상메모리에서 위쪽에 저장된다.
Chapter26 문제 1
- 문자배열을 만든 후 거기에 문장 ‘abc’를 저장해주세요.
- 널문자로 끝내기
// Chapter26 Problem 1
// 문제 : 문자배열을 만들고 거기에 문장 `abc`를 저장해주세요.
// 힌트 : c언어에서 모든 문장은 \\0(널문자)로 끝나야 한다.
#include <stdio.h>
int main(void) {
char arr[10]; // 문자 10개 저장 가능
// 구현시작
arr[0] = 'a';
arr[1] = 'b';
arr[2] = 'c';
arr[3] = '\\0'; // null
// 구현끝
printf("%c%c%c\\n", arr[0], arr[1], arr[2]);
// 출력 => abc
// %s : 문장으로 출력한다.
printf("%s\\n", arr);
// 출력 => abc
// %s : 문장으로 출력한다.
printf("%s\\n", &arr[0]);
// 출력 => abc
return 0;
}
문자열 포인터의 가상 메모리 공유 코드
- 공공재는 메모리를 공유한다.
// 문자열 포인터의 가상 메모리 공유
#include <stdio.h>
int main(void) {
// 가상메모리 위쪽에 저장된다.
char* arr1 = "abc"; // 배열에 a, b, c, null 포함, 공공재이다.
char* arr2 = "abc"; // 값이 같으면 같은 주소를 갖는다.(공공재를 재활용을 한다)
char* arr3 = "bc"; // 주소의 값이 b부터 시작
char* arr4 = "c"; // 4바이트 짜리 문자배열
char* arr5 = ""; // 공공재에는 없는 값이 있기 때문에 새로운 메모리 주소
char* arr6 = "abcd"; // abc 후 null이 들어가 공유를 할 수 없다.
printf("arr1 : %ld\\n", (long)arr1); // arr1 : 4202500
printf("arr2 : %ld\\n", (long)arr2); // arr2 : 4202500
printf("arr3 : %ld\\n", (long)arr3); // arr3 : 4202501
printf("arr4 : %ld\\n", (long)arr4); // arr4 : 4202502
printf("arr5 : %ld\\n", (long)arr5); // arr5 : 4202520
printf("arr6 : %ld\\n", (long)arr6); // arr6 : 4202504
return 0;
}
Chapter 26 문제 2
- ‘\0’이 없으면 계속 출력된다.
- 포인터를 사용해 출력한다.
// Chapyer 26 Problem 2
// 문장을 출력하는 함수(print_str)를 만들어주세요.(%s 사용 금지)
// 조건 : %s를 사용할 수 없다.
#include <stdio.h>
void print_str(char* str) {
for (int i = 0 ; *(str + i) != '\\0' ; i++) {
printf("%c", *(str + i));
}
printf("\\n");
}
int main(void) {
char str1[10];
str1[0] = 'a';
str1[1] = 'b';
str1[2] = 'c';
str1[3] = '\\0';
// print_str 함수를 활용하여 문장 str1 출력 실행
print_str(str1);
// 출력 => abc
char str2[10];
str2[0] = 'h';
str2[1] = 'e';
str2[2] = 'l';
str2[3] = 'l';
str2[4] = 'o';
str2[5] = ' ';
str2[6] = 'c';
str2[7] = '\\0';
// print_str 함수를 활용하여 문장 str2 출력 실행
print_str(str2);
// 출력 => hello c
return 0;
}
Chapter 25 문제 3
- 4중 포인터 사용하여 출력한다.
- 문자열을 사용하여 입력이 가능하다.
// Chapyer 25 Problem 3
// 문제 : 아래와 같이 출력되도록, change 함수를 구현해주세요.
#include <stdio.h>
void change(char**** pppp) {
// 첫번째 방법
****pppp = 'a';
*(***pppp + 1) = 'b';
*(***pppp + 2) = 'c';
*(***pppp + 3) = 'd';
*(***pppp + 4) = '\\0';
// 두번째 방법
(***pppp)[0] = 'a';
(***pppp)[1] = 'b';
(***pppp)[2] = 'c';
(***pppp)[3] = 'd';
(***pppp)[4] = '\\0';
}
int main(void) {
char str[10];
char* p = str;
char** pp = &p;
char*** ppp = &pp;
change(&ppp);
printf("%s\\n", str);
// 출력 => abcd
return 0;
}
Garbage Collector, GC
- 더 이상 사용하지 않는 메모리 영역을 알아서 해제 시켜주는 역할
- 알아서 작동하여 실행조건은 일정하지 않음
GC방법 1. Reference Counting
- GC ROOTS는 시작점으로써 연결되어 있으면 사용 가치가 있음을 의미한다.
- 단순히 참조하는 수만 센다.
- 서로 **순환참조(reference)**하고 있으면 삭제되지 않는 문제가 발생한다.
💡 순환참조
- 참조하는 대상이 서로 물려 있어 참조할 수 없게 되는 현상
GC방법 2. Mark and Sweep
- 가장 최신 방법
- 표시하고 삭제하는 방법
- Root Set부터 시작해 하나씩 따라가 참조 상태를 확인한다.
- Reference Counting의 순환참조 문제는 해결된다.
- 하지만, Root Set의 크기에 따라 Marking 시간이 늘어난다.
Java
💡 생성자 메소드 : 클래스와 같은 이름의 메소드
- 객체 생성 후 객체의 초기화를 하는 역할 수행
- return type은 없다.
class 칼 extends 무기 {
public 칼() { // 생성자 메소드
this.무기 = "칼";
}
}
💡 추상 메소드 : 자식 클래스에서 반드시 오버라이딩 해야만 사용할 수 있는 메소드
- 메소드 중 abstract가 붙는다면 반드시 class에도 abstact가 붙어야 한다.
→ 아무런 작동을 하지 않고 오류가 발생하기 때문에 - 다형성을 가지는 메소드의 집합을 정의할 수 있도록 한다.
- 추상 class는 객체를 따로 생성하지 않는다.
→ new 클래스명; 불가능
Chapter 12 문제 2
- 성향과 기호에 따른 적절한 음식 출력
- 추상 메소드 사용
public class Food {
public static void main(String[] args) {
사람 a김철수 = new 사람();
a김철수.이름 = "김철수";
a김철수.전화번호 = "010-1234-1234";
a김철수.a좋아하는_음식점 = new 영화반점();
a김철수.선호하는_음식의_매운정도 = "매운";
a김철수.선호하는_음식 = "짬뽕";
사람 a김영희 = new 사람();
a김영희.이름 = "김영희";
a김영희.전화번호 = "010-4321-4321";
a김영희.a좋아하는_음식점 = new 북경반점();
a김영희.선호하는_음식의_매운정도 = "안매운";
a김영희.선호하는_음식 = "짬뽕";
a김철수.배달_음식_주문하다();
// 영화반점에서 김철수(010-1234-1234)에게 매운 짬뽕(을)를 배달합니다.
a김영희.배달_음식_주문하다();
// 북경반점에서 김영희(010-4321-4321)에게 안매운 짬뽕(을)를 배달합니다.
a김영희.a좋아하는_음식점 = a김철수.a좋아하는_음식점;
a김영희.선호하는_음식의_매운정도 = "아주 매운";
a김영희.선호하는_음식 = "짜장";
a김영희.배달_음식_주문하다();
// 영화반점에서 김영희(010-4321-4321)에게 아주 매운 짜장(을)를 배달합니다.
}
}
class 사람 {
String 이름;
String 전화번호;
음식점 a좋아하는_음식점;
String 선호하는_음식의_매운정도;
String 선호하는_음식;
void 배달_음식_주문하다() {
a좋아하는_음식점.주문(이름, 전화번호, 선호하는_음식, 선호하는_음식의_매운정도);
}
}
abstract class 음식점 {
abstract void 주문(String 주문자명, String 주문자_전화번호, String 음식, String 매운정도);
}
class 영화반점 extends 음식점 {
void 주문(String 주문자명, String 주문자_전화번호, String 음식, String 매운정도) {
System.out.println("영화반점에서 " + 주문자명 + "(" + 주문자_전화번호 + ")에게 " + 매운정도 + " " + 음식 + "을(를) 배달합니다.");
}
}
class 북경반점 extends 음식점 {
void 주문(String 주문자명, String 주문자_전화번호, String 음식, String 매운정도) {
System.out.println("북경반점에서 " + 주문자명 + "(" + 주문자_전화번호 + ")에게 " + 매운정도 + " " + 음식 + "을(를) 배달합니다.");
}
}
Chapter 12 문제 4
- 들고있는 무기에 따라 다른 결과 출력
- 생성자 메소드 사용
// 문제 : 아래가 실행되도록 해주세요.
// 조건 : 매개변수를 사용하지 말아주세요.
class Warrior {
public static void main(String[] args) {
전사 a전사 = new 전사();
String 이름 = "칸";
a전사.이름 = 이름;
a전사.나이 = 20;
a전사.자기소개();
a전사.나이++;
a전사.자기소개();
a전사.나이 = 30;
a전사.이름 = "카니";
a전사.자기소개();
a전사.a무기 = new 활();
a전사.공격();
// 출력 : 카니가 활로 공격합니다.
a전사.a무기 = new 칼();
a전사.공격();
// 출력 : 카니가 칼로 공격합니다.
}
}
class 전사 {
// 인스턴스 변수
String 이름;
// 인스턴스 변수
int 나이;
// 인스턴스 변수
무기 a무기;
void 자기소개() {
System.out.println("안녕하세요. 저는 " + this.나이 + "살 " + this.이름 + " 입니다.");
}
void 공격() {
System.out.println(this.이름 + "가 " + a무기.무기 + "로 공격합니다.");
}
}
class 무기 {
String 무기;
}
class 칼 extends 무기 {
public 칼() {
this.무기 = "칼";
}
}
class 활 extends 무기 {
public 활() {
this.무기 = "활";
}
}
Chapter 13 문제 3
- 손과 무기에 따라 다른 결과 출력
- 추상 메소드를 사용하여 오버라이딩 및 파라미터를 통해 손과 무기의 값을 넣어서 출력
public class c3p4 {
public static void main(String[] args) {
전사5 a전사1 = new 전사5();
a전사1.a왼손무기 = new 칼5();
a전사1.공격();
// 출력 => 전사가 왼손으로 칼(을)를 사용합니다.
전사5 a전사2 = new 전사5();
a전사2.a왼손무기 = new 창5();
a전사2.a오른손무기 = new 도끼5();
a전사2.공격();
// 출력 => 전사가 왼손으로 창(을)를 사용합니다.
// 출력 => 전사가 오른손으로 도끼(을)를 사용합니다.
}
}
class 전사5 {
무기5 a왼손무기;
무기5 a오른손무기;
void 공격() {
if (a오른손무기 != null) {
a오른손무기.공격("전사", "오른손");
}
if (a왼손무기 != null) {
a왼손무기.공격("전사", "왼손");
}
}
}
class 무기5 {
void 공격(String 사용자, String 부위) {}
}
class 칼5 extends 무기5 {
void 공격(String 사용자, String 부위) {
System.out.println(사용자 + "가 " + 부위 + "으로 칼(을)를 사용합니다.");
}
}
class 활5 extends 무기5 {
void 공격(String 사용자, String 부위) {
System.out.println(사용자 + "가 " + 부위 + "으로 활(을)를 사용합니다.");
}
}
class 창5 extends 무기5 {
void 공격(String 사용자, String 부위) {
System.out.println(사용자 + "가 " + 부위 + "으로 창(을)를 사용합니다.");
}
}
class 도끼5 extends 무기5 {
void 공격(String 사용자, String 부위) {
System.out.println(사용자 + "가 " + 부위 + "으로 도끼(을)를 사용합니다.");
}
}
테스트 주도 개발(TDD)
💡 애자일 방법론
- 짝 프로그래밍
- TDD(테스트 주도 개발)
- 등….
TDD
- 재미있다.
- 신뢰도가 높은 프로그램을 만들 수 있다.
- 설계도가 저절로 되는 측면이 있다.
- 깔끔한 코드를 작성할 수 있다.(리팩토링을 통해)
- 장기적으로 개발 비용을 줄일 수 있다.
- 개발이 끝나면 테스트 코드를 작성하는 것은 매우 귀찮다. 실패 케이스면 더욱 그렇다.
TDD 규칙
- 실패하는 테스트를 생성. ⇒ 빨간색 출력
- 꼼수를 사용해 테스트를 통과하게 만들어라. ⇒ 초록색 출력
- 리팩토링 실시 ⇒ 파란색 출력
후기 : 죽겠다 어렵다. 어려운데 할만하다. 애매한게 제일 힘들다. 그래도 재밌다. 그래서 이해도 쏙쏙되고 재밌게 가르쳐주셔서 좋은 것 같다. 지금 잠시 바쁘지만 더 열심히 해보자
'멋쟁이 사자처럼 BE School' 카테고리의 다른 글
[멋쟁이사자처럼 Back-End School 1기] Day 15. 전처리기, 응집도와 결합도, Composition, 배열과 리스트 (0) | 2022.07.06 |
---|---|
[멋쟁이사자처럼 Back-End School 1기] Day 14. C언어, JAVA, TDD (0) | 2022.07.05 |
[멋쟁이사자처럼 Back-End School 1기] Day 12. C언어, Java (0) | 2022.06.30 |
[멋쟁이사자처럼 Back-End School 1기] Day 11. C언어, Java (0) | 2022.06.29 |
[멋쟁이사자처럼 Back-End School 1기] Day 10. Git, GatsBy (0) | 2022.06.28 |