• 단일문자 입력함수(버퍼화 입력의 의미)

- 전달인자 : 없음

- return 값 : 성공적으로 입력 받은 문자의 ASCII code 값


 함수명

입력버퍼

 사용여부 

입력된 문자 사용시점

Enter 키 인식  

 입력시 수정가능 여부 

입력문자 echo

  (화면에보인다)  

 getchar()

O

Enter 키 입력 후 

'\n' 

Enter키 입력 전 수정가능 

getche()

X

입력 즉시

'\r'(그행 제일앞으로) 

수정 불가능 

getch()

X

입력 즉시

'\r' 

수정 불가능 



EX) getchar() 부분을 getche()와 getch()로 바꿔서 테스트해보고 결과를 보면 차이를 이해하기 쉽다 !

#include <stdio.h> // getchar(), putchar() 사용위해
#include <conio.h> // getche(), getch() 사용위해

int main()
{
    char ch;
    while( (ch=getchar() ) != '\n')
    {
       putchar(ch);
    }
    getch();
    return 0;
}


  • 차원 및 차원 조절
C코드 내에서 사용되는 모든 상수나 변수는 차원이 부여되어있다. (최저차원 : 0차원)
- 상수나 변수의 차원은 차원조절 연산자에 의해서 차원이 변경될 수 있다. ( ↑ ↓ )
- Lvalue와 Rvalue는 차원이 같아야 대입연산이 가능하다.
 (주소상수는 자동형변환이 불가능 하다)


  • 차원조절 연산자

 연산자

선언문 

일반 실행문 

비 고 

*, [] 

차원 올림 

차원 내림 

중복사용 가능 

 &

사용불가 

차원 올림 

중복사용 불가능 

 (type)

사용불가 

여러차원 올리고 내리기 가능 

피연산자의 type과 차원 고려x 

-> 

사용불가 

차원 내림( * + . 의개념)  

중복사용 불가능 



  • 배열과 포인터 1
만약 int a[3][4]; 라는 2차원 배열이 있다고 가정하자.
배열 a를 받을 함수의 매개변수의 형태로 알맞는 것은 어떤 형태일까?
ex) void sub(  ?? )

가장먼저 2차원배열이니 2차원형태의 형태를 맞춰주어야겠다.

그다음으로 알아야할 것은,
n차원 배열의 시작주소는 그 배열의 가장 큰 구성요소의 한 차원 높은 주소이다. 라는 사실이다.

그러면 방법1 int **p 라고 하면 되는걸까? ( X )

int * *p 라고 조금 떨어져서 구분지어 생각하면 좋다. 위의 방법1은 차원맞 맞춰준거지 
결국 int *라는 곳을 가리키는 포인터라는 뜻이 되어버린다. 


방법2 int *p[4] 를 해석해보자. 

연산자 우선순위에 의하면 1번째로 해석될곳은 p[4] 부분이 된다.

그러면 int a[4]의 뜻과 비교해보자. 

a라는 녀석은 int라는 요소를 4개가진(4개의방) 녀석이 된다.

이와 같이 위의 경우를 해석해보면 p[4]도 int *라는 포인터를 4개가진 녀석이 되어버린다. ( X )


방법3 int (*p)[4] 를 다시 해석해보자. 연산자 우선순위에의해 처음으로 해석될 곳은 (*p)이다. 

(연산자 우선순위에서 보면 ( ) 와 [ ] 의 우선순위가 1순위로 같지만 -> 방향의 형태이다.)

나는 포인터라고 먼저 명시를 해주는 것이다. 

그러면 이 녀석은 int [4]를 가리키는 포인터가 되어버린다.

이는 int[4]보다 1차원 높은 구성요소이면서,

주소를 나타내 줄수 있는 포인터이므로 맞는 표현이 된다. ( O )

cf) int p[4](*)는 p[4]가 먼저 해석되므로 배열이다. ( X )


마지막으로 방법4 int p[3][4] 를 해석해보자. 

parameter 자리에 선언된 배열은 실제 배열로 잡히지 않고,

