반응형

메모리 초기화 함수

memset( void * _Dst,

            int _Val,

            size_t _Size );

연속된 메모리 초기화 함수, _Dst 시작되는 메모리 주소를 넣어주고, _Size sizeof(자료형*) * 개수 만큼 _Val 값으로 모두 초기화 해준다, for 대신에 사용할 있다.

 

 

 

메모리 복사 함수

memcpy( void* destination,

            void* source,

            size_t num );

 

memmove( void* destination,

               void* source,

               size_t num );

함수 모두 메모리의 일부분을 복사하여 가리키는 위치에 붙여넣는다, source 가리키는 곳부터 num 바이트 만큼을 destination 가리키는 곳에 복사한다. 또한 source '\0' 종료 문자(null terminating character) 검사하지 않는다. 언제나 정확히 num 바이트 만큼을 복사한다.

 

두함수의 차이는

memcpy 메모리의 내용을 직접 copy 하고, memmove copy 메모리의 내용을 임시 버퍼에 저장한 copy 한다, 그렇기 때문에 memcpy memory overlap 현상이 일어날 있고, memmove 그렇지 않지만

memcpy 비해 속도가 떨어진다

속도는 memcpy 좋고, 안정성은 memmove 좋다 하지만 2019 기준으로 memmove 속도가 memcopy 많이 따라잡아서 memmove 사용을 권장하는편이다

 

오버 플로우 문제를 방지하기 위해 destination source 가리키는 배열의 크기는 반드시 num 바이트 이상이어야 하며, 서로 겹치면 안된다.(만일 메모리 블록이 겹쳐져 있다면  memmove 함수를 이용하는것이 좋다)

반응형

'C' 카테고리의 다른 글

expression(표현식)  (0) 2020.03.12
Local Variable, Global Variable, Static Variable  (0) 2020.02.28
fseek, ftell, 파일 크기 알아내기  (0) 2020.02.25
FileStream Input Output  (0) 2020.02.22
반응형

Reference Variable

(c++11, L-value reference)

L-value, 기존 메모리 공간(변수) 대한 별명을 만들어 변수처럼 쓴다,

별명만 붙이는 것이기 때문에, 메모리 주소는 동일한 공간을 쓴다

Reference(참조)라는 뜻에서 있듯이, 어떤 변수를 참조하게 만들어 준다

typedef 다르다(typedef 자료형에 별명을 주는것)

 

선언법

 

자료형& 레퍼런스식별자 = 변수;

 

 

pass by reference 할때 포인터 대신에 사용할 있다,

하지만 포인터와는 다르다, 구지 포인터를 Reference Variable 비슷하게 쓴다면

 

자료형 * const ptr = &변수;

비슷한 모양이다, 선언시에 정해진, 가리키고 있는 변수의 주소를 수정 없다

그러나 포인터는 주소가 가리키는 값에 접근하기 위해 indirection operator(역참조)* 사용하지만

Reference Variable 역참조를 없다,

 

int main()

{

    int a = 8;

    int &a_ref = a; // 포인터와 다르게 &a 대입하지 않음

 

    std::cout << a_ref << std::endl; // 결과는 8 나옴

    return 0;

}

 

R-value Reference

(c++11)

c++11 부터 move semantic 개념이 도입되면서, 기존 refernce variable

L-value refernce, R-value reference 나뉘게 되었다

 

선언법
 

자료형&& 레퍼런스식별자 = R-value;

 

 

비교 연산자(&&)와는 아무 관련 없음

R-value 대입할 있다, 식별자가 없는 값들만 대입 있다.

 

R-value, 즉 곧 사라지는 값, 식별자가 없는 값만 대입 할 수 있다.

 

 

R-value reference parameter

 

 

이때 20번라인 doSomething L-value 인자로 받고

21번라인 doSomething R-value 인자로 받았다

반응형
반응형

C언어, C++11이전까지의 L-value, R-value

 

