부동소수점변환에 대하여 탐구하였습니다
c++ 코드를 작성하여 예를 들어보겠습니다
#include <iostream>
using namespace std;
int main() {
int a, b;
a = 10;
b = 15;
cout << a + b << endl;
return 0;
}
변수 a 와 b를 선언하였습니다
이 때 a와 b의 자료형은 int (정수) 입니다
a와 b 각각 10과 15를 저장하였습니다
그 다음으로 a+b를 출력하도록 하였습니다
이 때 출력 결과는 25로 정상적인 값이 나왔습니다
하지만 자료형을 float (실수) 로 바꿔주게 된다면 무슨일이 발생할까요?
#include <iostream>
using namespace std;
int main() {
float a, b;
a = 10;
b = 15;
cout << a + b << endl;
return 0;
}
이 때의 출력결과도 당연히 25가 나왔습니다
10과 15가 아닌, 0.1과 0.11같은 소수와 소수의 연산에서도 정상적으로 작동하는지 확인해보겠습니다
#include <iostream>
using namespace std;
int main() {
float a,b;
a = 0.1;
b = 1.1;
cout.precision(22);
cout << fixed;
cout << a + b << endl;
return 0;
}
코드를 약간 수정해주었습니다.
cout.precision(22);
cout << fixed;
이 코드는 소수점 아래 22번째 자리까지 표현한다는 코드입니다
이 때의 실행 결과로는 1.2000000476837158203125 로 비정상적인 값이 출력되었습니다
왜 이런 일이 일어나는지 알아보겠습니다
일단 컴퓨터가 숫자를 저장하는 방법을 먼저 알아야합니다
예를들어 숫자 5를 저장하는 방법에 대하여 설명해보겠습니다
컴퓨터의 램 이라는 부품에 숫자를 포함한 데이터들을 잠시 저장합니다
cpu는 데이터를 저장하지 못하기 때문에 하드디스크나 ssd같은 저장장치에서 필요한 데이터들을 빠르게 연산하기 위해 램에 저장합니다
왜냐하면 hdd나 ssd에서 바로 cpu로 연산할 데이터들을 옮기는건 비효율적이고 속도가 느립니다
한 마디로 램은 cpu를 위한 작업공간 이라고 생각하면 편합니다
그리고 이 램을 확대시켜보면 0과 1을 저장 할 수 있는 칸들이 매우 많이 있습니다 흔히
메모리라고 불립니다
저는 숫자 5를 저장하기 위해 메모리에 8칸 정도를 마련해봤습니다
컴퓨터는 2진법을 사용하기 때문에 숫자 5를 2진수로 변환하여 저장하였습니다
물론 숫자 5 말고 더 큰 숫자를 저장하려면 방금 보셨던 칸을 늘리면 됩니다
하지만 5.125 같은 소수는 어떻게 저장할까요?
소수 저장하는 법
5.125를 2진수로 변환한다면 101.001 로 표현할 수 있습니다
이렇게 컴퓨터 메모리에 저장하려면 정수와 소수부분 따로따로 저장 할 수 있습니다
하지만 속도와 효율이 중요하니, 이 방법은 사용하지 않습니다
맨 첫번째 칸은 숫자의 부호를 결정합니다
5.125는 양수이기 때문에 0을 넣어주었습니다
그 다음으로 5.125를 2진수로 바꾸어줍니다
5.125 ---> 101.001
그리고 소수점을 옮겨줍니다
101.001 ---> 1.01001
그 후 2의 제곱을 곱해줍니다
1.01001 x 2^2
소수점 기준으로 우측에 있는 수를 mantissa 라고 합니다
이 mantissa를 맨 뒤에서부터 23칸에 차례대로 넣어줍니다
다음으로 지수에 127을 더한 후 2진법으로 변환 후 앞 자리에다 넣어줍니다
이게 컴퓨터가 소수를 저장하는 방법입니다
순환소수 (무한소수) 문제
0.125 같은 소수들은 0.001로 깔끔하게 떨어집니다
하지만 0.1같은 수들은 2진수로 변환하였을 때 0.00011001100110011001100.....
이렇게 순환하는 무한소수가 발생하게 됩니다
그래서 아까 방식과 같이 메모리에 저장한다면 이렇게 칸을 넘어가게 됩니다
메모리를 더 사용하면 된다고 생각할 수 있겠지만,
이 32칸은 float자료형의 메모리 크기라고 할 수 있고 32바이트입니다
더 크게는 double의 64바이트입니다
하지만 저희는 단지 0.1이라는 소수만 저장할 것이기 때문에 더 많은 칸을 차지하는 것은 낭비입니다
그렇기 때문에 칸을 넘어가는 부분을 모두 잘라주었습니다
넘어가는 부분들을 모두 다 잘라버리게 된다면 잘린 부분만큼 오차가 발생합니다
그래서 0.1을 메모리에 저장한다면 0.1이 정확이 저장되지 않고 근삿값이 저장됩니다
문제 해결 방법
실제 중요한 프로그램을 작성할 때 이만큼의 오차도 일어나서는 안됩니다
아주 작은 수 이지만, 여러면 더해지거나 오차가 증가하면 치명적입니다
또한 비교연산자를 사용하였을때 결과가 달라집니다
그렇기 때문에 실수를 표현 할 때 반올림을 해버리거나 단위를 바꿔줄 수 있습니다
단위를 바꾼다는 말은 예를들어 1.1km 대신 1100m로 표현 할 수 있습니다
참고 영상 / 글
유튜브 코딩애플 - https://youtu.be/-GsrYvZoAdA
MISRA-C 요약 글 - https://grapevine9700.tistory.com/45
언어의 특성과 c언어 포인터에 관련한 내용입니다
프로그래밍 언어를 배우다보면 포인터라는 단어가 처음 들어보는 단어는 아닐겁니다
그만큼 어렵고 복잡하고 헷갈리는 내용으로 유명합니다
그래서 c언어를 사용하지 않으면 포인터를 안배워도 상관 없다고 착각을 합니다
하지만 요리사가 요리만 잘 하는게 아닌 재료와 도구 관리도 중요시 하는 것 처럼
포인터 또한 중요합니다
저수준 언어의 개념과 지식 없이도 웹 서비스나 앱을 만들 수 있겠지만,
아무래도 경력이 쌓이고 중요한 시스템을 구현 할 때 컴퓨터가 어느방식으로 굴러가는지 아는 것은 중요합니다
메모리의 구조에는 4가지 영역이 있습니다
실행할 프로그램의 코드가 저장되는 영역
프로그램이 시작하고 끝날 때 까지 메모리에 계속 남아있습니다
컴파일된 기계어가 들어갑니다
cpu는 이 영역에 있는 기계어를 하나씩 가져다 연산합니다
프로그램의 global 변수와 static 변수, 문자열, 상수가 저장되는 영역
프로그램의 시작과 동시에 할당되고, 종료시 데이터는 소멸합니다
프로그램이 자동으로 사용하는 임시 메모리 영역
함수의 호출시 필요한 지역변수와 매개변수가 저장됩니다
선입선출의 방식으로 가장 나중에 들어온 데이터가
이곳에 저장되는 함수의 정보를 스택 프레임이라고 합니다
스택 영역은 메모리의 높은 주소에서 낮은 주소의 방향으로 할당되기 때문에
LIFO 형식이고, 후입선출의 방식입니다
스택 영역에서 푸시로 데이터를 저장하고 팝으로 데이터를 내보냅니다
프로그래머가 직접 관리해야하는 영역
힙 영역은 프로그래머가 메모리 공간이 동적으로 할당되고 해제됩니다
힙 영역은 메모리의 낮은 주소에서 높은주소의 방향으로 할당되기 때문에 FIFO 방식이고, 선입선출입니다
unmanaged 언어와 managed 언어의 차이점
unmanaged 언어는 대표적으로 c와 c++ 있습니다
특징은 개발자가 메모리 관리를 조금 더 직접적으로 할 수 있습니다
메모리의 할당과 해제 작업을 통해 메모리 누수 현상이 없도록 관리해준다면
managed 언어에 비해서 속도가 빠릅니다
대표적으로 managed 언어에는 java와 c#이 있습니다
managed 언어는 가비지컬랙터를 통해 메모리의 할당과 해제를 언어 자체적으로 관리합니다
메모리의 직접적인 할당과 해제를 하지 못하기 때문에 프로그래밍의 자유도가 상대적으로 낮으며 비정기적으로 메모리의 정리가 이루어집니다
포인터는 무엇일까요
메모리관리에 사용되는 수단 중 하나입니다
포인터는 가비지컬랙터를 사용하지 않고 보다 직접적으로 컴퓨터를 제어할 수 있게 해줍니다
예시로 c언어 코드를 사용하겠습니다
#include <iostream>
using namespace std;
int main(int argc, const char* argv[]) {
char lang = 'c' ;
int any_num = 123 ;
double pi = 3.141592 ;
return 0;
}
문자변수 lang, 정수변수 any_num, 그리고 double 변수 pi를 저장했습니다
이 값들은 메모리 어딘가에 저장됩니다
한정된 메모리 안에서 변수나 함수 같은 값들이 할당과 해제를 통해 관리됩니다
프로그램을 만들다 보면 변수에 있는 값을 다른 여러 곳에서 써야 할 경우가 있습니다
예를들어 생명과학 수행평가를 준비한다고 하면
내용을 알려주기위해 노트에 다 적고 보여주는 것 보다
생명과학의 책 페이지 수만 알려주면 됩니다
void function_1(int _arg) {
//작업 수행
}
int argument = 10;
function_1(argument)
c언어에서 어느 함수에 변수가 인자로 주어질 때는 그 값이 복사되어서 넘어갑니다
복사된다는 것은 중복된 크기만큼 메모리의 공간을 차지한다는 말입니다
즉 수행평가 내용을 알려주기 위해 종이에 내용을 다 쓰지 않고 페이지 수만 알려주는 것과 같이
메모리를 낭비하지 않고 페이지 번호만 적어 보여줄 수 있도록 하는것이 포인터입니다
메모리는 각각 주소를 가지고있습니다
#include <iostream>
using namespace std;
int main(int argc, const char* argv[]) {
char lang = 'c' ;
int any_num = 123 ;
double pi = 3.141592653 ;
char* p0 = ⟨
return 0;
}
p0이란 포인터 변수로 해서 lang의 위치를 가리키는 코드입니다
#include <iostream>
using namespace std;
int main(int argc, const char* argv[]) {
char lang = 'c' ;
int any_num = 123 ;
double pi = 3.141592653 ;
char* p0 = ⟨
cout << *p0 << endl;
return 0;
}
p0를 출력해보면 lang 변수에 저장된 값이 출력됩니다
수행평가 범위는 시작하는 페이지와 끝나는 페이지로 구성되어있습니다
마찬가지로 포인터도 끝나는 부분도 필요합니다
int (정수)는 1이 들어오든, 1273891이 들어오든 4바이트를 차지합니다
반면 double 자료형은 0.1이라는 값에도 8바이트를 차지합니다
다른 자료형들도 정해진 바이트들이 있습니다
포인터를 지정할 때 자료형도 같이 표시하는 이유입니다
#include <iostream>
using namespace std;
int main(int argc, const char* argv[]) {
char lang = 'c' ;
int any_num = 123 ;
double pi = 3.1415926535897 ;
char* p0 = ⟨
cout << *p0 << endl;
int x = 1;
int y = 200;
int z = 7894123;
int* p1 = &x;
cout << *p1 << endl;
//1 출력
x++;
cout << *p1 << endl;
//2 출력
return 0;
}
x의 값을 1증가시키면 2가 당연히 출력됩니다
#include <iostream>
using namespace std;
int main(int argc, const char* argv[]) {
char lang = 'c' ;
int any_num = 123 ;
double pi = 3.1415926535897 ;
char* p0 = ⟨
cout << *p0 << endl;
int x = 1;
int y = 200;
int z = 7894123;
int* p1 = &x;
cout << *p1 << endl;
//1 출력
x++;
cout << *p1 << endl;
//2 출력
p1 ++;
cout << *p1 << endl;
//-500688741 출력
return 0;
}
하지만 포인터에 정수값을 더해준다면 자료형의 크기 x 그 값 만큼 메모리 구역이 오른쪽으로 이동합니다
변수들은 프로그래머가 지정하는대로 예측가능한 곳에 배열되지 않습니다
이렇게 포인터를 제대로 알고 사용하지 않으면 이런 오류가 날 수 있습니다
배열 자료형을 사용하면 값들이 메모리에 나란하게 배열됩니다
#include <iostream>
using namespace std;
int main(int argc, const char* argv[]) {
char lang = 'c' ;
int any_num = 123 ;
double pi = 3.1415926535897 ;
char* p0 = ⟨
cout << *p0 << endl;
int x = 1;
int y = 200;
int z = 7894123;
int* p1 = &x;
cout << *p1 << endl;
//1 출력
x++;
cout << *p1 << endl;
//2 출력
p1 ++;
cout << *p1 << endl;
//-500688741 출력
int numbers[] = {1,2,3,4,5,6,7}
int* p2 = &numbers[0]
cout << *p2 << endl;
//1 출력
p2++;
cout << *p2 << endl;
//2 출력
return 0;
}
포인터는 이렇게 배열과 연계되어 사용될 수 있습니다
void _Performance_ssessment_Jeong_woo_value(int _arg) {
_arg = 24;
}
void _Performance_ssessment_Jeong_woo_pointer(int* _arg) {
*_p++ = 24;
}
int arg = 10;
int *p_arg = &arg;
_Performance_ssessment_Jeong_woo_value(arg);
cout << arg << endl;
//10 출력
_Performance_ssessment_Jeong_woo_pointer(&arg);
cout << &arg << endl;
//24출력
수행평가 내용을 배껴적은 노트를 정우가 받았을 때
포인터 없이 노트에 배껴적어준 내용에다 수정하면 정우만 볼 수 있습니다
이렇게 출력했을 때 정우에게만 인자로 주어진 것만 변하고 원본은 그대로 남습니다
포인터로 주어진 페이지로 원본상의 내용을 찾아서 거기다 수정을 해주어야 정우는 물론이고 재혁이와 학진이까지 볼 수 있습니다
변수가 함수에 의해 값이 변경될 수 있습니다
이처럼 특정 변수나 객체의 값을 그대로 함수에 복사해주는것이 아닌
포인터로 위치만 넘겨주는 것을 참조에 의한 호출 (reference) 라고 합니다
참고영상 글
유튜브 얄팍한 코딩사전 - https://youtu.be/u65F4ECaKaY
메모리엔진 - https://www.site24x7.com/learn/java/heap-and-stack-memory-management.html
스택 내용 - https://gmlwjd9405.github.io/2018/08/03/data-structure-stack.html
힙 내용 - http://www.tcpschool.com/c/c_memory_structure
c언어 시작하기
#include <stdio.h>
int main() {
}
이 라인은 c언어의 표준 매크로 정의, 상수, 여러 형의 입출력 함수가 포함된 stdio.h라는 헤더 파일을 불러오는 코드입니다
이 라인은 main이라는 함수를 정의한다는 코드입니다.
실행될 코드들을 {} 안에 작성하면 됩니다
추후 자세히 다룰 내용입니다
#include <stdio.h>
int main(){
printf("hello world!");
}
괄호 사이에 출력될 대상을 넣습니다
참고로 문자열을 출력할시 "" 를 사용해야합니다
; 는 세미콜론으로, 컴파일 오류가 나지 않도록 한 줄이 끝나면 붙여야합니다
int main(){
int result;
result = 100;
printf("%d",result);
}
result 라는 변수를 선언하는 코드입니다
int 자료형의 변수로, int의 자료형을 가진 데이터만 이 변수에 들어올 수 있습니다
선언한 result 변수에 100의 값을 저장하라는 코드입니다
이 때 = 은 같다는 의미가 아닌, 대입연산자입니다
"%d" 의 위치에 result 변수의 값을 출력시키는 코드입니다
이 코드를 실행시키면 100이라는 값이 출력됩니다
변수에 직접 값을 입력 할 수 있습니다
scanf("%d",&a);
scanf 함수를 사용하여 변수에 직접 입력값을 넣어줄 수 있습니다
일반 수학에서 사용하는 연산 부호를 사용할 수 있습니다
#include <stdio.h>
int main(){
int a,b,result;
scanf("%d",&a);
scanf("%d",&b);
result = a+b;
printf("%d + %d = %d\n",a,b,result);
result = 0;
result = a-b;
printf("%d - %d = %d\n",a,b,result);
result = 0;
result = a*b;
printf("%d x %d = %d\n",a,b,result);
result = 0;
result = a/b;
printf("%d / %d = %d\n",a,b,result);
result = 0;
}
a, b, result 변수들을 선언해주었습니다
콘솔창에서 사용자 입력을 받고 변수에 저장합니다
마찬가지로 다음 줄 또한 같습니다
덧셈 연산자입니다
뺄셈 연산자입니다
곱셈 연산자입니다
나눗셈 연산자입니다
정수형 변수이기 때문에 몫만 저장됩니다
int a = 123;
float b = 123.45;
정수형 변수 a 와 실수형 변수 b를 선언하고 각각 123 과 123.45 값을 저장했습니다
printf("a의 값 =>%d\n",a);
printf("b의 값 =>%.2f\n",b);
123을 출력합니다
123.45의 소수점 둘째자리까지 출력합니다
float c = 0.2345678912345678912345;
double d = 0.2345678912345678912345;
printf("%.25f\n",c);
printf("%.25f\n",d);
double 자료형은 float 자료형보다 데이터를 담을 수 있는 공간이 더 많습니다
그렇기 때문에 저 코드를 실행하면 값이 각각 다르게 출력되며,
double 자료형인 d의 변수값만 제대로 출력됩니다
char e, f, g;
char 로 선언합니다
문자열과 달리 ' ' 안에 들어갑니다
문자를 아스키코드표에 따라 10진수 숫자로 저장합니다
그렇기때문에
e = 'E';
printf("%c\n", e);
printf("%d\n", e);
정수와 문자 모두 출력이 가능합니다
#include <string.h>
문자열 관련 함수를 사용하기 위해서 string.h 파일을 불러옵니다
char str1[10];
char str2[10];
char str3[10] = "CookBook";
char str[문자열 배열] 로 문자열을 선언할 수 있습니다
string.h 파일 안에는 문자열에 사용할 수 있는 함수들이 있습니다
strcpy(str1, "Basic-C");
strcpy(복사한 문자를 저장할 변수, 복사할 문자열) 로 사용할 수 있습니다
위 코드는 Basic-C 라는 문자열을 str1문자열에다 복사합니다
일반 산술식에서 사용하는 연산자를 그대로 사용할 수 있습니다
a = b + c; // 덧셈
printf("더하기 %d + %d = %d\n", b,c,a);
a = b - c; // 뺄셈
printf("빼기 %d - %d = %d\n", b,c,a);
a = b % c; // 나머지
printf("나머지 %d %% %d = %d\n", b,c,a); // %%에서 앞의 %는 탈출문자
a = b / c; // 나눗셈
printf("나누기 %d / %d = %d\n", b,c,a); // int끼리의 연산은 몫만 출력
위와같은 연산자들이 있습니다
참고로 나눗셈 연산자를 사용할 때 나누는 수가 float 자료형이여야만 소수점까지 연산됩니다
변수의 값을 증가시키거나 감소시킬 수 있습니다
a++; // 1 증가
printf("a++ >> %d\n",a);
a = 10;
a--; // 1 감소
printf("a-- >> %d\n",a);
a = 10;
a+=5; // 5 증가
printf("a+=5 >> %d\n",a);
a = 10;
a*=5; // a = a*5;
printf("a*=5 >> %d\n",a);
a = 10;
a/=5; // a = a/5;
printf("a/=5 >> %d\n",a);
a = 10;
a%=5; // a = a%5;
printf("a/=5 >> %d\n",a);
a = 10;
a = 10; // b = a 를 수행시킨 후 a를 1 증가시킨다
b = a++;
printf("%d\n",b);
b = ++a; // a를 1 증가시킨 후 b = a를 수행함
printf("%d\n",b);
= 앞에 연산자를 붙여 변수의 값을 증감시킬 수 있습니다
둘 다 참이여야 AND 연산의 결과가 참입니다
연산자는 &&을 사용합니다
둘 중 하나만 참이여야 OR 연산의 결과가 참입니다
연산자는 ||을 사용합니다
반대의 결과로 바꿉니다
연산자는 !을 사용합니다
참이면 거짓, 거짓이면 참으로 바꿉니다
//논리연산자
a = 90;
printf("AND연산 : %d\n",(a>=100)&&(a<=200));
printf("OR연산 : %d\n",(a>=100)||(a<=200));
printf("NOT연산 : %d\n",!(a==100));
a = 100;
b = 200;
printf("상수의 AND연산 : %d\n",a&&b);
printf("상수의 OR연산 : %d\n",a||b);
printf("상수의 NOT연산 : %d\n",!a);
//0빼고 다 1임
출력결과 위와 같습니다
각 자리의 비트끼리 AND 연산을 합니다
각 자리의 값이 두 수 모두 1이여만 결과도 1입니다
printf("10 & 7 = %d\n",10 & 7); // 10과 7의 비트 논리곱(AND)을 수행
printf("123 & 456 = %d\n",123 & 456); // 123과 456의 비트 논리곱을 수행
연산자는 &를 사용합니다
각 자리의 비트끼리 OR 연산을 합니다
각 자리의 값 중 하나만 1이면 결과또한 1입니다
printf("10 | 7 = %d\n",10 | 7); // 10과 7의 비트 논리합(OR)을 수행
printf("123 | 456 = %d\n",123 | 456); // 123과 456의 비트 논리합을 수행
연산자는 |를 사용합니다
각 비트끼리의 XOR 연산을 합니다
XOR 연산은 두 값 중 하나만 1일때 0을 출력합니다
나열된 비트의 자리값을 왼쪽으로 이동시키는 연산자입니다
왼쪽으로 시프트를 할 때마다 2의 n승을 곱한 효과입니다
a = 10;
printf("%d를 왼쪽으로 1회 시프트하면 %d 이다\n",a,a << 1);
printf("%d를 왼쪽으로 2회 시프트하면 %d 이다\n",a,a << 2);
printf("%d를 왼쪽으로 3회 시프트하면 %d 이다\n",a,a << 3);
나열된 비트의 자리값을 오른쪽으로 이동시키는 연산자입니다
오른쪽으로 시프트를 할 때마다 2의 n승을 나눈 효과입니다
a = 10;
printf("%d를 오른쪽으로 1회 시프트하면 %d 이다\n",a,a >> 1);
printf("%d를 오른쪽으로 2회 시프트하면 %d 이다\n",a,a >> 2);
printf("%d를 오른쪽으로 3회 시프트하면 %d 이다\n",a,a >> 3);
다음 코드의 실행 여부를 판단하는 문법입니다
코드에 조건을 걸어 다음 코드가 실행될지 판단하는 문법입니다
a = 1;
if(a == 1){ //참
printf("%d",a)
}
() 안의 조건이 참이라면, 코드블럭 안에있는 값을 실행합니다
조건이 거짓이라면 코드를 실행하지 않고, 건너뜁니다
else if 를 사용하여 조건을 추가할 수 있습니다
a = 1;
if(a == 2 ){ //거짓
printf("%d",a)
}
else if (a == 1){ //참
printf("hello");
}
마지막에 else를 사용하여 위의 조건들이 모두 참이 아닐경우 다음 코드 블럭을 실행시킵니다
a = 1;
if(a == 2 ){ //거짓
printf("%d",a)
}
else if (a == 7){ //거짓
printf("hello");
}
else{
printf("good");
}
if문과 비슷한 역할을 하지만, 변수의 값에 따라 코드를 실행합니다
switch (변수)
{
case 변수의 값1:
실행시킬 코드
break;
case 변수의 값2:
실행시킬 코드
break;
default:
break;
}
변수의 값이 무엇이 들어오는지에 따라 실행시키는 코드들이 달라집니다
break로 해당 switch 문을 탈출할 수 있습니다
default로 case에 해당하지 않는 값이 들어왔을때 처리할 수 있습니다
else와 비슷한 코드입니다
예시로 계산기 코드를 들어보겠습니다
#include <stdio.h>
int main() {
int a,b;
char ch;
while (1)
{
printf("계산할 두 수 입력 (멈추려면 컨트롤 c): ");
scanf("%d %d",&a,&b);
printf("계산할 연산자 입력 (멈추려면 컨트롤 c): ");
scanf(" %c",&ch,1);
switch (ch)
{
case '+':
printf("%d + %d = %d\n",a,b,a+b);
break;
case '-':
printf("%d - %d = %d\n",a,b,a-b);
break;
case '/':
printf("%d / %d = %.2f\n",a,b, a/(float)b);
break;
case '%':
printf("%d %% %d = %d\n",a,b,a%b);
break;
default:
printf("연산자 잘못 입력했음\n");
}
}
}
연산자를 입력받아 연산을 진행하는 코드입니다
두 수를 입력받고 연산자를 입력받습니다
입력받은 연산자는 swich문에서 각 일치하는 케이스의 코드를 실행시킵니다
일정 코드를 반복수행하게 하는 문법입니다
반복해야하는 횟수가 정해져있을 때 주로 사용합니다
for(변수; 반복 조건; 변수값 변화량){
반복할 코드
}
for(int i = 0; i < 5;i++;){
printf("%d",i)
}
for 반복문이 한번 반복 할 때 마다 i의 값이 1씩 증가하는 코드입니다
반복 조건이 i가 5보다 작다면 반복하기 때문에 i가 5이상이라면 반복을 멈춥니다
위 코드는 i의 값이 1씩 증가되며 반복되어 출력되기때문에 출력값은
0 1 2 3 4 가 될 것입니다
주로 조건에 따라 반복을 해야하는 상황에서 쓰이는 반복문 입니다
while(조건식){
반복할 코드;
}
이런 형식으로 작성됩니다
int flag = 1;
int a = 0;
while(flag == 1){
a ++;
if(a > 5){
flag = 0;
}
}
초기 flag 값은 while문이 반복되면서 a의 값은 1씩 증가합니다
a의 값이 6이 되었을 때 조건문에 의하여 flag 값은 1에서 0으로 바뀝니다
while의 조건인 flag == 1 이 거짓이 되었기 때문에 반복을 종료합니다
참고로 c++의 헤더파일인 iostream이 아닌, stdio.h로 진행한다면
bool 자료형은 사용할 수 없습니다
그렇기 때문에 0과 1로 참 거짓을 나타낼 수 있습니다
시작과 끝을 모를때 사용합니다
#include <stdio.h>
int main(){
int menu;
do {
printf("\n손님 주문하시겠습니까?");
printf("<1> 카페라떼 <2> 카푸치노 <3> 아메리카노 <4>그만 주문==>");
scanf("%d",&menu);
switch (menu)
{
case 1:
printf("카페라떼 주문하셨습니다");
break;
case 2:
printf("카푸치노 주문하셨습니다");
break;
case 3:
printf("아메리카노 주문하셨습니다");
break;
case 4:
printf("주문하신 커피 준비하겠습니다");
break;
default:
printf("잘못 주문하셨습니다");
break;
}
}
while (menu != 4); //입력값이 4면 종료
}
예시로 카페 메뉴를 주문하는 코드를 들겠습니다
반복해서 입력을 받습니다
만약 입력값이 4이면 do while 문을 종료합니다
프로그램의 진행 여부를 결정해주는 코드입니다
반복을 멈추고 반복문을 탈출합니다
int sum = 0;
int num;
for( num =1; num++) {
sum += num;
if(sum >= 100) {
break;
}
}
다음 for문은 종료조건 없이 무한반복하는 반복문입니다
하지만 sum의 값이 if문의 조건을 만족시켰을 때
break문을 만나 반복을 종료합니다
break와 반대로 코드를 계속 진행시킵니다
프로그램이나 함수를 종료하거나 값을 반환하는 return이 있습니다
함수 단원에서 자세히 다룰 예정입니다
배열은 여러 데이터를 연속적으로 저장할 수 있는 자료 구조입니다
배열에 들어올 데이터의 자료형 배열 이름[배열의 크기];
int a[100];
함수는 특정한 역할을 하는 코드들을 독립적으로 모아둔 집합체입니다
함수를 사용했을 시 유지보수가 간편해지며 코드의 가독성이 좋아집니다
함수는
반환형 함수이름(매개변수){
실행할 코드
return 반환값; (반환값이 없으면 없어도 됨)
}
이런 형태로 생겼습니다
int Add(int n1, int n2){
return n1 + n2;
}
정수를 반환하는 함수입니다
n1과 n2 자리에 값들을 전달받아 n1과 n2를 더한 값을 반환합니다
void Add2(int n1, int n2){
printf("연산 결과 : %d\n",n1+n2);
}
void를 사용하여 반환값이 없는 함수를 선언할 수 있습니다
블록 내부에서 선언된 변수로 블록 내부에서만 유효하고 블록이 끝나면 해제됩니다
지역 내부에 새로운 지역에서 같은 이름의 변수가 선언되면
외부에 있는 변수보다 내부에 있는 변수가 더 높은 우선순의를 가지게 됩니다
함수 외부에서 선언된 변수로 프로그램이 종료될 때 해제됩니다
전역변수는 별도의 초기화를 진행하지 않으면 0으로 초기화 됩니다
전역변수와 지역변수의 이름이 같다면 해당 지역에 선언된 지역변수가 더 높은 우선순의를 가집니다
전역 변수와 지역변수의 특성을 둘 다 가지고 있습니다
전역변수의 특성인 프로그램이 종료될 때 메모리의 공간이 해제된다는 특성을 가지고 있습니다
지역변수의 특성인 블록 내부에서만 유효하다는 특성을 갖고있습니다
(정적변수 선언 원형 : static 자료형 변수명;)
C언어의 꽃이자 가장 중요한 내용입니다
변수는 선언될 때 메모리에 저장되는 위치값을 가집니다
그 때 위치값을 주소 라고 부릅니다
포인터는 변수의 주소를 저장하는 변수입니다
포인터변수는 다음과 같은 형식으로 선언할 수 있습니다
저장한 공간의 자료형* 변수명
int num = 5;
int* ptr; // int* - int 자료형을 가진 공간의 주소
정수형 변수 num을 선언하고 5로 초기화 해주었습니다
그리고 ptr 이라는 포인터 변수를 선언해주었습니다
(* : 애스털리스크라고 읽으며, 주소에 해당하는 변수의 값을 참조하는 역할을 합니다)
ptr = #
그 후 ptr에 num의 주소값을 저장해주었습니다
(& : 앰퍼센드라고 읽으며, 메모리에서의 주소를 나타냅니다)
printf("(&num의 값 출력)num의 주소 : %p\n",&num);
&num을 출력해본다면
5가 아닌 num의 메모리 주소가 출력됩니다
printf("num의 주소 : %p\n",ptr);
ptr변수에 저장된 값 또한 출력했을시 동일하게 주소값이 출력됩니다
#include <stdio.h>
int main(){
int a = 0;
int* ptr;
ptr = &a;
printf("입력 : ");
scanf("%d",ptr);
printf("출력 : %d", a);
return 0;
}
이렇게 scanf에서 포인터 변수로 사용할 수 있습니다
포인터 변수는 다양하게 사용합니다
메모리를 사용하는 부분만 빌려와 사용한 후, 다시 반납하는 방법입니다
메모리를 효율적으로 관리할 수 있습니다
*메모리 사용이 끝난다면 꼭 해제를 해주어야 합니다
#include <stdlib.h>
#include <malloc>
둘 중 하나를 사용하여 메모리를 동적으로 할당할 수 있게 해주는 함수들을 불러옵니다
int* p;
p = (int*)malloc(sizeof(int));
*p = 100
printf("%d",*p);
free(p);
포인터 변수 p를 선언하고, int자료형 (4바이트) 만큼 할당하라는 코드입니다
free() 함수로 할당된 메모리를 운영체제에 반납해주어야합니다
#include <stdio.h>
#include <stdlib.h>
int main(){
int p,*s;
int i,j;
print("malloc함수 사용\n");
p = (int*)malloc(sizeof(int)*3);
for(i=0;i<3;i++){
printf("할당된 곳의 초기값 p[%d] >> %d\n",i,s[i]);
}
free(p);
printf("\ncalloc함수 사용\n");
s = (int*)calloc(p,sizeof(int)*3);
for(i=0;i<3;i++){
print("할당된 곳의 초기값 s[%d] >> %d\n",i,s[i]);
}
free(p);
}
malloc 함수와 calloc 함수의 예제입니다
배열에서 사용한다면 필요한 배열의 메모리만큼 사용되기 때문에 효율적으로 관리 할 수 있습니다
int main() {
char* p[3];
char temp[100];
int i, size;
for(i = 0; i < 3; i++) {
printf("%d 번째 문자열:", i + 1);
fgets(temp, sizeof(temp), stdin); // 입력한 문자열을 입력받는다
size = strlen(temp); // 입력한 문자열의 길이를 계산한다
p[i] = (char*) malloc(sizeof(char) * (size + 1)); //입력한 길이 + 1 (널문자)의 크기의 메모리를 확보한다
strcpy(p[i], temp); //입력한 문자열 temp의 내용을 메모리를 확보한 공간에 복사한다
}
printf("\n입력과 반대로 출력(포인터)\n");
for(i = 2; i >= 0; i--) {
printf("%d : %s\n", i + 1, p[i]); //포인터 배열에 저장된 문자열을 출력한다
}
for(i = 0; i < 3; i++) {
free(p[i]); //할당된 메모리 3개를 운영체제에 반납한다
}
}
메모리를 동적으로 할당하여 문자열을 반대로 출력하는 코드입니다
TCP/IP 프로그래밍에서 심도있게 다룰 예정입니다
구조체는 여러개의 변수들을 한 블럭에 묶어 조금 더 쉽게 사용하도록 해주는 도구입니다
타입스크립트의 오브젝트와 유사하다고 할 수 있겠지만, 전혀 다른 것이니 유의해야합니다
struct book //
{
int a;
float b;
char c;
char d[5];
};
구조체 변수 b1을선언합니다 (실제 저장공간을 확보함)
그 후 각각 서로다른 자료형의 변수들을 선언해줍니다
struct book b1;
구조체 변수의 멤버 변숫값을 대입합니다
b1.a = 10;
b1.b = 1.1f;
b1.c = 'A';
printf("b1.a >> %d\n",b1.a);
printf("b1.b >> %f\n",b1.b);
printf("b1.c >> %c\n",b1.c);
printf("b1.d >> %s\n",b1.d);
그 후 구조체이름.변수이름 으로 변수를 사용할 수 있습니다
int main(){
struct student {
char name[10];
int kor;
int eng;
float avg;
};
struct student s;
printf("이름 : ");
scanf("%s",&s.name,9);
printf("국어 점수 : ");
scanf("%d",&s.kor);
printf("영어 점수 : ");
scanf("%d",&s.eng);
s.avg = (s.kor + s.eng) / 2.0f;
printf("학생이름 : %s\n",s.name);
printf("국어 점수 : %d\n",s.kor);
printf("영어 점수 : %d\n",s.eng);
printf("평균 점수 : %.1f\n",s.avg);
}
위 코드는 학생 정보를 관리하는 구조체를 만드는 코드입니다
구조체에서 포인터를 사용할 수 있습니다
포인터의 개념과 구조체의 개념을 알고있다면 쉽게 이해할 수 있습니다
이 때 . (도트 연산자) 대신 -> (화살표 연산자) 를 사용하여 포인터 변수에 접근할 수 있습니다
#include <stdio.h>
int main(){
struct student
{
char name[10];
int kor;
int eng;
float avg;
};
struct student s;
struct student* p;
p = &s; //포인터 p에 s의 주소를 대입한다
printf("이름 : ");
scanf("%s",p->name,9);
printf("국어 점수 : ");
scanf("%d",&p->kor);
printf("영어 점수 : ");
scanf("%d",&p->eng);
p->avg = (p->kor + p->eng) / 2.0f;
printf("학생이름 : %s\n",p->name);
printf("국어 점수 : %d\n",p->kor);
printf("영어 점수 : %d\n",p->eng);
printf("평균 점수 : %.1f\n",p->avg);
}
union student2{
int tot;
char grade;
};
union student2 u;
u.grade = 'A';
u.tot = 300;
printf("총점 >> %d\n",u.tot);
printf("등급 >> %c\n",u.grade);
공용체는 구조체와 유사하지만, 메모리 공간을 공유합니다
따라서 위 코드는 나중에 들어간 값만 먼저 출력됩니다
열거형은 서로 연관된 상수들을 그룹화하여 정의하는 데이터 형식입니다
열거형은 프로그램에서 사용되는 명칭을 간결하고 의미있게 표현할 수 있는 장점이 있습니다.
enum week{sun,min,tus,wed,thu,fri,sat};
enum week ww;
ww = sat;
if(ww == sun){
printf("오늘은 일요일입니다\n",ww);
}
else{
printf("오늘은 일요일이 아닙니다\n",ww);
}
}
무언갈 연결하는 것
한 장비에서 다른 장비를 연결해서 정보나 자료, 자원의 공유가 편해졌습니다
Network : 길
H/W, S/W : 교통수단
Network의 핵심키워드 : 연결성 (유/무선 모두 포함)
네트워크의 시작점 : 전쟁
빠른 군사 정보를 공유할 목적으로 통신이 발전됐습니다
최초의 인터넷 : 미국방성과 4개의 대락과 연결 패킷교환을 성공한 알파넷
연결된 네트워크간에는 서로 동일한 프로토콜 (protocol)을 사용합니다
한번에 하나의 프로토콜만 사용합니다
전세계의 수많은 WAN와 LAN이 연결된 거대한 네트워크
정보를 공유하기 위한 통신망의 집합체
인터넷을 하기 위해선 '웹브라우저'를 사용합니다
ex) www.naver.com
인터넷을 하려면 'IP'주소라는 것이 필요합니다
인터넷 초창기에는 IP주소를 외워서 사용했습니다
네트워크 설정에 등록된 DNS Server에 도메인 이름을 질의합니다
그 후 DNS Server는 보유하고 있는 (타 서버에서 제공받은) IP 주소를 제공합니다
Client 는 제공받은 IP를 갖고 수많은 장비를 경유해서 서버에 서비스 요청합니다
서버는 정상적인 요청인지 확인 후 서비스를 제공합니다
도메인의 이름체계
ex) www.11st.co.kr.
최상위 도메인
모든 도메인의 이름 시작
모든 도메인에 공통적으로 들어가 생략합니다
전 세계에 13대의 Root DNS server가 존재합니다
(미국10대, 노르웨이, 네덜란드, 일본)
서비스 기관의 속성
국가의 속성을 의미합니다 (필요에 따라 사용하지 않기도 합니다)
.com, .edu, .org 등... 이 있습니다
서비스(회사) 의 이름
이 이름만 알면 도메인을 사용할 수 있습니다
서비스 하는 서버의 이름 (사전적 의미)
서비스의 종류를 의미합니다
회사에서 쓰는 여러 가지 프로그램들을 마치 인터넷을 사용하는 것 처럼
쓰도록 만들어 놓은 것 (내부의 네트워크)
인트라넷 역시 TCP/IP 프로토콜을 사용하고 웹 브라우저를 이용해
마치 인터넷을 사용하듯이 사내 업무를 처리할 수 있습니다
기업의 인트라넷을 그 기업의 종업원 이외에도 협력 회사나 고객에게
사용할수있도록한것
구성범위에 따른 네트워크 분류
LAN (Local Area Network)
WAN (Wide Area Network)
근거리 통신망
한정된 좁은 지역에 구성된 네트워크
LAN 구성 장비로는 Switch(Bridge), HUB 등이 있습니다
원거리 통신망
넓은 지역을 연결하는 네트워크 , 서로 멀리 떨어진 곳을 네트워크로 연결 하는 것입니다
관리는 ISP 업체가 담당합니다
WAN 구성 장비로는 Router가 있습니다
DSU / CSU (증폭 변조장치)
증폭시키는 이유
멀리 보내기 위해 (멀리 갈수록 세기가 약해지기때문에)
변조시키는 이유
컴퓨터는 디지털신호이지만, 전기 신호는 아날로그 신호이기 때문에
isp 업체(통신사)가 담당합니다
우리나라에서 사용하고 있는 네트워킹 방식의 거의 90% 이상이 이더넷 방식입니다
“대충 알아서 눈치로 통신하자” 라는 개념
CSMA / CD
(Carrier Sense Multiple Access / Collision Detection)
CS (Carrier Sense)
이더넷 환경에서 통신을 원하는 PC가 네트워크상에 통신이 일어나고 있는지 확인하는 것
MA (Multiple Access)
네트워크 상에서 두 개 이상의 PC나 서버가 동시에 네트워크 상에 데이터를 실어 보내는 경우
CD (Collision Detection)
두 개의 장비들이 데이터를 동시에 보내려 다 부딪치는 경우를 Collision이라 합니다
옆으로 전달하는 방식으로 통신이 이루어짐
한 네트워크 상에서 오직 토큰을 가진 한 pc, 이 네트워크 에데이터를 실어보낼 수 있습니다
데이터를 다 보내고 나면 바로 옆 pc에게 토큰을 건네주는 방식
토큰을 가지고 있는 pc가 전송할 데이터가 없다면 토큰을 다시 옆 pc에게 전달합니다
충돌이 발생하지 않음 (토큰을 가지고있는 컴퓨터만 데이터를 전송하니까)
but 토큰이 돌아올때까지 기다려야하기 때문에 느릴수도있다
MAC address (물리적 주소)
IP address (논리적 주소)
각 장비들은 정확한 통신을 위해 네트워크 상에서 서로 구분 해야합니다
이 역할을 하는 것이 바로 MAC(Media Access Control) address
TCP/IP Protocol을 사용하는 네트워크 (ex. Internet) 에서는 IP address를 사용하여 통신
하지만 최종적으로 MAC address를 사용하여 데이터를 전달
네트워크 장비의 인터페이스는 고유의 MAC address를 가지고 있습니다
(ex. NIC 카드, Router, Switch 등)
네트워크에 연결된 장비들이 가지는 48bit(6 Octet)의 고유한 주소
(전 세계에서 유일한 주소이다.)
Physical address, 즉 물리적 주소라고 부릅니다
이진수로 48bit인 주소이지만 16진수로 표현
이진수 4개를 묶어 16진수 한 자리로 표현합니다
즉, 16진수 12자리로 MAC address를 표현
앞의 24bits (6개의 16진수)는 생산자(생산 회사)를 나타내는 코드로 OUI라고 합니다
OUI를 보면 어느 회사(메이커) 에서 생산했는지 알 수 있습니다
뒤의 24bits는 회사에서 각 장비에 분배하는 Host identifier 즉, 시리얼 넘버입니다
이진수 32비트로 구성된 주소체계
8bit씩4octet로구분,각octet을10진수로변환해서 표현합니다
일반적으로 IP 주소만을 보기 때문에 IP주소로만 통신을 한다고 생각하지만d
IP 와 MAC을 하나로 묶는(바인딩) 절차
ex) 스마트폰의 개통
IP 주소와 MAC 주소를 서로 매핑하는 절차를 ARP라고 합니다
수신측이 한 곳으로 정해져있는 경우
즉, 정확한 특정 목적지의 주소 하나만 가지고 일 대 일로 전달하는 방식
ex) 일대일 카카오톡, 편지
유니캐스트 통신 방식은 그 목적지 주소가 아닌 다른 PC들의 CPU 성능을
저하시키지는 않습니다
일 대 전체 (제한된 불특정 다수) 전달 방식
제한된 범위
같은 네트워크
같은 망
하나의 브로드캐스트 도메인
불특정 다수에게 전부 전송하는 경우
Destination IP address : 255.255.255.255
Destination MAC address : FF-FF-FF-FF-FF-FF
동일 Network에 연결된 모든 네트워크 장비에게 보내는 통신
(즉, Broadcast Domain안의 모든 장비들에게 전송)
브로드캐스트 주소가 오면 PC의 랜카드는 자신의 MAC 주소가 같지 않아도
이 브로드캐스트 패킷을 CPU로 보내게 된다
그래서 과도한 브로드캐스트는 전체 네트워크 성능뿐 아니라,
PC 자체의 성능을 하락시킨다
일 대 그룹(대상이 명확한 집단 / 대상이 정해진 집단) 전송방식
정해진 특정 그룹으로 전송하는 경우
Destination IP address : 224.0.0.5
Destination MAC address : 01-00-5E-00-00-02
특정 다수에게 전송하는 방식
라우터나 스위치에 이 기능을 지원해주어야만, 사용이 가능하다
네트워크 상에서 IP 주소를 물리적 네트워크 주소로 대응(bind)시키기 위해 사용되는 프로토콜
ARP 실습
ip 설정
ip 주소를 입력하면 서브넷 마스크가 자동으로 채워짐
메모에 있는대로 PC3번까지 아이피를 입력해줌
프로토콜
ARP와 ICMP만 설정
ip는 신뢰성를 제공하지 않는 프로토콜임
그래서 icmp를 통해서 목적지 주소의 상태 여부를 확인 할 수 있음
회신된 상태 메세지에 따라서 통신 여부를 확인할 수 있음
ping 이라는 유틸리티를 이용하여 icmp 를 사용할 수 있음
pc0에 커맨드 프롬프트를 열고
이렇게 입력해주면
메세지가 생성됨
ARP 메시지의 정보에서 Outbound PDU Detailes로 가면
주고받는 데이터의 정보를 확인할 수 있음
캡쳐 포워드를 누름
더이상 눌리지 않을때 까지 누르고 확인함
총 4번이 전송된것을 확인할 수 있음
회산된 TTL 값으로 알 수 있는 정보 2가지
운영체제 : window -128 / linux -64
라우터를 1대 경유할때마다 1씩 차감됨
(단, 공유기 / 보안처리된 라우터는 포함 안됨)
arp - a는 arp목록을 보여줌
ARP 특징
Dynamic 은 메모리에 저장됨
Rebooting 시 소멸됨
저장수명시간은 300초 (운영체제마다 상이함)
dynamic에서 static으로 바꾸는 법
apr -s 192.168.0.2 aaaa.bbbb.cccc
영구 보존은 가능하지만, 커널메모리에 저장되고, 어디에 저장되는지 알 수 없음
static의 단점
컴퓨터가 교체되면
요청시간 초과가 나옴
arp -d 192.168.0.3 으로 수동 초기화 해주면 해결 가능
패킷 트레이서는 위 기능을 지원하지 않기 때문에 재부팅을 해주어야함
arp 재설정 방법
재설정 시간을 기다린다
arp -d 명령어로 수동 초기화 해준다
재부팅
서로 다른 네트워크가 통신을 하기 위한 언어 혹은 약속
네트워크 상에는 많은 규칙이 존재하는데 서로 연결된 네트워크는 같은 규칙을 사용해야 함
대표적인 네트워크 protocol로 인터넷 환경에서 데이터를 전송하는 TCP/IP가 있음
국제 표준화 기구(ISO)가 1984년에 발표한 OSI 7 Layer는
통신이 일어나는 과정을 7단계로 구분해서
한눈에 들어올 수 있도록 보여줌
컴퓨터 통신 구조의 모델과 앞으로 개발될
프로토콜의 표준적인 뼈대를 제공하기 위해서
개발된 참조 모델
순서가 중요함 (피데네트세프에 로 외우자)
데이터의 흐름이 한 눈에 보임
Trouble shooting이 쉬움
네트워크 동작 과정을 쉽게 습득할 수 있음
표준 모델이기 때문에 여러 회사 장비를 사용가능
네트워크 통신을 위한 물리적인 표준 정의
물리적인 표준정의
두 장치간의 기계적인 그리고 절차적인 연결을 정의 하는 계층
케이블의 종류, 커넥터, 신호의 세기(전기, 전압 등...)
계층 통신단위 : 비트
계층 장비 : 리피터, 허브
리피터 : 증폭, 연장
허브 : 증폭, 연장, 멀티 포트
논리적인 개통구간
물리적 계층을 통한 데이터 전송에 신뢰성을 제공
프레임을 안전하게 전송하는 것을 목적으로 함
계층 통신 단위 : 프레임
계층 장비 : 스위치, 브릿지
계층 주소 : Mac
피지컬 레이어를 통해 송수신되는 정보의 오류와
흐름을 관리하여
안전한 정보의 전달을 수행할 수 있도록 도와주는 역할
통신의 오류도 찾아주고 재전송도 하는 기능을 가지고 있음
라우팅 프로토콜을 이용해서 Best path선택
계층 통신단위 : 패킷
계층 장비 : 라우터
계층 주소 : ip, ipx (현재 사용 안됨)
Logical address (IP, IPX)를 담당하고 packet(패킷)의 이동 경로를 결정함
데이터를 목적지까지 가장 안전하고 빠르게 전달함
라우터 : 서로다른 네트워크로 통신할 수 있게 해줌
Distance Vector
홉카운트 (라우터 경유) 만으로 최적경로 선택
장점 : 설정이 간단함
단점 : 대규모에서는 사용불가 (최대 15홉)
다양한 네트워크에서는 비효율적
Link State
장치간의 속도 및 적은 수의 라우터 등 종합 연산을 통하여 최적경로 선택
장점 : 빠른속도를 유연하게 유지할 수 있음
단점 : 설정이 복잡하다
많은 리소스 (자원) 을 소모하므로 라우터의 성능이 좋아야함
정보를 분할하여 전송하고, 목적지에 도달하기 전 하나로 합치는 과정을 담당
계층 통신 단위 : 세그먼트
계층 장비 : 게이트웨이
계층 프로토콜
TCP : 신뢰성, 연결지향성, 속도가 느림
목적지까지 안전하게 도달해야하는 성향의 통신
( http / https / ftp / ssh / Telent / 등 ...)
UDP : 비신뢰성, 비연결지향성, 속도가 빠름
많은 양의 데이터를 빠르게 목적지까지 전송만 하면 되는 경우
(dns / dhcp / 스트리밍 / 등...
목적지 컴퓨터에서 발신지 컴퓨터 간의 통신에 있어서
에러제어 (error control) 와 흐름제어 (flow control)을 담당
네트워크 상에서 통신을 할 경우 양쪽 호스트 간에 최초 연결이 되게 하고
통신 중 연결이 끊어지지 않도록 유지 시켜주는 역할을 한다
'
다양한 데이터 포맷을 일관되게 상호 변환하고 압축기능 및 암호화, 복호화 기능을 수행
사용자 인터페이스의 역할을 담당하는 계층
사용자와 가장 가까운 프로토콜 정의
HTTP(80), FTP(20, 21), Telnet(23), SMTP(25), DNS(53), TFTP(69) 등...
옆에 숫자는 포트 숫자를 의미함
1) 10.21.100.4
00001010.00010101.01100100.00000100
2) 165.111.17.90
10100101.01101111.00010001.01011010
3) 192.128.134.72
11000000.10000000.10000110.01001000
TCP / IP 를 사용하는 네트워크 상에 연결되 장비들에게는 고유의 IP 주소가 부여됨
IP address = Network ID + Host ID
하나의 네트워크란, 하나의 Broadcast Domain
하나의 네트워크란, L3장비
(3계층 장비 : 라우터) 를 거치지 않고 통신이 가능한 영역
다른 네트워크와 통신하가 위해서는 라우터를 거쳐야 한다
(중요)
동일 네트워크에소는 Network 부분은 모두 같고, Host 부분이 모두 달라야 한다
이렇게 IP 주소를 network 부분과 host 부분으로 구분해주는 역할을 하는것이 Subnet mask 이다
IP 주소를 효율적으로 배분하기 위해 정해진 약속
첫 번째 옥텟을 보고 구분할 수 있음
EX ) 123.5.67은 Class A임
0과 127은 특별한 역할이 있기 때문에 전체 범위에서 빠짐
0과 127은 제외되고, 1 ~ 126까지 사용
Default Subnet Mask : 255.0.0.0 (/8)
A Class 사설주소 : 10.0.0.0 ~ 10.255.255.255
사설IP는 공인IP와 통신이 불가능
Network 숫자 : 128개 (2개는 예약), 네트워크 당 Host 숫자 : 16,777,214 개
첫 번째 옥텟이 10이면 무조건 Class A
Default Subnet Mask : 255.255.0.0 (/16)
Class 사설주소 : 172.16.0.0 ~ 172.31.255.255
Network 숫자 : 16,384개, 네트워크 당 Host 숫자 : 65,534개
Default Subnet Mask : 255.255.255.0 (/24)
C Class 사설주소
192.168.0.0 ~ 192.168.255.255
Network 숫자 : 2,097,152 개, 네트워크 당 Host 숫자 : 254 개
메인이 아닌 어떤 가공을 통한 네트워크를 만들기 위해서 씌우는 마스크
총 네트워크 범위에서 Network field에 ‘1’을 할당하고 Host field에 ‘0’을 할당한 값이 Subnet mask
편하게 넷아이디라고 부름
ip대역대의 대표주소를 의미
주로 라우팅 할 때 많이 사용됨
IP address : 210.5.1.7
Subnet mask : 255.255.255.0
11010010.00000101.00000001.00000111
11111111.11111111.11111111.00000000
11010010.00000101.00000001.00000000
= 210.5.1.0 (Network ID)
11010010.00000101.00000001.11111111
= 210.5.1.255 (Broadcast)
Network ID와 Broadcast 주소는 IP 주소로 사용할 수 없음
(총 호스트의 숫자 - 2) = 2^n - 2 = 사용 가능한 IP주소의 숫자
2진수로 표현했을 때 (맨 왼쪽부터)
1이 연속적으로 나와야 함
255.255.255.0 => Subnet mask 사용 가능
255.255.255.10 => Subnet mask 사용 불가능
255.255.255.128 => Subnet mask 사용 가능
255.255.255.0 (128 / 192 / 224 / 240 / 248 / 252 / 254 / 255)
255.255.255 ( 254 / 252 / 248 / 240 / 224 / 192 / 128 / 0) .0
Prefix 란 Subnet mask의 ‘1’이 들어간 bit의 숫자
(Subnet mask의 다른 표현 방법)
255.255.255.0 => /24
255.255.0.0 => /16
255.0.0.0 => /8
255.255.255.128 => /25
255.255.255.224 => /27
1.1.1.1 과 1.1.2.1은 같은 네트워크에 속해 있는가?
=> 같은 네트워크
클래스 A는 첫 번째 옥텟이 똑같아야함
128.13.4.1과 128.13.5.2는 같은 네트워크 속해 있는가?
=> 같은 네트워크
클래스 B는 두 번째 옥텟까지 똑같아야함
이렇게 Subnet mask를 각 Class별 default 값으로 사용하는 것을 Classful 하다고 표현함
한 사무실에서 200대의 PC를 사용할 때 어느 Class의 IP를 배정하는 것이 좋은가?
=>Class C가 적당하다. Class A 나 Class B는 사용 호스트의 수에 비해 IP를 낭비함
IP를 효율적으로 낭비 없이 분배하고 Broadcast Domain의 크기를 작게 나눠주는 것
Class별 default Subnet mask를 사용하지 않고 적당한 크기의 Subnet mask로 사용자의 상황에 따라 하나의 네트워크를 작게 여러 개로 나눠 사용
1) 피자조각의 크기
2) 피자 조각의 개수
사용 장치
desktop OS : windows / MAC OS / Linux
workstation OS : Unix / Linux / windows server
사용 환경
CLI : Command Line Interface
명령줄을 이용한 환경 (CUI / TUI) 화면에 글자만 보임
GUI : Graphic User Interface
그래픽을 이용한 환경
오픈소스 운영체제
다양한 회사에서 소스를 가져다가 Linux 운영체제를 만들어냄
Unix 기반의 대표적인 운영체제
하나의 장치에 하나의 운영체제만 설치
부티 시 boot loader 가 설치된 운영체제 바로 부팅
하나의 장치에 여러개의 운영체제를 설치
부팅 시 boot loader가 설치된 운영체제 중 사용자가 선택한 운영체제로 부팅
운영체제 간 자료 취급 방법 등의 각종 호환성 문제로 현재는 잘 사용되지 않는 방식
가상의 컴퓨터를 만들어서 별도 운영체제를 설치하고 사용
실제 컴퓨토는 single booting mode 를 사용
가상 컴퓨터는 별도의 파일로 저장
oracle 제품
무료로 사용
인터페이스가 불편하게 구성
메뉴들이 숨겨져 있는 경우가 있음
a기능의 설정을 하기 위해 b 기능의 설정을 제어하는 경우도 존재
VMware 회사 제품 ( VMware : Virtual Machine software)
여러가지 제품군이 존재
workstation player
개인 사용시 무료
pro의 거의 모든 기능을 사용할 수 있음
workstation pro
유료
모든 메뉴를 사용할 수 있음
Vmware workstation에서 create a New Virtual Machine
커스텀으로 설치 진행
가장 높은 버전 사용
나중에 설치하기로 진행
Linux와 Ubuntu 64bit 선택
가상머신의 이름과 가상머신이 저장될 파일의 경로 설정
CPU의 수와 코어의 수를 선택 한 후 진행
RAM 용량 선택
네트워크 타입 선택
입출력 장치 선택
디스크 타입 선택
가상 디스크 선택
디스크 용량을 40GB로 늘림
디스크의 일부분을 램 처럼 사용할 것이기 때문
가상머신의 디스크 파일이름 확인
가상머신의 세부 사항 점검 후 진행
가상 컴퓨터 생성 완료
edit virtual machine setting 클릭
CD / DVD 항목에서 다운받은 iso 파일 경로 입력
필요없는 장치들 제거 후 진행
power on 버튼 클릭
host 환경 -> guest 환경 : guest 화면 클릭
guest 환경 -> host 환경 : ctrl + alt
try ot install ubuntu 항목 선택 후 진행
try ubuntu 로 진입
(진입 모습)
settings 진입 후 디스플레이 설정에서 1920 * 1080 으로 설정
install Ubuntu 더블클릭
한국어 설정 후 계속하기
키보드 레이아웃 - korean으로 진행
변경 없이 계속하기
기타로 진행
새 파티션 테이블 후 남은공간 클릭 후 + 버튼
크기를 500mb 설정 후 용도를 EFI 시스템 파티션 설정
용량이 가장 큰 남은 공간에서 + 버튼 클릭 후 크기와 마운트 위치 지정
다시 남은 공간에 크기와 스왑영역을 지정
다시 + 버튼 후 크기는 기본값 유지 한 채 마운트 위치는 / 로 지정
(해당 과정 끝 모습)
지금 설치 누른 후 계속하기로 진행
지금 다시 시작하기
엔터 누르고 로그인 화면 진입
Linux 설치 완료
root@localhost:~#
root : 사용자명 / 어느 사용자로 로그인 했는지 표시
localhost : 장치명 / 현재 어느 장치에 연결되어 있는지 표시
~ 현재 위치한 디렉토리
# : 사용 권한 ( # : 관리자 권한 / $ : 일반 사용자 권한)
Linux의 최상위에는 / 라는 이름의 디렉토리가 존재하고, Linux 내부의 모든 파일 / 디렉토리는 / 내부 어딘가에 위치
-> 표시가 있는 항목은 symbolic link로, 바로가기 역할을 한다
/ 내부에 생성되어있는 디렉토리
/bin : 공용 명령어 (일반 사용자 + 관리자) 들이 저장된 디렉토리로 연결되는 link 파일
/sbin : 시스템 제어 명령어 (관리자 명령어) 들이 저장된 디렉토리로 연결되는 link 파일
/boot : 부팅에 관련된 각종 설정 파일과 이미지 파일들이 저장된 디렉토리
/cdrom : cd를 편하게 연결할 수 있도록 만들어놓은 디렉토리
/dev : 장치파일이 생성되는 디렉토리
/ect : 각종 설정 파일과 OS의 환경 설정 파일이 저장되는 디렉토리
/home : 일반 사용자들의 홈 디렉토리가 생성되는 기본 위치
/root : 관리자 root의 홈 디렉토리
/lib ~ : 각종 라이브러리가 저장된 디렉토리로 연결되는 link 파일
/media : local device를 사용하기 편하게 연결해주는 디렉토리
/mnt : remote device를 사용하기 편하게 연결해주는 디렉토리
/usr : 대부분의 응용 프로그램들이 설치되는 위치
/opt : /usr에 저장되지 않은 프로그램들이 저장되는 위치
/proc : 실행중인 프로세스에 대한 가상 파일들이 저장되는 디렉토리
/run : 실행중인 각종 서비스에 필요한 파일들이 생성되는 디렉토리
/snap : snap 명령어를 이용한 프로그램 관리를 하기 위헤 존재하는 디렉토리
/srv : 서버 동작시 외부 사용자가 비교적 쉽게 접근할 수 있는 디렉토리
/sys : 시스템 동작 과정에서 필요한 각종 파일들이 생성되는 디렉토리
/tmp : 임시 파일(디렉토리) 가 생성되는 디렉토리
/var : 러그 등 자주 변경되는 시스템 파일들이 저장되는 디렉토리
홈 디렉토리 : 사용자 개인 디렉토리, 로그인 시 최초 접속 위치
기본적으로 다른 사용자의 접근 불가능 (다른 사람은 접근 불가능)
명령줄 한 줄에는 하나의 명령어만 사용
여러 명령어를 순차적으로 적용시키는 존재
기호들을 사용하지 않으면 한 줄의 명령어에는 하나의 명령어만 사용
대소문자를 엄격하게 구분
파일 / 디렉토리에 찾아가는 길
절대 경로와 상대경로로 구분 (두 가지 방식 전부 사용 가능해야 한다)
절대경로 ./ 를 기준으로 파일 / 디렉토리에 찾아가는 방식
상대경로 : 내 현재 위치를 기준으로 파일 / 디렉토리에 찾아가는 방식
cd ./ : 현재 디렉토리
cd ../ : 상위 디렉토리
형식
명령어 [옵션] [보조옵션] [대상]
내 현재 위치를 절대 경로로 출력
내 현재 위치를 다른 디렉토리로 변경할 때 사용
(= 다른 디렉토리로 이동)
형식은 기본 형싣으로 사용
대상
directory : 해당 디렉토리로 이동
. : 현재 디렉토리로 이동 (의미 X)
.. : 상위 디렉토리로 이동
생략 : 명령어를 입력한 사용자 자신의 홈 디렉토리로 이동
~ : 명령어르 입력한 사용자 자신의 홈 디렉토리로 이동
~ 사용자명 : 해당 사용자의 홈 디렉토리로 이동(관리자 전용)
대상에 따라 출력되는 범위가 달라진다
파일을 대상으로 하면 파일 자체를 출력
디렉토리를 대상으로 하면 디렉토리 내부의 목록을 출력
대상을 생략하면 현재 위치하 디렉토리 내부의 목록을 출력
대상을 생략할 수 있고, 여러개의 파일과 디렉토리를 대상으로 한 번에 지정할 수 있다
옵션
-l : 자세한 정보를 함께 출력
-a : 대상이 디렉토리인 경우 내부의 숨겨진 항목을 함께 출력
-d : 대상이 대렉토리인 경우 디렉토리 자체의 정보를 출력
-R : 대상이 디렉토리인 경우 하위 디렉토리가 존재하면 그 내부까지 출력
자세한 정보 출력 내용
-rw-r--r 1 root root 2888 8월 5 12:58 /etc/passwd
- : 대상의 종류 ( - : 파일 / d : 디렉토리)
rw-r--r : 허가권
1 : link 개수
root root : 소유권 (허가권과 소유권을 권한이라고 말함)
2888 : 크기 (byte 단위 / 디렉토리는 용량출력 불가능)
8월 5 12:58 : 마지막으로 수정된 날짜와 시간
/etc/passwd : 대상의 경로와 이름
기본적으로는 파일만 복사 가능
원본의 이름을 유지하면서 복사 + 이름을 변경하면서 복사 가능
형식
cp [옵션] 원본 ... [원본] 복사할 위치 [+이름]
옵션
(-r 옵션이 없을 경우)
(-r 옵션이 있는 경우)
- move : 잘라내기 + 붙여넣기
원본의 이름을 유지하면서 이동 + 이름을 변경하면서 이동 가능
이름을 변경하면서 이동할 때는 우너본 하나만 사용
이름바꾸기 명령어로 가능
cp 명령어와 사용법이 동일함
파일과 디렉토리 전부 이동 가능
옵션
make directory : 디렉토리 생성
빈 디렉토리를 생성
생성하려는 디렉토리의 경로 (상위 디렉토리)가 없으면 생성 X
형식은 기본형식으로 사용
옵션
remove directory : 디렉토리 삭제
빈 디렉토리의 삭제만 가능
형식은 기본형식으로 사용
옵션
remove : 삭제
기본적으로 파일의 삭제 가능
휴지통 개념 없기 때문에 바로 완전 삭제가 된다
옵션
-i : 확인 메세지 출력
-r : 디렉토리도 삭제
단축어 등록
형식
alias : 현재 등록된 키워드 등록
alias 키워드='명령어[옵션]'
특정 내용을 출력
형식
cat : 입력한 내용을 그대로 출력
cat 파일명 : 해당 파일의 내용 전체를 출력
기호
. : 현재 디렉토리
.. : 상위 디렉토리
~ : 홈 디렉토리
* 모든 종류, 모든 길이의 문자를 대처하는 문자
> : redirection : 기호 왼쪽 명령어가 동작하여 화면에 출력되는 내용을 기호 오른쪽에 저장
기호 오른쪽에 없는 이름을 넣으면 해당 이름의 파일로 생성
이미 존재하는 이름을 넣으면 > 기호는 덮어쓰기
>> 는 내용 추가를 함
| : pipe, 여러 명령어를 순차적으로 동작시키는 기호
괄호
[] 생략이 가능한 항목을 묶어주는 괄호
a랑 b를 이렇게 쓰고
이러면 파일 두 개 합칠 수 있음
대상이 없으면 새로운 빈 파일 생성
대상이 있르면 마지막으로 수정된 날짜와 시간 갱신
형식 : 기본형식 사용
파일의 내용을 처음 10줄만 출력
형식 : 기본 형식 사용
옵션
파일의 내용을 마지막 10줄만 출력
형식 : 기본 형식 사용
옵션
출력되는 내용을 화면 높이에 맞춰 끊어서 출력
지나간 내용을 다시 볼 수 없다
다른 명령어와 일반적으로 (| 기호 사용)
형식 : 기본 형식
동작 후 추가 입력
enter : 한 줄 너어가기
spacebar : 한 화면 넘어가기
q : more 중간에 종료
more와 같은 동작 + 지나간 내용을 다시 볼 수 있다
일반적으로 다른 명령어들과 함께 사용
형식 : 기본 형식 사용
동작 후 추가 입력
enter : 한 줄 너어가기
k : 한 줄 돌아가기 ( 위 방향키 )
spacebar : 한 화면 넘어가기 ( = page down)
page up : 한 화면 돌아가기
shift + g : 마지막 줄로 이동
g : 첫 줄로 이동
q : less 종료
출력되는 내용에 줄 번호를 함께 출력
다른 명령오들과 함꼐 사용 (| 기호 사용)
형식 : 기본 형식 사용
파일의 내용이 몇 줄, 몇 단어, 몇 글자인지 출력
옵션
-w : 줄의 수 (개행문자로 구분)
-c : 단어의 수 (개행문자와 공백문자로 구분)
-l : 글자의 수 (특수문자 모두 포함)
장치에 설정된 날짜와 시간을 출력
형식은 기본 형식으로 사용
형식 rdate[옵션]<타임서버>
옵션
형식
cal : 달력 출력
cal 숫자 : 해당 년도 달력을 출력
cal 숫자1(월) 숫자2(년) : 해당 년도의 해당하는 달을 출력
검색 명령어
범위를 지정하고 옵션으로 검색할 내용을 작성할 수 있음
형식
옵션
-name : 이름으로 검색
-type : 개체 형식으로 검색
-newer : 마지막으로 수정된 날짜와 시간을 기
준으로 더 새로운 개체 검색
-exec : 일반적으로 마지막 옵션으로 사용
검색 결과들을 대상으로 특정 명령을 동작시키기 위해 사용
특정 명령이나 파일에 대한 설명을 제공
형식
enter : 한 줄 너어가기
k : 한 줄 돌아가기 ( 위 방향키 )
spacebar : 한 화면 넘어가기 ( = page down)
page up : 한 화면 돌아가기
shift + g : 마지막 줄로 이동
g : 첫 줄로 이동
q : less 종료
/내용 : 특정 내용을 검색 (검색 후 n을 눌러서 다음 찾기 shift + n 눌러서 이전 찾기)
shutdown -h now
poweroff
halt
init 0
shutdown -r now
reboot
init 6
굉장히 오래 된 CLI 환경의 문서 편집기
90년대에 vi 에디터를 기반으로 한 vim 편집기가 만들어짐
사용환경
명령모드 : 기본 사용 환경, 커서 이동, 복사/ 잘라내기/붙여넣기, 실행취소/다시실행, 삭제, 입력/실행 모드 전환
입력모드 : 내용의 편집을 위한 환경, 파일 내용의 입력/ 수정/ 삭제, 명령 모드 전환
실행모드 : 그 외 대부분의 기능들을 위한 환경, 명령 모드 전환
(ex 모드)
vi 실행 명령
vi : 빈 파일 열기
vi 파일명 : 해당 파일 열기
1) 글자 단위 커서 이동
h : 한 글자 왼쪽으로 이동
j : 한 글자 아래로 이동
k : 한 글자 위로 이동
l : 한 글자 오른쪽으로 이동
2) 단어 단위 커서 이동
( 소문자로 입력하면 특수문자를 별개의 단어로 인식
대문자로 입력하면 공백문자와 개행문자만으로 단어를 구분)
w : 다음 단어의 첫 글자로 이동
b : 이전 단어의 첫 글자로 이동
e : 다음 단어의 마지막 글자로 이동
3) 줄 내부 커서 이동
0 : 줄의 첫 글자로 이동
$ : 줄의 마지막 글자로 이동
4) 화면 내부
H : 화면의 첫 줄로 이동
M : 화면의 가운데 줄로 이동
L : 화면의 마지막 줄로 이동
5) 문서 내부 커서 이동
i : 커서 왼쪽으로 내용 입력
I : 그 줄의 맨 왼쪽에서 내용 입력
a : 커서 오른쪾으로 내용 입력
A : 커서 맨 오른쪽에서 내용 입력
o : 커서 아래쪽에 빈 줄 삽입 후 내용 입력
O : 커서 위쪽으로 빈 줄 삽입 후 내용 입력
s : 커서가 있던 글자를 지우고 내용 입력
S : 그 줄 전체가 사라지고 내용 입력
u : 마지막으로 수행한 동작 취소 (되도리기)
커서가 있는 줄의 내용만 삭제
x : 커서 뒤쪽의 내용을 삭제 (delecte 기능)
X : 커서 앞쪽의 내용을 삭제 (backspace 기능)
yy : 커서가 있는 줄 복사
숫자 + yy : 커서가 있는 줄 부터 숫자만큼의 줄 복사
y + 커서이동 : 커서가 이동해야 하는 만큼 복사
dd : 커서가 있는 줄 잘라내기
숫자 + dd : 커서가 있는 줄 부터 숫자만큼의 줄 잘라내기
d + 커서이동 : 커서가 이동해야 하는 만큼 잘라내기
p : 커서 오른쪽으로 붙여넣기
p : 커서 왼쪽으로 붙여넣기
/찾을내용 : 맨 위에서 아래로 탐색
?찾을내용 : 맨 아래에서 위로 탐색
동작 후 추가 입력
n : 검색 방향으로 다음 찾기
N : 검색 방향의 반대 방향으로 다음 찾기
:[범위]s/찾을 내용/바꿀 내용/[옵션]
범위
생략 : 커서가 위치한 줄에서 특정 내용을 찾아 서 변경
n : n번째 줄에서 특정 내용을 찾아서 변경
n1,n2 : n1 번째 줄 부터 n2 번째 줄 까지 범위에서 특정 내용을 찾아서 변경
% : 문서 전체에서 특정 내용을 찾아서 변경
옵션
(: 뒤에 숫자를 입력해서 숫자번째 줄을 기준으로 동작 가능)
:.! 명령어 : 커서가 있던 줄의 내용을 지유고 명령어 동잡 결과 삽입
:r! 명령어 : 커서가 있는 줄 아래로 명령어 동작 결과 삽입
:r 파일명 : 커서가 있는 줄 아래로 다른 파일의 내용 삽입
( !를 붙여서 강제 동작이 가능)
w : 저장
q : 종료
wq : 저장하고 종료
e 파일명 : 기존 문서를 종료하고 다른 파일 불러오기
ctrl + w + n : 화면 분활
ctrl + w + w : 분활된 화면 간 커서 이동
운영체제를 사용하기 위해 로그인 하는 계정
운영체제를 사용하는 사람들에게 각각 만들어주는 계정
권한을 부여하기 위해 사용
여러 사용자 계정을 하나의 객체로 묶어주기 위해 사용하는 계정
그룹에 권한을 부여하여 그룹에 소속된 모든 사용자들이 동일한 권한을 적용
사용자 계정에 관련된 파일
사용자 계정의 일반적인 정보가 저장된 파일
/etc/passwd
itbank:x:1000:1000:dust,,,:/home/itbank:/bin/bash
itbank : 사용자명, 뒤의 정보가 어느 사용자의 정보인지 표시
x : 비밀번호, passwd 파일에는 보안상의 이유로 암호를 표시 X
1000(왼) : UID, 해당 사용자의 고유 번호
1000(오) : GID, 해당 사용자가 주요 그룹으로 지정한 그룹의 고유 번호
dust,,, : 사용자 별칭, GUI 환경에서 표시되는 이름, ID로 사용 X
/home/itbank : 사용자의 홈 디렉토리를 절대경로로 출력
/bin/bash : shell, 사용자가 어떤 shell을 사용하는지 출력
UID : User ID, 사용자의 고유 번호
GID : Group ID, 그룹의 고유 번호
0 : root
1 ~ 999 : system or service accounts
1000 ~ : 일반 사용자 or 그룹
운영체제에 명령어를 전달해주는 역할
shell은 종류가 다양하고, 운영체제에 따라 기본 설치되어 있는 shell이 다르다
현재 설치된 shell은 /etc/shells 파일에서 확인 가능
사용자 계정의 고급 정보가 저장된 파일
/etc/shadow
itbank:$y$~$~~$~~~:19574:0:99999:7:::
itbank : 사용자명, 뒤의 정보가 어느 사용자의 정보인지 표시
$y$~$~~$~~~ : 비밀번호, 사용자의 비밀번호를 암호화하여 저장
19574 : 암호 생성 일자, 1970년 1월 1일을 기준으로 며칠 후에 생성된 암호인지 표시
0 : 암호 최소 사용 일자
99999 : 암호 최대 사용 일자(암호 만료 일자)
7 : 암호 만료 전 경고 일자
(이 후의 정보는 거의 사용 X, 생략)
사용자/그룹의 생성과 삭제 과정에서 적용되는 여러가지 설정이 저장된 파일
/etc/login.defs
useradd [옵션][값] ... [옵션][값] 사용자명
옵션
-u : UID 지정, 생성하는 사용자 계정의 고유 번호를 지정
-g : GID 지정, 함께 생성되는 그룹이 아닌 다른 그룹을 주요 그룹으로 사용
-m : make directory, 홈 디렉토리 생성
-c : 별칭 지정
-s : shell 지정, 운영체제에 설치된 shell을 절대경로로 작성
-d : 생성될 홈 디렉토리의 경로와 이름을 지정
절대경로로 작성, 홈 디렉토리의 상위 디렉토리(경로)는 미리 생성되어 있어야 한다
-k : skel 지정, 기본 디렉토리인 /etc/skel이 아닌 다른 디렉토리를 skel로 사용할 때 작성
-D : 사용자 생성 시 적용되는 몇 가지 기본 설정을 확인하는 옵션, 이 옵션을 사용하면 사용자 생성 X
추가 옵션을 사용하여 기본 정보 변경이 가능(ex. -b 옵션을 함께 사용하여 홈 디렉토리 생성 위치 변경)
사용자 생성 시 함께 만들어지는 홈 디렉토리 내부에 복사될 개체들을 담아놓는 디렉토리
사용자 홈 디렉토리의 뼈대가 되는 디렉토리
이 디렉토리에 기본적으로 저장된 개체들은 사용자 홈 디렉토리의 필수 요소
사용자 생성 시 적용되는 몇 가지 기본 설정을 저장한 파일
useradd의 -D 옵션 사용 시 출력되는 정보는 이 파일의 내용이다
usermod 옵션 값 [옵션][값]...[옵션][값] 사용자명
옵션은 useradd의 옵션 몇 가지를 제외 하고 전부 동일하게 사용 가능
-m 옵션은 move directory의 의미로 사용
-k 옵션과 -D 옵션은 usermod에서는 사용하지 않음
userdel [옵션] 사용자명
옵션
여러 사용자를 하나의 그룹에 소속시켜서(하나로 묶어서) 사용
그룹에 관련된 파일
파일 내용 보는 방법
itbank:x:1000 :
itban : 그룹명, 뒤의 정보들이 어느 그룹의 정보인지 출력
x : 암호, 그룹은 암호를 사용하지 않는다
1000 : GID, 해당 그룹의 고유번호
마지막 필드 : 해당 그루븽 일반 소속된 사용자 목록
groupadd [옵션][값]...[옵션][값] 그룹명
gorupmode 옵션 값 [옵션][값]...[옵션][값] 그룹명
옵션
-g : GID 지정
-n : 이름 변경
gropdel 그룹명
사용자가 그룹에 소속되는 방식을 크게 두 가지로 나눔
1 ) 사용자가 그룹을 자신의 주요 그룹으로 사용( GID로 사용)
2) 사용자가 그룹에 일반 소속
사용자가 그룹에 소속되는 방식은 필요에 따라 제어할 수 있다
1) 주요 그룹(GID) 지정
사용자를 생성하면 사용자의 이름과 같은 이름의 그룹을 함께 생성하고
만들어지는 사용자는 함께 생성된 그룹을 자신의 주요 그룹을 지정
2) 일반 소속
사용자는 처음에 일반 소속된 그룹이 없는 상태
usermod 명령의 -G 옵션을 사용하거나 gpasswd 명령을 사용하여 사용자가 일반 소속된 그룹의 정보를 제어할 수 있다
(단 usermod의 -G 옵션은 가급적 사용하지 않는다)
사용자의 암호를 제어하는 명령어
형식
passwd : 명령어를 입력한 사용자 자신의 암호를 변경 ( 모든 사용자 가능)
passwd 사용자명 : 해다 ㅇ사용자의 암호를 변경( 관리자만 가능)
그룹의 일반 소속된 사용자 목록을 보여주는 명령어
형식 : gpasswd 옵션 값 그룹명
옵션
-a : 그룹에 특정 사용자를 일반 소속
-d : 그룹에서 특정 사용자를 제외
파일이나 디렉토리를 사용할 수 있는지 정하는 개념
(허가권 + 소유권 = 권한)
실제 적용되는 권한 값들을 나열해놓은 영역
ls 옵션의 -l 옵션이나 -n 옵션을 사용했을 때 나오는 내용 중 개체 형식 문자 뒤에 붙은 9자리 문자가 허가권 영역
8종류의 문자로 각종 권한을 표현 : r,w,x,-,s,S,t,T
r,w,x,- : 일반 권한 표현 문자
s,S,t,T : 특수 권한 표현 문자
일반 권한 표현 문자의 의미
r : 읽기
파일 : 파일 내용을 읽기 위한 권한 (cat,head, tail, less, vi로 열었을 때 등)
디렉토리 : 디렉토리 내부 목록 확인을 위한 권한 (ls 명령어, GUI 환경에서 폴더 열었을때 등)
w : 쓰기
파일 : 파일의 내용을 수정하기 위한 권한 ( 문서 편집 후 저장, > 기호를 이용하여 덮어쓰기 / 내용추가 등)
디렉토리 : 디렉토리 내에 하위 파일 / 디렉토리를 생성 또는 삭제하기 위한 권한
x : 접근 / 실행
- : 권한 없음
허가권 영역에서 r,w,x 문자를 대체하여 입력
- 이 입력된 권한은 없는 권한이다
허가권 9자리의 권한 문자는 3개씩 끊어서 Owner, Group., Other 영역으로 구분
각 영역엑는 r,w,x가 순서대로 들어가고, 특정 권한이 없으면 r,w,x 대신 - 이 들어간다
Owner : 소유자 ( 파일 / 디렉토리를 소유하고 있는 사용자) 를 위한 권한 영역
Group : 그룹 사용자( 파일 /디렉톨티를 소유하고 있는 그룹에 소속된 사용)를 위한 권한 영역
Other : 그 외 사용자를 위한 권한
(Linux의 모든 파일/ 디렉토리는 반드시 하나의 사용자와 하나의 그룹이 소유하도록 되어있다)
문자를 이용한 방법 : r,w,x,- 문자를 보이는 순서대로 읽어주는 방법
숫자를 이용한 방법 : 권한 문자를 바탕으로 숫자값을 계산
영역 분리
r = 4, w = 2, x = 1, - = 0 을 각 영역의 문자에 대입 후 영역별 합을 계산
각 영역에서 구한 합에 Owner은 100, Group은 10, Other은 1을 곱해서 전체 합 계산
chmod [옵션] 권한값 대상 [대상]...[대상]
권한값 작성 방식 : 권한값을 숫자 또는 문자로 입력
숫자로 입력 : numeri method : 변경할 권한 전체를 숫자로 입력
문자로 입력 : symbolic method : 영역 문자에 +,- 기호를 사용하여 더하거나 뺸다
symbolic method 에서 사용하는 영역 문자
u : Owner
g : Group
o : Other
아래 8가지 종류들로, 실제 연산을 위한 값들이 메모리에 저장된다
자바는 C언어와 달리 참조형 변수간의 연산을 할 수 없으므로 실제 연산에 사용되는 것은 모두 기본형 변수이다
논리형 (Boolean) : true / false로 구분되며, 조건식과 논리 게이트에 사용된다.
문자형 (char) : 문자를 저장하는데 사용되며, 하나의 문자만 저장할 수 있다. 저장되는 값은 유니코드 값으로 정수형과 크게 다르지 않다
정수형(byte, short, int, long) : 정수를 저장하는데 사용되며 int형이 가장 많이 사용된다.
실수형 (float, double) : 주로 소수점이 붙은 값을 저장하는데 사용된다
각 타입들의 변수들이 저장할 수 있는 값의 범위는 위와같다
객체의 주소를 저장하기 위한 변수이다. 8개의 기본형을 제외한 나머지 타입
참조형 변수를 선언할 때는 변수의 타입으로 클래스의 이름을 사용하므로 클래스의 이름이 참조변수의 타입이 된다
기본형 변수와 같이 변수 이름 앞에 타입을 적어주면된다. 여기서 참조변수의 타입은 클래스의 이름이다
Date today = new Date(); //Date 객체를 생성해서 그 주소를 today에 저장함
Data타입의 today라는 참조변수를 선언한 것이다
new 연산자의 결과로 참조변수 today에 Date 객체의 주소를 저장했다
변수 : 하나의 값을 저장하기 위한 공간
상수 : 값을 한번만 저장할 수 있는 공간
리터럴 : 그 자체로 값을 의미하는 것
상수는 한번 값을 저장하면 이후에 값을 변경하지 못한다
상수를 선언함과 동시에 초기화를 해주어야한다
상수의 이름은 모두 대문자로 하는것이 관례이며, 여러 단어로 이루어져있는 경우 ' _ ' 으로 구분한다
package Ch02;
public class EX02 {
public static void main(String[] args) {
// TODO Auto-generated method stub
final int MIN_SPEED = 10; // 상수 MIN_SPEED를 선언 & 초기화
final int MAX_SPEED; // 에러 : 선언과 동시에 초기화 해주어야함
final int MAX_VALUE = 10;
MAX_VALUE = 20; // 에러 : 상수의 값은 변경 불가
}
}
수학에서 사용되는 상수 용어가 프로그래밍에서 '한 번 저장하면 변경할 수 없는 저장공간' 이라는 의미로 정의하였기 때문에 이와 구분하기 위해 리터럴이라는 용어를 사용한다
삼각형과 사각형의 넓이를 구해서 변수에 저장하는 코드이다
int triangleArea = (20 * 10) / 2; // 삼각형 면적
int reactangleArea = 20 * 10; // 사각형 면적
식이 간단해서 의미가 없지만, 만약 값이 10과 20을 사용하지 않게 된다면 여러곳을 수정해야한다
final int WIDTH = 20;
final int HEIGHT = 10;
int reactangleArea = WIDTH * HEIGHT; // 사각형 면적
int triangleArea = (WIDTH * HEIGHT) / 2; // 삼각형 면적
하지만 상수를 사용하게 된다면 값을 바꾸기 위해 초기화를 다른 수로 저장하면되고, 상대적으로 가독성이 좋다.
이처럼 상수는 리터럴에 의미있는 이름을 붙여서 코드의 이해와 수정을 쉽게 만든다
코드 간의 관계를 맺어 줌으로써 보다 유기적으로 프로그램을 구성하는 것
코드의 재사용이 쉽다
새로운 코드를 작성할 때 기존의 코드를 이용하여 쉽게 작성할 수 있다
코드의 관리가 용이하다
코드간의 관계를 이용해서 적은 노력으로 쉽게 코드를 변경할 수 있다
신뢰성이 높은 프로그래밍을 가능케 한다
제어자와 메서드를 이용해서 데이터들을 보호하고 올바른 값을 유지하도록 하며, 코드의 중복을 제거하여 코드의 불일치로 인한 오작동을 막을 수 있다
정의 : 객체를 정의해둔 것
용도 : 객체를 생성하는데 사용된다
객체의 설계도라고 정의할 수 있다.
정의 : 실제로 존재하는 것 (사물 또는 개념)
용도 : 객체가 가지고 있는 기능과 속성에 따라 다름
클래스로 부터 객체를 만드는 과정을 클래스의 인스턴스화 (instantiate) 라고 하며, 어떤 클래스로부터 만들어진 객체를 그 클래스의 인스턴스 (instance) 라고 한다
책상은 책상 클래스의 인스턴스다 라고 할 수 있다
클래스 --> (인스턴스화) --> 인스턴스(객체)
객체는 속성 + 기능으로 이루어져있다
일반적으로 객체는 다수의 속성과 다수의 기능을 갖는다
여기서 속성과 기능을 멤버라고 부른다
속성 : 멤버변수, 특성, 필드, 상태
기능 : 메서드, 함수, 행위
예를들어 Tv클래스를 만들어보았다
class TV {
String color; // 색깔
boolean power; //전원 상태
int channel; // 채널
void power(){
power = !power;
}
void setChannelp(){
channel++;
}
void setChannelDown(){
channel--;
}
}
package CH06;
class Tv {
String color; // 색깔
boolean power; //전원 상태
int channel; // 채널
void power(){
power = !power;
}
void setChannelp(){
channel++;
}
void setChannelDown(){
channel--;
}
}
public class EX01 {
public static void main(String[] args){
Tv t;
t = new Tv();
t.channel = 7;
t.setChannelDown();
System.out.println("현재 채널 : "+ t.channel);
}
}
Tv t;
Tv클래스 타입의 참조변수 t를 선언한다
t = new Tv();
new 연산자에 의해 Tv클래스의 인스턴스가 메모리의 빈 공간에 생성된다
t.channel = 7;
참조 변수 t에 저장된 주소에 있는 인스턴스의 멤버변수 channel애 7을 저장한다
t.channelDown();
참조변수 t가 참조하고있는 Tv 인스턴스의 channelDown 메서드를 호출한다.
인스턴스는 참조변수를 통해서만 다룰 수 있으며, 참조변수의 타입은 인스턴스의 타입과 일치해야한다
class Tv {
String color; // 색깔
boolean power; //전원 상태
int channel; // 채널
void power(){
power = !power;
}
void setChannelp(){
channel++;
}
void setChannelDown(){
channel--;
}
}
public class EX02 {
public static void main(String[] args){
Tv t1 = new Tv();
Tv t2 = new Tv();
System.out.println("t1의 channel 값 : " + t1.channel);
System.out.println("t2의 channel 값 : " + t2.channel);
t1.channel = 7;
System.out.println("t1의 channel 값을 7로 변경");
System.out.println("t1의 channel 값 : " + t1.channel);
System.out.println("t2의 channel 값 : " + t2.channel);
}
}
같은 클래스로부터 생성되었을지라도, 각 인스턴스의 속성은 서로 다른 값을 유지할 수 있으며, 메서드의 내용은 모든 인스턴스에 대해 동일하다
package CH06;
class Tv {
// Tv의 속성(멤버변수)
String color; // 색상
boolean power; // 전원상태(on/off)
int channel; // 채널
// Tv의 기능(메서드)
void power() { power = !power; } // TV를 켜거나 끄는 기능을 하는 메서드
void channelUp() { ++channel; } // TV의 채널을 높이는 기능을 하는 메서드
void channelDown() { --channel; } // TV의 채널을 낮추는 기능을 하는 메서드
}
public class EX03 {
public static void main(String[] args){
Tv t1 = new Tv();
Tv t2 = new Tv();
System.out.println("t1의 channel 값 : " + t1.channel);
System.out.println("t2의 channel 값 : " + t2.channel);
t2 = t1;
t1.channel = 7;
System.out.println("t1의 channel 값을 7로 변경");
System.out.println("t1의 channel 값 : " + t1.channel);
System.out.println("t2의 channel 값 : " + t2.channel);
}
}
참조변수에서는 하나의 값만이 저장될 수 있으므로 둘 이상의 참조변수가 하나의 인스턴스를 가리키는(참조하는) 것은 가능하지만, 하나의 참조변수로 여러개의 인스턴스를 가리키는 것은 가능하지 않다
많은 수의 객체들을 다뤄야 할 때, 배열로 다루면 편리할 것이다
Tv tv1, tv2, tv3;
Tv[] tvArr = new Tv[3]; // 길이가 3인 Tv타입의 참조변수 배열
tvArr : 0x100 >> (0x100) >> tvArr[0] : null, tvArr[1] : null, tvArr[2] : null
이렇게 객체 배열을 생성하는 것은 그저 객체를 다루기 위한 참조변수들이 만들어진 것일 뿐, 아직 객체가 저장되지 않았다
객체를 생성해서 객체 배열의 각 요소에 저장하는 것을 잊으면 안 된다
tvArr[0] = new Tv();
tvArr[1] = new Tv();
tvArr[2] = new Tv();
배열의 초기화 블럭을 사용하면 다음과 같이 한 줄로 간단히 할 수 있다
Tv[] tvArr = { new Tv(), new Tv(), new Tv()};
단, 다루어야할, 객체의 수가 많을 때는 for 문을 사용하면 된다
Tv[] tvArr3 = new Tv[100];
for(int i=0; i < tvArr1.length; i++){
tvArr3[i] = new Tv();
}
모든 배열이 그렇듯이 객체 배열도 같은 타입의 객체만 저장할 수 있다.
package CH06;
class Tv {
// Tv의 속성(멤버변수)
String color; // 색상
boolean power; // 전원상태(on/off)
int channel; // 채널
// Tv의 기능(메서드)
void power() {
power = !power;
} // TV를 켜거나 끄는 기능을 하는 메서드
void channelUp() {
++channel;
} // TV의 채널을 높이는 기능을 하는 메서드
void channelDown() {
--channel;
} // TV의 채널을 낮추는 기능을 하는 메서드
}
public class EX05 {
public static void main(String[] args){
Tv[] tvArr = new Tv[3];
for(int i=0; i < tvArr.length; i++){
tvArr[i] = new Tv();
tvArr[i].channel = i+10; // tvArr[i]의 channel에 i + 10을 저장
}
for(int i = 0; i < tvArr.length; i++){
tvArr[i].channelUp();
System.out.printf("tvAarr[%d].channel = %d%n",i,tvArr[i].channel);
}
}
}
클래스는 객체를 생성하기 위한 틀이며 클래스는 속성과 기능으로 정의되어있다
이것은 객체지향 이론의 관점에서 내린 정의이고, 이번엔 프로그래밍 관점에서 클래스의 정의와 의미를 공부할 것이다
프로그래밍 언어에서 데이터 처리를 위한 데이터 저장 형태의 발전과정은 다음과 같다
변수 : 하나의 데이터를 저장할 수 있는 공간
배열 : 같은 종류의 여러 데이터를 하나의 집합으로 저장할 수 있는 공간
구조체 : 서로 관련된 여러 데이터를 종류에 상관없이 하나의 집합으로 저장할 수 있는 공간
클래스 : 데이터와 함수의 결합 (구조체 + 함수)
사용자정의 타입이란, 기본 자료형 이외에 프로그래머가 서로 관련된 변수들을 묶어서 하나의 타입으로 새로 추가하는 것
시간을 표현하기 위해서 다음과 같은 3개의 변수를 선언하였다
int hour;
int minute;
int second;
만약 3개의 시간을 다루어야한다면, 다음과 같이 해야한다
int hour1, hour2,hour3;
int minute1, minute2, minute3;
int second1, second2, second3;
이렇게 다뤄야 할 시간의 개수가 늘어날 때마다 변수를 늘려주어야 한다
int[] hour = new int[3];
int[] minute = new int[3];
float[] second = new float[3];
배열로 처리한다면 데이터의 개수가 늘어나도 배열의 길이만 변경해주면 되기 때문에, 변수를 매번 선언해줘야 하는 불편함과 복잡성은 사라지지만,
하나의 시간을 구성하는 시, 분, 초가 따로 분리되어있기 때문에 프로그래밍 수행 과정에서 올바르지 않은 데이터가 될 가능성이 있다
이런 경우 시, 분, 초를 하나로 묶는 클래스를 정의해야 한다
class Time {
int hour;
int minute;
int second;
}
변수의 종류를 결정짓는 중요한 요소는 '변수가 선언된 위치' 이다
변수의 종류를 파악하기 위해서는 변수가 어느 영역에 선언되었는지 확인하는 것이 중요하다
class Variables{
int iv; // 인스턴스 변수
static int cv; // 클래스 변수 (static 변수, 공유변수)
void method() {
int lv; // 지역변수
}
}
클래스 영역에 선언된다
클래스의 인스턴스를 생성할 때 만들어진다
인스턴스 변수의 값을 읽어오거나 저장하기 위해서는 인스턴스를 생성해야한다
인스턴스는 독립적인 저장공간을 가지므로 서로 다른 값을 가질 수 없다
인스턴스마다 고유한 상태를 유지해야하는 속성의 경우 인스턴스 변수로 선언한다
선언 하는 법 : 변수 앞에 static을 붙인다
모든 인스턴스는 공통된 변수를 공유한다
한 클래스의 모든 인스턴스들이 공통적인 값을 유지해야하는 속성의 경우 클랫 변수로 선언해야한다
인스턴스를 생성하지 않아도 언제라도 바로 사용할 수 있다
메모리에 로딩 될 때 생성되어 프로그램이 종료될 때 까지 유지된다
맨 앞에 public를 붙이면 프로그램 어디서나 접근할 수 있는 전역변수의 성격을 갖는다
메서드 내에 선언되어 메서드 네에서만 사용 가능하다
메서드가 종료되면 소멸된다
두 변수의 차이를 이해하기 위해 트럼프 카드를 클래스로 정의해보았다
카드 클래스를 작성하기 위해서 먼저 카드의 속성과 기능을 알아야 한다
카드의 무늬, 폭, 높이 정도를 생각했다
어떤 변수를 클래스 변수로, 어떤 변수를 인스턴스 변수로 선언할지 생각한다
class card {
String kind; // 무늬
int number; // 숫자
static int width = 100; // 폭
static int height = 250; // 높이
}
각 card 인스턴스는 각 카드마다 다른 무늬와 숫자를 가지고 있어야 하므로 인스턴스 변수로 선언하였고,
모든 카드의 폭과 높이는 같아야하기 때문에 클래스 변수로 선언하였다
카드의 폭이 변하는 경우 모든 카드의 width 변수값을 변경하지 않고, 한 카드의 width 값만 변경하여도 모든 카드의 width 값이 변경된다
package CH06;
class Card {
String kind; // 무늬
int number; // 숫자
static int width = 100; // 폭
static int height = 250; // 높이
}
public class EX08 {
public static void main(String[] args){
System.out.println("card.width : " + Card.width);
System.out.println("card.height : " + Card.height);
Card c1 = new Card();
c1.kind = "Heart";
c1.number = 7;
Card c2 = new Card();
c2.kind = "Spade";
c2.number = 4;
System.out.println("c1은 " + c1.kind + "," + c1.number + " 이며, 크기는" + c1.width + "," + c1.height);
System.out.println("c2는 " + c2.kind + "," + c2.number + " 이며, 크기는" + c2.width + "," + c2.height);
System.out.println("c1의 width와 height 값을 각각 50 80 으로 변경합니다");
c1.width = 50;
c1.height = 80;
System.out.println("c1은 " + c1.kind + "," + c1.number + " 이며, 크기는" + c1.width + "," + c1.height);
System.out.println("c2는 " + c2.kind + "," + c2.number + " 이며, 크기는" + c2.width + "," + c2.height);
}
}
Card의 클래스 변수(static 변수)인 width와 height는 Card 클래스의 인스턴스를 생성하지 않고도 사용할 수 있다
Card 인스턴스인 c1와 c2는 클래스 변수인 width와 height를 공유하기 때문에 c1의 height 와 width를 변경하면 c2의 height 와 width 또한 변경된다
Card.width, c1.width, c2.width는 모두 같은 저장공간을 참조하므로 항상 같은 값을 갖는다
응용프로그램이 실행되면, JVM은 시스템으로부터 프로그램을 수행하는데 필요한 메모리를 할당받고 JVM은 이 메모리를 용도에 따라 영역으로 나누어 관리한다
프로그램 실행 중 어떤 클래스가 사용되면 JVM은 해당 클래스의 클래스파일(*.class)을 읽어서 분석하여 클래스에 대한 정보 (클래스 데이터)를 이곳에 저장한다. 이 때, 그 클래스의 클래스 변수 (class variable)도 이 영역에 함께 생성된다
인스턴스가 생성되는 공간, 프로그램 실행 중 생성되는 인스턴스는 모두 이곳에 생성된다
즉 인스턴스 변수들이 생성되는 공간이다
호출스택 메서드의 작업에 필요한 메모리 공간을 제공한다
메서드가 호출되면, 호출스택에 호출된 메서드를 위한 메모리가 할당되며, 이 메모리는 메서드가 작업을 수행하는 동안 지역변수 (매개변수 포함) 들과 연산의 중간결과 등을 저장하는데 사용된다
메서드가 작업을 마치면 할당되었던 메모리 공간을 반환되어 비워진다
메서드가 호출되면 수행에 필요한 만큼의 메모리를 스택에 할당받는다
메서드가 수행을 마치고 나면 사용했던 메모리를 반환하고, 스택에서 제거된다
호출스택의 제일 위에 있는 메서드가 현재 실행중인 메서드이다
아래에 있는 메서드가 바로 위의 메서드를 호출한 메서드이다
package CH06;
public class EX09 {
public static void main(String[] args){
firstMethod(); //
}
static void firstMethod(){
secondMethod();
}
static void secondMethod(){
System.out.println("secondMethod()");
}
}
변수에서와 같이 static이 붙어있으면 클래스 메서드, 없으면 인스턴스 메서드이다
클래스 메서드도 클래스 변수처럼 객체를 생성하지 않고 호출이 가능하다
반면 인스턴스 메서드는 객체를 생성하여 호출해야한다
인스턴스 메서드는 인스턴스 변수와 관련된 작업을 하는, 즉 메서드의 작업을 수행하는데 인스턴스 변수를 필요로 하는 메서드이다
인스턴스 변수는 인스턴스(객체)를 생성해야만, 사용가능하기 때문에 인스턴스 메서드 또한 인스턴스를 생성해야만 호출 할 수 있다
인스턴스와 관계 없는 (인스턴스 변수나 인스턴스 메서드를 사용하지 않는) 메서드를 클래스 메서드라고 정의한다
물론 인스턴스 변수를 사용하지 않는다고 해서 반드시 클래스 메서드로 정의해야 하는 것은 아니지만, 특별한 이유가 없다면 클래스 메서드로 정의하는 것이 일반적이다
클래스를 설계할 때 멤버변수 중 모든 인스턴스에 공통적으로 사용하는 것에 static를 붙인다
생성된 각 인스턴스는 서로 독립적이기 때문에 각 인스턴스의 변수 (iv) 는 서로 다른 값을 유지한다
그러나 모든 인스턴스에서 같은 값이 유지되어야 하는 변수는 static을 붙여서 클래스 변수로 정의해야 한다
클래스 변수 (static 변수)는 인스턴스 변수를 사용할 수 없다
클래스 메서드에는 인스턴스 변수를 사용할 수 없다
인스턴스 변수는 인스턴스가 반드시 존재해야 사용할 수 있지만, 크래스 메서드는 인스턴스 생성 없이 호출이 가능하므로 클래스 메서드가 호출되었을 때 인스턴스가 존재하지 않을 수 있다
반면에 인스턴스 변수나 인스턴스 메서드에서는 static이 붙은 멤버들을 사용하는 것이 언제나 가능하다. 인스턴스 변수가 존재한다는 것을 의미하기 때문이다
메서드 내에서 인스턴스 변수를 사용하지 않는다면 static을 붙이는 것을 고려한다
메서드의 작업내용 중에서 인스턴스 변수를 필요로 한다면 static을 붙일 수 없다
인스턴스 변수를 필요로 하지 않는다면 static을 붙이자. 메서드 호출시간이 짧아지므로, 성능이 향상된다. static을 안 붙인 메서드는 실행시 호출되어야할 메서드를 찾는 괒어이 추가적으로 필요하기 때문에 시간이 더 걸린다
package CH06;
class MyMath2 {
long a,b;
// 인스턴스 변수 a,b 만을이용해서 작업하므로 매개변수가 필요없다
long add() {
return a + b;
}
long subtract() {
return a - b;
}
long multiply() {
return a * b;
}
long divide() {
return a / b;
}
// 인스턴스변수와 관계없이 매개변수만으로 작업이 가능하다.
static long add (long a, long b) {
return a + b;
}
static long substract (long a, long b) {
return a - b;
}
static long multiply (long a, long b) {
return a * b;
}
static long divide (long a, long b) {
return a / b;
}
}
public class EX10 {
public static void main(String[] args) {
//클래스 메서드 호출, 인스턴스 생성없이 호출 가능
System.out.println(MyMath2.add(200L, 100L));
System.out.println(MyMath2.substract(200L, 100L));
System.out.println(MyMath2.multiply(200L, 100L));
System.out.println(MyMath2.divide(200L, 100L));
MyMath2 mm = new MyMath2();
mm.a = 200L;
mm.b = 100L;
System.out.println(mm.add());
System.out.println(mm.subtract());
System.out.println(mm.multiply());
System.out.println(mm.divide());
}
}
인스턴스 메서드인 add()와 같이 매개변수가 없는 인스턴스 메서드들은 a와 b만으로도 충분히 작업이 가능하기 때문에 매개변수를 선언하지 않았다
반면 static long add(long a, long b) 와 같이 매개변수와 static가 있는 있는 클래스 메서드 들은 매개변수 만으로 작업을 수행하기 때문에 매개변수를 선언ㄹ하였다
그리고 인스턴스 매서드들은 인스턴스를 생성해야 사용할 수 있다
인스턴스 멤버가 존재하는 시점에 클래스 멤버는 항상 존재하지만, 클래스 멤버가 존재하는 시점에 인스턴스 멤버가 존재하지 않을 수도 있기 때문에 같은 클래스에 속해있는 멤버들 간에는 별도의 인스턴스를 생성하지 않고 서로 참조 또는 호출이 가능하다
class TestClass {
void instanceMethod() {}
static void staticMethod() {}
void instanceMethod2() {
instanceMethod();
staticMethod();
}
static void staticMethod2() {
instanceMethod(); // 에러 >> 인스턴스 메서드를 호출할 수 없다
staticMethod();
}
}
같은 클래스 내의 메서드는 서로 객체의 생성이나 참조변수 없이 직접 호출이 가능하지만, static메서드는 인스턴스 메서드를 호출할 수 없다
class TestClass2 {
int iv;
static int cv;
void instanceMethod(){
System.out.println(iv);
System.out.println(iv);
}
static void staticMethod(){
System.out.println(iv); // 에러 >> 인스턴스 변수를 사용할 수 없다
System.out.println(cv);
}
}
메서드간의 호출과 마찬가지로 인스턴스 메서드는 인스턴스 변수를 사용할 수 있지만, static메서드는 인스턴스 변수를 사용할 수 없다
.toLowerCase() : 지정 된 문자열을 소문자로 반환
.toUpperCase() : 지정 된 문자열을 대문자로 반환
String str = new String("Java is Easy");
System.out.println("기본 : " + str );
System.out.println("소문자 변환" + str.toLowerCase());
System.out.println("대문자 변환" + str.toUpperCase());
String str = new String("Java is Easy");
String changeStr = new String();
changeStr = str.replace("Easy", "Hard");
System.out.println("문자열 치환 : " + changeStr);
이 메서드의 경우 배열을 이용하여 분리 된 문자열을 따로 저장
String str = new String("Java is Easy");
String[] arrStr = str.split("is");
System.out.println("문자열 분리:" + arrStr[0] + "*");
System.out.println("문자열 분리:" + arrStr[1] + "*");
String Str2 = new String(" Java is Hard ");
System.out.println("공백 제거" + Str2.trim() );
동일 패키지 클래스 내부, 외부에서 모두 접근이 가능한 접근 제한자
다른 패키지의 클래스 또한 접근이 가능하다
일반 클래스, 중첩 클래스, 필드, 생성자, 메소드
Public은 내외부 모두 접근이 가능하므로, 전부 적용이 가능
package Day06;
import java.util.Scanner;
class AccessModifier1 {
public String name;
public int age;
public String addr;
}
public class EX01 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
AccessModifier1 am = new AccessModifier1();
System.out.print("이름 : ");
am.name = input.next();
System.out.print("나이 : ");
am.age = input.nextInt();
System.out.print("주소 : ");
am.addr = input.next();
System.out.println("이름 : " + am.name);
System.out.println("나이 : " + am.age);
System.out.println("주소 : " + am.addr);
input.close();
}
}
다른 클래스에서도 접근 가능하기 때문에 오류가 발생하지 않는다
클래스 내부에서만 접근이 가능하며 다른 클래스에서는 접근이 불가능하다
다른 패키지의 클래스 또한 접근이 불가능하다
중첩 크랠스, 필드, 생성자, 메소드
내부에서만 접근이 가능하므로, 클래스 내부에서만 사용 가능
package Day06;
import java.util.Scanner;
class AccessModifier2 {
private String name;
private int age;
private String addr;
}
public class EX02 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
AccessModifier2 am = new AccessModifier2();
System.out.print("이름 : ");
am.name = input.next();
System.out.print("나이 : ");
am.age = input.nextInt();
System.out.print("주소 : ");
am.addr = input.next();
System.out.println("이름 : " + am.name);
System.out.println("나이 : " + am.age);
System.out.println("주소 : " + am.addr);
input.close();
}
}
The field AccessModifier2.name is not visible
다른 외부의 클래스에서는 접근 불가능하기 때문에 오류가 발생한다
동일 패키지에서는 접근이 가능하며, 다른 패키지에서는 접근이 불가능하다
상속된 자식 클래스에서는 어디에서든 접근이 가능하다
중첩 클래스, 필드, 생성자, 메소드
동일 패키지 접근이 가능하지만, 클래스 내부에서만 사용 가능
상속 된 클래스에서만 접근을 허용하는 것이 목적이다
접근 제한자에 대한 명시가 없을 경우 Default 접근 제한자가 설정된다
동일 패키지에서는 접근이 가능하며, 다른 패키지에서는 접근이 불가능하다
일반 클래스 중첩 클래스, 필드, 생성자, 메소드
동일 패키지에서 접근이 가능하므로 전부 적용이 가능
package Day06;
import java.util.Scanner;
class AccessModifier3 {
private String name;
private int age;
private String addr;
}
public class EX03 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
EX04 am = new EX04();
System.out.print("이름 : ");
am.name = input.next();
System.out.print("나이 : ");
am.age = input.nextInt();
System.out.print("주소 : ");
am.addr = input.next();
System.out.println("이름 : " + am.name);
System.out.println("나이 : " + am.age);
System.out.println("주소 : " + am.addr);
input.close();
}
}
package Day07;
public class EX04 {
String name;
int age;
String addr;
}
다른 패키지 파일에서 선언된 변수들의 접근 제한자가 명시되어있지 않으니 Default 로 적용되었다
사용하기 위해선 public을 사용해야 한다
클래스의 필드변수의 접근 제한을 통해 클래스의 정보를 숨기는 행위를 의미한다
모든 멤버변수가 외부에 공개되어있을 경우 누구나 클래스의 멤버변수 값을 임의로 조작할 수있는 상태가 만들어질 수 있다
클래스의 정보은닉을 구현하기 위해서는 멤버변수의 접근제한자 Private 설정을 통해 외부에서의 접근 제한을 명시한다
접근제한이 설정 된 멤버변수의 값은 객체 내부의 검사 및 검증 작업을 진행 한 후 멤버변수의 값을 변경할 수 있도록 구현한다
EX)
자동차의 속도를 저장하느 멤버변수의 값이 외부에 공개되어있을 경우 외부 사용자가 자동차의 속도를 저장하는 멤버변수에 임의적으로 접근하여 음수값 데이터를 설정 할 경우 멤버변수의 무결성이 깨지는 상황이 발생하게 된다
하나의 온전한 기능을 수행 할 수 있는 클래스를 저의한 것을 의미한다
클래스의 구성요소인 Field, Method, Constructor, Getter & Setter, Access Modifier 둥 이 정의된 상태를 말한다
클래스의 캡슐화를 진행할 경우 객체 내부에서 발생하는 검증 및 검사등의 작업은 외부에서 알 수 없는 상태가 구현된다
접근 제한이 설정 된 필드 변수에 접근하기 위한 메서드
Getter Method : 필드 변수의 값을 사용할 때 사용
Setter Method : 필드 변수의 값을 설정할 떄 사용
Getter, Setter 는 프로그래머들간 약속 된 이름 구조 (다른 이름 사용 가능)
Getter Method 이름지정 기본형식 : get + Field name ( getName )
Setter Method 이름지정 기본형식 : set + Field name ( setName )
접근 제한자에 따라 [공개형, 비공개형, 읽기 전용] 등으로 구성할 수 있다
비공개형 : 외부와 연결 가능한 Method를 추가 구성 후 사요한다
읽기 전용의 경우 Setter는 비공개 / Getter는 공개 형식으로 구성한다
this 는 객체 자기 자신을 의미한다
객체 내부에서 인스턴스 멤버에 접근 시 사용된다
주로 생성자와 메서드의 매개변수의 이름이 필드 이름과 동일할 때 사용한다
매개변수는 지역변수로 구성되며, 인스턴스 변수보다 우선순위가 높다
지역변수와 필드 이름이 동일 한 경우 인스턴스 변수에 접근이 불가능하다
만약 동일이름 구조에서 인스턴스 변수에 접근하기 위해서는 this를 사용한다
package Day06;
import java.util.*;
class Person1 {
String name = "펭수";
int age = 20;
public void setPerson(String name, int age) {
name = name;
age = age;
}
}
public class EX29 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Person1 per = new Person1();
Scanner input = new Scanner(System.in);
System.out.print("이름 입력 : ");
String name = input.next();
System.out.print("나이 입력 : ");
int age = input.nextInt();
per.setPerson(name, age);
System.out.println("이름 : " + per.name);
System.out.println("나이 : " + per.age);
input.close();
}
}
값이 변경되지 않는다
package Day06;
import java.util.*;
class Person2 {
String name = "펭수";
int age = 20;
public void setPerson(String name, int age) {
this.name = name;
this.age = age;
}
}
public class EX30 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Person2 per = new Person2();
Scanner input = new Scanner(System.in);
System.out.print("이름 입력 : ");
String name = input.next();
System.out.print("나이 입력 : ");
int age = input.nextInt();
per.setPerson(name, age);
System.out.println("이름 : " + per.name);
System.out.println("나이 : " + per.age);
input.close();
}
}
값이 변경된다
이렇게 유용한 정보를 공유해주셔서 감사합니다.