그렇게 생긴 배열을 가리키는 포인터변수로 잡히기에 가능하다. ( O )


위와같이 인식된 포인터의 경우 포인터가 그 배열의 첫 번방을 가리키는 주소를 나타내기에,

마치 자신이 그 배열의 배열명인 것처럼 쓰일 수 있다.


결론 :  2차원배열의 파라미터형태는 방법 3과 4의 형태로 쓰면되며,

  배열의 이름은 곧 그 배열의 시작주소 상수이므로....

  포인터 하나로 여러방을 가리킬 수 있다는 결론에 도달 할 수 있다. p[i][j]와 같은 꼴로...


  • 배열과 포인터 2
  • a[i]          == *( a+i )
  • a[i][j]       == *( *( a+i ) + j )
  • a[i][j][k]    == *(*(*( a+i ) +j ) +k )

       면[i] 행[j] 열[k] 

  1. 배열명을 스고 (딱 1회만)
  2. 첨자를 더하고
  3. ( ) 로 묶고
  4. * 연산자를 붙인다.



  •  ary[3][4]에서 ary[2][3] = 77; 과 같은 표현을 포인터로 나타내면?


 -> *(*(ary+2)+3) = 77;

  행  열


-> 풀어서 내부결과를 나타내보면

-> ary의 시작주소가 100번지라고 가정하면

-> 100번지(int(*)[4] : 2차원) + 2(행첨자) * sizeof(int[4]) = 132번지 (int(*)[4] : 2차원)
-> 실행문이므로 * 에 의해 차원이 내려가면 int * : 1차원

-> 132(int *) + 3(열첨자) * sizeof(int) = 144번지 (int *)

-> 실행문이므로 * 에 의해 차원이 내려가며 int형태가되고 int형태인 77 값이 들어가게 되는 원리이다.




  • 배열과 포인터 3 (정리)
  1.  int **p1;     : p1은 1차원 int형 포인터를 가리키는 포인터
  2.  int *p2[5];   : p2는 요소가 5개인 배열로서 각 배열의 요소는 int형 포인터이다. ( 포인터배열 )
  3.  int (*p3)[5]; : p3은 포인터로서 열이 5개인 2차원 배열을 가리키는 포인터 변수, 그 배열의 각 요소는 모두 int형 이다. ( 배열 포인터 )


  • 절댓값 함수 #define n abs(i) 를 이용한 별 찍기. (방법1)

  • if문을 활용한 반복형태 .. (방법2)
 -> 공백의 숫자 : 3 2 1 0 1 2 3
 -> 별의 숫자 :    1 3 5 7 5 3 1
 -> 원래 i의숫자: 0 1 2 3 4 5 6 ( 7줄 )
  •  if문을 통해서..
 -> 변형된 i숫자: 0 1 2 3 2 1 0

 -> 이 논리에 의하면 iLine의 숫자만 바꿔주어도 원하는 줄만큼의 다이아몬드 형태의 별찍기 가능.





'ComputerScience > 꿀같은 예제들' 카테고리의 다른 글

C, sprintf() 함수 예제  (0) 2018.07.15
C++ 야구게임 만들기 (셔플함수이용)  (0) 2018.07.04
10진수 16진수 변환하기  (0) 2018.07.03
namespace  (0) 2018.07.02

어제 정리하고 잔다는 것을, 너무일찍 잠들어서 새벽에깼다가... 결국 잠을 설쳤다.

그래서 다음날 아침에 정리한다. ㅠㅠ



  • 야구게임 문제설명


  • 함수선언부

  • 필요한 변수 선언 및 셔플함수 호출 부분


  • 반복문 구조


  • 셔플함수

--> 셔플함수내에서 쓰일 swap형태를 기존의 temp를 써서 하던 방식(방법1)temp라는 공간을 사용하지 않고 쓰는 방식을 사용해보았는데(방법2), 반복문의 횟수가 커지면 temp함수는 괜찮지만 새로 쓰인 temp변수를 쓰지않는 방식에서는 대부분이 0으로 변하는 이상한 현상이 발생했다. 