L-value : locator value, 저장 장소 위치의 값, 할당 연산자 기준으로 왼쪽에 오는 값

R-value : value of an expression, 수식의 값, 할당 연산자 기준으로 오른쪽에 오는 값

 

 

 

C++11 이후

출처: https://docs.microsoft.com/ko-kr/cpp/cpp/lvalues-and-rvalues-visual-cpp?view=vs-2019

glvalue, xvalue, prvalue 개념이 새로 생겼다 일단 

 

 

L-value와 R-value 부터 정리하면

 

 

위 코드에서 left_value, right_value, result 는 모두 L-value 로서 식별자(변수이름)를 가지고 다른 데이터를 복사해서 자신의 상태(값)를 변경 할 수 있다.

3, 7, 0 은 모두 R-value 이다.

R-value는 다른 데이터의 메모리를 복사할 공간이 없거나, 식별자가 따로 존재하지 않기 때문에 대입이 불가능하다.

또한 3,7,0 은 식별자가 따로 존재 하지 않기 때문에, 따로 변수처럼 접근 할 수 없어, 일시적인 값, 사라지는 값이라고 할 수 있다

 

 

L-value는 Locator value, 존재하는 메모리를 식별할 수 있는지의 여부, 즉 식별자가 있어야 하고, 식별자를 가지고 다른 값을 복사 받을 수 있으면 L-value 라고 할 수 있다.

그러나 배열타입, 불완전한타입, const 타입은 Lvalue 로 올 수 없다

 

R-value는 value of an expression, 즉 수식을 계산한 후의 값이다, 위에서 left_value + right_value 는

수식 (left_value의 값) + (right_value의 값)의 결과 값 10 이 되고

10( left_value + right_value 의 결과 값 )은 식별자가 존재 하지 않기 때문에 R-value인 것이다 

 

 

 

이제  glvalue, xvalue, prvalue 를 파헤쳐 보면

크게 식별자의 유무에 따라서 나눌 수 있고

식별자 있음 : glvalue( xvalue, lvalue)

식별자 없음 : prvalue

 

move의 가능 여부 에 따라서 나눌 수 있다

move 가능 : rvalue(xvalue, prvalue)

move 불가능 : lvalue

 

여기서 move의 가능이란, move semantics 가 가능하다 또는 값이 메모리에서 이동 될 수 있는것을 말한다.

 

 

위 MSDN 정리 그림을 https://docs.microsoft.com/ko-kr/cpp/cpp/lvalues-and-rvalues-visual-cpp?view=vs-2019

다시 표시하면

이렇게 볼 수 있다

 

 

lvalue : identity 가짐, move 없는 표현식들

 

 

xvalue : identity 가짐, move 있는 표현식들

 

 

prvalue : identity 안가짐, move 있는 표현식들

 

 

glvalue : identity 가지고 있는 표현식들(lvalue, xvalue)

 

 

rvalue : move 있는 표현식들(prvalue,xvalue)

반응형
반응형

expression(표현식)

프로그램 언어에서 값을 나타내기 위해서, 변수나 상수, 연산자로 구성된식, 표현식은 항상 결과(반환)값을 갖음

  1. 일차식
  2. 상수
  3. 괄호식
  4. 전위연산자 수식
  5. 후위연산자 수식
  6. 단항식
  7. 이항식
  8. 삼항식
  9. 할당 수식

 

 

1. 일차식

  • 식별자,변수이름(identifier)

    • iNum, fLength, INT_MAX 등등

    • 연산자(operator) 없이 오직하나의 피연산자(operand) 이루어진 가장 기본적인 형태

 

2. 상수(Constants)

    • 5, 3.14, 'A', "HelloWorld" 등등

 

3. 괄호식(Parenthetical Expression)

    • (2*3)+4, (a = 23+b*) 등등

 

4. 전위 연산자 수식

  • 연산자(operator)가 피연산자(operand) 앞에 오는 형태

  • x = ++a;

    1. a = a+ 1; // a 값에 + 1 값을 a 대입한다
    2. x = a // x a 값을 대입한다,
    3. ++a a 1증가한 이후의 값이다, 변수의 참조보다 먼저 연산을 수행

 

