IntelliJ


JAVA 개발환경에는 크게 Eclipse와 jetBrain사에서 만든 IntelliJ, 그리고 NetBeans이 있습니다.
오늘은 그 중의 하나인 IntelliJ의 설치방법에 대해서 설명하겠습니다.


1. JetBrains의 홈페이지(https://www.jetbrains.com/)에 접속합니다.

   화면에서 IntelliJ IDEA를 선택합니다.





 2. Download를 선택합니다.




3. JVM&Andorid버전(IntelliJ)과, Web버전 2가지로 구분되어지는데, 사용하실 언어를 기준으로 설치해주시면 됩니다. 

   [ 저는 두 버전 다 설치하는 모습을 보여드리겠습니다. ]

   




4. Next를 눌러주세요.




5. IntelliJ를 설치할 경로를 지정해주시고 나서, NEXT를 눌러주세요.




6. Desktop일 경우, 32bit와 64bit를 구분하여서 설치해주세요.

   .java / .groovy / .kt 확장자 파일들에 대한 연결 여부를 선택합니다.

[Java를 설치하지 않은 경우]

 : Download and install JRE x86 by JetBrains 체크박스를 선택해주세요.

# JRE 나, JDK 1.8 버전 이상이 설치되어 있지 않은 경우에는 IntelliJ가 실행되지 않으니 유의해주세요!




7. Install를 눌러주시면 됩니다.










8. 설치하신 후, 바탕화면에서 IntelliJ를 선택하시면, 이전에 설치한 적이 있는 지, 

있으면 이전버전 설정을 등록할 건지에 대한 여부를 물어봅니다.




9. Privary Policy의 스크롤을 끝까지 내려면 Accept 버튼이 활성화 되니, 선택해주세요.




10. 소프트웨어나, 하드웨어를 설정 등을 공유하는 지에 대한 여부를 물어봅니다.




11. 원하시는 UI 테마를 선택하시면 됩니다.




여기까지는 WEB버전과 JVM&Android버전 모두 동일하게 이루어지는 과정이었습니다. 

아래에서부터는 두 버전이 나뉘어서 설명됩니다.







[JVM 및 Andorid 버전]





[WEB버전]






학생인증을 통해서, IntelliJ를 설치하는 방법을 다음에 포스팅하겠습니다!



'JAVA' 카테고리의 다른 글

final  (0) 2018.01.19
cmd로 클래스 실행  (0) 2018.01.19
접근 지정자  (0) 2018.01.19
class간의 관계  (0) 2018.01.18
Class의 기본구조  (0) 2018.01.18

final은 문자 그대로 마지막을 나타낸다는 의미로,


java에서 변화를 방지하기 위해서 이용되는 키워드이다.


final을 사용하는 곳은 필드(field), 메소드(method), 그리고 클래스(class) 3군데 이다.





#필드(field)


필드에 final을 붙이게 되면, 마지막 변수로


한번 변수에 값을 저장하면, 저장한 값을 바꾸지 않겠다는 것을 의미한다.


그렇기 때문에, final을 붙은 필드는 선언과 동시에 초기화를 해주는 것을 원칙으로 한다.


만약 선언과 동시에 초기화를 하지 않을 시에는 필드에 기본값이 들어가게 되고,


개발자가 다른 곳에서 필드를 초기화하더라도 그 값은 바뀔 수가 없기 때문이다.





#메소드(method)


메소드에 final을 붙이게 되면 오버라이딩(overriding)을 금하겠다는 것을 의미한다.


 + [오버라이딩(overriding)]


   : 오버라이딩이라는 것은 내가 상속을 통해 부모클래스가 가지고 있는 메소드들을 물려받았을 때,


     자식이 부모의 메소드가 마음에 들지 않아, 메소드의 코드를 재정의 하는 것을 의미한다.


     예를 들자면, 부모가 자식에게 천지갑을 물려줬는데 자식이 그 지갑이 마음에 들지 않아


     그 지갑을 악어지갑으로 바꾸었다고 말할 수 있다.





#클래스(class)


클래스에 final을 붙히게 되면, 상속을 금지한다는 의미이다.


상속은 블로그 내의 '클래스의 관계'에서 자세히 설명하였듯이 클래스끼리 is ~a관계를 이루는 것을 의미하는 데, 


이 관계를 이용하지 못한다는 것은 has ~a관계, 즉 가져다가 쓰는 클래스로 밖에 이용하지 못한다는 것을 의미한다.


기본적으로 모든 클래스들은 is~a관계와 has~a관계가 모두 제공되기 때문에


상황에 맞추어 둘 중에 선택이 가능하나, final클래스는 오로지 has~a관계만 이용할 수 있다. 

'JAVA' 카테고리의 다른 글

IntelliJ 설치  (0) 2018.10.26
cmd로 클래스 실행  (0) 2018.01.19
접근 지정자  (0) 2018.01.19
class간의 관계  (0) 2018.01.18
Class의 기본구조  (0) 2018.01.18

개발자에게는 자바(Java)를 손쉽게 이용할 수 있도록 이클립스(Eclipse)라는 툴을 제공되는데,


이 툴을 이용하지 않고도, 자바의 코딩이 가능하다.





[실행 순서]


1. 메모장에 자바의 코드를 적는다.


<Example Code>








2. 메모장의 메뉴중 파일을 클릭하여 다른 이름으로 저장을 선택한다.








3. 메모장에 적은 public class의 이름과 동일한 이름으로 저장을 하는데,


  저장하는 타입을 java로 해야한다. 




그러면 바탕화면(저장된 장소)에 Hello.java가 생성된다.









4. 파일탐색기를 들어가서 Hello.java가 저장된 장소를 찾아 장소의 위치를 Ctrl+C를 한다.








5. Cmd 창을 열어서  cd 를 적은 후 복사한 내용을 붙혀 적으면

 

Cmd창이 가리키고 있는 위치에서 내가 Hello.java를 만든 위치로 이동하게 된다.


[cd + 위치 : 적혀 있는 위치로 이동할 수 있게 해주는 명령어]






6. 위치를 이동한 후, javac Hello.java를 입력하는데,


이는 JAVA타입의 파일을 class로 변환시켜준다.


[javac + java파일명 : java 파일을 class로 변환시켜주는 명령어]



다 적고 Enter 키를 누르게 되면, java파일이 있던 위치에 같은 이름을 가진 class파일이 형성되게 된다.








7."  java 클래스명 "을 cmd창에 입력하게 되면, 


    아까 java파일에 적은 명령어가 실행되게 된다.


    [java + 클래스명 : 클래스를 실행시키는 명령어]



아까 Hello.java 파일에 Hello, Welcome을 출력하라는 함수를  적어 놓았기 때문에,


Hello, Welcome이 출력되는 것을 확인할 수가 있다. 






옛날에는 툴이 제공되지 않았기 때문에, 이런 방식을 이용하여 java를 작성하기도 했다.


그러나 지금 제공되고 있는 이클립스(Eclipse)와 다르게, java code상의 오류가 발생하게 되면, 


javac명령어로 클래스를 만들때 에러가 발생하여 만들기 전까지는 에러를 발견할 수 없으며,


이클립스와 같이 자동완성기능이 없기 때문에 코드를 일일히 손으로 쳐야 한다는 단점이 존재한다.




'JAVA' 카테고리의 다른 글

IntelliJ 설치  (0) 2018.10.26
final  (0) 2018.01.19
접근 지정자  (0) 2018.01.19
class간의 관계  (0) 2018.01.18
Class의 기본구조  (0) 2018.01.18

외부에서 클래스를 이용할 때 


클래스 내부의 필드는 못 사용하게 하고, 메소드는 사용할 수 있게 설정할 수 있는 이유는


JAVA에 접근 지정자가 존재하기 때문이다.



접근 지정자는 외부에서 클래스를 접근할 때 접근 하는 범위를 한정하겠다는 의미이다.


접근 지정자는 좁은 범위에서부터 private, default, protected, public 4가지로 나뉘어져 있다.





#private


private으로 선언된 것은 외부에서 직접적인 사용이 불가능하다.


필드(field)의 경우에는 외부에서 내부의 필드를 직접이용할 수 없고.


메소도(method)의 경우에도 메소드를 직접 접근할 수 없게 된다.




private은 주로, 데이터의 손실과 소멸을 방지하기 위해, 


클래스(class)내부의 데이터의 직접적인 접근을 금할 때 사용된다.


클래스를 상속받을 때 부모클랙스의 모든 것을 자식클래스가 이용가능하다고 말하나. 


private field나 method를 가진 클래스를 상속받으면


private으로 적힌 것들은 자신의 것처럼 직접적으로 이용할 수 없다.


왜냐하면, 자기 자신 이외에는 아무도 접근할 수 없게 명시하였기 때문이다.





#default


자바(Java)에서 프로젝트(Java Project)를 먼저 생성하게 되면, src 폴더가 생성되는데,


개발자는 주로 여기에 패키지(Package)를 만들어, 자바(Java)의 클래스파일들을 효율적으로 관리한다.




default로 선언되게 되면, 같은 Package내에 있는 모든 곳에서 접근할 수 있게 된다.


필드나 메소드를 만들때, 앞에 접근 지정자를 적지 않으면, 


기본적으로 default로 인식한다.





#protected


protected는 주로 상속관계를 사용할 때 자주 볼 수 있는데,


Package의 동일유무와 상관없이 protected가 선언된 클래스를 상속받은 모든 클래스들은 


상속받은 클래스 내부의 protected타입의 모든 것을 자신의 것처럼 이용할 수 있다.





#public 


우리가 클래스에서 가장 많이 볼 수 있는 접근 지정자로,


클래스 내부의 public 으로 선언된 모든 것을 제한없이 외부의 어떤 곳이든지 이용할 수 있다.


Package동일유무, 상속유무와 상관없이 어떤 클래스라도 사용이 가능하며,


대부분의 클래스의 메소드들은 클래스내부의 필드를 


간접적으로 접근하여 이용할 수 있도록 하기 때문에, public으로 선언되어 있다.

'JAVA' 카테고리의 다른 글

IntelliJ 설치  (0) 2018.10.26
final  (0) 2018.01.19
cmd로 클래스 실행  (0) 2018.01.19
class간의 관계  (0) 2018.01.18
Class의 기본구조  (0) 2018.01.18

 자바(JAVA)는 모든 클래스들이 서로 관계를 맺고 있다.


이런 관계는 Has ~a관계와 Is ~a 관계로 크게 2개로 구분할 수 있다.





#has ~a관계


has ~a관계는 '~는 ~을 가지고 있다'라는 것을 의미한다.




노트북을 예시로 들어서 설명하자면, 


내가 사용하고 있는 노트북에는 여러기능들이 존재한다.


노트북음향을 조절하는 기능, 노트북화면의 밝기를 조정하는 기능들이 존재하는데,


내가 음향을 조절하는 기능을 이용하지 않는다고 가정해보자.


그럼 내 입장에서는 노트북에 굳이 음향을 조절하는 기능을 넣을 필요가 없는 것이다.


나와 같은 사람들이 많이 존재한다면, 


노트북 만드는 회사에서는 음향조절기능을 뺀 노트북과 음향조절기능이 있는 노트북을 둘다 만들어야 할까?


아니면 음향조절기능이 있는 노트북만 만들어야 할까?


정답은 후자, 음향조절기능이 있는 노트북만 만들어야 한다는 것이다.


왜냐하면, 음향조절기능을 가진 노트북은 


음향조절이 필요치 않은 사람과 음향조절이 필요한 사람 모두를 만족시키기 때문이다.


필요하지 않은 사람이 있다고 해서 그 기능을 뺀 제품을 만들 필요는 없다.


필요한 사람은 사용하면 되고, 필요하지 않은 사람은 사용하지 않으면 된다.


즉, 노트북을 만드는 회사는 모두에게 보편적으로 이용가능한 노트북을 생산해야 한다는 것이다.




다시 has ~a관계로 돌아와서 이야기 하자면, 


has ~a는 한 클래스 내부에서 외부에 정의된 클래스를 이용하는 관계이다.


외부에서 가져오는 클래스는 앞에서 설명했던 노트북과 같이 


어느 누가 가져와서 사용하든 보편적이여야 하며, 독립적으로 이용가능하여야 한다.


이러한 클래스를 Data Class라고 한다.


데이터 클래스(Data Class)는 말 그대로 데이터들만 담겨 있는 클래스로서,


클래스 내부에는 데이터와 외부에서 데이터를 접근할 수 있는 메소드들이 존재한다.




외부에서 클래스를 가져와 데이터의 입출력만 한다면 그것은 데이터 클래스이나,


클래스 내부의 데이터를 가지고 연산을 하고, 값을 처리하거나 출력하는 기능을 하게 된다면,


이는 데이터 클래스가 아닌 데이터들을 관리하는 데이터 관리 클래스가 된다.




has ~a관계는 데이터클래스와 데이터관리클래스로 나타낼 수 있다. 


<사용예시>








#Is ~a관계


Is ~a관계는 '~는 ~이다'라는 것을 의미하며, JAVA에서 상속이라고도 불린다.


상속이란, 한 클래스가 가진 모든 것을 다른 클래스에 물려주는 것이다. 


상속을 하는 클래스를 우리는 부모클래스, Super Class라고 부르며, 


상속을 받은 클래스를 자식클래스, Sub Class라고 부른다. 


Java에서는 모든 클래스들이 상속구조를 이루고 있기 때문에, 


맨 위로 올라가게 되면 모든 클래스의 최종 부모클래스가 존재하는데,


이를 최상위클래스라고 한다. 





상속을 이용할 경우, 가장 중요한 것은 Class간의 연관성이 존재해야 한다는 것이다.


pen이라는 클래스를 생성하고 water이라는 클래스를 생성했다고 가정해보자.


pen클래스와 water클래스 관계내에는 연관성이 존재하지 않는다. 


그렇기 때문에, 개발자가 pen클래스에서 사용하는 함수(메소드)를 이용하기 위해


water클래스에 pen클래스를 상속할 경우, 이는 Is ~a관계에 어긋나게 된다.


water이 pen일 수는 없다.




상속은 클래스명 옆에 extends 클래스명을 적게 되면 적혀진 클래스를 상속받게 되는데,


우리가 처음 클래스를 만들 경우에는 extends가 존재하지 않는다.


그러면 상속을 받지 않는 것일까?



정답은 아니다. 


모든 클래스는 생성과 동시에, 최상위 클래스인 Object클래스를 상속받게 된다.



코드상에서 상속을 받지 않는 것처럼 보이지만, 


사실은 이미 클래스가 만들어질때 부터 상속은 이루어진 것이다. 




[상속의 특징]


상속은 최상위 클래스에서 최하위자식클래스로 갈수록 추상화가 이루어진다.


추상화란 추상적인 개념을 구체화하는 행위를 의미한다. 


예시를 들어 설명을 하자면, 동물을 생각하면 무엇이 떠오르른가?


토끼, 인간, 양서류 등의 몇몇 단어들이 떠오르게 될 것이다.


이러한 단어들은 모두 동물이란 단어과 연관성이 있으며,


동물들을 구체적으로 설명하였다고 할 수 있다.


또한 토끼, 인간과 같은 단어들 속에서 동물만이 가질 수 있는 공통점들을 찾을 수 있을 것이다.


숨을 쉬고, 귀가 있다는 공통점들은 토끼와 인간 뿐만 아니라,


모든 동물들에게 해당될 수 있는 공통점이다.


이러한 공통점을 우리는 토끼를 명시할때나, 혹은 인간을 명시할때,


일일히 명시할 필요가 있을까?



공통점들만을 모아 부모클래스로 구성하여 상속관계를 맺는다면,


자식클래스는 이러한 공통점들을 가질 수 있으며, 자신만의 다른 점을 추가할 수 있다. 


즉, 다르게 말하면, 자식클래스 입장에서는 부모클래스의 공통점만으로 


자신을 완벽하게 표현 할 수 없다고 생각할 수 있다는 의미이다.


그렇기 때문에, 부모클래스의 공통점을 받고, 자신만의 특징을 추가하는 자식 클래스는 


부모클래스가 자신을 나타내는 것 보다 , 자신을 보다 추상화하고 있다고 할 수 있다.



'JAVA' 카테고리의 다른 글

IntelliJ 설치  (0) 2018.10.26
final  (0) 2018.01.19
cmd로 클래스 실행  (0) 2018.01.19
접근 지정자  (0) 2018.01.19
Class의 기본구조  (0) 2018.01.18

Java는  class단위로 코드를 구성한다.


class의 기본적인 구조는 크게 3가지로 구분할 수 있다.




#field


[기본형태 : 접근지정자 데이터타입(dataType) 변수명]


필드라고 불리기도 하고, 변수라고 불리기도 하는 이것은, 


한 class내에서 모든 메소드(method)이 접근가능한 변수를 의미한다.




이러한 필드는 인스턴스(instance) 필드와 스테틱(static)필드 두가지로 구분되는데,


인스턴스 필드(instance field)는 말 그대로 객체, 즉 클래스(class)를 생성했을 시에 같이 생성되는 필드이다.


스테틱 필드(static field)은 객체가 생성되기 이전에 객체보다 먼저 생성되는 필드로서, 


객체의 생성유무와 연관성이 없기 때문에, 어떤 클래스에서도 공통적으로 사용할 수 있다.






#method


[기본형태 : 접근지정자 리턴타입(return type) 함수명(메소드명) (매개변수)]


메소드(method)는 기능을 가진 함수라고 할 수 있다.




개발자가 클래스외부에서 클래스를 이용할 경우, 


정보보호와 은닉을 위해 클래스의 직접적인 필드을 건드리지 못한다.


그러나 메소드를 이용하면 메소드(함수)는 클래스 내부에 위치해 있기 때문에, 


같은 클래스 내부의 필드를 이용하거나, 값에 대한 수정이 가능하다.


클래스의 외부와 클래스 내부의 필드를 연결해주는 다리의 역활을 한다고 말할 수 있다.




메소드(method)도 필드와 마찬가지로, 


인스턴스 메소드(instance method)와 스테틱 메소드(static method)로 구분할 수 있다.


설명은 필드와 동일하다.


여기서 하나, 인스턴스 메소드와 스테틱 메소드의 차이를 말하자면,


인스턴스메소드는 this가 이용가능하나, 스테틱메소드는 this가 이용불가능하다.


this에 대한 설명은 블로그내의 'this와 super의 이용'에서 자세히 설명하고 있다.






#constructor


생성자는 말 그대로 생성을 하는 역활을 하는데, 정확하게 이야기를 하자면,


객체를 등록하는 역활을 한다고 할 수 있다.


객체를 만들기 위해서 우리는 main에서 아래와 같은 코딩을 하는데,



여기서 new뒤에 오는 No4() 이부분이 생성자를 호출하는 부분이다.


위와 같은 코드를 실행하면 main은 No4의 생성자로 이동하여,


생성자는 객체를 등록하게 되고, main은 이 객체를 인식하여 이용할 수 있게 된다. 




생성자는 주로 개발자가 클래스(class)내의 필드(field)를 초기화해줄 때 이용된다.


생성자의 생김새는 아래와 같다.




생성자의 가장 큰 특징중 하나는 리턴타입(return type)이 없다는 것과 시작글자가 대문자라는 것이다.


객체를 등록하는 역활을 하기 때문에, 반환값이 필요하지않으며,


생성자의 이름은 클래스의 이름과 동일해야 하기 때문에,


클래스의 시작글자가 대문자인 것처럼, 생성자의 시작글자 또한 대문자이다.




그런데, 우리가 객체를 만들 때 따로 생성자를 만들지 않고 객체를 등록하여 이용한다.


이렇게 할 수 있는 이유는 바로 객체 내에는 생성자가 이미 존재하기 때문이다.


눈에 보이지 않지만, 객체등록을 위해 생성되있는 생성자를 "default constructor"라고 한다.


이 디폴드 생성자(default constructor)는 개발자가 생성자를 하나도 명시하지 않았을 경우에 존재한다.


만약 개발자가 하나라도 명시할 경우에는, default constructor는 존재하지 않기 때문에,


개발자가 따로 명시를 해줘야 한다.




생성자는 또한 오버로딩(overloading)이 가능한다.


 + [오버로딩(overloading)]


   : 오버로딩이란, 개발자가 동일한 기능을 하는 메소드들을 만들때, 


    같은 메소드(method)명을 가지고, 각각 다른 매개변수를 지정하고 싶을 때 사용하는 기법이다.


    JAVA는 함수명(메소드명)이 동일해도 매개변수의 타입과, 매개변수의 갯수가 다르다면,


    상황에 맞추어 알맞은 메소드들을 찾아간다.


 < 오버로딩(overloading) 사용예시>







'JAVA' 카테고리의 다른 글

IntelliJ 설치  (0) 2018.10.26
final  (0) 2018.01.19
cmd로 클래스 실행  (0) 2018.01.19
접근 지정자  (0) 2018.01.19
class간의 관계  (0) 2018.01.18

포인터는 메모리의 주소값을 저장하는 변수이다.


[ 기본형태 : 포인터 타입* 포인터명 ]


Pointer, 가르키는 지시자인 포인터는 DataType 명시하는 대신, 자신이 가르킬 변수의 DataType을 명시한다.



다른 변수들은 선언 시 DataType에 의해 변수의 크기가 결정되는 반면,


포인터는 주소값을 저장하기 때문에, DataType과는 상관없이 항상 4byte의 크기를 유지한다.


<예시>




<결과값>









[포인터 문제]


다음 값이 어떻게 찍히는 지 생각해 보시오.



































= 답 







==문제풀이



printf("%d", *ptr++);        printf("%d", *ptr);


 : 포인터명 뒤에 붙은 ++은 증감연산자중에서 후 중감연산자로, 


  printf함수를 먼저 실행한 후에, 해당 값을 증가시킨다.


  printf함수를 실행하고 나면, *ptr++ 앞의 *이 사라지고, ptr++만 남게 되는데,


  이는 주소값을 증가하라는 의미임으로, ptr의 주소값은 그 다음주소로 이동하게 된다.


  그렇기 때문에 그 다음 printf로 ptr의 값을 찍게 되면, ptr[1]의 값인 10이 찍히게 된다.




printf("%d", *ptr+1);        printf("%d", *ptr);


 : 포인터명 앞에 별표(*)를 찍음으로써, 값을 의미하며 *ptr 의 값은 10이 나오게 된다.


  값에다가 +1을 한 값을 출력하라고 하였기 때문에, *ptr+1은 11이 찍히게 된다.


  그러나, +1은 값자체를 증가시키는 것이 아니라, printf함수를 이용한 출력시에만 이용되는 것이기 때문에,


  *ptr을 다시 출력하게 되면, 원래의 값 10이 나오게 된다.




printf("%d", ++*ptr);        printf("%d", *ptr);


 : 포인터명 앞에 붙은 ++은 증감연산자 중에서 선 증감연산자로,


  해당 값을 먼저 증가 시킨 후, printf함수를 실행하기 때문에, 11이 찍히게 된다.


  증감연산자는 앞의 +1과 달리 ptr의 값 자체를 증가시키기 때문에,


  다음  printf함수로 출력하게 되면, 바뀐 값(11)이 찍히는 것을 알 수 있다.




printf("%d", *(ptr+1));        printf("%d", *ptr);


 : 포인터명에 +1이 붙었으니, 해당값을 증가시켜야 하나, 별표(*)와 괄호로 구분되어 있으므로,


  주소값을 증가시켜 값을 출력하라는 의미이기 때문에, 22가 찍히게 된다.


  +1은 앞에서도 말했다 싶이, 값자체를 증가하는 것이 아니기 때문에, 


  *ptr을 다시 출력하면, 원래의 값 11이 찍히게 된다.




printf("%d", *ptr+=1);        printf("%d", *ptr);


 : *ptr+=1은 *ptr= *ptr+1과 같기 때문에, 값을 증가시키라는 의미이다.


  그래서 11에 +1이 증가된, 12가 찍히게 된다.


  +=은 값 자체가 증가된 것이기 때문에, *ptr를 찍게 되면, 증가된 값인 12가 찍히게 된다.




printf("%d", *++ptr);        printf("%d", *ptr);


 : ++은 포인터명 앞에 붙었으니, 증감연산자 중에서 선 증감연산자인데, 


  별표(*)와 포인터명 사이에 쓰였으므로, *(++ptr)과 동일하다.


  그러므로, ptr의 주소값을 증가시킨 후에, 값을 출력하라는 의미로, 


  주소값이 증가된 22가 찍히게 된다.


  ++은 해당 값 자체를 증가 시키기 때문에, 다시 ptr을 찍게 되면 22가 찍히게 된다.




printf("%d", (*ptr)++);        printf("%d", *ptr);


 : 괄호의 값을 먼저 계산해야 함으로, 후증감연산자는 값을 증가시킨라는 의미이다.


  그렇기 때문에, 처음에 printf함수로 출력시, 22가 찍히게 되지만,


  2번째로 찍게 되면, 22에서 값이 1증가된 23이 찍히게 된다.

'C' 카테고리의 다른 글

배열  (0) 2018.01.08
입력버퍼 비우기  (0) 2018.01.06

배열이란 동일한 DataType을 담는 변수들의 집합이다.


개발자가 프로그램내에서 변수를 선언하게 되면, 


운영체제는 변수의 크기에 맞춰 메모리상의 빈 공간을 찾아 메모리를 할당한다.


변수들에게 할당된 공간은 운영체제가 임의로 찾은 공간이기에, 


프로그램내에 선언된 변수들은 메모리상에 그 위치가 붙어있을 수도 있고, 혹은 떨어져 있을 수도 있다.


그렇기 때문에 값을 넣거나 변경하기 위해서는 변수들을 일일이 처리할 수 밖에 없다.


<예시>



그러나 배열을 사용하게 되면, 굳이 일일이 처리할 필요가 없다.


개발자가 배열을 선언하게 되는 순간, 개발자가 설정한 배열의 크기만큼 메모리 공간에 잡히게 되는데, 


이는 위의 방식처럼 변수의 할당위치가 재각각이 아닌, 연속적으로 이어져 있다.



개발자는 p배열의 첫주소값을 이용하여, p배열이 가진 모든 요소들을 접근할 수 있기 때문에, 


반복문을 이용하여 일괄처리가 가능해 지는 것이다.


<예시>





[ 배열 ] 


기본형식 : DataType 배열명 [갯수];


배열 선언시에는 첨자사이의 숫자가 개발자가 만들고자 하는 배열의 갯수를 나타내지만,


선언 후에는 배열명은 배열의 시작주소를 나타내며, 첨자 사이의 숫자는 배열의 시작주소로부터 상대적인 거리를 나타낸다.


<예시>


p[0]는 배열의 시작주소로부터 한칸도 떨어져 있지 않다는 것을 의미한다.


p[1]은 배열의 시작주소로부터 한 요소의 크기만큼 떨어져있다는 것을 의미하는데, 


p배열은 int형 배열이기 때문에 시작주소로부터 4byte 떨어져 있다는 것을 알 수 있다.




일차원 배열에다가 +1을 하면, 한요소의 크기 만큼 떨어져 있다는 것을 의미하나,


2차원배열에 +1을 하게 되면, 한 행의 크기만큼 떨어져 있다는 것을 의미한다.


마지막으로, 3차원배열에 +1을 하게 되면, 한 면의  크기만큼 떨어져 있다는 것을 말한다.




[주소값과 값의 구분]


주소값과 값의 구분 기준은 첨자([ ])와 별표(*)이다.


위에서는 나타내지 않았지만, 배열의 첨자는 별표로, 별표를 첨자로도 바꾸어 나타낼 수 있다.


그렇기 때문에, 배열의 선언할 때의 첨자의 갯수혹은 별표의 갯수보다 더 적다면 주소값이고, 갯수가 동일하다면 값이다.


+배열의 첨자의 갯수혹은 별표의 갯수가 동일하더라도, 앞에 &가 붙어있다면 값이 아닌 주소값을 의미한다.



<예시>


int a[2][2][2];




#주소값


&a[0][0][0]   &a[0][0][1]  &a[0][1][0]  &a[0][1][1]  &a[1][0][0]  &a[1][0][1]  &a[1][1][0]  &a[1][1][1]


a[0][0]  a[0][0]+1  a[0][1]  a[0][1]+1  a[1][0]  a[1][0]+1  a[1][1]  a[1][1]+1


*a[0]  *a[0]+1  *(a[0]+1)  *(a[0]+1)+1  *a[1]  *a[1]+1  *(a[1]+1)  *(a[1]+1)+1


**a  **a+1  *(*a+1)  *(*a+1)+1  **(a+1)  **(a+1)+1  *(*(a+1)+1)  *(*(a+1)+1)+1


a[0]  a[0]+1  a[1]  a[1]+1


*a  *a+1  *(a+1)  *(a+1)+1


a  a+1




#값


a[0][0][0]   a[0][0][1]  a[0][1][0]  a[0][1][1]  a[1][0][0]  a[1][0][1]  a[1][1][0]  a[1][1][1]


*a[0][0]  *(a[0][0]+1)  *a[0][1]  *(a[0][1]+1)  *a[1][0]  *(a[1][0]+1)  *a[1][1]  *(a[1][1]+1)


**a[0]  *(*a[0]+1)  **(a[0]+1)  *(*(a[0]+1)+1)  **a[1]  *(*a[1]+1)  **(a[1]+1)  *(*(a[1]+1)+1)


***a  *(**a+1)  **(*a+1)  *(*(*a+1)+1)  ***(a+1)  *(**(a+1)+1)  **(*(a+1)+1)  *(*(*(a+1)+1)+1)


'C' 카테고리의 다른 글

포인터  (0) 2018.01.08
입력버퍼 비우기  (0) 2018.01.06

[Visual Studio 2015버전]


숫자를 입력한 뒤 Enter키를 누르게 되면, 다음에 입력받는 단계를 건너뛰는 경우가 발생한다.


<Example>


 #include"stdio.h"

 #pragma warning(disable : 4996)


 void main(){


 int num1, num2;

 char op;

 

 printf("Enter the 1st number : ");

 scanf("%d", &num1);


 printf("Enter the operation : ");

 scanf("%c", &op);


 printf("Enter the 2nd number : ");

 scanf("%d", &num2);


 printf("%d%c%d = %d", num1, op, num2, num1+num2);


}


  예제를 실행하게 되면, enter the 1st number : 에 커서가 깜빡거린다.


 그 곳에다가 3을 입력하고 Enter키를 누르게 되면,  다음과 같은 결과가 나오게 된다.



즉, 연산자를 입력할 공간이 사라지고, 다음 숫자를 넣을 공간에 커서가 깜빡거리게 된다.






[원인]


"이렇게 되는 이유는 Enter키 때문이다."


원리를 설명하자면,


scanf함수를 이용하여 값을 입력하게 되면, 변수에 값이 저장되기 전에 입력버퍼에 먼저 그 값이 쓰여지게 된다.



여기서 \0는 'Null'값을 말하며, 이는 Enter를 칠 경우 입력버퍼에 \0의 형태로 들어가게 된다.


이렇게 쓰여진 값들은 데이터타입에 따라 변수에 저장되게 된다.


num1에 저장되는 것은 오직 3뿐이다. 이유는 num1의 데이터 타입이 int 이기 때문이다.


'\0'는 char 타입이기 때문에, num1에는 저장될 수 없다. 그렇기 때문에 '\0'는 입력버퍼에 그대로 잔류하게 된다.


다음에 입력 받는 연산자가 char타입이기 때문에, 이 변수 op는 추가적인 입력없이 입력버퍼에 남아있는 '\0'를 저장하게 된다.



그렇기 때문에, 프로그램을 실행시켰을 때는 위와 같이, 연산자를 입력할 공간이 건너 뛰어, 다음숫자를 입력할 단계로 넘어가는 것처럼 보이게 된다.







[해결 방안]


1. getchar()이용


  getchar함수는 입력버퍼에서 문자 하나를 가져오는 함수이다.


  getchar()를 이용하게 되면, 입력버퍼에 '\0'를 가져오게 됨으로써, 입력버퍼가 비게 되어 다음 값을 입력받을 수 있다.


  <사용 예시>



 + 응용버전.


 getchar()는 문자하나만을 가져오기 때문에, 입력버퍼에서 있는 문자전체를 가져와서 입력버퍼를 비우고 싶을 경우에는


 위의 getchar()가 적혀있는 부분에, getchar() 대신, while(getchar()!='\n') 를 적어주면 된다. 


 while 문의 조건을 통해, 문자가 '\n'(개행문자)가 아닌 경우에는 모두 가져와서 입력버퍼를 비워주는 역활을 한다.





2. %*c 이용



 scanf함수에서 '%*c' 는 'read the data but do not assign it to a variable in the argument list' 이다.


 즉, 입력버퍼의 값을 읽어오지만, 그 값을 변수에 대입하지는 않는 다는 뜻이다.



<사용예시>


  #include"stdio.h"

  #pragma warning(disable : 4996)


  void main(){


  int num1, num2;

  char op;

 

  printf("Enter the 1st number : ");

  scanf("%d", &num1);


  printf("Enter the operation : ");


  scanf("%c", &op);     -> scanf("%*c%c", &op); 로 변환 : 입력버퍼에 있는 '\0'를 %*c에서 가져가게 된다. 


    그러나, %*c는 가져간 값을 변수에 대입하지는 않기 때문에, 다음 %c로 넘어가게 된다.


    (원래 입력버퍼에 있던 값을 한번, scanf로 입력하는 값 한번) = 두개의 문자를 입력받는 방식.


  printf("Enter the 2nd number : ");

  scanf("%d", &num2);


  printf("%d%c%d = %d", num1, op, num2, num1+num2);


 }





3. scanf("%c", &op) 한번 더 이용



<사용예시>



scanf("%c", &op)를 처음 사용하게 되면 op에는 '\0'의 값이 들어오게 된다.


두번째 이용 시에는, 입력버퍼에 남은 값이 없기 때문에 op변수에 키보드를 통해 값을 입력할 수 있게 된다.





4.  rewind(stdin) 이용


[ 기본형태 :  void rewind ( FILE * stream ) ]


rewind함수는 스트림의 위치를 재설정하는 함수이다.


스트림은 프로그램과 장치사이를 연결해 주는 통로라고 할 수 있으며, 


표준 스트림은 모든 프로그램에서 기본적으로 사용하는 3개의 스트림(stdin, stdout- 표준 출력, stderr - 표준 오류)을 말한다.


그 중에서도 stdin(standard input)은 표준 입력 스트림으로써, 


키보드에서 입력받는 값이 변수에 저장되기 전에 임시로 저장되는 공간으로 가는 통로라고 할 수 있으며, 


사용자의 개별적인 지정없이는 키보드에서 받아 오게 된다. 


또한 이 통로를 통해 값이 임시로 저장되는 공간을 입력버퍼라고 한다.



rewind함수는 스트림의 위치를 스트림의 시작점으로 이동하게 하는 함수로서, 


주는 곳에 stdin를 주게 되면, 입력 스트림의 위치를 처음 위치로 이동시키게 된다. 


rewind함수를 이용 후, 값을 입력하게 되면, 이전에 쓰여있던 값을 덮어 쓰고, 입력하게 된다. 



<사용예시>



+추가


비슷한 예시로는 fseek함수가 있다.


[ 기본형식 : int fseek(FILE *stream, long offset, int whence) ]


fseek함수는 rewind함수와 유사하게 위치를 재설정해주나,


시작점으로 이동하는 rewind함수와 다르게 위치를 이동시키는 함수로서, 인자를 3개를 요구한다.


offset는 기준점에서 부터 byte 단위로 사용자가 위치를 지정할 수 있으며, 


whence는 그 위치를 변경할 기준점으로 SEEK_SET, SEEK_CUR, SEEK_END 3가지가 있다.


SEEK_SET는 스트림의 시작점을, SEEK_CUR은 현재 스트림의 위치를, SEEK_END는 스트림의 마지막점을 말한다. 


<사용예시>

fseek(stdin, 0, SEEK_SET)을 이용하여 현재 스트림의 위치를 시작점으로 이동시켜 입력을 받을 수도 있지만,


fseek(stdin, -1, SEEK_CUR)를 통해, 현재스트림의 위치에서 -1한 위치로 이동시켜, 입력을 받을 수도 있다.



<사용예시>

참고자료 : https://www.joinc.co.kr/w/man/3/fseek





5. 공백(White Space) 이용


scanf함수의 기본적인 사용형식은 scanf("문자 서식 및 구분자", 데이터의 값) 이다. 


구분자란 문자를 여러개 입력 받는 경우 값을 구분해 주는 요소이다.


구분자는 공백(white space)혹은 개행문자(\n), Tab(\t) 등 여러가지가 있는데, 


이 구분자가 들어가게 되면 값 입력시 구분자형식과 동일한 값이 들어오게 되면


해당값을 입력에서 제외하고 입력을 받는다. 


+ 지정 구분자와 다른 형식의 구분자을 입력할 시에는 입력 값을 구분자로 인식하지 않고,


   값으로 인식하여 입력을 받아들인다.



<사용예시>



++예외적으로 안되는 함수


1. fflush함수


fflush함수는 원래는 출력버퍼를 비우는 함수로 이용되나, fflush(stdin)로 입력버퍼를 비우는 함수로도 이용할 수 있었다.


그러나, visual studio 2015년도 버전부터 보완을 강화시켜 이용이 불가능하다.


'C' 카테고리의 다른 글

포인터  (0) 2018.01.08
배열  (0) 2018.01.08

+ Recent posts