여기에 대한 고찰은 다음에 다시 해보기로한다. 반복문을 100번하다보니 연산이 많아져서 이상해지는건가... 

20번정도가 넘어가면서 셔플이 잘되지않았다.(방법2) 




  • 스트라이크와 볼체크 함수 부분



  • 승리판단 함수



'ComputerScience > 꿀같은 예제들' 카테고리의 다른 글

C, sprintf() 함수 예제  (0) 2018.07.15
C++ 다이아몬드 별찍기  (0) 2018.07.04
10진수 16진수 변환하기  (0) 2018.07.03
namespace  (0) 2018.07.02

  • 해설 : 10진수를 16진수로 변환 하는 예제다. 간단히 입출력형태의 형태만 바꿔서 해도 되지만 저런식으로 직접 구현을 해보았다. C++ 코드를 기본으로 작성했으며, 메인함수에다가 다 때려넣긴 했지만 입력에서의 예외처리부분까지 구현한 코드다. nextLine은 매크로 연습겸 써본코드인데, 개행이 잘된다.






'ComputerScience > 꿀같은 예제들' 카테고리의 다른 글

C, sprintf() 함수 예제  (0) 2018.07.15
C++ 다이아몬드 별찍기  (0) 2018.07.04
C++ 야구게임 만들기 (셔플함수이용)  (0) 2018.07.04
namespace  (0) 2018.07.02

소개

학습한 내용들을 응용해서 예제들을 만들어 볼 예정이다.

참고한 강의나 책과 소스코드가 같을 수도 있고, 다를 수도 있지만 학습에 도움이 되는 목적으로 작성 한다.


1. namespace


(gamer.h)

namespace gamer

{

extern int number;   // 선언시에는 변수는 extern을 사용해야 한다.

void print();            // 함수는 extern 키워드 생략가능

}


(gamer.cpp)

#include <iostream>

using namespace std;

namespace gamer

{

int number =3;    // 정의시에는 extern 생략가능

void print()

{

cout << "gamer print()내에서의 number = " << number << endl;

}

}


(melona.h)

namespace melona

{

extern int number;

void print();

}


(melona.cpp)

#include <iostream>

using namespace std;

namespace melona

{

int number =7;

void print()

{
    cout << " melona print() 내에서의 number = " << number << endl;

}

}


(main.cpp)

#include <iostream>

using namespace std;

#include "melona.h"

#include "gamer.h"



int main()

{

cout << main()에서 출력하는 gamer 네임스페이스의 number = " << gamer::number << endl;

gamer::print();

cout << main()에서 출력하는 melona 네임스페이스의 number = " << melona::number << endl;

melona::print();


return 0;

}


  • 해설 : namespace의 선언부와 정의부에대해 나누어 작성해보고, extern키워드의 유무 및 사용법에 주의하여 본다.

   또한, using 키워드를 사용함으로서 std::cout과 같이 안써도 됨을 보고, using gamer::number; 와같이 한후 number를 찍어 볼 수도 있겠다.

출력결과는 딱보아도 알 수있게 작성했으므로 생략한다.






소개

18년 07월 02일 월요일, 여름방학인 오늘부터  C / C++ 에대한 전반적인 공부를 시작!!

전공은 Computer Science이며, 프로그래밍 공부가 많이 부족한 상태다!!

게임 프로그래머가 되고 싶어, 시작한 공부인 만큼 기초를 잘 다져서 꼭 이루어내겠다.


블로그를 시작한 이유?..

 전체적으로 훑어 본 적은 있으나 체계적으로 정리하지 못했던 문법들을 정리해보기에 좋아보였기 때문.


날 밝을때는 강의등을 통한 학습 -> 

날 어두울 때는 예제들을 통한 복습 ->

개념정리를 블로그에 날마다 할 계획.

(목요일은 쉴예정)


전반적으로 구글링, 유투브 (특정채널), 가지고있는 책을 위주로 참고해서 정리 할 예정. 