5. 후위 연산자 수식

  • 연산자(operator)가 피연산자(operand) 뒤에 오는 형태

  • x = a++;

    1. x = a // x a 값을 대입한다
    2. a = a + 1 // a 값에 +1 값을 a 대입한다.
    3. a++ a 1증가하기 이전의 값이다, 변수의 참조 후에 연산을 수행

※전위연산자, 후위연산자는 오직 변수만 피연산자로 가능

상수나 일반 수식을 피연산자로 사용 불가능

int a = ++10; // 상수에는 불가능

(a+1)--; // 일반 수식 에도 불가능

 

 

6. 단항식(Unary epxression)

  • 피연산자(operand)즉 연산자에 적용되는 항이 한 개 있는 표현식(expression)

  1. 전위, 후위 증감 연산자 : ++a, --a, a++, a--

  2. sizeof

  3. 부호 연산자 : +a, -a

    • 여기서 산술연산자와 부호연산자가 같다고 생각할 있지만, 다르다, 산술연산자는 연산자가 피연산자 사이에 올때만 가능하다, 1+a, 2-a, a*b, a/b, a%b

  4. 형변환(casting) 연산자, (자료형)변수 : (float) iNum

  5. 주소 연산자(&) : &iNum

  6. 역참조 연산자 *  : *ptr_iNum;

 

7. 이항식(Binary expression)

  • 연산자가 피연산자 사이에 있음
  1. 산술연산자 : a + 7 , 3 + 4, b - 11, 5%2
  2. 논리 연산자 : !, &&, ||, &, |, <, >, <=, >=, ^

 

8. 삼항식(Ternary expression)

  • a ? B : C
  • 조건식 A 참이면 B 아니면 C

    • int result = a > 3 ? 1 : 0; // a 3보다 크면 1 result 대입, 아니면 0 result 대입

       

       

 

9. 할당수식(Assignment expression)

  • a = 7

  • 우측의 값을 좌측의 저장장소에 저장 하라는 의미
  • 할당 연산자를 기준으로 좌측은 Lvalue 라고 하고 우측을 Rvalue 라고 한다
  • Lvalue는 또다른 명칭으로 locator value이며 저장 장소를 뜻한다,
  • Rvalue는 evaluated value, value of an expression 즉 수식의 결과 값이다

 

반응형

'C' 카테고리의 다른 글

memset, memcpy, memmove  (0) 2020.03.13
Local Variable, Global Variable, Static Variable  (0) 2020.02.28
fseek, ftell, 파일 크기 알아내기  (0) 2020.02.25
FileStream Input Output  (0) 2020.02.22
반응형

C++ Inheritance (상속) _ 다형성, 업캐스팅, 다운캐스팅

 

다형성(Polymorphism)

  • 생물학에서 유래한 단어, 사전적 의미로 동일한 종에 속하는 생물이라 할지라도 다양한 변이를 가지는 현상을 말함, 즉 여러개의 형태를 갖는다는 것,
  • OOP의 특징중 하나

 

C++ 에서 다형성을 가능하게 해주는 요소들

  1. 상속 관계에서 상위 클래스 또는 하위 클래스로 형변환(up casting, down casting)
  2. 메소드 오버라이딩, 가상함수
  3. 순수 가상 함수
  4. 함수 오버로딩
  5. 연산자 오버로딩

 

상속 관계에서 상위 클래스 또는 하위 클래스로 형변환

  • Up casting : 상속관계에서  하위 클래스가 상위클래스로 형변환 하는 것
  • Down casting : 상속관계에서 업캐스팅했던 상위 클래스 인스턴스가 하위클래스로 형변환 하는 것 

 

Up casting 방법

상위클래스* 클래스이름 = new 하위클래스; 

 

이때 하위클래스 와 상위클래스의 접근 권한이 아래와 같이

 

