외로운 Nova의 작업실

c# 언어 공부 - 2(산술연산자, 코드흐름제어, 메소드) 본문

Programming/C#

c# 언어 공부 - 2(산술연산자, 코드흐름제어, 메소드)

Nova_ 2022. 4. 30. 19:49

안녕하세요. 오늘은 저번시간에 이어 c#에 대해서 좀 더 자세하게 알아보겠습니다.

해당 문서는 c언어를 마스터하신분들에게 적합함으로 만약 c언어를 모르신다면 c언어부터 공부하시면 되겠습니다.

특히 c언어랑 많이 비교하면서 공부해보도록 하겠습니다.

먼저 연산자는 다들 아실테니 정리만 간단한게 해보겠습니다.

 

<연산자>

산술연산자 +, -, *, /, %
증가/감소 연산자 ++, --
관계연산자 <, >, ==, !=, <=, >=
조건연산자 ? :
null 조건부 연산자 ?., ?[]
논리연산자 &&, ||, !
비트연산자 >>, <<, &, |, ^, ~
할당연산자 =. +=, -=, /=, %=, &=, |=, ^=, <<=, >>=
null병합 연산자 ??

c#은 c언어와 다르게 null을 중요시 여깁니다.

보통의 자료형에도 null을 넣을 수 없게 되어있습니다.

저번시간에 배웟던대로 int i = null은 불가하고 int? i = null이 가능한게 예입니다.

 

c언어에서 보지못한 null조건부 연산자와 null병합 연산자에대해서 알아보도록 하겠습니다.

 

<null조건부 연산자>

using System;

namespace StudyCSharp
{
    class MainApp
    {

        static void Main(string[] args)
        {
            Foo foo = null;

            int? bar;

            bar = foo?.member; //foo가 null이라면 null을 반환하고 아니라면 foo의 member반환

            Console.WriteLine($"{bar}");
        }

    }

    class Foo
    {
        public int member = 3;
    }
}

위의 코드의 주석대로 해당 클래스나 변수가 null이라면 null을 반환하고 아니라면 .뒤에있는 속성을 반환합니다.

 

<null 병합 연산자>

using System;

namespace StudyCSharp
{
    class MainApp
    {

        static void Main(string[] args)
        {
            int? a = null;
            Console.WriteLine($"{a ?? 0}"); //a변수가 null이면 0을출력

            a = 3;

            Console.WriteLine($"{a ?? 0}"); //a변수가 null이 아니면 a출력
        }

    }
}

위의 코드대로 사용하고 a 변수가 null이면 ??뒤에 상수를 반환하고 null이 아니라면 a를 반환합니다.

 

<코드흐름제어>

코드 흐름을 제어하는 구문은 분기문과 반복문이 있습니다.

먼저 c#의 분기문먼저 살펴보겠습니다.

c#의 분기문은 if문, ifelse문, switch문이있습니다.

if문과 ifelse문은 c언어와 동일하지만 switch문은 c언어와 동일하고 특별히 추가된게있습니다.

바로 objcet 자료형때문입니다.

object 자료형을 사용하는 switch문에서는 데이터형식으로 분기하게됩니다.

using System;

namespace StudyCSharp
{
    class MainApp
    {

        static void Main(string[] args)
        {
            object obj = 345;

            switch (obj)
            {
                case int i:
                    Console.WriteLine("int 형식입니다.");
                    break;
                case float f:
                    Console.WriteLine("float 형식입니다.");
                    break;
            }
        }

    }
}

따라서 위 코드의 결과는 int형식입니다. 라고 출력됩니다.

더 나아가서 switch 식에대해서 알아보겠습니다.

switch 식은 switch구문으로 알맞는 값을 어떠한 변수에 넣는 식을 말합니다.

아래와 같은 구문으로 사용됩니다.

using System;

namespace StudyCSharp
{
    class MainApp
    {

        static void Main(string[] args)
        {
            string grade = "";
            int i = 70;

            grade = i switch // i 를 i의 값에따라 grade에 값을 넣는다.
            {
                90 => "a",
                70 => "b"
            };

            Console.WriteLine($"{grade}");
        }

    }
}

일반적인 switch 구문으로도 구현가능하지만 switch식을 이용하면 더욱 간결하게 사용할 수 있습니다.

 

이제 c#의 반복문에대해서 알아보겠습니다.

반복문에는 while문, do while문, for문, foreach문이 있습니다.

while문, do while문, for문은 c언어와 같게 사용됩니다.

c#에서 추가된 foreach문에대해서 알아보겠습니다.

using System;

namespace StudyCSharp
{
    class MainApp
    {

        static void Main(string[] args)
        {
            int[] arr = new int[] { 0, 1, 2, 3, 4 };

            foreach(int a in arr)//arr 배열에서 첫번째부터 하나씩 a에 할당하여 아래 블록을 수행함
            {
                Console.WriteLine($"{a}");
            }
        }

    }
}