1. namespace (네임스페이스)

  • 개념 : 여러 가지 식별자들을 이름이 있는 범위로 그룹화하는 기법

 - 식별자들의 종류 : 변수, 함수, 구조체, 클래스, 공용체, typedef 등

  • 동일한 이름을 갖는 함수나 변수라도 서로 다른 namespace 안에 만들 수 있다.
  • 코드 내에서 이름이 같은 식별자나 라이브러리 사용하는 과정에서 생기는 식별자명 충돌 (name clash) 문제를 해결할 수 있음.
  • scope resolution operator ('::')를 사용하여 네임스페이스를 구분함. 

ex) 네이스페이스명 :: 식별자명

  • using 지시자 :  네임스페이스내의 식별자를 네임스페이스명 없이 사용하기위한 명령어.
  1. using 네임스페이스명 :: 식별자명;       // 네임스페이스 내의 하나의 식별자명만 using 하기
  2. using namespace 네임스페이스명;       // 네임스페이스 내의 모든 식별자를 바로 사용 하기


2. main()

  • main함수 없으면 링크에러가 발생한다. 
  •  동작순서 : main()가 어디에 위치에있던간에 startup code가 찾아서 main()을 불러준다.  그리고 main함수 안의 내용들을 처리하고 마지막 return 값을 startup code가 받아준다. 리턴값에 대한 의미는 UNIX, LINUX와 같은 운영체제에서는 정상종료와 비정상종료를 나누는 것과 같이 의미있게 다루지만, Windows같은경우는 main()의 리턴값을 특별한 의미로 다루지 않는다.
  • 여기서 Startup Code가 하는 일은
  1. 메모리를 확보(Ram안에)
  2. (buffer할당)
  3. main함수 호출
  4. main함수의 리턴값을 OS에 전달
  • 메인함수는 함수의 정의부만 보이는 사용자 정의함수이다.  우리가 부르는게 아니기 때문이다.
cf.) printf와 같은 함수들의 정의부는 어디에있을까? -> 라이브러리루틴에 있다.


3. % ? . ?
  • % 필드너비지정 . 정밀도
  • 필드너비지정은 출력될 데이터가 크기에 맞지 않으면 크기 무시
  • 정밀도는 %f, %e, %g에서는 소수이하 자리수를 의미
  • 정밀도는 %s에서는 프린트될 최대 문자의 개수를 의미
  • 정밀도는 %d.에서는 출력될 수의 최소개수를 의미
  • %*.* 필드의 너비나 정밀도등을 임의로 지정하고자 할 때 사용

  ex) int b=10;

 int c=3; 

 double fa = 123.7546;

printf("%*.*lf\n", b, c, fa); -> %10.3lf 의 형태로 인식 

(10자리폭(소수점포함)에 소수점은 3자리) 

결과-> 빈빈빈123.755



4. 유효정밀도

  • 개념 : 실수 데이터형에만 있는개념으로 유효숫자를 몇 자리까지 저장할 수 있는가를 10진수 기준으로 나타낸것.
  • float 형 : 7 ~ 8자리 , double 형 : 14 ~ 16자리

 cf) 실수형의 오차 2가지

  1.  유효정밀도에 의한 오차
  2. 2진수 변환 시 순환소수로 변환되어 발생하는 오차 

   ex.) float fa = 7.33f;



5. const , #define, enum 의 비교

  • #define(매크로 정의)는 프로그램을 읽기쉽게하고, 유지보수를 용이하게 해주며, 변수 사용 시 보다 처리속도를 높여준다. but 실행파일의 크기는 커질수 있다.
  • #define을 쓴 매크로 함수는 타입에서는 자유로운편이지만 정밀도는 떨어질 수 있다. 하지만 타입에 민감한 경우는 조심해야 한다.  

    ex) #define mod(a,b)  a%b  -> 이 경우 double형이 날라오면 바보가 된다.

  • const 변수는 반드시 선언문에서만 초기화가 가능하다. 초기화 이후 실행문에서는 그 값을 변경할 수 없다.
  • 포인터에 const를 사용할 경우 포인터의 대상이 상수화되는 경우와 포인터 변수 자체가 상수화 되는 경우가 있다.

