자료형: 값들의 집합
사전 정의된 기본 자료형: boolean, char, int, float, double,..
사용자 정의 기본 자료형: 열거형: 열거된 값들로 이루어진 타입
C/C++ 열거형 예
enum Day {Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday}; enum Day today=Monday;
Ada 열거형 예
type Day is (Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday); today:Day;
열거형이 실제로 갖는 값은 0,1,2,…이다.
구조체
여러 개의 변수들을 묶어서 구성하는 자료형
struct in C, record in Pascal, Ada, …
C++의 Class
C의 struct를 확장
데이터뿐 아니라 연산(함수)들을 포함하도록 확장한 자료형
C의 예
struct Employee { int age; char name[10]; floar salary; }; int main() { struct Employee person; strcpy(person.name, "kim"); person.age = 10; person.salary = 10000; printf("person.name:%s\n", person.name); printf("person.age:%d\n", person.age); printf("person.salary:%f\n", person.salary); return 0; }
// 구조체에 새로운 이름 typedef struct { int age; char name[10]; floar salary; }Employee;
배열 타입: 같은 타입의 연속된 변수들로 구성하는 자료형
정수 배열의 주소
int a[3];일 때 a[i]의 주소 -> a[0]의 주소 + i*sizeof(int)
int a[3][4];일 때 a[i][j]의 주소 -> a[0][0]의 주소 + (i*4+j)*sizeof(int)
리스트
파이썬의 리스트는 다른 타입의 변수들로 구성가능한 자료형
week=['Monday','Tuesday','Wednesday','Thursday','Friday'] primes=[2,3,5,7,11,13,17] b=[1,'two','3','four','5','six'] a=[1,2,3,['a','b','c']] print(week[0]) print(primes[2]) print(b[1]) print(a[1],a[3])
Java의 ArrayList (동적 배열)
파이썬의 리스트와 유사하나, <>을 이용해서 타입 지정도 가능
import java.util.*; public class MyClass{ public static void main(String[] args){ ArrayList list=new ArrayList(); // ArrayList<Integer> integers1 = new ArrayList<Integer>(); // 타입 지정 list.add("ONE"); list.add(3.0); System.out.println(list); } }
포인터
변수의 주소를 저장하는 변수, 변수를 가리키는 변수
#include <stdio.h> #include <stdlib.h> int main() { int *p = (int*)malloc(4); int y = 10; *p = y; *p = *p / 2; printf("%d: %d\n", p, *p); p = &y; printf("%d: %d\n", p, *p); return 0; }
자료형 종류
Java에서는 long이 8바이트임
묵시적 형변환
ex) 정수(int형) 4바이트 -> 실수(doublie형) 8바이트
double y=99; // 99.0
확장 변환
표현의 범위가 더 넓은 쪽으로 변환
축소 변환
표현의 범위가 더 좁은 쪽으로 변환
대입 변환
대입문의 경우에도 확장 변환인 경우에만 자동 수행,
축소 변환인 경우에는 자동으로 수행하지 않음 (축소하다 범위 밖이라 오류가 걸릴 수도 있으므로)
byte b=123; // 정수는 기본적으로 int형이므로 축소 변환 short s=456; // 축소 변환 int i=s; // 확장 변환 byte b2=456; // 축소 변환 중 오류
정적 타입 언어
변수의 타입이 컴파일 시간에 결정되어 고정되는 언어로, 보통 컴파일 시간에 타입 검사를 한다.
ex) Java, C, C++, fortran, pascal, scala
동적 타입 언어
변수의 타입이 저장되는 값에 따라 실행 중에 바뀔 수 있는 언어로, 보통 실행 시간에 타입 검사를 한다.
ex) perl, python, scheme, javascript
JavaScript의 예
변수 name은 선언된 타입이 없고, 대입된 값에 따라 변수의 타입이 변경된다.
var name; name="john"; name=34;
정적 타입 언어와 동적 타입 언어의 차이
아래 코드에 대해 java(정적 타입 언어)는 에러가 발생함. 그러나 python(동적 타입 언어)는 에러가 발생
하지 않음
int x=1; bool y=true; y=x; x=x+y
강한 타입 언어
엄격한 타입 규칙을 적용하여 타입 오류를 찾아낼 수 있는 언어
ex) java, c#, python
약한 타입 언어
느슨한 타입 규칙을 적용한 언어
ex) c/c++, php, perl, javascript
타입 규칙
정수와 +식에 대한 타입 규칙
|- E1: int |-E2:int이면, |-E1+E2:int이다.
-> |- E1: int |-E2:int / |-E1+E2:int
안전한 타입 시스템
어떤 수식의 타입이 t라고 결정했으면 수식 E를 실제 실행하여 계산된 값이 t타입의 값이어야 한다.
-> |-E:t이면(수식 E의 타입이 t이면), 실제 실행에서 E의 계산된 값 V(E)이 t타입이다.
-> if |-E:t and V(E)=v. then v:t
안전하지 않은 타입 시스템 종류
C,C++
느슨하면서 안전하지 않은 타입 시스템을 갖추고 있음
주로 타입 캐스트(cast)나 포인터 연산 때문에 안전하지 않음
거의 안전한 타입 시스템 종류
pascal, Ada
허상 포인터(dangling pointer) 때문에 안전하지는 않다
안전한 타입 시스템 종류
ML, Java
엄격하면서 안전한 타입 시스템을 갖추고 있다.
컴파일 과정에서 엄격하게 타입 검사를 함으로써 실행시간에 타입으로 인한 오류를 미연에 방지한다.
타입 환경
Gamma |- Identifer:type
1. 상수를 위한 규칙
Γ |- n:int, Γ |- true:bool, Γ |- false:bool
2. 변수를 위한 규칙 (t=type)
Γ(id)=t / Γ |- id:t
연산
Γ = { x|->int, y|->int }
Γ |- x*x+y:int
Γ |- x*x:int, Γ|-y:int
Γ|-x:int, Γ|-x:int
관계
Γ = { x|->int, y|->int }
Γ|-x==y:bool
Γ|-x:int, Γ|-y:int
대입
{x|->int} |- x=x+1:void
{x|->int} |- x:int, {x|->int} |- x+1:int
{x|->int} |- x:int, {x|->int} |- 1:int
let문
{}|-let int x=0 in x=x+1 end:void
{} |- 0:int, {x|->int} |- x=x+1:void
{x|->int} |- x:int, {x|->int} |- x+1:int
{x|->int} |- x:int, {x|->int} |- 1:int
리턴문
{x|->int} |- return x*x:int
{x|->int} |- x*x:int
조건문
Γ={x|->int} |- if … then … else …:void
Γ |- (x>0):bool, Γ|-return true:bool, Γ|-return false:bool
Γ |- x:int, Γ|-0:int, Γ|-true:bool, Γ|-false:bool
반복문
Γ={x|->int} |- while …:void
Γ|-(x>0):int, Γ|-{…}:void
Γ|-x:int, Γ|-0:int, Γ|-y=y*x:int, Γ|-x=x-1:int
Γ|-y:int, Γ|-y*x:int, Γ|-x:int, Γ|-x-1:int
재귀 함수
Γ = {fact|->int|->int, n|->int}
{} |- fun int fact(int n) if(n==1) …: int ->int
Γ|-if(n==1) then return 1;else return n*fact(n-1):int
Γ|-(n==1):bool, Γ|-return 1:int, Γ|-return n*fact(n-1):int
Γ|-n:int, Γ|-fact(n-1):int
프로시저
한 그룹의 계산 과정을 추상화하는 메커니즘으로, 반환값이 없으며 매개변수나 비지역 변수를 변경한다.
함수
반환 값이 있으므로 식에 나타날 수 있고 매개변수나 비지역 변수 값 변경은 선택적이다.
매개변수 전달 방법
1. 값 전달 (pass by value)
2. 참조 전달 (pass by reference)
3. 값-결과 전달 (pass by value-result)
4. 이름 전달 (pass by name)
값 전달
값만 전달하므로, a의 주소에 대응되는 메모리 값, b의 주소에 대응되는 메모리 값은 변함없음
참조 전달
레퍼런스 변수(참조자)에게 주소를 전달함
-> 동일한 주소의 이름이 여러 개가 되는 효과가 있음
아래 예시에 의하면, a의 주소의 이름은 a와 x가 됨, b의 주소의 이름은 b와 y가 됨
따라서 x,y를 수정하면 a,b의 메모리 값이 변경됨
값-결과 전달
호출할 때: 실 매개변수 값은 형식 매개변수에 전달한다.
반환할 때: 형식 매개변수 값을 실 매개변수에 역으로 전달한다.
(copy-in, copy-out이라고도 한다)
문제 (값 전달, 참조 전달, 값-결과 전달의 메모리 상태를 그려라)
void p(int x,int y){ x++; y++; } main(){ int a=1; p(a,a); }
1. 값 전달
2. 참조 전달
3. 값-결과 전달
이름 전달
실 매개변수는 형식 매개변수가 사용될 때까지 계산되지 않고, 형식 매개변수가 사용될 때 비로소 계산된다.
이는 함수형 언어의 지연 계산에서 사용된다.
int i; int a[10]; void p(int x){ i=i+1; x=x+10; // a[i]=a[i]+10; } main(){ i=1; a[1]=10; a[2]=20; p(a[i]); }
p함수의 형식 매개변수 x에게 a[i]를 전달하면, x=a[i]가 된다. i=i+1 문장이 실행되고, a[i]=a[i]+10 문장이 실행될 때는, a[i=2]의 주소에 대응되는 메모리 값은 a[i=2]+10이 되어 30이 된다.
int i=0; int a[10]; void swap(int x,int y){ int t=x; // int t=i; x=y; // i=a[i]; y=t; // a[i]=t; } main(){ a[0]=2 swap(i,a[i]); }
swap함수의 형식 매개변수 x,y에게 i,a[i]를 전달하면 x=i,y=a[i]가 된다. int t=i(0) 문장이 실행되고, i=a[i]가 실행될 때는 i의 주소에 대응되는 메모리 값이 a[i=0]이 되어 2가 된다. 이후 a[i]=t가 실행될 때는 a[i=2]=t가 되어 a[2]가 0이 된다.
필자의 생각: 값 전달, 값-결과 전달은 형식 매개변수 개수만큼의 메모리 공간이 할당된다. 참조 전달은 형식 매개변수의 개수만큼 메모리 공간의 이름이 추가된다. 이름 전달은 형식 매개변수는 실 매개변수의 형태와 완전 동일해진다.
Ada
in 매개변수는 값 전달이고, in out매개변수는 값-결과 전달이다.
C
값 전달, 포인터를 이용한 참조 전달 효과가 있다.
C++, Pascal, Modula-2
값 전달과 참조 전달이 가능하다.
Java
기초 타입은 값 전달이고 객체는 참조 전달이다.
Fortran, Python
참조 전달이고, python은 객체 참조 전달이다.
함수와 유효범위 규칙
1. 정적 유효범위
선언된 이름은 선언된 블록 내에서만 유효함, 대부분 언어에서 표준 규칙으로 사용됨
2. 동적 유효범위
선언된 이름은 선언된 블록의 실행이 끝날 때까지 유효함, 실행 경로에 따라 유효 범위가 달라질 수 있음
Old Lisp와 SNOBOL에서 사용됨
int x=0; fun void g(int y) x=x+y*y; let int x=10; in g(5); end;
– 정적 유효범위: g함수의 블록과 let블록이 다르므로 x는 블록별로 다르다. -> g함수에서 나온 최종 x는 25이다.
– 동적 유효범위: let블록이 끝날 때까지 x는 다른 블록에서도 공유되는 변수이다. 따라서 g함수에서 x는 10이 되서 최종적으로 35가 된다.
int x=0; fun void g(int y) x=x+y*y; fun void f(int z) let int x=10; in g(z); end; f(5);
– 정적 유효범위: x=25
– 동적 유효범위: x=35
바인딩
이름을 어떤 속성과 연관짓는 것
1. 정적 바인딩: 컴파일 시에 한 번 이루어지고 실행동안 변하지 않고 유지된다.
2. 동적 바인딩: 실행 중에 이루어지는 바인딩으로 실행 중에 속성이 변경될 수 있다.
심볼 테이블
유효한 바인딩 정보를 유지, 관리하기 위한 자료구조, 환경이라고 도 한다.
컴파일러는 컴파일하기 위해 필요한 변수 또는 함수의 바인딩 정보를 심볼 테이블에 저장한다.
인터프리터는 변수의 값, 함수의 코드 위치 등을 심볼 테이블에 저장한다.
int y; fun int square(int x) return x*x; y=square(5);
함수 구현
함수 호출 구현을 위해 필요한 사항
1. 매개변수 메모리 할당
2. 매개변수 전달
3. 지역변수 메모리 할당
4. 호출자로의 반환에 필요한 반환 주소 저장
5. 피호출자 함수 시작 부분으로 제어 이전
함수 반환 구현을 위해 필요한 사항
1. 지역 변수, 매개변수 등을 위한 기억공간 해체
2. 반환 값 저장
3. 호출자로의 반환
인터프리터에서 함수 구현 원리
상태 스택을 실행시간 스택으로 사용
함수 정의를 만나면 (함수이름, 함수의 AST)를 PUSH!
함수 호출을 만나면 스택 프레임을 구성
int x=0; fun void g(int y) x=x+y*y; fun void f(int z) let int x=10; in g(z); end; f(5);
함수 g가 호출됐을 때 상태 스택
검사 예외
예외가 발생하면 처리될 수 있는지 컴파일러가 미리 검사한다
비검사 예외
예외처리 여부를 컴파일러가 미리 검사하지 않는다.
객체지향 언어의 역사
simula: 시뮬레이션을 위한 언어
smalltalk: 최초로 GUI를 제공하는 언어
c++: 상속, 가상 함수, 추상 클래스, 예외 처리 등과 같은 다양한 기능 추가
Java: 가장 많이 사용되는 언어
Object-C: C와 객체지향 언어를 혼합한 언어, C++보다는 smalltalk에 더 가깝된 정의된 언어이며 swift로 발전함
c#: 마이크로소프트에서 개발한 언어, Java와 상당히 유사
Python: 대화형 인터프리터 언어, 다중 패러다임 언어
객체와 클래스
클래스는 객체의 정의 혹은 타입
객체는 어떤 클래스 타입으로 선언, 어떤 클래스의 실체
실체화
클래스로부터 객체를 생성하는 것
프로그램
클래스들의 집합
프로그램의 실행
서로 상호작용하는 객체들의 집합
생성자
클래스와 이름이 같은 특별한 메소드, 생성된 객체를 초기화해주는 역할
객체 참조 변수 선언
클래스이름 변수;
ex) Account acc1;
객체를 가리키위한 변수로 객체가 생성된 것은 아님
객체 생성
변수=new 클래스 이름(인자);
ex) Account acc1=new Account(“Kim”);
new 연산자는 클래스로부터 객체를 생성한다.
캡슐화
일반적으로 연관있는 필드변수와 메소드를 클래스로 묶고(1), 내부 구현 내용을 외부에 감추는 것(2)을 말한다.
접근지정자
public: 클래스 내외 어느 곳에서나 접근 가능
private: 클래스 내부에서만 접근 가능
package: 같은 패키지 내에서만 자유롭게 접근 가능
protected: 클래스 내부와 이 클래스의 자손 클래스에서 접근 가능
실체 변수
각 객체마다 기억 공간이 할당됨
정적 변수
static으로 선언된 변수로 클래스 변수라고도 함, 객체가 아니라 클래스 내에 변수를 위한 기억 공간이 생성됨
제네릭 프로그래밍
타입 매개변수를 이용하여 여러 타입에 적용가능한 포괄적 코드
제네릭 클래스
타입 매개변수를 받는 클래스
ArrayList처럼 클래스에서 사용할 타입을 매개변수로 받을 수 있음
제네릭 메소드
타입 매개변수를 받는 메소드
제네릭을 사용한 ArrayList 클래스 사용 예제
public class Collection2{ public static void main(String[] args[]){ ArrayList<Drawable> myList=new ArrayList<Drawable>(); myList.add(new Circle()); myList.add(new Rectangle()); for(Drawable obj:myList) obj.paint(); } }
리스트에 저장하는 내용물은 다르게 사용 가능
제네릭을 사용한 클래스
‘Box<String> box1=new Box<String>();’ 로 호출 시
를 호출하게 됨
제네릭을 사용한 메소드
“Box<String> box=TestBox.<String>boxing(“string”);”로 호출 시
를 호출함