위의 실행결과는 0, 1, 2, 3, 4가 출력됩니다.

주석과 함께 코드를 이해하시면 되겠습니다.

 

반복문에는 점프문이 같이 사용됩니다.

c#에서 점프문은 break문, continue문, goto문 return문, throw문이 사용됩니다.

break문과 continue문은 c언어와 같습니다.

return문과 throw문은 다음에 천천히 설명하기로합시다.

그렇다면 남은 goto문을 알아봅시다.

goto문은 레이블을 이용하여 사용됩니다.

using System;

namespace StudyCSharp
{
    class MainApp
    {

        static void Main(string[] args)
        {
            Console.WriteLine("1");

            goto JUMP; //jump레이블로 이동

            Console.WriteLine("2");
            Console.WriteLine("3");

            JUMP:   //jump레이블
            Console.WriteLine("4");
        }

    }
}

 

우와같이 JUMP라는 레이블을 이용하여 사용됩니다.

하지만 goto문을 너무 남발하면 코드흐름이 복잡해지므로 대체로 잘 안씁니다.

단, 중첩된 반복문을 나갈때 사용이됩니다.

 

<메소드>

객체지향프로그래밍에서는 프로그램을 하나의 실체화된 모듈로써 보게됩니다.

예를들어 프린터기같은 모듈로 예를들어보겠습니다.

프린터기 클래스안에는 복사해주는 기능과 컴퓨터의 화면을 프린트해주는 기능이 있습니다.

이러한 기능을 c#에서는 메소드라고 부릅니다.

using System;

namespace StudyCSharp
{
    class MainApp
    {

        static void Main(string[] args)
        {
            int sum = Calculator.Plus(3, 4);//계산기 모듈에서 plus기능을 가져와서 사용함

            Console.WriteLine($"{sum}");
        }

    }

    class Calculator//계산기 모듈
    {
        public static int Plus(int a, int b)//plus기능
        {
            int result = a + b;
            
            return result;
        }
    }
}

메소드 선언 방법은 c언어에서 함수 선언 방법과 비슷합니다.

사용방법도 비슷합니다.

단, c#에는 로컬함수라는게 있습니다.

메소드안의 함수들은 다 로컬함수로 불리게됩니다.

클래스안에 있는 함수는 메소드, 메소드 안에있는 함수는 로컬 함수라고 부릅니다.

 

<값에의한 참조에의한 매개변수 전달>

c언어에서도 함수에는 값의 의한 매개변수전달과 참조에의한 매개변수 전달이있습니다.

c#도 똑같이 있습니다. 다만 c언어와 다르게 포인터가 없고 ref키워드를 사용하여 구현합니다.

using System;

namespace StudyCSharp
{
    class MainApp
    {

        static void Main(string[] args)
        {
            int A = 3;
            int B = 4;

            ChangeValue.Change(A, B); //A와B의 값을 변경한다.

            Console.WriteLine($"{A}, {B}");
        }

    }

    class ChangeValue
    {
        public static void Change(int a, int b)
        {
            int temp;

            temp = a;
            a = b;
            b = temp;
            
            return;
        }
    }
}

위의 결과는 아래와 같습니다.

즉, A는3 B는4로 값이 변하지 않았습니다.

값에의한 매개변수 전달이기때문입니다.

주소를 넘기지 않고 값을 복사해서 따로 저장해두고 사용하는 것입니다.

주소를 넘기는 참조에 의한 매개변수 전달은 아래와 같은 코드로 구현됩니다.

using System;

namespace StudyCSharp
{
    class MainApp
    {

        static void Main(string[] args)
        {
            int A = 3;
            int B = 4;

            ChangeValue.Change(ref A, ref B); //A의 주소값고 B의 주소값을 넘긴다.

            Console.WriteLine($"{A}, {B}");
        }

    }

    class ChangeValue
    {
        public static void Change(ref int a, ref int b) //메소드 선언도 ref 키워드를 사용합니다. 주소 a와b를 받는다.
        {
            int temp;

            temp = a; //a주소에 있는 값을 temp에 복사
            a = b; //b주소에 있는 값을 a에 복사
            b = temp; //temp의 값을 b의 주소에 복사
            
            return;
        }
    }
}

위코드의 결과는 아래와 같습니다.

참조에 의한 매개변수 전달이 잘 된것을 확인 할 수 있습니다.

 

또 c#에는 출력전용 매개변수라는 것이 있습니다.

먼저 코드부터 봅시다.

using System;

namespace StudyCSharp
{
    class MainApp
    {

        static void Main(string[] args)
        {
            int A = 3;
            int B = 4;
            int C = 0;

            Calculator.Plus(A, B, ref C);

            Console.WriteLine($"{C}");
        }

    }

