알고리즘 주차에 WIL으로 진행했던 부분을 이번주 부터는 TIL으로 변경한다.
C언어를 활용해 RB트리를 구현하는 과정에 있어 C언어의 기본에 대해 복습을 하고 이후 과정들을 진행하려 한다.
C언어에 대한 수많은 자료들이 있지만, 깊이 있고 정리가 잘 되어 있는 블로그(modoocode.com)를 발견해 이를 바탕으로 포스팅 하겠다
최대한 카테고리를 정리해서 작성을 하겠으나, 미흡한 부분이 있을 수도 있음
C언어를 배우는 이유
- C언어를 학습을 통해서, 컴퓨터 내부 원리를 더 쉽게 이해할 수 있다.
- 많은 언어들이 C언어에서 파생되어 생겨났다.
C언어 코드의 구성
#include <stdio.h>
int main() {
printf("Hello, World! \\n");
return 0;
}
#include <stdio.h>
#include : 괄호 안에 있는 파일을 프로그램으로 불러온다
<stdio.h>: stdio: 표준 입출력, .h: 헤더파일
int main()
int: 정수 값을 반환한다
main: 모든 C 프로그램이 처음으로 시작하는 부분, main의 첫 번째 명령어의 주소값이 전달됨
return 0;
int main 이므로, 정수형을 반환시 retrun 0은 컴퓨터에게 프로그램이 무사히 종료됨을 알리는 것
기수법
이진법
23
=16+4+2+1
=1×2^4 + 0×2^3 + 1×2^2 + 1×2^1 + 1×2^0
=10111(2)
16진법
이진수는 너무 길어, 간소화를 위해 16진법을 사용함
(10: A, 11:B, 12:C, 13:D, 14:E, 15:F)
ex)
16782
=4×16^3+1×16^2+8×16^1+14×16^0
=**0x**418E
8 비트(1바이트)로 나타낼 수 있는 수, 다시말해 8 자리 이진수로 나타낼 수 있는 최대의 수
00000000(2) ~ 11111111(2) = 0 ~ 255 = 0∼0xFF
0 부터 255 로 총 256 개의 수를 나타내게 됩니다.
워드(word): cpu 레지스터에 값을 불러 연산 → 연산이 실행되는 최소 단위, 32비트 컴퓨터: 1워드 = 32비트(4바이트), 64비트 컴퓨터:1 워드=(8바이트)
변수
(메모리와 부분은 이해하는데 시간이 걸려, 가볍게 사용법만 익히고 추후 구현에 필요한 부분이 있으면 추가)
타입들의 크기는 char, float, double 말고는 정확히 정해진 것이 없음
int의 경우 C표준에 최소 2바이트 인 타입 이라고 되어 있지만, 대부분의 시스템에서 4바이트로 구현
unsigned int: 양수만 표현할 수 있는 대신, 양수 표현 범위가 두 배로 늘어남
실수형 자료형: float, double, long double
printf("a 의 값은 %d 진수로 %o 입니다. \\n", 8, a);
printf("a 의 값은 %d 진수로 %d 입니다. \\n", 10, a);
printf("a 의 값은 %d 진수로 %x 입니다. \\n", 16, a);
- %o: 8진수 형식 출력
- %x: 16진수 형식 출력
- %d: 10진수 형식 출력
printf("%f", 1.0); // 실수형은 소수점 까지 제대로 작성해야 오류가 나지 않음
float a = 3.141592f; // 확실한 float형 명시를 위해, 끝에 f를 붙임
double b = 3.141592;
printf("b : %6.3f \\n", b);
전체 자리수는 6 자리로 맞추고 반드시 소수점 이하 3 째 자리 까지만 표시한다는 뜻
*변수명 선언 주의사항
- 숫자가 앞에 위치하면 안됩니다. 그러나 중간이나 뒤는 괜찮음
- 변수명은 오직 영어, 숫자, _ 로 만 구성되어 있어야 함
- 사실 비주얼 스튜디오와 같은 컴파일러에서는 유니코드(한글 포함)로 변수 이름을 지어도 괜찮지만 관습상 코드는 모두 영어로 작성하는 것이 맞음
- 변수의 이름에 띄어쓰기가 있으면 안됨
연산자
기본적으로 연산자의 사용법은 동일함
int형으로 선언된 변수는 오직 '정수' 데이터만 담당 int 선언된, a 와 b 는 모두 정수 데이터만 처리하기 때문에 a 를 b 로 나누면, 즉 10 을 3 으로 나누면 3.3333... 이 되겠지만 정수 부분인 3 만게 됨 ∴ 3출력
만약 a 는 정수형 변수, b 는 실수형 이들에 대해 연산을 한 후에 결과를 실수형으로 출력하였는데 정상적으로 나왔습니다. 산술 변환 이라는 과정을 거치기 때문이다. 즉, 어떠한 자료형이 다른 두 변수를 연산 할 때, 숫자의 범위가 큰 자료형으로 자료형들이 바뀐다.
#1 ++c;
#2 d++;
증감연산자
#1 전위형(prefix): 먼저 1을 더해준 후 결과를 돌려줌
#2 후위형(postfix): 결과를 돌려준 후 1을 더해줌
/* prefix, postfix */
#include <stdio.h>
int main() {
int a = 1;
printf("++a : %d \\n", ++a);
a = 1;
printf("a++ : %d \\n", a++);
printf("a : %d \\n", a);
return 0;
}
-------------
**실행결과**
++a : 2
a++ : 1
a : 2
비트연산자
& (And 연산), | (Or 연산), ^ (XOR 연산), <<, >> (쉬프트 연산) , ~ (반전)
AND 연산 (&)
OR 연산 (|)
XOR 연산 (^)
반전 연산(~)
반전연산은 간단히 말에 0 을 1 로 1 을 0 으로 바꿔주는 것
~1100 결과 0011
2의 보수
덧셈을 고려하였을 때 가장 자연스러운 방법으로 음수를 표현하는 방식이 2 의 보수 표현
2 의 보수 표현 체계 하에서 어떤 수의 부호를 바꾸려면 먼저 비트를 반전 시킨 뒤에 1 을 더하면 됨
- 음수나 양수 사이 덧셈 시에 굳이 부호를 고려하지 않고 덧셈을 수행해도 되고
- 맨 앞 비트를 사용해서 부호를 빠르게 알아낼 수 있음
7 -> -7
0111(2) 1000(2) -> 1001(2): 2의 보수
-7 -> 7
1001(2) -> 0110 -> 0111(2): 2의 보수
자료형의 최대 범위보다 큰 수를 대입하므로써 발생하는 문제를 오버플로우(overflow)
하지만 CPU 는 그냥 0x7FFFFFFF 값을 1 증가 시킨다. 따라서 해당 a++ 이후에 a 에는 0x80000000 (이진수로 1000 0000 ... 0000) 이 들어가겟죠. 문제는 0x80000000 을 2의 보수 표현법 체계하에서 해석한다면 반전 하면 (0111 1111 ... 1111) 이 되고 다시 1 을 더하면 (1000 0000 ... 0000) 이 되므로 -0x80000000, 즉 -2147483648 이 된다.
문자 입력 받기
/* 문자를 저장하는 변수 */
#include <stdio.h>
int main() {
char a;
a = 'a';
printf("a 의 값과 들어 있는 문자는? 값 : %d , 문자 : %c \\n", a, a);
return 0;
}
%d: 아스키 코드 값
*scanf_s 를 사용하라는 의미는 scanf 가 입력받는 데이터의 크기를 확인하지 않기 때문에 버퍼 오버플로우 (입력받는 데이터의 크기가 준비된 공간보다 큰 문제) 가 발생할 수 있기 때문
double: %lf
float: %f
정수: %d
문자: %c
조건문
c언어 조건문의 경우 개념적으로는 다른 언어들과 차이가 없기 때문에, 간단한 사용법(문법)만 체크 하고 넘어가겠다.
#include <stdio.h>
int main() {
float ave_score;
float math, english, science, programming;
printf("수학, 영어, 과학, 컴퓨터 프로그래밍 점수를 각각 입력해 주세요 ! : ");
scanf("%f %f %f %f", &math, &english, &science, &programming);
ave_score =
(math + english + science + programming) / 4; // 4 과목의 평균을 구한다.
printf("당신의 평균 점수는 %f 입니다 \\n", ave_score);
if (ave_score >= 90) {
printf("당신은 우등생 입니다. ");
} else if (ave_score >= 40) {
printf("조금만 노력하세요!. \\n");
} else {
printf("공부를 발로 합니까? \\n");
}
return 0;
}
논리연산자
&&(and), || (or)
0 <= a <= 1 (x)
0 <= a && a <= 1(o)
반복문
개념은 동일하나 사용법에 있어 최근에 사용빈도가 높았던 파이썬과 큰 차이가 있어, 사용법에 대해 자세히 다룬다
for
#include <stdio.h>
int main() {
int i;
for (i = 0; i < 20; i++) {
printf("숫자 : %d \\n", i);
}
return 0;
}
for (/* 초기식 */; /* 조건식 */; /* 증감식 */) {
// 명령1;
// 명령2;
// ....
}
/* 무한루프 */
#include <stdio.h>
int main() {
int usranswer;
printf("컴퓨터가 생각한 숫자를 맞추어 보세요! \\n");
for (;;) {
scanf("%d", &usranswer);
if (usranswer == 3) {
printf("맞추셨군요! \\n");
break;
} else {
printf("틀렸어요! \\n");
}
}
return 0;
}
/* continue 사용법 */
/* 5 의 배수를 제외한 숫자 출력 */
#include <stdio.h>
int main() {
int i;
for (i = 0; i < 100; i++) {
if (i % 5 == 0) continue;
printf("%d ", i);
}
return 0;
}
while
/* while 문 */
#include <stdio.h>
int main() {
int i = 1, sum = 0;
while (i <= 100) {
sum += i;
i++;
}
printf("1 부터 100 까지의 합 : %d \\n", sum);
return 0;
}
while (/* 조건식 */) {
// 명령1;
// 명령2;
// ...
}
do - while
#include <stdio.h>
int main() {
int i = 1, sum = 0;
do {
sum += i;
i++;
} while (i < 1);
printf(" sum : %d \\n", sum);
return 0;
}
do {
// 명령1;
// 명령2;
// ...
} while (/* 조건식 */);
switch
if문과 유사
switch 활용
#include <stdio.h>
int main() {
int input;
printf("마이펫 업그레이드\\n");
printf("무엇을 하실 것인지 입력하세요 \\n");
printf("1. 밥주기 \\n");
printf("2. 씻기기 \\n");
printf("3. 재우기 \\n");
scanf("%d", &input);
switch (input) {
case 1:
printf("아이 맛있어 \\n");
break;
case 2:
printf("아이 시원해 \\n");
break;
case 3:
printf("zzz \\n");
break;
default:
printf("무슨 명령인지 못 알아 듣겠어. 왈왈 \\n");
break;
}
return 0;
}
switch (/* 변수 */) {
case /* 값1 */:
// 명령들;
break;
case /* 값2 */:
// 명령들;
break;
//.. (생략) ..
}
if 활용
/* 마이펫 */
#include <stdio.h>
int main() {
int input;
printf("마이펫 \\n");
printf("무엇을 하실 것인지 입력하세요 \\n");
printf("1. 밥주기 \\n");
printf("2. 씻기기 \\n");
printf("3. 재우기 \\n");
scanf("%d", &input);
if (input == 1) {
printf("아이 맛있어 \\n");
} else if (input == 2) {
printf("아이 시원해 \\n");
} else if (input == 3) {
printf("zzz \\n");
} else {
printf("무슨 명령인지 못 알아 듣겠어. 왈왈 \\n");
}
return 0;
}
switch와 if - else 차이 (https://blog.naver.com/kki2406/80041410085)
성능을 향상 시키느냐 메모리를 향상 시키느냐는 결국 선택해야할 문제이다.
만약에 if~else문이 매우 많이 있고, 그 함수를 매우 많이 호출하는데, 성능이 중요하다면,
switch case 문으로 성능 향상을 할 수 있을 것이다.
또한, switch case문에서 case의 값은 가급적이면 순차적으로 감소 또는 증가하는 것이 메모리 관리면에서 좋을 것이다.
마지막으로, case 문의 개수에 따라 switch 문은 jump table을 사용할 것인지 사용하지 않을 것인지를 결정한다.
switch 문이 효과적으로 처리되기 위해서는 case 의 '값' 들의 크기가 그다지 크지 않아야 하고, '값' 들이 순차적으로 정렬되어 있고, 그 '값' 끼리의 차이가 크지 않다면최고로 효율적인 switch 문을 이용할 수 있게 됩니다.
형변환(캐스팅)
더 자세한 내용은 필요할 때 추가 작성
실수 표현 방법
- 고정 소수점(fixed point)
- 부동 소수점(floating point)
float 가수 부분:23 비트, 지수 부분:8 비트,부호 비트: 1 비트 → 총 4 바이트
double 가수 부분: 52 비트 지수 부분: 11 비트로 → 8 바이트
배열(array), 상수
배열(array)
컴퓨터 메모리 상에 같은 타입의 변수를 연속적으로 여러 개를 한 꺼번에 정의할 수 있는 방법
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
(배열의 형) (배열의 이름)[원소 개수];
*배열의 정의 부분에서만 가능하고, 이미 정의된 배열에서는 사용할 수 없음
int arr[3] = {1, 2, 3}; // 가능
arr = {4, 5, 6}; // 불가능!
열의 크기를 생략하면 원소의 개수에 맞게 컴파일러가 알아서 배열을 정의
'sw 사관학교 정글 > TIL & WIL' 카테고리의 다른 글
[2022.05.01 ]TIL - C언어(포인터, 구조체, 동적 할당), 고급알고리즘 개념(AVL, BST) (0) | 2022.05.03 |
---|---|
[2022.04.30 ]TIL - C언어(상수, 고차원 배열, 포인터) (0) | 2022.05.02 |
[sw 사관학교 정글] [WEEK04] WIL 04주차 개발일지 (0) | 2022.04.30 |
[sw 사관학교 정글] [WEEK03] WIL 03주차 개발일지 (0) | 2022.04.21 |
[sw 사관학교 정글] [WEEK02] WIL 02주차 개발일지 (0) | 2022.04.15 |