class 하위클래스 : public 상위클래스

{

}

 

public 으로 되있어야 한다.

 

 

 

 

Down casting 방법

하위클래스* 클래스이름 = (하위클래스*)업캐스팅된상위클래스변수;

 

 

 

 

ex1)

동물

  ↑

고양이

실행결과

40번라인에 있는 animal은 Animal 이 아닌 Cat을 할당 받았고 sound()를 호출해보면 ??? 가 뜬다 즉 하위 클래스를 할당 했더라도, 상위클래스 처럼 쓸 수 있는것이다, 이렇게 상위 클래스의 자료형에 하위 클래스를 할당하는 것을 업캐스팅 이라고 한다,

 

41번 라인은 Down casting 이다, 상위 클래스처럼 쓰이고 있는 하위클래스를 본래의 자료형에 맞게 할당하는것 이때 상위 클래스에서 하위클래스로 형변환 할때는 명시적 형변환이 필요하다, 그뒤 sound()를 호출해보면 Cat::Sound() 함수 정의대로 Mero~ 를 호출 하는것을 볼 수 있다.

 

 

주의점

이러한 형변환 성질을 이용해 여러 객체들을 상속관계로 디자인하고 최상위 클래스들로 Upcasting 한뒤, 객체들을 한꺼번에 하나의 배열에 두고 관리 할 수도 있다, 즉 한번에 for문 하나로 delete 할수도 있게 된다, 그러나 Upcasting 상태에서 delete 하게 되면, 하위클래스의 소멸자는 호출되지 않는다. 

 

 

업캐스팅 한뒤 delete 하게되면 상위 클래스 소멸자만 호출된다.

위 문제를 해결 하기위해서 즉, 하위클래스의 소멸자까지 호출해주게 하기 위해서는 다시 다운캐스팅을 한뒤 delete 해야 한다.

 

 

위처럼, down casting을 하여, delete 해주면 되긴하다, 그러나 만약 상속계층이 cat에서 끝나지 않고 하위클래스가 더 존재한다면?, 그리고 그중에 본래의 하위클래스 형태를 추적하기 힘들다면? 아래와 같은 상황을 보자

 

 

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include <iostream>
 
class Animal
{
public:
    Animal()
    {
        std::cout << "Animal 생성자" << std::endl;
    }
 
    ~Animal()
    {
        std::cout << "Animal 소멸자" << std::endl;
 
    }
};
 
class Cat :public Animal
{
 
 
public:
    Cat()
    {
        std::cout << "Cat 생성자" << std::endl;
    }
 
    ~Cat()
    {
        std::cout << "Cat 소멸자" << std::endl;
    }
};
 
 
class SuperCat :public Cat
{
 
 
public:
    SuperCat()
    {
        std::cout << "SuperCat 생성자" << std::endl;
    }
 
    ~SuperCat()
    {
        std::cout << "SuperCat 소멸자" << std::endl;
    }
};
 
class MegaCat :public SuperCat
{
 
 
public:
    MegaCat()
    {
        std::cout << "MegaCat 생성자" << std::endl;
    }
 
    ~MegaCat()
    {
        std::cout << "MegaCat 소멸자" << std::endl;
    }
};
 
 
class SpecialCat :public MegaCat
{
 
 
public:
    SpecialCat()
    {
        std::cout << "SpecialCat 생성자" << std::endl;
    }
 
    ~SpecialCat()
    {
        std::cout << "SpecialCat 소멸자" << std::endl;
    }
};
 
 
 