    class Calculator
    {
        public static void Plus(int a, int b, ref int c) 
        {
            c = a + b;
            
            return;
        }
    }
}

위와 같은 코드에서 c의 주소에 a+b의 값이 들어갑니다.

하지만 c의 주소에 있는 값을 변경하지 않아도 컴파일러는 에러를 내지않습니다.

하지만 out키워드를 사용하면 컴파일러는 에러를 냅니다.

out키워드는 아래와 같이 사용됩니다.

using System;

namespace StudyCSharp
{
    class MainApp
    {

        static void Main(string[] args)
        {
            int A = 3;
            int B = 4;
            int C = 0;

            Calculator.Plus(A, B, out C);

            Console.WriteLine($"{C}");
        }

    }

    class Calculator
    {
        public static void Plus(int a, int b, out int c) 
        {
            c = a + b;
            
            return;
        }
    }
}

ref 대신 out을 써주면 됩니다.

 

<메소드 오버로딩>

c# 메소드의 이름은 한가지인데 여러개의 기능을 할 수 있습니다.

이를 메소드 오버로딩이라고합니다.

먼저 코드를 봐봅시다.

using System;

namespace StudyCSharp
{
    class MainApp
    {

        static void Main(string[] args)
        {
            double A = 3.1121354;
            double B = 4.245648;

            var sum = Calculator.Plus(A, B); // A, B의 자료형에따라 알맞게 기능을 해줌

            Console.WriteLine($"{sum}");
        }

    }

    class Calculator
    {
        public static int Plus(int a, int b) //둘다 int형일때
        {
            
            return a + b;
        }
        public static double Plus(double a, double b) //둘다 double형 일때
        {
            return a + b;
        }
    }
}

위와 같이 똑같은 Plus이름의 메소드지만 다른 기능을 수행합니다.

c#의 컴파일러는 메소드를 호출하면 여러개의 메소드중 매개변수의 자료형에 맞는 메소드를 선택하여 실행합니다.

굉장히 좋은 기능입니다!

 

<가변 개수 인수>

메소드는 인수를 여러개 가질 수 있습니다.

c#에서는 인수의 개수와 상관없이 유한적이면 실행 할 수 있는 메소드를 param 키워드로 만들 수 있습니다.

먼저 코드부터 봅시다.

using System;

namespace StudyCSharp
{
    class MainApp
    {

        static void Main(string[] args)
        {
            int A = 3;
            int B = 4;

            var sum = Calculator.Plus(A, B, 6, 9, 10);

            Console.WriteLine($"{sum}");
        }

    }

    class Calculator
    {
        public static int Plus(params int[] args) //파라미터를 배열 args에 하나씩 담겠다
        {
            int sum = 0;

            for(int i = 0; i < args.Length; i++) //args배열의 크기 만큼 실행
            {
                sum += args[i]; //args에 담겨있는 파라미터들을 하나씩 더해줌
            }

            return sum;
        }
        
    }
}

위의 실행결과는 32입니다.

 

<명명된 인수>

함수에 인수가 너무 많게되면 뭐가 뭔지 잘 모르는 경우가 많습니다.

그래서 c#에서는 메소드에 명명된 인수를 지원해줍니다.

인수를 넣을때 이게 뭔지 한눈에 볼수 있게 말입니다.

코드를 먼저 보겠습니다.

using System;

namespace StudyCSharp
{
    class MainApp
    {

        static void Main(string[] args)
        {
            int A = 3;
            int B = 4;

            var sum = Calculator.Plus(second : B, first : A);

            Console.WriteLine($"{sum}");
        }

    }

    class Calculator
    {
        public static int Plus(int first, int second) 
        {

            return first + second;
        }
        
    }
}

이렇게 어느 매개변수에 어떤 값을 넣을지 직접 정할 수있습니다.

해당 코드의 결과는 7입니다.

 

<선택적 인수>

함수의 매개변수에 기본값을 정해야할때도 있습니다.

c#에서는 이를 손쉽게 구현 할 수 있습니다.

먼저 코드먼저 봅시다.

using System;

namespace StudyCSharp
{
    class MainApp
    {

        static void Main(string[] args)
        {
            int A = 3;
            int B = 4;

            var sum = Calculator.Plus(A); //3만 전달함

            Console.WriteLine($"{sum}");
        }

    }

    class Calculator
    {
        public static int Plus(int first, int second = 4) //second 매개변수 기본값은 4로 설정
        {

            return first + second;
        }
        
    }
}

plus 메소드의 매개변수로 A만 전달해도 출력값은 7입니다.

 

이로써 오늘의 공부는 마치도록 하겠습니다.

다음 시간에는 클래스에대해서 좀더 자세하게 알아보도록 하겠습니다.

Comments