해당 링크를 토대로 주요 문법들을 복습했다. 5년 전 기억을 더듬고 있는데 꽤 기억에 남았다는 사실이 재밌다. 이번 만큼은 그 당시 힘들었던 포인터를 극복하고 RedBlack트리까지 멋있게 구현해보고 싶다.
반복적으로 실수했던 부분
1. 모든 변수는 자료형 선언해주기
2. printf 변수를 위해서는 자료형 지정 필요함
3. 세미콜론(;) 필수
4. char s 작은 따옴표로 할당하기
주제별로 학습하기
// C언어
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<math.h>
void practice_data_type() {
/* 모든 자료형 - 형식 지정자 연결 짓기 */
// 정수형
int a = 123;
long b = pow(10, 6);
printf("a=%d, int자료형 크기: %llu Byte\n", a, sizeof(a));
printf("b=%d, long자료형 크기: %llu Byte\n", b, sizeof(b));
// 문자, 문자열
char c = 'A'; // 쌍따옴표이면 %c로 출력 안됨
char* s = "Hello World!";
printf("c=%c, char 자료형 크기: %llu Byte\n", c, sizeof(c));
printf("ascii code of c =%d\n", c);
printf("s=%s\n", s);
// 실수형
float f = 1234.5678;
double df = 1234.5678;
printf("f=%f, float 자료형 크기: %llu Byte\n", f, sizeof(f));
printf("f(절삭)=%.2f\n", f);
printf("df=%f\n", df);
// 그 외
printf("5칸 띄고 출력:%5c\n", '*');
}
void practice_operator() {
// 산술 연산자
int a = 4, b = 2;
printf("a=%d, b=%d\n", a, b);
printf("덧셈: %d\n", a + b);
printf("뺄셈: %d\n", a - b);
printf("곱셈: %d\n", a * b);
printf("나눗셈: %d\n", a / b);
printf("나머지: %d\n", a % b);
// 단항 연산자
int x = 4;
int y = --x;
printf("x=%d, y=%d\n", x, y); // 3, 3
int z = x++;
printf("x=%d, z=%d\n", x, z); // 4, 3
// 관계 연산자 결과는 int (0 or 1)
// 주의: false, true 와 같은 bool 자료형 없음
int c = 10, d = 2;
printf("c <= d = %d\n", c <= d);
printf("c <= d = %d\n", c != d);
// 논리 연산자
printf("&& : %d\n", 1 && 2);
printf("|| : %d\n", 1 || 0);
// 조건 연산자
printf("한줄 조건문 가능; %s\n", 1 == 1 ? "YES" : "NO");
// 비트 연산자
printf("\n[비트단위]\n");
printf("AND %d\n", 1 & 0);
printf("OR %d\n", 1 | 0);
printf("XOR %d\n", 1 ^ 0);
printf("NOT %d\n", ~1); // 보수값 이해 필요
// 쉬프트 연산자
printf("\n[쉬프트 연산자]\n");
printf("곱하기 2^n%d\n", 1 << 2);
printf("나누기 2^n%d\n", 8 >> 1);
}
void practice_overflow() {
/*
TMI: C언어에서는 char 형식도 정수 형식으로 취급함.
char = 1Byte (8bit, 2^8 표현 가능) (2^7 = 128)
표현 가능한 수의 범위 -128 ~ + 127
*/
char num1 = -129; // 언더플로우
char num2 = 128; // 오버플로우
printf("%d \n", num1); // 127
printf("%d \n", num2); // -128
}
void practice_scanf() {
char a;
int b;
printf("문자 입력: ");
scanf("%c", &a);
printf("%c 의 ASCII 코드 값: %d", a, a); // a 97
}
void practice_loop() {
int i = 1;
while (i <= 5) {
if (i == 3) {
continue;
}
printf("i=%d\n", i++);
}
printf("\n");
for (int i = 1; i <= 5; i+=2) { // step up
printf("i=%d\n", i);
}
printf("\n");
int j= 0;
do {
printf("우선 출력 %d\n", j);
} while (j > 1);
}
void practice_switch() {
int i = 1;
switch (i) {
printf("이곳은 미출력됩니다.");
case 1:
printf("숫자 1입니다.\n");
case 2:
printf("break를 써주지 않으면 다음 구문까지 진행돼요\n");
break;
case 3:
printf("여기까지 출력이 될까요?\n");
default:
printf("case 중에 없다면 이곳이 출력됩니다.");
}
}
void practice_array() {
#define ARRAY_SIZE 5 // 상수 선언 주의) 세미콜론, 등호 없어야함
/* 배열을 통해 포인터 개념 살짝 맛보기 */
int a = 123;
int* p = &a; // 포인터 변수 선언 (*), 등호 좌측에 있을때는 포인터 변수 및 주소값
printf("a=%d\n", *p); // 역참조 (*), 등호 오른쪽에 있을 경우 혹은 값 조회 위치
printf("a주소=%p\n", p); //
*p = 456; // 메모리 주소 접근해서 값 재할당
printf("a=%d\n", *p);
// 주의) 안되는 문법; 주소에 접근해서 재할당될 것 같은데 안됨
// *a = 789;
// &a = 789;
int arr[ARRAY_SIZE] = { 1 }; // 요소 생략 시 데이터 0으로 초기화
printf("arr[0]의 주소 = 배열 시작 주소: %p\n", &arr[0]);
printf("배열의 이름 = 배열 시작 주소: %p\n", arr);
printf("arr[1] 주소: %p\n", (arr + 1));
printf("arr[1] 주소: %p\n", &arr[1]);
printf("배열의 길이(ARRAY_SIZE): %d\n", sizeof(arr) / sizeof(arr[0]));
printf("arr[0]=%d\n", arr[0]);
printf("arr[0]=%d\n", *arr);
printf("arr[0]=%d\n", *&*arr); // 값을 가지는 주소의 값
for (int i = 0; i < ARRAY_SIZE; i++) {
printf("i=%d\n", arr[i]);
}
}
void practice_pointer_basic() {
/* 2차원 포인터 */
char a = 'A';
char* p = NULL;
char** pp = NULL;
p = &a;
pp = &p;
printf("%c %p %p\n", a, p, pp);
printf("%p %p %p\n", &a, &p, &pp);
printf("%c %c %c\n", a, *p, **pp);
/* 함수의 이름은 함수의 시작 주소 */
printf("%p %p\n", printf, scanf);
void (*fp); // 함수 포인터 선언 시 괄호 필요함
fp = printf;
printf("%p\n", fp);
/* 문자열 (배열 vs 포인터) */
char array1[] = { 'A', 'B', 'C', 'D', '\0' };
char array2[] = { 'A', 'B', 'C', 'D' };
printf("%s\n", array1);
printf("%s\n", array2); // 주의) 원하지 않는 결과 생성
char sentence_by_array[] = "ABC";
char* sentence_by_pointer = "DEF"; // 문자열 상수 DEF\0
printf("%c\n", sentence_by_array[1]);
printf("%c\n", sentence_by_pointer[1]);
/* 포인터의 상수화 */
char aa = 'A';
char bb = 'B';
const char* const p_aa = &aa; // 포인터와 데이터 모두 상수화
printf("%c %c %c\n", aa, bb, *p_aa);
//p = &bb; // 에러 발생한다는데 안함
//*p = bb;
/* void형 포인터 */
// 모든 자료형의 주소 저장 가능, 내용 변경 불가, 강제 형변환만 가능
void* vx = NULL;
}
// pointer advanced
int call_by_value(int i) {
i = i + 1;
return i;
}
int call_by_reference(int* i) {
*i = *i + 1;
return *i;
}
void practice_call_func() {
int a = 1;
printf("%d (after a=%d)\n", call_by_value(a), a);
printf("%d (after a=%d)\n", call_by_reference(&a), a);
}
int main(void) {
practice_call_func();
return 0;
}
더 알아볼 것
1. define vs const
2. 자료형 크기 및 부동 소수점
3. 실수형 오차는 어떻게 대응하면 될까?
4. malloc, struct
5. lib vs header file
'2️⃣ 개발 지식 B+ > OS' 카테고리의 다른 글
어셈블리어 기초 (1) | 2024.10.02 |
---|---|
[네트워크] echo 예제로 이해하는 소켓 인터페이스 (0) | 2024.09.16 |
[우분투 20.04] 인코딩 utf-8 (0) | 2021.03.30 |
[우분투 20.04] 듀얼 모니터 설정 (0) | 2021.02.07 |
우분투 20.04 마우스 휠 속도 조정 (0) | 2020.12.23 |