int main()
{
    Animal* superCat = new SuperCat;
    std::cout << std::endl;
    Animal* superCat_2 = new SuperCat;
    std::cout << std::endl;
    Animal* megaCat = new MegaCat;
    std::cout << std::endl;
    Animal* cat = new Cat;
    std::cout << std::endl;
 
    Animal* animalArr[4= { superCat,superCat_2,megaCat,cat };
 
    for (int i = 0; i < 4; i++)
    {
        delete animalArr[i];
    }
 
 
 
    return 0;
}
cs

실행 결과

예상대로 상위클래스 소멸자만 호출됐다

특히나 위와같이 배열에 담고서 관리할 경우 원래 형태가 어떤 것이었는지 추적하기 어렵다, 이때 한가지 방법이 존재하는데, 가상함수 라는 것이다, 가상함수는 따로 다시 정리하겠지만 여기서는 최상위 클래스의 소멸자에 virtual 이라는 키워드만 붙여주면 된다

 

virtual 키워드는 가상함수를 정의할 때 쓰인다

오직 최상위 클래스 소멸자 앞에 virtual 만 붙였을 뿐인데, 아래와 같은 결과가 나온다

정상적으로 소멸자가 모두 호출된것을 볼 수 있다.

 

즉 최상위 클래스의 소멸자는 가상함수로 만드는게 좋다

 

 

 

정리

  • 상위클래스와 하위클래스간에는 형변환이 가능한데, 이를 Up Casting, Down Casting 이라한다
  • Up Casting 하면 하위 클래스를 상위 클래스처럼 사용 가능하다
  • 어떤 객체들을 최상위 클래스로 Upcasting 하면 하나의 배열로 관리하기 용이하다 그러나 최상위 클래스의 소멸자는 가상함수로 만들어 소멸자가 원활하게 호출되게 해야한다.

 

반응형
반응형

C# Inheritance(상속)

대상:

클래스

 

목적:

클래스의 재사용-> 코드량 줄이기

 

상속 클래스의 역할

부모클래스 : 상속을 하는 클래스

(parent class, base class, 상위 클래스)

 

자식 클래스 : 상속을 받는 클래스

(child class, derived class, 파생 클래스)

 

 

 

 

 

 

상속 관계 표시 형식

class Parent

{

}

 

class Child : Parent

{

}

Parent class

  

Child class

 

상속 관계 표시는 화살표로 하며, 화살 정방향이 부모를 가리키고, 역방향은 자식을 향한다

 

 

 

 

 

 

 

상위 클래스 접근 지정자

class Parent

{

private //Child 에서 접근 불가

protected //Child 접근 가능

public //Child Main 같은 외부에서도 접근 가능

}

 

class Child : Parent

{

}

 

 

 

ex1)

 

using System;

 

namespace Inheritance

{

    class A

    {

        private void PrintPrivate()

        {

            Console.WriteLine("private");

        }

 

        protected void PrintProtected()

        {

            Console.WriteLine("protected");

        }

 

        public void PrintPublic()

        {

            Console.WriteLine("public");

        }

    }

 

    class B : A

    {

        public void Print()

        {

            //PrintPrivate(); //접근 불가능

            PrintProtected();

            PrintPublic();

        }

    }

 

 

    class Program

    {

        static void Main(string[] args)

        {

            B Test = new B();

            Test.Print();

            Test.PrintPublic();

        }

    }

}

 

 

 

 

상속 관계에서 생성자, 소멸자 호출 순서

  • 생성자 호출 : 상위 -> 하위

 

  • 소멸자 호출 : 하위 -> 상위

 

 

 

ex2)

 

using System;

 

namespace Inheritance

{

    class A

    {

        public A()

        {

            Console.WriteLine("A 생성자");

        }

        ~A()

        {

            Console.WriteLine("A 소멸자");

 

        }

 

        private void PrintPrivate()

        {

            Console.WriteLine("private");

        }

    }

 

    class B : A

    {

        public B()

        {

            Console.WriteLine("B 생성자");

        }

 

        ~B()

        {

            Console.WriteLine("B 소멸자");

 

        }

    }

 

    class Program

    {

        static void Main(string[] args)

        {

            B test = new B();

        }

    }

}

 

코드 실행 결과

생성자는 Base생성자 -> Derived 생성자 순, 소멸자는 Derieved 소멸자 -> Base 소멸자 순이다 

 

 

