Recommanded Free YOUTUBE Lecture: <% selectedImage[1] %>

아무리 작은 프로그램이라고 하더라도, 실행되는 프로그램은 항상 값을 다룬다. 이러한 값들은 메인 메모리의 작은영역을 차지하게 된다. 우리가 이 데이터를 사용할려면 메인 메모리의 주소를 알아야 겠지만, 숫자를 사용해서 접근하는 것은 쉽지 않다. 그래서 변수라고 불리우는 심볼을 사용하게 된다.

이번 장에서 다룰 주제는 다음과 같다.
  • 변수
  • Assignment Statements
  • Expressions
  • 산술 연산자들
문제 변수가 어떻게 값으로 바뀌는지 기술할 수 있는가 ?

변수

당신이 사용하는 PC의 저장장치에는 수기가 바이트의 공간을 가지고 있다. 여기에는 기계 명령과 데이터들이 저장된다. 메인 메모리의 전자회로는 이들 두개의 데이터에 대해서 어떠한 구분도 하지 않는다. 프로그램이 시작되면 메모리의 특정영역에 기계 명령들과 기타 다른 데이터들이 위치하게 된다. 이렇게 명령과 데이터가 동일하게 메모리에 함께 두도록 하자는 아이디어는 현대적 컴퓨터의 선구자인 John von Neumann에 의해서 제안되었다.

메모리상에 데이터를 집어 넣었다면, 나중에 다시 빼낼수 있어야 한다. 그러기 위해서 프로그램은 사용하고 있는 각각의 메모리 영역에 대해서 이름을 가지고 있어야지만 한다. 변수 : 값이 저장된 메인메모리의 위치를 가리키는 심볼

메인 메모리에 있는 비트패턴을 사용하기 위해서 변수를 이용해서 호출하게 되면, 변수가 가리키는 메인메모리의 데이터를 읽어오게 된다. 변수란 하나 혹은 그 이상의 특별한 데이터 타입의 값이 저장된 상자라고 볼 수 있다.

attachment:payAmount.gif

그림에서 변수는 payAmount라는 이름을 가지며 long타입의 데이터를 가진다.

문제 변수는 반드시 데이터 타입을 가지고 있어야 하는가 ?

변수의 선언

여기에 변수 payAmount를 이용하는 프로그램이 있다.
class Example
{
  public static void main ( String[] args )
  {
    long payAmount = 123;    //a declaration of a variable

    System.out.println("The variable contains: " + payAmount );
  }
}
long payAmount = 123;가 변수를 선언하는 곳이다. 변수의 선언이란 프로그램에게 변수가 필요함을 요청하는 것이다. 위의 예제 프로그램에서는 main 메서드에 단지 하나의 변수만 선언되어 있다.

선언을 위해서는 이름과 변수의 데이터 타입이 필요하다. 이것은 변수가 저장될 공간에 어떤 데이터가 저장될지를 알려주는 역할을 한다. Java와 같은 고급언어에서는 프로그래머는 컴퓨터 하드웨어가 데이터 타입을 위한 공간을 어떻게 만들지 걱정할 필요가 없다. 만약 long타입의 변수를 선언했다면, Java 컴파일러가 long를 위해서 필요한 만큼의 메모리 공간을 확보해 주기 때문이다.

예제 프로그램에서는 payAmount라는 이름을 가지는 long원시데이터타입을 위한 64bit의 메모리영역을 요구하고 있다. 이제 프로그램이 시작되면, 메모리 공간이 할당되고, 123이 변수영역에 저장이 된다.

변수는 선언되기 전에는 프로그램에서 사용될 수 없으며, 단 한번만 선언될 수 있다.

문제 위의 프로그램이 실행되면 모니터에 어떤 값을 출력하는가.

자바프로그램 Simulated

이번에는 간단한 자바프로그램을 흉내내는 프로그램을 만들도록 하겠다. 아래의 코드는 앞전에 이미 다룬 코드다. 여기에는 빈칸이 있는데, 빈칸에 값을 집어 넣고, CompileRun버튼을 누르면, 어떻게 컴파일 되고 실행되는지를 확인할 수 있다. 일종의 자바 시뮬레이션 환경이라고 보면 될거 같다.

