--*p : 단항 연산자는 연산 결합 순서가 오른쪽부터 시작된다. 그러므로 *p가 먼저 해석 되고 -- 연산이 되므로 *p값이 1줄어든 4로 출력된다.






*p-- : 단항 연산자는 연산 결합 순서가 오른쪽부터 시작한다. 그러므로 p--가 먼저 해석 되기 때문에 p값 자체가 줄어든다.

연산자 우선순위 및 결합순서
 컴퓨터언어는 개발자를 비롯한 컴퓨터 과학/공학자들의 요구에 따라 다양하게 진화되었다. 최대한 인간의 일반적인 사고를 바탕에 두고 문법과 체계를 만든 것이지만, 아무래도 언어 개발자들의 마인드가 포함되어 있어 일반에게는 약간 어렵기도 한 것 같다. 다음은 C++ 연산자 우선순위표이다. 이것을 잘 알아야, 복잡한 포인터와 구조체, 배열이 섞인 복잡해 보이는 식도 기계적으로 풀어낼 수 있다. 그러므로 다음은 반드시 암기 가능하면 이해할 사항이다.

간략본(http://www.winapi.co.kr/clec/cpp1/5-4-1.htm)

순위

연산자

결합순서

1

( ) [ ] -> .

왼쪽 우선

2

! ~ ++ -- + -(부호) *(포인터) & sizeof 캐스트

오른쪽 우선

3

*(곱셈) / %

왼쪽 우선

4

+ -(덧셈, 뺄셈)

왼쪽 우선

5

<< >>

왼쪽 우선

6

< <= > >=

왼쪽 우선

7

== !=

왼쪽 우선

8

&

왼쪽 우선

9

^

왼쪽 우선

10

|

왼쪽 우선

11

&&

왼쪽 우선

12

||

왼쪽 우선

13

? :

오른쪽 우선

14

= 복합대입

오른쪽 우선

15

,

왼쪽 우선


상세본(http://www.cppreference.com/operator_precedence.html)
사용자 삽입 이미지

자바(http://www.tech-faq.com/lang/ko/java-operator-precedence.shtml)
자바 연산자 우선순위는 자바를 결정하는 방법을 평가 연산자를 사용하여 첫 번째합니다.

In this chart, operator precedence is displayed from highest precedence to lowest precedence. 이 차트, 연산자를 우선 순위가 높은 우선 순위가 낮은 우선순위를 표시합니다.

우선순위 연산자 기능 결합순서
1 [] Array index 어레이 색인 Left to Right
() Method call 메서드 호출
. Member access 회원에 액세스
2 ++ Prefix or postfix increment 접두사 또는 postfix 증감 Right to Left
-- Prefix or postfix decrement 접두사 또는 postfix 감소
+ - Unary plus, minus 단항 플러스, 마이너스
~ Bitwise NOT 비트없는
! Boolean (logical) NOT 부울 (논리)
(type) Type cast 유형 캐스트
new Object creation 개체를 창출
3 * / % Multiplication, division, remainder 곱셈, 부서, 나머지 Left to Right
4 + - Addition, subtraction 또한 뺄셈 Left to Right
+ String concatenation 문자열 연결
5 << Signed bit shift left to right 서명 비트 교대 왼쪽에서 오른쪽으로 Left to Right
>> Signed bit shift right to left 서명 비트 교대 오른쪽에서 왼쪽으로
>>> Unsigned bit shift right to left 오른쪽에서 왼쪽으로 서명되지 않은 비트 교대
6 < <= Less than, less than or equal to 미만, 이하 같음 Left to Right
> >= Greater than, greater than or equal to 보다 큼, 크거나 같음
instanceof Reference test 참조 테스트
7 == Equal to 같음 Left to Right
!= Not equal to 같지 않음
8 & Bitwise AND 비트 및 Left to Right
&& Boolean (logical) AND 부울 (논리)과
9 ^ Bitwise XOR 비트 xor Left to Right
^ Boolean (logical) XOR 부울 (논리) xor
10 | Bitwise OR 비트 또는 Left to Right
| Boolean (logical) OR 부울 (논리) 또는
11 && Boolean (logical) AND 부울 (논리)과 Left to Right
12 || Boolean (logical) OR 부울 (논리) 또는 Left to Right
13 ? : Conditional 조건부 Right to Left
14 = Assignment 과제 Right to Left
*= /= += -= %=
<<= >>= >>>=
&= ^= |= 
Combinated assignment 임무는 combinated
(operation and assignment) (작업과 배정)

Notes: 참고 사항 :

  • Expressions inside parentheses are evaluated first 괄호 안에 표현을 평가할 수있습니다 첫 번째
  • Nested parentheses are evaluated from the innermost parentheses to the outermost parenthesis. 중첩된 괄호는 괄호를 안쪽에서 바깥쪽 괄호을 평가합니다.
  • Operators in the same row in the chart have equal precedence. 차트에서와 같은 행에 연산자를 우선 순위가 동일합니다.

참고
- 이쪽 블로그를 보면 연산자 우선 순위에 대한 여러 생각들을 정리해 놓았다

출 처 : http://learder.tistory.com/827019

void quick_sort(int *data, int left, int right)
{
  int k;
  int i, j, pivot;
  i = left;
  j = right;
  pivot = left;

  if(i >= j)
    return;

  while(i < j)
  {
    while(data[++i] < data[pivot])
    {
      if(i >= right)
        break;
    }
    while(data[j] > data[pivot])
    {
      j--;
      if(j <= left)
        break;
    }
    if(i < j)
      swap(data, i, j);
  }
  swap(data, pivot, j);
  quick_sort(data, left, j - 1);
  quick_sort(data, j + 1, right);
}

void swap(int *data, int i, int j)
{
  int tmp;

  tmp = data[i];
  data[i] = data[j];
  data[j] = tmp;
}

// 버블 정렬
void bubble(int *arr, int size)
{
  int i, j;
  int tmp;

  for(i = 0 ; i < size - 1 ; i++)
  {
    for(j = 0 ; j < size - i - 1 ; j++)
    {
      if(arr[j] > arr[j + 1])
      {
        tmp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1= tmp;
      }
    }
  }
}

 intToChar() - 정수를 문자열로 바꿔주는 함수
void intToChar(char *buf, int num)
{
  int i, j;
  int target;    // 각 자리수
  int value = 1;  // 숫자 크기 확인
  
  while(value <= num)
  {
    value *= 10;
  }  
  
  for(i = 0, j = value/10 ; j >= 10 ; j /= 10)
  {
    target = num / j;
    num = num % j;
    buf[i++] = target + 48;    // buf에 문자값 저장
  }
  buf[i++] = num + 48;
  buf[i] = '\0';
}

 atoi() - 문자열로 된 수를 정수형으로 바꿔주는 함수
int atoi(char *c)      // Charter to Integer
{
  int result = 0;
  int val = 1;
  int i;
  char *tmp = c;

  while(*tmp != '\0')
  {
    val *= 10;
    tmp++;
  }

  tmp = c;
  for(i = (val / 10) ; 1 <= i ; i /= 10)
  {
    result += ((*tmp - 48) * i);
    tmp++;
  }

  return result;
}

1. 1바이트는 8개의 비트로 이루어집니다. 255 8개 비트 전체가 1인 경우이고, 1은 최하위 1비트만 1인 경우입니다. 문자 ch의 켜진 비트 개수는 몇 개입니까? 켜진 비트는 1로 설정된 비트의 다른 표현입니다.

대문자 ‘A’의 값은 65이고 6번째와 1번째 비트가 켜져 있습니다.


 Character.h
#ifndef CHARACTER_H
#define CHARACTER_H

class Character
{
public:  
  // 생성자
  Character();
  Character(char c);

  // 소멸자
  ~Character();

  void setChar(char c);
  char getChar() const;
  int bitCount() const;

protected:
  char data;
};

#endif

 Character.cpp
#include "Character.h"

void Character::setChar(char c)
{
  data = c;
}

char Character::getChar() const
{
  return data;
}

int Character::bitCount() const
{
  int cnt = 0;
  int tmp = 1;

  for(int i = 0 ; i < 8 ; ++i)
  {
    if(data & tmp)
    {
      ++cnt;
    }
    tmp <<= 1;
  }
  return cnt;
}

 main.cpp
#include "Character.h"
#include <iostream>
using namespace std;

int main()
{
  char c;

  cout << "문자 입력: ";
  cin >> c;

  Character ch(c);
  cout << "켜진 비트의 개수: " << ch.bitCount() << endl;
  cout << "값: " << (int)ch.getChar() << endl;
  
  return 0;
}


2. 정수 N이 소수입니까?


 Integer.h
#ifndef INTEGER_H
#define INTEGER_H

class Integer
{
public:
  // 생성자
  Integer();
  Integer(int num);

  // 소멸자
  ~Integer();

  // 멤버 함수
  void setNum(int num);
  int getNum() const;
  int sumNum() const;
  bool isPrime() const;  // 소수 여부 확인 해주는 함수

protected:
  int num;
};

#endif

 Integer.cpp
#include "Integer.h"

void Integer::setNum(int num)
{
  this -> num = num;
}

int Integer::getNum() const
{
  return num;
}

int Integer::sumNum() const
{
  int result;
  int tmp = num;

  result = tmp / 100;    // 100자리
  tmp %= 100;
  result = result + (tmp / 10);  // 100자리 + 10자리
  tmp %= 10;
  result += tmp;    // 100자리 + 10자리 + 1자리

  return result; 
}

// 소수 여부 확인 해주는 함수
bool Integer::isPrime() const
{
  int i;

  if(2 == num)
  {
    return true;
  }
  else if(num % 2 == 0)
  {
    return false;
  }

  for(i = 3 ; i <= num ; i += 2)
  {
    if(num % i == 0)
    {
      break;
    }
  }
  if(i == num)
  {
    return true;
  }
  else
  {
    return false;
  }
}

Integer::Integer()
{
  setNum(0);
}

Integer::Integer(int num)
{
  setNum(num);
}

Integer::~Integer()
{

}

 main.cpp
#include "Integer.h"
#include <iostream>
using namespace std;

int main()
{
  int num;

  cout << "정수 입력: ";
  cin >> num;

  Integer i(num);

  if(i.isPrime())
    cout << "결과 : 소수" << endl;
  else
    cout << "결과 : 합성수" << endl;
  
  return 0;
}



3. 로또 번호 생성 프로그램


 Lotto.h
#ifndef LOTTO_H
#define LOTTO_H

class Lotto
{
public:
  // 생성자
  Lotto();

  // 소멸자
  ~Lotto();

  // 멤버 함수
  void createRandom();
  void printNum() const;

protected:
  int num[6];

  bool sameNum(const int *arr, int size, int num) const;

};

#endif

 Lotto.cpp
#include "Lotto.h"
#include <iostream>
#include <stdlib.h>
using namespace std;

bool Lotto::sameNum(const int *arr, int size, int num) const
{
  for(int i = 0 ; i < size ; ++i)
  {
    if(arr[i] == num)
    {
      return 1;
    }
  }
  return 0;
}

void Lotto::createRandom()
{
  int tmp;
  
  for(int i = 0 ; i < 6 ; ++i)
  {
    tmp = (rand() % 45) + 1;
    while(sameNum(num, i + 1, tmp))
    {
      tmp = (rand() % 45) + 1;
    }
    num[i] = tmp;
  }
}

void Lotto::printNum() const
{
  for(int i = 0 ; i < 6 ; ++i)
  {
    cout.width(2);
    cout << num[i] << " ";
  }
  cout << endl;
}

Lotto::Lotto()
{
  createRandom();
}

Lotto::~Lotto()
{

}


 main.cpp
#include "Lotto.h"
#include <iostream>
#include <time.h>
#include <stdlib.h>
using namespace std;

int main()
{
  int cnt;

  srand((unsigned int)time(NULL));

  cout << "Enter the Game count: ";
  cin >> cnt;

  cout << "========================" << endl;
  for(int i = 0 ; i < cnt ; ++i)
  {
    Lotto l;
    l.printNum();  
  }
  cout << "========================" << endl;

  return 0;
}



SRCS    = $(wildcard *.cpp)
CC        = g++
TARGET    = main

all : $(TARGET)

$(TARGET) : $(SRCS:.cpp=.o)
    $(CC) -o $@ $^

clean :
    rm -rf $(SRCS:.cpp=.o)

// 타겟을 main으로 하는 c++ Makefile... 디렉토리 안의 모든 cpp 파일을 컴파일, 링크해서 main 실행 파일을 만들어 준다.



 Rect.h
#ifndef RECT_H
#define RECT_H

#include "Point.h"

class Rect
{
public:
  // 생성자
  Rect();

  // 각 점의 값 지정/얻기
  void SetTopLeft(const Point& topLeft);
  void SetBottomRight(const Point& bottomRight);
  void SetRect(int left, int top, int right, int bottom);
  Point GetTopLeft() const;
  Point GetBottomRight() const;
  void GetRect(int& left, int& top, int& right, int& bottom);

  // 넓이, 높이 계산
  int GetWidth() const;
  int GetHeight() const;

  // 내 용 출력
  void Print() const;

protected:
  Point _topLeft;
  Point _bottomRight;
};

#endif

 Rect.cpp
#include "Rect.h"
#include <iostream>
using namespace std;

Rect::Rect()
{

}

void Rect::SetTopLeft(const Point& topLeft)
{
  _topLeft = topLeft;
}

void Rect::SetBottomRight(const Point& bottomRight)
{
  _bottomRight = bottomRight;
}

void Rect::SetRect(int left, int top, int right, int bottom)
{
  _topLeft.SetX(left); 
  _topLeft.SetY(top); 
  _bottomRight.SetX(right); 
  _bottomRight.SetY(bottom); 
}

Point Rect::GetTopLeft() const
{
  return _topLeft;
}

Point Rect::GetBottomRight() const
{
  return _bottomRight;
}

void Rect::GetRect(int& left, int& top, int& right, int& bottom)
{
  left = _topLeft.GetX(); 
  top = _topLeft.GetY(); 
  right = _bottomRight.GetX(); 
  bottom = _bottomRight.GetY(); 
}

int Rect::GetWidth() const
{
  if(_bottomRight.GetX() > _topLeft.GetX())
  {
    return (_bottomRight.GetX() - _topLeft.GetX() + 1);
  }
  else
  {
    return (_topLeft.GetX() - _bottomRight.GetX() + 1);
  }
}

int Rect::GetHeight() const
{
  if(_bottomRight.GetY() > _topLeft.GetY())
  {
    return (_bottomRight.GetY() - _topLeft.GetY() + 1);
  }
  else
  {
    return (_topLeft.GetY() - _bottomRight.GetY() + 1);
  }
}

void Rect::Print() const
{
  cout << "{L=" << _topLeft.GetX() << ", T=" << _topLeft.GetY();
  cout << ", R=" << _bottomRight.GetX() << ", B=" <<
    _bottomRight.GetY() << "}\n";
}

 main.cpp
#include "Rect.h"
#include <iostream>
using namespace std;

int main()
{
  // Rect 객 체 생성
  Rect rc1;

  // 값을 바 꿔본다.
  rc1.SetRect(101000);

  // 내용 출력
  rc1.Print();
  
  // 넓이, 높이 출력
  cout << "rc1.GetWidth() = " << rc1.GetWidth() << endl;
  cout << "rc1.GetHeight() = " << rc1.GetHeight() << endl;

  // 값을 바꿔본다.
  rc1.SetRect(10102020);

  // 내용 출력
  rc1.Print();

  // 넓이, 높이 출력
  cout << "rc1.GetWidth() = " << rc1.GetWidth() << endl;
  cout << "rc1.GetHeight() = " << rc1.GetHeight() << endl;

  return 0;
}


출처 : http://blog.naver.com/psychoria?Redirect=Log&logNo=40108323175

C++은 메모리 관리를 하기가 상당히 까다로운 언어입니다.

특히 동적 할당과 관련해서는 조금만 실수하면

메모리 누수나, 메모리 접근 위반으로 프로그램이 죽기가 일쑤입니다.

메모리 누수란 프로그램이 종료시까지는 할당한 모든 메모리가해제가 되어야 하는데

할당된 메모리가 해제가 되지 않을 때 발생하는 문제이고,

메모리 접근 위반은 초기화되지 않은 포인터 혹은 동적 할당된 범위 밖을 호출할 때 발생합니다.

초기화되지 않은 포인터는 어떻게 작동할 지 예측을 할 수 없습니다.

(10중 8, 9는 프로그램이 죽는다고 보면 됩니다.)

new 사용 시에 주의할 점은 다음과 같습니다.

new로 할당 시에는 delete로 해제하고, new[]로 할당 시에는 delete[]

해제해줘야 한다는 것입니다.

C++을 공부한 입장에서는 너무도 당연한 이야기겠지만,

사실 신경쓰지 않고 사용했다가 나중에 메모리 누수가 났을 때,

디버깅시에 상당히 오랜 시간을 투자해야할 수도 있기 때문에 꼭 다시 한 번 상기하시기 바랍니다.

Effective C++에서는 다음과 같은 그림을 들어서 new를 delete[]로 해제했을 때나

new[]를 delete로 해제했을 때의 위험성을 설명합니다.


 
한 개를 해제하려고 하는데 갯수를 참조하게 되고,
 
배열을 해제하려고 하는데 크기 정보를 못 가져 오는 상황을 의미하는 거 같습니다.
 
실제 코드를 통해서 알아보도록 하겠습니다.
 
console project에서 확인하기 위해서
 
#define _CRTDBG_MAP_ALLOC

#include <crtdbg.h>
 
를 추가합니다.


 
F5를 눌러서 Debug를 실시해보면
 
delete가 호출되는 시점 이전의 _CrtDumpMemoryLeaks() 함수를 호출할 때
 
출력창에 다음과 같이 표시됩니다.
 

 
Detected memory leaks! 라는 문장이 보이네요.
 
메모리 누수가 생긴것이지요.
 
기본에 충실해야 더 나아갈 수 있는 것 같습니다.

1. 문자가 숫자인지 알려주는 isDigit 함수를 구현하세요. 문자 ch를 입력 받고, ch가 숫자인지 출력하세요. 맞다면 YES, 아니면 NO를 출력합니다.


 character.h
#ifndef CHARACTER_H
#define CHARACTER_H

class Character
{
public:
  // 생성자
  Character();
  Character(char c);

  // 멤버 함수
  void setChar(char c);
  int getChar() const;
  bool isDigit() const;
protected:
  // 멤버 변수
  char ch;
};

#endif

 character.cpp
#include "Character.h"

void Character::setChar(char c)
{
  ch = c;
}

int Character::getChar() const
{
  return ch;
}

bool Character::isDigit() const
{
  if(('0' <= ch) && ('9' >= ch))
  {
    return 1;
  }
  else
  {
    return 0;
  }
}

Character::Character()
{
  ch = 0;
}

Character::Character(char c)
{
  setChar(c);
}

 main.cpp
#include "Character.h"
#include <iostream>
using namespace std;

int main()
{
  char ch;
  
  cout << "문자: ";
  cin >> ch;

  Character c(ch);
  if(c.isDigit())
  {
    cout << "결과: YES" << endl;
  }
  else
  {
    cout << "결과: NO" << endl;
  }
}


2. 정수 N을 입력하면 2 N승을 출력하는 프로그램을 작성하세요. , 비트 연산을 이용합니다.

그리고 -1을 입력할 경우 프로그램은 종료됩니다.


 Multiplier.h
#ifndef MULTIPLIER_H
#define MULTIPLIER_H

class Multiplier
{
public:
  // 생성자
  Multiplier();
  Multiplier(int num);

  // 멤버 함수
  void setNum(int num);
  int getNum() const;
  void twoMulti(int num);
  int getResult() const;
protected:
  int num;  // 승수
  int result;  // 결과
};

#endif

 Multiplier.cpp
#include "Multiplier.h"

void Multiplier::setNum(int num)
{
  this -> num = num;
}

int Multiplier::getNum() const
{
  return num;
}

void Multiplier::twoMulti(int num)
{
  result = 1 << num;  
}

int Multiplier::getResult() const
{
  return result;
}

Multiplier::Multiplier()
{
  num = 0;
  result = 0;
}

Multiplier::Multiplier(int num)
{
  setNum(num);
  twoMulti(num);
}

 main.cpp
#include "Multiplier.h"
#include <iostream>
using namespace std;

int main()
{
  int num;

  while(1)
  {
    cout << "입력: ";
    cin >> num;

    if(num == -1)
    {
      return -1;
    }

    Multiplier m(num);

    cout << "출력: 2 ^ " << m.getNum() << = " << m.getResult() <<endl;
  }

  return 0;
}

+ Recent posts