생성자 호출 순서

 

 

소멸자 호출 순서

 

반응형
반응형

C++ Inheritance(상속)

  • 어떤 클래스가 다른 클래스와 기반(base) 파생(derived) 관계를 가질때, 파생클래스 에서는 기반클래스의 필드(멤버변수)   메소드(멤버함수) 들을 사용할 있다.
  • 하지만 기반 클래스의 private 변수,함수 들은, 파생클래스에서도 접근이 불가능하다, protected, public 가능하다, 반면에 friend 키워드를 쓰면 가능하긴하다(friend 상속에 관계없이, 모든 변수, 함수에 접근할 있도록 접근 허용 권한을 주는것)

 

 

 

상속 관계 짓는 방법

클래스를 디자인할때, 콜론(:) 넣고 뒤에 접근제어자와 다른 클래스의 이름 붙이면 된다

 

ex1)

 

파생클래스 : 외부접근권한 기반클래스

class MyClassB : public MyClassA

 

 

이때 외부 접근권한을 public, private 정해 있는데

public 경우 클래스 외부에서도 기반 클래스의 public 변수, 함수들에 접근할 있게 되고

private 경우 파생클래스만 기반 클래스의 public 변수 함수들에 접근할 있다

 

 

ex2)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
class CParent
{
public:
    CParent()
        :m_iA(0),m_iB(0),m_iC(0)
    {
        std::cout << "CParent 생성자" << std::endl;
    }
    
    ~CParent()
    {
        std::cout << "CParent 소멸자" << std::endl;
    }
public:
    int        m_iA;
 
protected:
    int        m_iB;
 
private:
    int        m_iC;
 
public:
    void Output()
    {
        std::cout << "A : " << m_iA << std::endl;
        std::cout << "B : " << m_iB << std::endl;
        std::cout << "C : " << m_iC << std::endl;
    }
};
 
class CChild : public CParent
{
public:
    CChild()
        :m_iD(0)
    {
        m_iB = 200;
        // m_iC는 private 이기 때문에 자식 내부에서도 접근이 불가능 하다
        //m_iC = 300; // error
        std::cout << "CChild 생성자" << std::endl;
    }
 
    ~CChild()
    {
        std::cout << "CChild 소멸자" << std::endl;
    }
 
protected:
    int        m_iD;
};
 
class  CChild1 : private CParent
{
public:
    CChild1()
        :m_iD(0)
    {
        m_iA = 100;
        m_iB = 200;
        std::cout << "CChild1 생성자" << std::endl;
 
    }
 
    ~CChild1()
    {
        std::cout << "CChild1 소멸자" << std::endl;
    }
 
private:
    int        m_iD;
};
 
class CChildChild : public CChild
{
public:
    CChildChild()
        :m_iE(0)
    {
        m_iD = 500;
        std::cout << "CChildChild 생성자" << std::endl;
    }
 
    ~CChildChild()
    {
        std::cout << "CChildChild 소멸자" << std::endl;
 
    }
 
private:
    int        m_iE;
};
 
 
int main(void)
{
    /*
    상속 관계에서의 생성자 호출 순서 : 부모 -> 자식 순으로 호출됨
    상속관계에서의 소멸자 호출 순서 : 자식 -> 부모 순으로 호출됨
    */
    CParent            parent;
    std::cout << std::endl;
    CChild            child;
    std::cout << std::endl;
    CChild1            child1;
    std::cout << std::endl;
    CChildChild        childchild;
    std::cout << std::endl;
 
    parent.m_iA = 100;
 
    child.m_iA = 200;
 
    // CChild1 클래스는 CParent를 private 상속을 하고 있으므로 CParent에 
    // Public으로 설정되어있는 멤버들도 외부에서는 접근이 불가능하다.
    //child1.m_iA = 300;
    //child1.Output();
 
 
    return 0;
}
cs

실행화면

 