아래의 자바 시뮬레이션 프로그램은 자바스크립트를 지원하는 브라우저에서 작동을 한다.
class Example
{
  public static void main ( String[] args )
  {
    long payAmount = ;    //a declaration of a variable

    System.out.println ("The variable contains: " + payAmount );
  }
}
Simulated Monitor

이 시뮬레이션 프로그램을 이용해서 여러분은 소스코드를 만들고 컴파일하고 실행시키는 귀찮은 과정없이, 실행과정을 확인할 수 있다.

문제 시뮬레이션 변수에 rats 와 같은 문자열을 입력해 보자.. 성공적으로 컴파일 되는가 ?

변수선언 문법

모든 언어가 그렇듯이 컴퓨터 언어도 나름대로의 고유 문법을 가지고 있으며, 이를 엄격히 지켜야 한다. 마찬가지로 변수를 선언하는데에도 문법규칙에 따라야 한다.

여기에서는 변수를 선언하는 다양한 방법에 대해서 알아볼 것이다.

dataType variableName; 가장 일반적으로 사용되는 방법으로 변수의 데이터 타입과 변수명만을 명시한다. 이렇게 될경우 해당 변수명을 위한 메모리가 할당될 것이다. 이 메모리 공간에는 아무런 값이 들어가지 않았는데, 이경우 자동적으로 초기화가 된다.

dataType variableName = initialValue; 두번째 방법은 변수의 테이터 타입과 변수명을 지정하고, 해당 변수의 메모리 영역에 초기값을 넣는다. 이 초기값은 반드시 dataType와 일치해야만 한다.

dataType variablenameOne, variableNameTwo; 두개의 변수를 동시에 선언한다. 두개 모두 메모리만 할당하고, 특별한 값은 저장되지 않는다. 원한다면 두개 이상의 변수에 대한 선언도 가능하다.

dataType variableNameOne = initialValueOne, variableNameTwo = initialValueTwo; 두개의 변수를 동시에 선언하며, 모두 초기값으로 초기화 한다.

문제 다음 선언은 옳은가 ? int answer;

변수명

http://chortle.ccsu.edu/java5/Notes/chap09A/ch09_6.html

프로그램은 프로그램에서 사용될 각각의 변수의 이름을 지어줘야 한다. 덧붙여서 각 이름이 사용하고자 하는 용도에 맞으며, 규칙에 어긋나지 않도록 지어줄 필요가 있다. 이렇게 변수에 이름을 붙여주는 것을 identifier이라고 하며, 아래의 규칙을 따라서 이름지어져야 한다.
  • 'a'~'z', 'A'~'Z', '0'~'9', '_', '$'를 사용할 수 있다.
이름중간에 빈칸이 포함되면 안된다.
  • 숫자로 시작될 수 없다.
  • 길이는 상관없다.
  • 변수명은 대소문자를 구별한다.
SUMSum은 서로 다르다.
  • 예약어는 변수명으로 선택될 수 없다.
  • 해당 영역에서 두번 선언할 수 없다.
예약어는 자바에서 사용하는 미리정의된 단어들이다. int, double, true, import등이 대표적인 예약어들이다.

변수의 이름을 어떻게 짓는지는 프로그래밍 스타일에 따라서 달라질 수 있다. 일반적으로 변수명은 소문자로 시작하는걸 관례로 하고, 두단어 이상이 함께 사용될경우, 두번째부터 시작되는 단어의 첫자를 대문자로해서 단어간 의미구분을 한다. 예를 들자면 payAmount, grandTotal등이다.

물론 pay_amount, grand_total와 같은 스타일을 따를 수도 있다. 실제 C와 같은 언어에서는 후자의 스타일을 선호하기도 한다. 그러나 여기에서는 Java 스타일을 따르도록 할 것이다.

문제 다음의 변수선언이 규칙에 위배되는지 확인하라.
  • long good-by;
  • short shrift = 0;
  • double bubble =0, toil=9, trouble = 8;
  • byte the bullet;
  • int double;
  • char thisMustBeTooLong;
  • int 8ball;

