참조값과 변수값 변경
두 배열(참조형 데이터)을 서로 바꿀 경우
int[] num1 = { 1, 2, 3 };
int[] num2 = { 4, 2, 3 };
int[] tmp;
tmp = num1;
num1 = num2;
num2 = tmp;
스택 메모리에 들어있는 각 변수의 ref 값만 바뀌고 힙 메모리에 있는 값은 변경되지 않는다.
출력 전용 변수
// 출력 키워드로 매게 변수를 출력 전용 변수로 사용하는 함수
// 매개 변수에 out 키워드를 이용하여 매개 변수를 출력 전용으로 바꾼다.
// 출력 전용 매개 변수로 선언된 변수에는 반드시 값을 저장해야한다.
// 문법
// 한정자 반환형 함수명(out 출력전용매개변수자료형 출력전용매개변수명, ....)
// 대신 ref 키워드를 사용할 수도 있지만, 출력 전용인 경우에 코드의 명시성을 위해서 사용한다.
static float GetArverageToArrayOutcount(int[] arr, out int count)
{
float average = 0;
count = 0;
for(int i = 0; i < arr.Length; i++, count++)
{
average += arr[i];
}
average /= count;
return average;
}
static void main()
{
int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int count;
float average = GetArverageToArrayOutcount(arr, out count);
Console.WriteLine("총 {0}개 값의 평균은 {1}입니다", count, average);
Console.ReadKey();
}
[과제1] int.TryParse 함수
int.TryParse 함수를 이용하여 ReadLine으로 받은 string이 숫자인지 확인하고
숫자면 out 변수를 통해 변환된 값을 return하고,
숫자가 아니면 다시 입력받아 int.TryParse로 확인하는 것을 반복하는 함수를 만드시오.
답안
/// <summary>
/// ReadLine으로 string을 받아 해당 string이 int.TryParse를 통해 int로 변환이 가능하면 변환한 숫자를 return하고 아니면 메시지와 함께 다시 입력받는 함수
/// </summary>
/// <param name="text">입력을 받기 전 보여줄 메시지, 뒤에 " : "이 붙는다.</param>
/// <returns>int로 변환된 입력값</returns>
static int ReadInt(string text)
{
string input;
int result;
while (true)
{
Console.Write(text + " : ");
input = Console.ReadLine();
if (int.TryParse(input, out result))
{
//Console.WriteLine("숫자를 입력하셨습니다.");
break;
}
else
{
Console.WriteLine("숫자를 입력해주세요.");
}
}
return result;
}
static void main()
{
#region [과제1]
int num;
num = ReadInt("숫자를 입력하세요.");
Console.WriteLine($"숫자 [{num}]을(를) 입력하였습니다.");
#endregion [과제1]
}
함수 오버로딩
함수 오버로딩은 하나의 함수명으로 매개변수에 따라 다른 동작을 하는 함수를 만드는 것이다.
///
#region [함수 오버 로딩]
static void myRead(string text, out float input)
{
while (true)
{
Console.Write(text + " : ");
if (float.TryParse(Console.ReadLine(), out input))
{
break;
}
else
{
Console.WriteLine("실수형 숫자가 아닙니다.");
}
}
}
같은 이름의 함수지만 매개변수가 다르므로 오버로딩되어 사용할 때 매개 변수에 따라 다르게 동작한다.
매개변수 초기화 (혹은 default 값 설정)
매개 변수 초기화는 매개 변수에 값을미리 넣어줌으로서 함수를 좀 더 편하게 이용할 수 있게 하는 기능이다.
매개 변수 초기화 문법
한정자 반환형 함수명(...., 매개변수 자료형 매개변수 = 디폴트값)
초기화된 매개변수 뒤에 오는 매개변수 또한 초기화가 필요하다
void test(int param1, int param2 = 0, int param3) (X) void test(int param1, int param2 = 0, int param3 = 0) (X)
오버로딩 시 초기화된 매개변수를 사용할 경우 어느 함수가 실행되는지 알 수 없으므로 명시적으로 표기해서 실행해야함
예를 들어
void test(int a){ }
void test(int a, int b = 1){ } 일때
test(1)을 실행하면 첫번쨰 test(1)이 실행될지 test(1, 1)이 실행될지 애매해짐 따라서 이 경우 두번째를 실행하려면 초기화 되어 있더라도 test(1,1)로 실행해 명시적으로 알 수 있게 해줘야함
#region [매개변수 초기화]
/// <summary>
/// 끝 정수값과 시작 정수값을 받아 두 정수와 그 사이 값을 출력하는 변수
/// </summary>
/// <param name="endNum">끝나는 값</param>
/// <param name="startNum">시작하는 값, 입력 안할 시 1로 자동 설정됨</param>
static void PrintInOrderTo(int endNum, int startNum = 1)
{
string ouput = "";
for(int n = startNum; n <= endNum; n++)
{
ouput = $"{n}, ";
}
Console.WriteLine(ouput.TrimEnd(' ').TrimEnd(','));
}
#endregion
static void main()
{
#region [매개변수 초기화]
PrintInOrderTo(21);
Console.WriteLine("=================");
PrintInOrderTo(84, 61);
#endregion [매개변수 초기화]
}
매개변수 초기화는 함수를 사용할 때 특정 값이 매개변수에 자주 입력될 것이라 예상되는 경우에 사용한다
[과제 2]
배열을 외부에서 받아 지정된 방법으로 배열 값을 재정렬 하는 함수를 만드시오.
지정된 방법은 오름차순 혹은 내림차순 있으며 지정하지 않으면 기본적으로 오름차순을 사용하도록 사용한다.
(단, 배열의 원본 값이 수정되어서는 안되며 정렬된 배열을 반환해야 한다.)
결과화면 예시
[원본 배열 자료]
배열명[0] = ##
....배열명 [n] = ##
(내림차순시)
답안 (Array.Copy() 와 Array.Sort()에 대해서는 따로 알아볼 것)
enum sortType { asc = 0, desc = 1, MAX }
static int[] SortArray(int[] array, sortType sortType = sortType.asc)
{
int[] copyArray = new int[array.Length];
Array.Copy(array, copyArray, array.Length);
Array.Sort(copyArray);
if (sortType == sortType.asc)
{
// do nothing...
}
else if(sortType == sortType.desc)
{
Array.Reverse(copyArray);
}
return copyArray;
}
static void main()
{
int[] myArr = { 29, 1, 42, 7, 111, 17, 99, 8, 57, 13, 731, 47, 11, 144000 };
// foreach 는 for 비슷한 반복문인데 지금은 알 필요 없음 그냥 배열 내 요소 전부 한번씩 돌려주는 반복문인것만 알고 있을 것
foreach(int num in sortArray(myArr))
{
Console.Write(num + " ");
}
Console.WriteLine();
Console.WriteLine("==============");
foreach (int num in sortArray(myArr, sortType.desc))
{
Console.Write(num + " ");
}
}
가변길이 매개변수
가변길이 매개변수는 매개변수의 개수가 유연하게 변할 수 있는 매개변수를 말한다.
이 매개변수는 params 키워드를 통해 사용해서 만든다.
가변 길이 매개변수 문법
한정자 반환형 함수명(params 매개변수자료형 매개변수명, ....)
static int sumInt(out int count, params int[] numbers)
{
count = 0;
int total = 0;
foreach (int number in numbers)
{
total += number;
count++;
}
return total;
}
static void main()
{
int count;
int total = sumInt(out count, 34, 54, 1, 23, 456, 7);
Console.WriteLine("total = {0}, count = {1}", total, count);
total = sumInt(out count, 75, 3, 6);
Console.WriteLine("total = {0}, count = {1}", total, count);
}
재귀함수
함수가 가진 명령어 중 자기 자신을 호출하는 명령어를 가진 함수를 뜻한다.
재귀 함수는 반복문과 유사하지만 반복문과 달리 무한 반복으로 인해 메모리 스택 오버 플로우 오류가 날 수 있으니 주의가 필요하다.
재귀함수 예제
static void showStart(int count)
{
if (count <= 0)
{
Console.WriteLine();
return;
}
Console.Write("*");
showStart(count - 1);
}
[과제3]
몇 라인을 출력하시겠습니까? : 4
[과제4]
(과제 3에서 만든 함수에 플래그로 기능 추가하기)
몇 라인을 출력하시겠습니까? : 4
**
정답
static void showStarTower(int count, showStartFlag flag = showStartFlag.asc)
{
if (count <= 0)
{
return;
}
if (flag == showStartFlag.asc)
{
showStarTower(count - 1, flag);
showStart(count);
}
else if(flag == showStartFlag.desc)
{
showStart(count);
showStarTower(count - 1, flag);
}
else
{
Console.WriteLine("잘못된 플래그 값입니다.");
}
}
자기 자신을 호출하는 위치만 바뀌었음에도 결과가 크게 바뀌었음에 주의
static void showStart(int count)
{
if (count <= 0)
{
Console.WriteLine();
return;
}
Console.Write('*');
showStart(count - 1);
}
[과제5] 주차 정상 함수
주차 시간과 출차 시간을 입력받아 얼마의 비용이 발생했는지 계산해 반환하는 함수를 만드시오.
(주차비용은 10분당 500원이지만 함수 외부에서 변경할 수 있습니다. 10분 미만의 시간은 반올림 처리 합니다. (15분은 20분으로 계산)
입차 시각 (시) :
입차 시각 (분) :
출차 시각(시) :
출차 시각(분) :
주차 시간은 반올림 처리하여 ###분입니다.
주차 요금은 ##,###원입니다.
정답
static int myRead(string text, int min, int max)
{
string input;
int result;
while (true)
{
Console.Write(text + " : ");
if (int.TryParse(input = Console.ReadLine(), out result))
{
if (result < min)
{
Console.WriteLine($"{min}보다 큰 값만 입력할 수 있습니다.");
continue;
}
else if (result > max)
{
Console.WriteLine($"{max}보다 작은 값만 입력할 수 있습니다.");
continue;
}
break;
}
else
{
Console.WriteLine($"{min} ~ {max} 사이의 숫자를 입력해주세요.");
}
}
return result;
}
static int GetParkingCharge( int startHour,
int startMin,
int endHour,
int endMin,
out int parkingMin,
out int parkingMinRounded,
int chargePer10Min = 500
)
{
parkingMin = 0;
startMin = startHour * 60 + startMin;
endMin = endHour * 60 + endMin;
if(endMin < startMin)
{
parkingMin = 24 * 60;
}
parkingMin += endMin - startMin;
parkingMinRounded = (int)Math.Round((double)parkingMin);
return parkingMinRounded * chargePer10Min;
}
구조체
구조체 본격적 입문 전 Main 함수 안쪽에 Readkey()를 넣는 방식을 변경함
Program 클래스에 아래와 같은 함수(메소드) 추가
public static void system(string commend)
{
if(commend.CompareTo("pause") == 0)
{
Console.Write("계속하시려면 아무키나 누르세요...");
Console.ReadKey();
}
else
{
Console.WriteLine("존재하지 않는 명령어입니다...");
System.Threading.Thread.Sleep(5000);
}
}
이후 Main 함수 안쪽 최하단에 아래 구문 추가
system("pause");
구조체란?
구조체란 사용자가 변수들을 사용하여 새로운 구조의 자료형을 만드는 자료형이다.
다시 말해, 구조체 를 사용하기 위해서는 만드는 과정 후에 사용해야한다.
구조체는 복합 자료형이다.
구조체를 만들때는 struct 키워드를 사용한다
문법
한정자 struct 구조체 이름
{
필드's;
함수's
}
사용 시 아래와 같이 선언한다.
구조체이름 변수명;
구조체는 여러 단위의 자료를 모아서 정보 집합체를 만드는데에 쓰인다.
class와 비슷하나 수명이 짥고 간단한 경우에 struct 를 사용하는게 PC 리소스 관리에 좋다
public struct myScore
{
public int _kor;
public int _eng;
public int _mat;
public float _average;
public void initScore(int k, int e, int m)
{
_kor = k;
_eng = e;
_mat = m;
_average = (k + e + m) / 3f;
}
}
internal class Program
{
static void Main(string[] args)
{
myScore man1 = new myScore();
//man1._kor = 70;
//man1._eng = 24;
//man1._mat = 96;
//man1._average = (man1._kor + man1._eng + man1._mat) / 3f;
man1.initScore(70, 24, 96);
system("pause");
}
public static void system(string commend)
{
if(commend.CompareTo("pause") == 0)
{
Console.Write("계속하시려면 아무키나 누르세요...");
Console.ReadKey();
}
else
{
Console.WriteLine("존재하지 않는 명령어입니다...");
System.Threading.Thread.Sleep(5000);
}
}
public static void myRead(string text, out int input)
{
string readLine;
int result;
while (true)
{
Console.Write(text + " : ");
readLine = Console.ReadLine();
if (int.TryParse(readLine, out result))
{
//Console.WriteLine("숫자를 입력하셨습니다. 계속 진행합니다.");
break;
}
else
{
Console.WriteLine("숫자가 아닙니다. 숫자를 입력해주세요.");
}
}
input = result;
}
public static void myRead(string text, out float input)
{
while (true)
{
Console.Write(text + " : ");
if (float.TryParse(Console.ReadLine(), out input))
{
break;
}
else
{
Console.WriteLine("실수형 숫자가 아닙니다.");
}
}
}
}