정리

  1. 상속관계에서 파생 클래스는 기반 클래스의 생성자를 먼저 호출한뒤 그 다음에 파생 클래스의 생성자를 호출한다 
  2. 소멸자는 생성자의 역순으로 호출된다, 즉 파생클래스 소멸자 -> 기반 클래스 소멸자 순으로 호출 된다
  3. 파생클래스 : public 기반클래스 -> 외부에서도 기반 클래스의 public 변수및 함수 접근 가능,                             
  4. 파생클래스 : private 기반클래스 -> 외부에서 기반클래스의 모든 변수 및 함수 접근 불가능
  5. protected 접근 제어자는 파생클래스가 기반클래스의 변수 또는 함수에 접근할 수 있도록 해준다
반응형
반응형

- Life(하트) 기능 추가

- 스테이지 이동

- 리팩토링 : stage 객체 수정, 더 이상 stage 객체에서 player 상태 변경 하지 않음, player 또한 stage 객체의 블록을 직접 수정하지 않고 get, set 메소드를 사용

 

반응형

'develop-note > MarioGame' 카테고리의 다른 글

MarioGame 스크롤 버그  (0) 2020.03.05
MarioGame UML  (0) 2020.03.03
반응형

주의_1 while문 안에 switch를 사용할 때 

while문안에 if 문에서 break 하면 그뒤에 코드들은 거치지 않는다, 즉 if문은 원하는 지점에서 while문을 탈출 시킬 수 있다

위와 같이 while 안에 if 문을 써서 조건을 만족하면 break 문을 사용하여 while 문을 탈출 시킬수 있다

 

그런데 조건문중에 switch 문이 존재하고, while문과 switch 문을 아래와 같이 사용하면

while 안에 switch 안에 break 는 while 문을 탈출 시키지 못한다

break 문이 있다 치더라도, while문을 빠져나오지 못한다, 이유는 switch 안에 break문의 용도는

다음 케이스 문을 거치지 않고, switch문을 중단 시키는 용도 뿐이지, while문을 빠져나오진 못한다

 

해결책

빠져나오게 하고 싶다면, switch 문을 가장 마지막에 두고, switch 문의 case 만족할때

while문의 조건을 두고 있는 bool 변수를 false 시키는 것이다, 그러나, while 문안에 if, break 처럼

원하는 부분에서 중단 시킬 없다

 

switch를 가장 마지막에 두고 while 조건을 false로 바꾸면 가능하긴 하다 그러나 if 문처럼 원하는 지점에서 바로 탈출할 수 없다.

 

 

 

또는 return 문을 써서 switch 문도 while 문을 원하는 지점에서 바로 탈출 할 수 있기는 하지만 그와 동시에 전체 함수가 종료 된다.

 

반응형
반응형

EX02 HEAP CORRUPTION DETECTED

동적 할당을 하는 프로그램을 만들던 도중, free() 함수를 실행할때 에러 발생

 

원인:

Google 찾아보니, 할당한 영역을 벗어나서 접근하게 될경우 발생하는 에러 라고

 

 

 

 

/*Decoding        */

FileStreamInit(&fileStream, fileName, "r"); //파일크기에 따른 g_CodeSize 초기화

 

if (g_CodeSize == 0)

{

     printf("\nError, No data in codefile, zero codeSize\n");

     exit(1);

}

 

g_Buffer = (char*)calloc(g_CodeSize, sizeof(char));

fread_s(g_Buffer, g_CodeSize, sizeof(char), g_CodeSize, fileStream);

decode(g_Buffer, g_CodeSize);

 

아래 decode 함수에서  str[i] != '\0' 원인 이었음

i size 만큼만 i++ 해야 되는데, 범위를 넘어서 버린듯

 

 

 

해결:

void decode(char* str,size_t size)

{

     size_t i = 0;

     while( i < size )

     {

            str[i] -= 3;

            i++;

     }

}

 

결론: 파일 안에서 글자 수에 따른 범위를 정할때는 index < size 방식이 제일 안전함

반응형

+ Recent posts