예제 프로그램

http://chortle.ccsu.edu/java5/Notes/chap09A/ch09_7.html

다음은 다양한 변수선언이 포함된 예제 프로그램이다.
class Example
{
  public static void main ( String[] args )
  {
    long   hoursWorked = 40;    
    double payRate = 10.0, taxRate = 0.10;    

    System.out.println("Hours Worked: " + hoursWorked );
    System.out.println("pay Amount  : " + (hoursWorked * payRate) );
    System.out.println("tax Amount  : " + (hoursWorked * payRate * taxRate) );
  }
}

*는 곱하라는 뜻이다. 이 프로그램에서 (hoursWorked * payRate)hoursWorked와 payRate를 곱하라는 의미다.

+는 문자열 뒤에 문자열을 덧붙이기 위해서 사용된다. 만약 뒤에 오는 값이 문자열이 아니고 숫자라면, 문자열로 변환되어서 덧붙여 진다. 이 프로그램을 실행시키면 다음과 같은 결과를 보여줄 것이다. {{{{#!plain Hours Worked: 40 pay Amount : 400.0 tax Amount : 40.0 }}}

소스 프로그램에서 System.out.println이 처음 사용된 줄의 경우 변수 hoursWorked를 사용하고 있는데, 이는 hoursWorked의 메모리영역에 가서 그 값을 읽어오라는 뜻이 된다.

문제 프로그램의 첫번째 실행결과인 40에 소숫점이 찍히지 않는 이유는 무언가. 왜 두번째 결과에는 소숫점이 찍혔는가

계산

아래의 프로그램을 다시 한번 살펴 보도록 하자.
class Example
{
  public static void main ( String[] args )
  {
    long   hoursWorked = 40;    
    double payRate = 10.0, taxRate = 0.10;    

    System.out.println("Hours Worked: " + hoursWorked );
    System.out.println("pay Amount  : " + (hoursWorked * payRate) );
    System.out.println("tax Amount  : " + (hoursWorked * payRate * taxRate) );
  }
}
붉은 색으로 표시된 줄을 주의깊게 살펴보기 바란다. 여기를 보면 아래와 같이 괄호로 둘러쌓인 영역을 확인할 수 있을 것이다. (hoursWorked * payRate) 이것은 괄호안의 *연산을 먼저하라는 의미다. 이 곱셈연산이 먼저 된뒤에, pay Amount:"과의 +연산이 수행이 된다. 어떤 연산을 할때 이렇게 우선순위를 정하기 위해서 괄호를 이용하는 것은 매우 중요하다. 이는 프로그램이 제대로 수행되도록 해주며, 또한 소스 코드를 더 쉽게 볼 수 있도록 도와준다.

문제 위의 한 줄을 두 줄로 풀어서 써도 될까 ?

각 Statement 를 여러줄로 쓰기

당신은 하나의 statement를 여러줄에 걸쳐서 쓸 수 있다. 중간에 스페이스 문자로 구분이 되어있다면, 어디든지 statement를 분리할 수 있다. 그러나 이것이 변수명등의 이름의 중간에서 가능한걸 의미하지는 않는다. 또한 따움표등으로 둘러쌓인 string에도 허용하지 않는다. 다음은 하나의 statement를 여러줄로 나타낸 소스 프로그램이다.
class Example
{
  public static void main ( String[] args )
  {
    long   hoursWorked = 40;    
    double payRate = 10.0, 
           taxRate = 0.10;    

    System.out.println("Hours Worked: " + 
hoursWorked );
    System.out.println("pay Amount  : " 
+ (hoursWorked * payRate) );
    System.out.println("tax Amount  : " + (hoursWorked 
* payRate * taxRate) );
  }
}
위의 소스 프로그램은 컴파일과 실행에 아무런 문제가 없으나, 사람이 보기에 깔끔하지 않다. 가능하면 아래와 같이 깔끔하게 작성하는걸 권장한다.
class Example
{
  public static void main ( String[] args )
  {
    long   hoursWorked = 40;    
    double payRate = 10.0, 
           taxRate = 0.10;    

    System.out.println("Hours Worked: " + 
        hoursWorked );
    System.out.println("pay Amount  : " +
       (hoursWorked * payRate) );
    System.out.println("tax Amount  : " + 
       (hoursWorked * payRate * taxRate) );
  }
}

문제 다음 소스프로그램은 제대로 컴파일 되는가?
cla
   ss Example
{

  public static void main ( String[] args )
  {
    long   hoursWorked = 40;    
    double payRate = 10.0, taxRate = 0.10;    

    System.out.println("Hours 
        Worked: " + hoursWorked );

    System.out.println("pay Amount  : " + (hours
        Worked * payRate) );

    System.out.println("tax Amount  : " + (
        hoursWorked * payRate * taxRate) );
  }
}

Assignment Statements

이제 어떻게 변수를 만들고, 값을 초기화 하는지에 대해서 알게 되었다. 그러나 아직 값을 바꾸는 방법에 대해서는 모르고 있다. 예상 했겠지만 값을 바꾸는 일은 매우 간단하다. 바꾸고자 하는 변수명에 값을 대입시켜주기만 하면된다. 그러면 프로그램의 실행중간에 값이 변경이 된다. 다음은 대입을 통해서 값을 변경하는 예제 프로그램이다.
class Example3
{
  public static void main ( String[] args )
  {
    long payAmount ;  // 초기화 없이 선언했다.

    payAmount = 123;  //an assignment statement
    System.out.println("The variable contains: " + payAmount );
  }
}

대입부분에서 변수 payAmount에 값 123을 밀어 넣었다. 변수가 64bit 자료형으로 선언되었기 때문에, 값 123은 변수가 가리키는 해당메모리의 블럭에 저장이 될 것이다.

문제 모니터에 무엇이 출력되는가.

Assignment Statement Syntax

위의 프로그램은 123을 출력한다. 이렇게 변수를 초기화 하지 않더라도, 필요할 때 값을 밀어 넣을 수 있다. 이러한 값을 밀어 넣는걸 변수에 값을 대입한다 라고 한다. 대입을 위해서는 대입과 관련된 문법을 사용해야 한다. 문법은 다음과 같다. variableName = expression;
  • 대입을 위해서는 =연산자를 사용한다. 대입연산자라고 한다.
  • variableName은 대입하기 전에 선언되어 있어야 한다.
  • expression은 값을 호출하기 위한 계산식 혹은 값 자체다.
문제 다음 문장에 문제가 있는가? (sum은 이미 선언되어 있다고 가정한다) sum = 42 - 12;

Assignment Statement Symatics

프로그래밍 언어에서 문법은 반드시 규칙에 맞게 작성해야 한다. 그래야지만 그걸 인식하고 바이트코드로 변환해낼수 있다. 대충 문법에 틀리게 말해도 알아서 해석해주는 인간과는 다르다.

프로그래밍 언어는 명령을 실행하기 위해서 그 명령을 분석하는 단계를 거치게 된다. 대입을 위해서는 다음의 두가지 단계를 거치게 된다.
  1. Evaluate the expression : 값의 계산
  2. 변수에 값을 저장
다음은 대입의 전형적인 예이다. sum = 32+8 실행단계는 다음과 같다.
  1. Evaluate the expression : 32+8을 계산한다.
  2. 변수에 값을 저장 : 40을 sum에 저장한다.
문제 아래의 대입구문이 실행되는 단계를 기술하라. sum = 42-12;

Expressions : 표현

sum에는 42-12의 결과 값인 30이 저장된다.

아주 간단하다. 그러나 때때로 두 단계이상의 분석을 요구하는 복잡한 표현이 사용될 때가 있다.

expression은 literals, 연산자, 변수명, 계산값, 괄호등의 조합이다. 아래에 이들 요소를 설명하고 있다.
  • literal - 값이 직접 의미를 가지는 문자 : 3.456
  • 연산자 - 산술 연산을 위한 +, * 와 같은 심볼들
  • 변수 - 값을 저장하기 위한 메모리 구역
  • 괄호 - ( 과 )
이들을 조합하면 다음과 같은 복잡한 표현이 가능하다. /는 나누기 연산자이다. (32 - y) / ( x + 5 )

다음은 잘못된 표현이다. 32 - y) / ( x 5 + )

산술연산에서의 표현은 은 우리가 알고 있는 대수학의 표현과 유사하지만 몇가지 다른 점이 있다. 예를 들어 두수를 곱하기 위해서는 *연산자가 사용되어야 한다. x와 y를 곱해야 하는 경우 수학에서는 xy로 표현할 수 있지만 자바에서는 x*y로 표현해야 한다.

문제 아래의 표현에 문제가 있는지 확인하라. 문제가 있다면 올바로 수정하라.
  • 53
  • 12 - 3)
  • x + 34
  • *z 99
  • sum + value
  • sum +* 3
  • (12-3)
  • sum*34/2
  • 3.1y

spaces는 문제가 되지 않는다

표현에서 스페이스 문자는 무시된다. 표현을 위해서 공백문자를 얼마를 사용한다고 해도 아무런 문제가 없다. 이들 공백문자는 보통 소스프로그램을 보기 좋게 만들기 위한 목적으로 사용된다.

예를 들어 아래의 두 표현은 서로 완전히 동일하다.
(hoursWorked*payRate)-deduction  -- 1
(hoursWorked * payRate) - deduction -- 2
또한 동일한 바이트코드를 생성해낸다. 그렇지만 2번째 표현이 읽기에 좀더 편함을 알 수 있다. 코드를 읽기 편하게 만들면 코드를 쉽게 이해할 수 있으며, 좀더 수월하게 디버깅을 할 수 있다. 그러나 아래와 같이 변수이름에 스페이스가 들어가는 등의 표현은 허용되지 않으며, 컴파일시 에러가 발생할 것이다.
( hours Worked * pay Rate) -deduction

다음과 같이 여러개의 스페이스를 이용하는 것도 가능하지만, 역시 사람이 보기에 좋지는 않으므로 권장하지는 않는다.
12-4     /     2+2
위의 수식은 12에서 4를 뺀결과인 8을 2로 나누고 여기에 2를 더하라는 것으로 결과는 8이 나올 것이다. 여기에서 공백문자는 전혀고려되지 않는다. 위 표현은 아래의 표현과 완전히 동일하다.
12 - 4/2 +2

산술 연산자

산술연산자 (arithmetic operator)은 간단한 수치연산을 위한 심볼들이다. 이 산술연산자들은 고유의 우선순위가 존재한다. 우선순위가 높음으로 되어 있는 것은 가장 먼저 계산이 수행된다는 것이고 낮음으로 표시된것은 가장 나중에 계산이 수행됨을 의미한다. 다음은 Java 언어에서 제공하는 산술연산자와 우선순의를 정리한 표이다.
연산자 설명 우선순위
- 음수표현 높음
+ 양수표현 높음
* 곱하기 중간
/ 나누기 중간
% 나머지 중간
+ 더하기 낮음
- 빼기 낮음
어떤 연산자들은 서로 같은 우선순위를 가진다. 예를 들어서 더하기 + 와 빼기 - 는 같은 연산자 우선순위를 가진다.

음수표현과 양수표현을 위한 -,+는 양수인지 음수인지를 결정하기 위해서 사용하는 심볼이다. 예를 들어 -12는 음의 12, +12는 양의 12로 가장 먼저 계산이 된다.

이러한 산술연산자는 두개의 피연산자들을 가지며, 두개의 피연산자 모두가 integer 이면 interger artithmetic을 수행한다. 만약 양쪽 피연산자가 모두 floating point 형이라면 floating point arthmetic를 수행할 것이다. 이것은 특히 나눗셈을 할 때 중요하다. intger 형으로 나눌것인지 아니면 float형으로 나눌것인지에 따라서 결과가 완전히 달라지기 때문이다. 예를 들어 5/2 는 2.5가 아닌 2이며, 5/10은 0.5가 아닌 0으로 결과 값이 계산된다. 자세한 것은 뒤에 다루도록 하겠다.

문제 다음의 산술연산 결과 값을 입력하라.
  • 16 - 12 / 4
  • 2 + 6 / 2
  • 8 + 4 * 2
  • 8+4 * 2
  • 12/2 - 3
  • 6/8 + 2

Evalution by Rewriting

http://chortle.ccsu.edu/java5/Notes/chap09A/ch09_17.html

산술연산등의 예에서 보듯이 표현은 우선순위와 같은 규칙에 의해서 평가가 된다. 그러므로 계산된 결과를 예측하기 위해서는 표현을 단계별로 나누어서 평가해야할 필요가 있다. 아래의 표현을 보도록 하자. 16 - 12 / 4

위의 표현에서는 우선순위에 의해서 나눗셈이 먼저 행해진다. 그러므로 위의 표현의 첫단계는 다음과 같이 평가될 것이다.

16 - 3

이제 남은빼기 연산자가 수행되고 결과가 도출 될 것이다. 13

이러한 과정은 다음과 같이 요약할 수 있을 것이다.
16 - 12 / 4
     ------
16 -    3
---------
   13
점선은 각 단계를 구분하기 위해서 사용되었다.

문제 아래의 표현을 평가하고 값을 예측하라.

같은 우선순위의 경우 왼쪽께 먼저 평가된다.

-+는 같은 우선순위를 가지는데, 이럴 경우 자연스럽게 왼쪽에서 오른쪽으로 평가가 된다. 다음은 간단한 예이다.
4 - 2 + 5
-----
  2   + 5
  -------
      7
왼쪽에서 오른쪽으로 계산을 하는 것은 우리의 직관과 잘 맞아 떨어지므로 이해하는데 크게 어려움이 없을 것이다.

문제 다음의 표현을 평가하고 값을 예측하라. 2 + 4/2 + 1

음수표현

연산자 테이블을 보면 -와 같은 경우와 같이 하나의 심볼이 2개의 표현으로 해석될 수 있음을알 수 있다. 어떤때는 음수임을 나타내기 위해서, 어떤때는 빼기연산을 위해서 사용된다.

음수를 나타내기 위해서 사용되는 경우는 아래와 같이 표현될 것이다. -97.34 위의 표현은 마이너스 97.34임을 의미한다. 반면 빼기연산자로 사용될 경우가 있다. 95-12 위의 표현은 95에서 12를 빼라는 의미다. 음수연산자는 가장 높은 우선순위를 가지고 빼기연산자는 가장 낮은 우선순위를 가진다. 아래의 코드는 -12 + 3 음수 12에 3을 더하라는 의미로 결과는 -9가 된다.

문제 아래의 표현을 평가하고 결과를 예측하라 +12 + 3 * -4

원하는 결과를 위해서 괄호를 사용하라

연산은 연산자 우선순위에 따르게 되는데, 때때로 이를 무시하고 싶을 때가 있을 것이다. 이럴 경우 괄호를 사용한다. -1 * (9-2) * 3

위와 같이 괄호를 사용하게 되면, 다른 연산자 우선순위를 무시하고 괄호안의 연산을 가장 먼저 수행하게 된다. 위의 경우라면 9-2를 먼저 수행하게 된다. 결국아래와 같이 평가가 된다. -1 * 7 * 3

나머지는 동등한 우선순위를 가진 곱하기 연산자이므로, 왼쪽에서 오른쪽으로 차례대로 연산이 된다.
-1 * 7 * 3  
------
  -7   * 3
  --------
     -21

문제 다음 표현의 값을 예측하라.
  1. (8-2)/2
  2. (2 + 6 )/2-9
  3. (8+4) * 2
  4. 8+(4*2)

중첩된 괄호

괄호는 중첩되어서 사용할 수 있다. 복잡한 수식의 경우에 주로 사용되는데, 이럴 경우 수식이 어떻게 평가되는지를 한눈에 파악할 수 있게 해준다. 아래의 수식은 모두 동일하게 평가된다.
  • a + b + c * d
  • a + b + (c * d)
  • (a + b ) + (c * d)
  • ( (a+b) + (c*d) )
문제 아래의 표현이 평가와 계산값은 ?
  • 8 + 2 / 2 + 3
  • (8 + 2) / (2 +3)
  • (8 + 2) / 2 + 3
  • 8 + 2 / (2+3)