const
키워드를 이용해 선언 : const
데이터형식
식별자(이름)
= 값
var a = 3; // a는 int 형식
var b = "Hello"; // b는 string 형식
복합 데이터 형식(Complex Data Type)
- 기본 데이터 형식을 부품으로 삼아 구성 (이미지나 소리 등의 데이터)
- 종류 : 구조체, 클래스, 배열 등
데이터를 담는 일정 크기의 메모리 공간
변수 선언
데이터 형식
식별자(변수의 이름)
;
의 형태로 컴파일러에게 선언→ 컴파일러는 int형식을 위해 메모리 공간을 할당하고 이 공간을 x라는 식별자가 사용할 수 있도록 준비
선언된 변수 x에 대입 연산자를 통해 데이터 입력!→ 이 코드가 실행되고 나면 x를 위해 할당된 메모리 공간에 데이터 100이 기록됨
어떤 변수는 태어나는 시점부터 특정한 값을 갖고 있어야 하는 경우가 있는데 이런 경우 선언과 데이터 할당을 동시에 할 수 있다.
// 선언과 데이터 할당을 별도로 하는 경우
int x;
x = 100;
// 선언과 초기화를 한번에 하는 경우
int x = 100;
// 변수 여러 개를 동시에 선언하는 경우
int a, b, c; // 단, 동시에 선언하는 변수들은 데이터 형식이 같아야함
int x=30, y=40, z=50; // 선언과 초기화를 여러 개 하는 것도 가능
- 초기화(Initialization)
- 변수에 최초의 데이터를 할당하는 것
- C, C++에서 변수 선언 후 데이터를 입력하지 않을 경우 쓰레기 데이터가 들어가 소프트웨어가 엉뚱하게 동작하는 문제를 미연에 방지하기 위해 C#은 초기화를 강제한다.
- C#은 초기화되지 않은 변수를 사용하면 컴파일러가 에러 메시지를 내면서 실행 파일을 만들어주지 않는다.
- 리터럴(Literal)
- 고정값을 나타내는 표기법
int a = 100; // 변수 a, 리터럴 : 100 int b = 0x200; // 변수 b, 리터럴 : 0x200 float c = 3.14f; // 변수 c, 리터럴 : 3.14f double d = 0.12345678; // 변수 d, 리터럴 : 0.12345678 string s = "가나다라마바사"; // 변수 e, 리터럴 : "가나다라마바사"
두 형식은 변수의 값, 데이터를 스택에 넣느냐 힙에 넣느냐에 따라 다르다.
스택 : 변수의 생명 주기가 다 하면 자동으로 데이터 제거
힙 : 데이터를 참
값 형식(Value Types)
{
실행 후 코드 순서대로 값 형식의 변수가 스택에 쌓였다가 블록을 닫는 괄호 }
를 만나면 모든 값 형식의 변수들은 역순으로 메모리에서 제거된다.{ // 코드 블록 시작
int a = 100;
int a = 200;
int a = 300;
} // 코드 블록 끝
참조 형식(Reference Types)
{
object a = 10; // 스택에 a가 저장된 힙 메모리 주소 저장
object b = 20; // 스택에 b가 저장된 힙 메모리 주소 저장
} // 스택에 쌓인 a와 b 사라짐
가비지 컬렉션과 참조 카운트
프로그래밍 언어의 종류는 다음의 두 가지가 있다.
- unmanaged 언어 : 메모리를 프로그래머가 직접 관리 (C/C++)
- managed 언어 : 언어단에서 관리 (C#, Java)
대부분의 매니지드 언어에선 자동으로 메모리 관리를 하기 위해 다음 중 하나의 기법을 사용한다.- Garbage collection (가비지 컬렉션 또는 쓰레기 수집)
- Reference counting (레퍼런스 카운팅 또는 참조 횟수)
가비지 컬렉션의 경우 힙에 할당된 메모리 중 이를 가리키는 포인터 또는 참조 변수(스택의 지역변수)가 사라지면(지역변수가 속한 함수를 빠져나가면 스택 메모리의 지역변수는 정리된다.) 이로 인해 메모리 누수 문제(=쓰레기 메모리)가 발생하게 되어 가비지 컬렉터는 이를 방지하기 위해 사용되지 않는 힙 메모리를 추적해 해제해준다.
정수 데이터를 담기 위해 사용
12가지의 숫자 데이터 형식 중 9가지 해당
예제 프로그램
/* IntegralTypes */
using System;
namespace IntegralTypes
{
class MainApp
{
static void Main(string[] args)
{
sbyte a = -10;
byte b = 40;
Console.WriteLine($"a={a}, b={b}");
short c = -30000;
ushort d = 60000;
Console.WriteLine($"c={c}, d={d}");
int e = -1000_0000; // 0이 7개 , 자릿수 구분자(_) 사용
uint f = 3_0000_0000; // 0이 8개
Console.WriteLine($"e={e}, f={f}");
long g = -5000_0000_0000; // 0이 11개
ulong h = 200_0000_0000_0000_0000; // 0이 18개
Console.WriteLine($"g={g}, h={h}");
}
}
}
바이트(byte)
- 컴퓨터가 데이터를 다루는 기본 단위
- 요즘 거의 모든 컴퓨터는
8 비트(bit) = 1바이트(byte)
로 취급1바이트(byte)
: 8개의 0과 1로 구성되는 데이터 덩어리129(10진수) = 1000 0001(2진수)
- 비트가 아닌 바이트를 사용하는 이유
: 대부분의 데이터 크기가 바이트 이상이므로 비트 단위로 잘게 나눠서 처리(밥알을 하나씩 젓가락으로 집어 먹는 것)하기 보다 한번에 처리(숟가락으로 밥을 잔뜩 퍼서 입에 떠 넣는 것)하는 것이 더 효율적이므로
비타민 퀴즈
sbyte a = -5000_0000_0000;
sbyte 코드 부분을 위와 같이 수정 후 컴파일하면 아래와 같은 error가 뜸
0b
(숫자 0과 알파벳 b)0X or 0x
/* IntegralLiterals */
using System;
namespace IntegralLiterals
{
class MainApp
{
static void Main(string[] args)
{
byte a = 240; // 10진수 리터럴
Console.WriteLine($"a={a}");
byte b = 0b1111_0000; // 2진수 리터럴
Console.WriteLine($"b={b}");
byte c = 0XF0; // 16진수 리터럴
Console.WriteLine($"c={c}");
uint d = 0x1234_abcd; // 16진수 리터럴
Console.WriteLine($"d={d}");
}
}
}
부호 : 음(-), 양(+)
컴퓨터가 음수를 표현하는 방법, 2의 보수법(2's Complement)
컴퓨터 시스템에서는 음수를 표현하기 위해 첫 번째 비트를 부호를 표현하는 데 사용하며 이를 부호 비트(Sign Bit)라고 한다. (부호 비트가 0일 때는 양수, 1일 때는 음수)
부호와 절댓값(Sign-and-magnitude) 방식은 부호 비트를 순수하게 음과 양을 나타내는 데 사용하고 나머지 비트도 순수하게 수를 나타내는 데만 사용하여 수를 나타내는 방식인데 이는 0의 표현이 +0(0000 0000)
과 -0(0000 0000)
두 가지가 존재한다는 문제가 발생해 이것 대신 2의 보수법(2's Complement)이라는 알고리즘을 채택해 음수를 표현한다.
2의 보수법을 통한 음수 표현 방법
1) 먼저 수 부분 비트를 채운다
2) 전체 비트를 반전시킨다
3) 반전된 비트에 1을 더한다
/* SignedUnsigned */
using System;
namespace SignedUnsigned
{
class MainApp
{
static void Main(string[] args)
{
byte a = 255; // 1111 1111 (byte 형식)
sbyte b = (sbyte)a; // (sbyte) : sbyte 형식으로 변환하는 연산자
Console.WriteLine(a);
Console.WriteLine(b);
}
}
}
// byte에서 1111 1111은 255
// sbyte에서 1111 1111은 -1
오버플로 : 변수에 데이터 형식의 크기를 넘어선 값을 담으면 넘치는 현상
/* Overflow */
using System;
namespace Overflow
{
class MainApp
{
static void Main(string[] args)
{
uint a = uint.MaxValue; // uint의 최대값
Console.WriteLine(a); // 4294967295
a = a + 1; // uint의 최대값 + 1
Console.WriteLine(a); // 0
}
}
}
비타민 퀴즈
Overflow 예제에서 uint를 int로 바꾸어 코드를 실행시키면 나오는 결과using System; namespace Overflow { class MainApp { static void Main(string[] args) { int a = int.MaxValue; Console.WriteLine(a); a = a + 1; Console.WriteLine(a); } } }
=> int값의 가장 최저값으로 바뀜 = 0이 되므로 그 데이터 형식의 값의 범위 중 가장 작은 값이 되는 것
정수 계열 형식
소수점이 고정되어 있지 않고 움직이면서 수를 표현한다는 뜻
부동 소수점 형식이 정수 형식을 대체하지 못하는 이유
float, double
IEEE754라는 표준 알고리즘에 기반한 데이터 형식
/* FloatingPoint */
using System;
namespace FloatingPoint
{
class MainApp
{
static void Main(string[] args)
{
float a = 3.1415_9265_3589_7932_3846f;
Console.WriteLine(a); // 3.1415927
double b = 3.1415_9265_3589_7932_3846;
Console.WriteLine(b); // 3.141592653589793
}
}
}
정밀도
decimal
실수를 다루는 데이터 형식
부동 소수점과는 다른 방식으로 소수를 다루며 정밀도가 훨씬 높다
/* Decimal */
using System;
namespace Decimal
{
class MainApp
{
static void Main(string[] args)
{
float a = 3.1415_9265_3589_7932_3846_2643_3832_79f; // f : float
double b = 3.1415_9265_3589_7932_3846_2643_3832_79; // 아무것도 없으면 : double
decimal c = 3.1415_9265_3589_7932_3846_2643_3832_79m; // m : decimal
Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);
}
}
}
decimal 형식도 표현 범위의 한계가 있다.
정밀도는 float
< double
< decimal
순으로 높다.
char
: 개별 문자 표현, 작은 따옴표('
)로 표시string
: 문자열 표현, 큰 따옴표("
)로 표시/* Char */
using System;
namespace Char
{
class MainApp
{
static void Main(string[] args)
{
char a = '안';
char b = '녕';
char c = '하';
char d = '세';
char e = '요';
Console.Write(a); // Console.Write() : 데이터 출력 후 줄바꿈 X
Console.Write(b);
Console.Write(c);
Console.Write(d);
Console.Write(e);
Console.WriteLine(); // Console.Write() : 데이터 출력 후 줄바꿈 O
}
}
}
/* String */
using System;
namespace String
{
class MainApp
{
static void Main(string[] args)
{
string a = "안녕하세요?";
string b = "박상현입니다.";
Console.WriteLine(a);
Console.WriteLine(b);
}
}
}
데이터 형식 | 설명 | 크기(바이트) | 범위 |
---|---|---|---|
bool | 논리 형식 | 1(8비트) | true, false |
/* Bool */
using System;
namespace Bool
{
class MainApp
{
static void Main(string[] args)
{
bool a = true;
bool b = false;
Console.WriteLine(a);
Console.WriteLine(b);
}
}
}
/* Object */
using System;
namespace Object
{
class Program
{
static void Main(string[] args)
{
object a = 123;
object b = 3.141592653589793238462643383279m;
object c = true;
object d = "안녕하세요.";
Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);
Console.WriteLine(d);
}
}
}
object a = 20;
object a = 20; // a는 20이 박싱되어 저장된 힙 참조
int b = (int)a; // b는 a가 참조하고 있는 메모리로부터 값 복사
/* BoxingUnboxing */
using System;
namespace BoxingUnboxing
{
class MainApp
{
static void Main(string[] args)
{
int a = 123;
object b = (object)a; // a의 담긴 값을 박싱해서 힙에 저장
int c = (int)b; // b에 담긴 값을 언박싱해서 스택에 저장
Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);
double x = 3.1414213;
object y = x; // x에 담긴 값을 박싱해서 힙에 저장
double z = (double)y; // y에 담긴 값을 언박싱해서 스택에 저장
Console.WriteLine(x);
Console.WriteLine(y);
Console.WriteLine(z);
}
}
}
변수를 다른 데이터 형식의 변수에 옮겨 담는 것
using System;
namespace IntegralConversion
{
class MainApp
{
static void Main(string[] args)
{
sbyte a = 127;
Console.WriteLine(a);
int b = (int)a;
Console.WriteLine(b);
int x = 128; // sbyte의 최대값 127보다 1 큰 수
Console.WriteLine(x);
sbyte y = (sbyte)x; // 오버플로 발생
Console.WriteLine(y);
}
}
}
using System;
namespace FloatConversion
{
class MainApp
{
static void Main(string[] args)
{
float a = 69.6875f;
Console.WriteLine("a : {0}", a);
double b = (double)a;
Console.WriteLine("b : {0}", b);
Console.WriteLine("69.6875 == b : {0}", 69.6875 == b);
float x = 0.1f;
Console.WriteLine("x : {0}", x);
double y = (double)x;
Console.WriteLine("y : {0}", y);
Console.WriteLine("0.1 == y : {0}", 0.1 == y);
}
}
}
위 코드 결과에서 69.6875와 0.1의 결과가 다른 이유
2진 배수의 끝자리는 손실이 적다.
1 2 4 8 이나
0.5 0.25 0.125 0.0625 는 손실이 없다.
부동소수는 큰 값이 될수록 오차가 커진다.
float의 경우 2^23 부터 소수를 표현할 수 없게된다.
0.1은 2진으로 볼때
1 / 2^n을 해서 떨어지지 않는다.
때문에 실제로는 float에 0.100000001490116119384765625 로 저장되고 float은 오차를 감안하여 이 값을 0.1에 아주 근접한(자기가 표현하기에) 값으로 표현하게 된다.
그러나 이를 double로 변환했을때 기존 오차 값이 그대로 남게되고, double 입장에선 이 오차값은 아주아주 큰 오차값이므로 실제 값이라 판단해 출력값은 0.1보다는 조금 크거나 작은 값이 실제로 출력되는 것이다.
0.100000001490116119384765625는 float이 보기에 오차가 거의 없는 완벽히 0.1로 인식될 수 있는 값이지만 double이 볼땐 1.490116119e-9 만큼의 오차가 있는것으로 보고 그 결과가 반영되는 것이다.
using System;
namespace SignedUnsignedConversion
{
class MainApp
{
static void Main(string[] args)
{
int a = 500;
Console.WriteLine(a);
uint b = (uint)a;
Console.WriteLine(b);
int x = -30;
Console.WriteLine(x);
uint y = (uint)x; // 언더플로우
Console.WriteLine(y);
}
}
}
using System;
namespace FloatToIntegral
{
class MainApp
{
static void Main(string[] args)
{
float a = 0.9f;
int b = (int)a;
Console.WriteLine(b);
float c = 1.1f;
int d = (int)c;
Console.WriteLine(d);
}
}
}
Parse()
: 문자열 → 숫자int a = int.Parse("12345");
float b = float.Parse("123.45");
ToString()
: 숫자 → 문자열 int c = 12345;
string d = c.ToString();
float e = 123.45;
string f = e.ToString();
using System;
namespace StringNumberConversion
{
class MainApp
{
static void Main(string[] args)
{
int a = 123;
string b = a.ToString();
Console.WriteLine(b);
float c = 3.14f;
string d = c.ToString();
Console.WriteLine(d);
string e = "123456";
int f = Convert.ToInt32(e);
Console.WriteLine(f);
string g = "1.2345";
float h = float.Parse(g);
Console.WriteLine(h);
}
}
}
프로그래머의 실수로 인한 프로그래머의 버그를 줄이기 위해 담긴 데이터를 절대 바꿀 수 없는 상수와 열거 형식을 사용
const 자료형 상수명 = 값;
using System;
namespace Constant
{
class MainApp
{
static void Main(string[] args)
{
const int MAX_INT = 2147483647;
const int MIN_INT = -2147483648;
Console.WriteLine(MAX_INT);
Console.WriteLine(MIN_INT);
}
}
}
상수의 값을 바꾸려고 할 경우 : 컴파일러가 에러 메시지 출력
여러 개의 상수 정리
선언 형식
enum 열거 형식명 : 기반자료형 { 상수1, 상수2, 상수3, ··· }
// 기반자료형은 정수 계열만 사용할 수 있다. (byte, sbyte, short, ushort, int, uint, long, ulong, char)
// default : int
열거 형식의 각 요소는 기본적으로 컴파일러에서 값을 자동으로 할당받는다. (0부터 선언된 순서에 따라 1씩 증가된 값을 컴파일러가 자동으로 할당)
using System;
namespace Enum
{
class MainApp
{
enum DialogResult { YES, NO, CANCEL, CONFIRM, OK }
static void Main(string[] args)
{
Console.WriteLine((int)DialogResult.YES);
Console.WriteLine((int)DialogResult.NO);
Console.WriteLine((int)DialogResult.CANCEL);
Console.WriteLine((int)DialogResult.CONFIRM);
Console.WriteLine((int)DialogResult.OK);
}
}
}
열거 형식의 변수를 선언하여 값을 대입하는 예
using System;
namespace Enum2
{
class MainApp
{
enum DialogResult { YES, NO, CANCEL, CONFIRM, OK }
static void Main(string[] args)
{
DialogResult result = DialogResult.YES;
Console.WriteLine(result == DialogResult.YES);
Console.WriteLine(result == DialogResult.NO);
Console.WriteLine(result == DialogResult.CANCEL);
Console.WriteLine(result == DialogResult.CONFIRM);
Console.WriteLine(result == DialogResult.OK);
}
}
}
enum 열거형식명 { 상수1 = 값1 + 상수2 = 값2, 상수3 = 값3, ···}
using System;
namespace Enum3
{
class MainApp
{
enum DialogResult { YES = 10, NO, CANCEL, CONFIRM = 50, OK }
static void Main(string[] args)
{
Console.WriteLine((int)DialogResult.YES);
Console.WriteLine((int)DialogResult.NO); // 컴파일러 : 자동으로 앞 요소 +1
Console.WriteLine((int)DialogResult.CANCEL);
Console.WriteLine((int)DialogResult.CONFIRM);
Console.WriteLine((int)DialogResult.OK);
}
}
}
C# 컴파일러는 메모리 공간에 반드시 어떤 값이든 넣어야 에러를 발생시키지 않는다.
어떤 값도 가지지 않는 변수가 필요할 때는 변수에게 할당된 메모리 공간을 비워둘 수 있도록 Nullable 형식을 사용한다.
데이터형식? 변수이름;
속성
HasValue
: 해당 변수가 값을 갖고 있는지 or 그렇지 않은지Value
: 변수에 담겨 있는 값int? a = null;
Console.WriteLine(a.HasValue); // a는 null이므로 False 출력
a = 37;
Console.WriteLine(a.HasValue); // a는 37을 갖고 있으므로 True 출력
Console.WriteLine(a.Value); // 37 출력
/* Nullable */
using System;
namespace Nullalble
{
class MainApp
{
static void Main(string[] args)
{
int? a = null;
Console.WriteLine(a.HasValue);
Console.WriteLine(a != null);
a = 3;
Console.WriteLine(a.HasValue);
Console.WriteLine(a != null);
Console.WriteLine(a.Value);
}
}
}
var a = 3; // a는 int형식
var b = "Hello"; // b는 string형식
using System;
namespace UsingVar
{
class MainApp
{
static void Main(string[] args)
{
var a = 20; // var로 선언하는 변수는 반드시 선언과 동시에 초기화
Console.WriteLine("Type:{0}, Value: {1}", a.GetType(), a);
var b = 3.1414213;
Console.WriteLine("Type: {0}, Value: {1}, b.GetType(), b);
var c = "Hello, World!";
Console.WriteLine("Type: {0}, Value: {1}", c.GetType(), c);
var d = new int[] {10, 20 30};
Console.Write("Type: {0}, Value: ", d.GetType());
foreach (var e in d)
Console.Write("{0} ", e);
Console.WriteLine();
}
}
}
object vs var
object a = 20;
위 코드가 실행되면 CLR은 20을 박싱해 힙에 넣어놓고 a가 힙을 가리키도록 만듦
var a =20;
컴파일 시점에 컴파일러가 a에 적합한 데이터 형식을 파악해
int a =20;
으로 바꿔 컴파일. CLR이 해당 코드를 실행할 때는 a가 var로 선언되었는지조차 눈치채지 못하고 int형식의 객체 a에 20을 담아 스택에 올리는 것.
using System;
namespace CTS
{
class MainApp
{
static void Main(string[] args)
{
System.Int32 a = 123; // int
int b = 456;
// GetType() : 해당 객체의 실제 형식 표시
// ToString() : 변수의 데이터를 문자열로 표시
Console.WriteLine("a type:{0}, value:{1}", a.GetType().ToString(), a);
Console.WriteLine("b type:{0}, value:{1}", b.GetType().ToString(), b);
System.String c = "abc"; // string
string d = "def";
Console.WriteLine("c type:{0}, value:{1}", c.GetType().ToString(), c);
Console.WriteLine("d type:{0}, value:{1}", d.GetType().ToString(), d);
}
}
}
using static System.Console;
namespace StringSearch
{
class MainApp
{
static void Main(string[] args)
{
string greeting = "Good Morning";
WriteLine(greeting);
WriteLine();
// IndexOf() : 문자 또는 문자열 앞에서부터 몇번째에 있는지 탐색
WriteLine("IndexOf 'Good' : {0}", greeting.IndexOf("Good"));
WriteLine("IndexOf 'o' : {0}", greeting.IndexOf('o'));
// LastIndexOf() : 문자 또는 문자열 뒤에서부터 몇번째에 있는지 탐색
WriteLine("LastIndexOf 'Good' : {0}", greeting.LastIndexOf("Good"));
WriteLine("LastIndexOf 'o' : {0}", greeting.LastIndexOf("o"));
// StartsWith() : 현재 문자열이 지정 문자열로 시작하는가 (bool)
WriteLine("StartsWith 'Good' : {0}", greeting.StartsWith("Good"));
WriteLine("StartsWith 'Morning' : {0}", greeting.StartsWith("Morning"));
// EndsWith() : 현재 문자열이 지정 문자열로 끝나는가 (bool)
WriteLine("EndsWith 'Good' : {0}", greeting.EndsWith("Good"));
WriteLine("EndsWith 'Morning' : {0}", greeting.EndsWith("Morning"));
// Contains() : 현재 문자열이 지정 문자열을 포함하는가 (bool)
WriteLine("Contains 'Evening' : {0}", greeting.Contains("Evening"));
WriteLine("Contains 'Morning' : {0}", greeting.Contains("Morning"));
// Replace() : 문자열 바꾸기
WriteLine("Replaced 'Morning' with 'Evening': {0}",
greeting.Replace("Morning", "Evening"));
}
}
}
// StringModify //
using static System.Console;
namespace StringModify
{
class MainApp
{
static void Main(string[] args)
{
WriteLine("Lower() : '{0}'", "ABC".ToLower()); // 대문자 → 소문자
WriteLine("ToUpper() : '{0}'", "abc".ToUpper()); // 소문자 → 대문자
WriteLine("Insert() : '{0}'", "Happy Friday!".Insert(5, " Sunny")); // 지정 위치에 문자열 삽입
WriteLine("Remove() : '{0}'", "I Don't Love You.".Remove(2, 6)); // 지정 위치의 문자열 제거
WriteLine("Trim() : '{0}'", " No Spaces ".Trim()); // 앞,뒤 공백 제거
WriteLine("TrimStart() : '{0}'", " No Spaces ".TrimStart()); // 앞 공백 제거
WriteLine("TrimEnd() : '{0}'", " No Spaces ".TrimEnd()); // 뒤 공백 제거
}
}
}
// ![](https://velog.velcdn.com/cloudflare/ssu_hyun/85393572-0aae-4ab1-be2e-6441478e149b/image.png)
//
using System;
using static System.Console;
namespace StringSlice
{
class MainApp
{
static void Main(string[] args)
{
string greeting = "Good morning.";
WriteLine(greeting.Substring(0, 5)); // "morning"
WriteLine(greeting.Substring(5)); // "Good"
WriteLine();
string[] arr = greeting.Split(
new string[] { " " }, StringSplitOptions.None); // 공백 기준 문자열 분리한 문자열의 배열
WriteLine("Word Count : {0}", arr.Length); // arr 배열 길이
foreach (string element in arr) // arr 배열 loop
WriteLine("{0}", element);
}
}
}
서식 : 문자열이 일정한 틀과 모양을 갖추는 것
string.Format( 문자열 틀, 문자열 틀 안에 집어넣을 데이터 );
Console.WriteLine()
메소드는 내부적으로 string.Format()
메소드를 사용한다.서식 항목(Format Item) : 문자열 틀에 입력하는 {}
부분
서식 항목 추가 옵션
왼쪽/오른쪽 맞춤
① 숫자로 서식 항목이 차지할 공간의 크기 선택
②+
,-
로 오른쪽,왼쪽 정렬 선택
string.Format("{0,-10}DEF", "ABC");
0
: 0번째 지정 데이터10
: 10의 공간 생성-
: 왼쪽부터 데이터 채우기!string.Format("{0,10}DEF", "ABC");
0
: 0번째 지정 데이터10
: 10의 공간 생성(+)
: 오른쪽부터 데이터 채우기// StringFormatBasic // using System; using static System.Console; namespace StringFormatBasic { class MainApp { static void Main(string[] args) { string fmt = "{0,-20}{1,-15}{2,30}"; // {0,-20} : 첫번째 지정 데이터, 20 공간에서 왼쪽부터 데이터 채우기 // {1,-15} : 두번째 지정 데이터, 15 공간에서 왼쪽부터 데이터 채우기 // {2,30} : 세번째 지정 데이터, 30 공간에서 오른쪽부터 데이터 채우기 WriteLine(fmt, "Publisher", "Author", "Title"); WriteLine(fmt, "Marvel", "Stan Lee", "Iron Man"); WriteLine(fmt, "Hanbit", "Sanghyun Park", "This is C#"); WriteLine(fmt, "Prentice Hall", "K&R", "The C Programming Language"); } } }
숫자 서식화
- 다양한 형태로 수를 서식화하는 기능 지원
- MSDN의 표준 숫자 서식 문자열
- 서식 지정자
- 자릿수 지정자(Precision Specifier)
서식 지정자
자릿수 지정자(0~99)
- D5 : 10진수 5자리
// StringFormatNumber // using System; using static System.Console; namespace StringFormatNumber { class MainApp { static void Main(string[] args) { // D : 10진수 WriteLine("10진수: {0:D}", 123); // 10진수 서식화 WriteLine("10진수: {0:D5}", 123); // 10진수 서식화 5자리 // X : 16진수 WriteLine("16진수: 0x{0:X}", 0xFF1234); // 16진수 서식화 WriteLine("16진수: 0x{0:X8}", 0xFF1234); // 16진수 서식화 8자리 // N : 숫자 WriteLine("숫자: {0:N}", 123456789); // 입력된 수 콤마로 구분해 출력 WriteLine("숫자: {0:N0}", 123456789); // 자릿수 0은 소숫점 이하 제거 // F : 고정소수점 WriteLine("고정소수점: {0:F}", 123.45); // 고정 소수점 형식 서식화 WriteLine("고정소수점: {0:F5}", 123.456); // 소수점 아래 5자리 // E : 공학용 WriteLine("공학: {0:E}", 123.456789); // 지수 표기로 서식화 } } }
날짜 및 시간 서식화
- 날짜 및 시간 서식 지정자
*MSDN의 사용자 지정 날자 및 시간 서식 문자열CultureInfo
: 문화권 정보 표시
*문화권 이름 - MSDN의 Product Behaviorusing System; using System.Globalization; using static System.Console; namespace StringFormatDatetime { class MainApp { static void Main(string[] args) { // 2018년 11월 3일 23시 18분 22초 DateTime dt = new DateTime(2018, 11, 3, 23, 18, 22); // 국가 및 지역 설정에 따라 다른 결과 출력 WriteLine("12시간 형식: {0:yyyy-MM-dd tt hh:mm:ss (ddd)}", dt); WriteLine("24시간 형식: {0:yyyy-MM-dd HH:mm:ss (dddd)}", dt); // CultureInfo 클래스를 통해 문화권 정보 표시 // 한국 CultureInfo ciKo = new CultureInfo("ko-KR"); WriteLine(); WriteLine(dt.ToString("yyyy-MM-dd tt hh:mm:ss (ddd)", ciKo)); // 12시간 형식 WriteLine(dt.ToString("yyyy-MM-dd HH:mm:ss (dddd)", ciKo)); // 24시간 형식 WriteLine(dt.ToString(ciKo)); // 한글 기본 형식 // 미국 CultureInfo ciEn = new CultureInfo("en-US"); WriteLine(); WriteLine(dt.ToString("yyyy-MM-dd tt hh:mm:ss (ddd)", ciEn)); // 12시간 형식 WriteLine(dt.ToString("yyyy-MM-dd HH:mm:ss (dddd)", ciEn)); // 24시간 형식 WriteLine(dt.ToString(ciEn)); // 미국(영어) 기본 형식 } } }
$
붙이기 + 서식항목에 첨자가 아닌 식// StringInterpolation //
using System;
using static System.Console;
namespace StringInterpolation
{
class MainApp
{
static void Main(string[] args)
{
string name = "김튼튼";
int age = 23;
WriteLine($"{name,-10}, {age:D3}");
// {name,-10} : name, 10공간에서 왼쪽부터 채우기
// {age:D3} : age, 10진수 3자리로 표현
name = "박날씬";
age = 30;
WriteLine($"{name}, {age,-10:D3}");
// {age,-10:D3} : age, 10공간에서 왼쪽부터 채우기, 10진수 3자리로 표현
name = "이비실";
age = 17;
WriteLine($"{name}, {(age > 20 ? "성인" : "미성년자")}"); // 조건문
}
}
}
사각형의 너비를 입력하세요.
30
사각형의 높이를 입력하세요.
40
사격형의 넓이는 : 1200
using System;
namespace RectArea
{
class MainApp
{
public static void Main()
{
Console.WriteLine("사각형의 너비를 입력하세요.");
string width = Console.ReadLine();
Console.WriteLine("사각형의 높이를 입력하세요.");
string height = Console.ReadLine();
Console.WriteLine($"사각형의 넓이는 : {int.Parse(width) * int.Parse(height)}");
// int area = int.Parse(width) * int.Parse(height);
// Console.WriteLine($"사각형의 넓이는: {area}");
}
}
}
int a = 7.3;
// int는 정수형 데이터 타입이므로 소수 7.3을 int형 변수 a에 할당하는 것은 잘못되었다. int를 float으로 바꿔주거나 (int)를 7.3앞에 붙여주어 해결할 수 있다.
float b = 3.14;
double c = a * b;
char d = "abc";
// char은 문자 1개를 저장하며 변수를 정의할 때 작은 따옴표(')를 사용한다.
string e = '한';
// string은 문자열(여러개의 문자)을 저장하며 변수를 정의할 때 큰 따옴표(")를 사용한다.
값 형식과 참조 형식의 차이는 무엇인가요?
값 형식과 참조 형식의 차이는 변수의 값, 즉 데이터를 어디에 담느냐에 있다. 값 형식은 데이터를 스택에 저장하고 참조 형식은 데이터를 힙에 저장한다.
박싱과 언박싱을 설명하세요.
박싱은 값 형식의 데이터를 힙에 할당하는 것을 말한다. 따라서 스택 메모리에는 힙 메모리에 할당되어 있는 값 형식의 데이터의 주소가 저장되어있다.
언박싱은 힙 메모리에 저장되어있는 값 형식의 데이터를 값 형식의 변수에 저장하는 과정이다.
다음 코드를 컴파일한 후의 a와 b는 각각 어떤 데이터 형식이겠습니까?
var a = 2020; // int
var b = "double"; // string