=> const가 변수의 이름과 가깝냐 머냐를 보면 된다.
  1.  포인터의 대상이 const화 되는 경우

const int *p;    // 상수화된 int를 가리키는 *p의 운명!!

int abc = 7;

p = &abc;

*p -= 10;     ( X )

abc -=10;    ( O )


  B. 포인터 변수가 const화 되는 경우


int abc[3] = {10, 20, 30};

int * const p = abc;

printf("%d \n", *p);         ( O )

printf("%d \n", ++*p);     ( O )    // 포인터가 가리키는곳을 증가시키는 것이니 괜찮다!

printf("%d \n", *++p);     ( X )    // 포인터를 증가시키는 경우가 되버린다.


  • 따라서 const char * cp = "kiwi";   <--- 이런표현을 쓰는게 좋은 것이다. ( string 영역은 Read Only 영역이기에 )
  • enum(나열형)을 이용하면 정수상수를 기호 이름으로 선언해서 사용하거나 정수기호상수를 저장하는 변수를 선언하여 사용할 수 있다.
  • enum은 이름을 부여할 수 있기에 결과적으로 가독성을 높여준다. -> Switch문과 잘 어울림

6. Shift 연산자
 - 비트단 좌/우 이동 연산자

Shift 방향 및 대상체 부호

공백 메우기 

 << (Left Shift)

 signed

0으로 채움 

unsigned 

 >> (Right Shift)

 signed

 sign bit값으로 채움

 unsigned

0으로 채움 


  • 왼쪽 쉬프트 하나당 * 2(곱하기2) 한 효과를 낼 수 있기 때문에 연산속도가 빠르지만 그 효과가 영원하지는 않다는 것에 주의 해야한다.
  • 유효숫자가 Sign Bit로 가면 음수로 되기도하고 거기서 또 쉬프트하면 유효숫자가 빠져나가버리기도 한다...
  • 마찬가지로 오른쪽 쉬프트 하나당 / 2(나누기2)한 효과를 낼 수 있지만 이 또한 주의할 것!

ex )  shift 연산자를 이용해 특정정수(n)의 값의 12배를 구하고자 한다면???

-> n의 8배수 + n의 4배수 형태로 결과를 얻으면 된다.

-> 즉, (n<<3) + (n<<2)로 계산한다.



7. 연산자 우선순위표 (C언어기준)


 순위 

명칭 

연산자 

결합방향 

1

1차 연산자 

() [] . -> 

->

2

다항 연산자

+ - ! ~ (type) sizeof ++ -- & *

<- 

3

승법 연산자

* / % 

-> 

4

가법 연산자 

+ - 

5

Shift 연산자 

<<  >> 

6

관계 연산자 

<  >  <=  >= 

7

등가 연산자 

==  != 

8

bit 곱 연산자 

 9 

bit 차 연산자 

 10 

bit 합 연산자 

 11 

논리곱 연산자 

&& 

 12 

논리합 연산자 

|| 

 13 

조건 연산자 

? : (삼항연산자) 

 ->

 14 

대입 연산자 

=  +=  -=  *=  /=  %=  <<=  >>=  &=  |=  ^= 

 <-

15

순차 연산자 

 ->


* 순위 3~12는 이항연산자.



8. 난수발생 방법

  • #include <time.h>

    srand((unsigned int)time(0));                      // 현재시간 기준으로 시간값 뽑아올수있다.
    cout << rand() % 100 << endl;                 // 0~99 
    cout << rand() % 101 + 100 << endl;        // 100~200
    cout << (rand() % 10000 / 100.f) << endl;  // 0~99.99%  \
-> rand % 10000 이 한번에 뽑을수 있는 최대의 수... 만자리... 응용해서 써야 더 큰 수 조절가능







+ Recent posts