#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
#include <float.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <stdlib.h>
주소연산
1. Type : 데이터를 해석하는 방법
2. Memory : 데이터를 저장하는 공간
3. Object : 데이터를 저장하는 영역 -> Memory
int main()
{
int a;
a = 10; // 왜 이게 되는 것일까?
연산자는 피연산자를 동반한다.
a + b
a = b : 할당 연산자는 피연산자가 2개 필요하다.
피연산자에 조건. => 타입.
모든 연산자는 피연산자의 조건(타입)이 있다.
int* p;
p = &a;
int arr[5];
arr[2];
*(arr + 2);
(arr + 2); // 배열 + 정수 => 포인터 + 정수 => 주소 연산
int* + int;
int*
*(int*) => int
a[b] == *(a + b);
1. 왜 a + b는 주소 연산일까? => 피연산자의 타입 때문에 주소 연산이란 걸 알게 됨. => a의 타입은 pointer고, b의 타입은 int
2. *연산자는 오직 pointer 타입에만 적용할 수 있음. => (a + b)의 타입은 pointer
3. 역참조한 값의 타입은? pointer가 가리키고 있는 타입.
(p + 2); //
*(arr + 2); // arr(value) + sizeof(type) * int
&arr[0] + sizeof(int) * 2;
int arr2[2][3];
*(*(arr2 + 2) + 3);
arr2 + 2; // arr2 : int(*)[3];
주소 연산
&arr2[0] + sizeof(int[3]) * 2;
첫 번째 원소로부터 24바이트 뒤에 있는 것을 참조.
arr2 + 2 : int(*)[3];
*(arr2 + 2); // int[3]
*(int*);
int;
arr[2][3];
enum { A, B, C } a = -1;
}
printf
#include <stdio.h>
#include <stdarg.h>
void myprintf(int count, ...)
{
char* == va_list
char의 크기는? 1바이트
byte*
va_list args; // 가변 인자를 다룰 객체를 만든다.
va_start(args, count); // 가변 인자의 시작 위치를 알려준다.
printf("My Variadic Function :");
for (int i = 0; i < count; ++i)
{
int number = va_arg(args, int); // 인자를 빼서 사용한다.
printf(" %d,", number);
}
va_end(args); // 끝낸다.
}
<summary>
printf와 유사하게 동작하나 기능이 제한됨.
%d / %c / %s
</summary>
<param name="format">형식 문자열</param>
<param name="">가변 인자값</param>
void myprintf(const char* format, ...);
int main(void)
{
-14
14 : 0000 0000 0000 0000 0000 0000 0000 1110
~14 : 1111 1111 1111 1111 1111 1111 1111 0001
+1 : 1111 1111 1111 1111 1111 1111 1111 0010
myprintf("My Printf : %d, %c, %s\\n", -14, 'A', "Hello");
return 0;
}
myprintf
void printNumber(int n) //숫자입력
{
1000 0000 0000 0000 0000 0000 0000
8 0 0 0 0 0 0
const int isNegative = n & (1 << 31);
if (isNegative)
{
putchar('-');
n -= 1;
n = ~n;
}
char numberString[16] = "";
int digitCount = 0;
do
{
int digit = n % 10;
numberString[digitCount] = digit + '0';
++digitCount;
n /= 10;
} while (n != 0);
for (int i = digitCount - 1; i >= 0; --i)
{
putchar(numberString[i]);
}
}
void printString(const char* str) //글자입력
{
while (*str != '\\0') //참조건 : str이 널이 아닐경우
{
putchar(*str);
++str;
}
}
void myprintf(const char* format, ...)
{
va_list args;
va_start(args, format);
int n, ch;
const char* str;
while (*format != '\\0')
{
if (*format == '%')
{
++format;
if (*format == '\\0')
{
break;
}
switch (*format)
{
case 'd':
n = va_arg(args, int);
printNumber(n);
break;
case 'c':
ch = va_arg(args, int);
putchar(ch);
break;
case 's':
str = va_arg(args, const char*);
printString(str);
break;
}
++format;
continue;
}
putchar(*format);
++format;
}
va_end(args);
}
int main(void)
{
myprintf("HELLO : %d, %c, %s", 123, 'A', "HELLO");
return 0;
}
양의 정수 n에 대해서 d(n) = n + (n / 10 + n % 10)
양의 정수 n이 주어졌을 때, n, d(n), d(d(n)), d(d(d(n)))..
결과값이 n으로 바뀐다.
1,3,5,7,9,20,31,42,53,64,75,86,97...9993
*/
assert (오류를 찾는 언어)
void CreateUser(const char* nickname)
{
int n = strlen(nickname);
assert(n <= 10); //반드시 만족하려면
if (n <= 10) //선택적 이라면
{
}
}
int main(void)
{
int n = 1;
assert(n == 10);
}
int IsSame(float a, float b)
{
if (a - b < FLT_EPSILON)
{
return 1;
}
else
{
return 0;
}
}
isSame
int main(void)
{
printf("float의 유효 숫자 : %d\\n", FLT_MIN); //f를 사용하면 너무 작은값이라 출력이 안나와서 e 사용
printf("double의 유효 숫자 : %d\\n", DBL_MIN);
printf("long double의 유효 숫자 : %d\\n", LDBL_MIN);
}
{
float f = 1.0 - 0.7;
if (f == 0.3)
{
printf("출력 되니?");
}
if (IsSame(f, 0.3))
{
printf("같음");
}
}
div_t result = div(a, b)
int main(void)
{
사용자로부터 두 수를 입력 받고
int a, b;
printf("두 수를 입력해 : ");
scanf("%d %d", &a, &b);
몫과 나머지를 출력해보세요.
div_t result = div(a, b);
printf("몫 : %d, 나머지 : %d\\n", result.quot, result.rem);
}
int main(void)
{
time_t result = time(NULL);
printf("현재 시간 : %s\\n", asctime(gmtime(&result)));
asctrime_s(str, sizeof(str), gmtime(&result))
printf("현재 시간 : %s\\n , str); -> 그리니치천문대 기준
}
파일 입출력
/* int main(void)
{
1. 파일을 다루기 위한 객체 생성
FILE* fp = NULL;
2. 파일을 연다.
1) 텍스트 파일 : 텍스트 에디터로 열 수 있는 파일로 우리가 읽을 수 있는 문자로 구성
2) 바이너리 파일 : 그 외의 모든 파일
fopen_s(&fp, "Metaverse.t", "w"); // 확장자는 안 적어도 된다 : .txt
if (0 != fopen_s(&fp, "Metaverse.txt", "w"))
{
printf("오류 발생.");
return 1;
}
3. 컨텐츠를 작성한다. (파일을 조작한다.)
텍스트 파일에 작성할 수 있는 함수 : fputs() / fputc() / fprintf()
바이너리 파일에 작성할 수 있는 함수 : fwrite()
fputs("Hello File!", fp);
fputc('J', fp);
fprintf(fp, "\\nThe name of the queen : %s\\n", "퀸균지"); //멀티바이스 방식(한글)
4. 파일을 닫는다.
fclose(fp);
if (0 != fopen_s(&fp, "Metaverse.txt", "r"))
{
printf("오류 발생함.");
return 1;
}
텍스트 파일에서 읽어들일 수 있는 함수 : fgets() / fgetc() / fscanf()
바이너리 파일에서 읽어들일 수 있는 함수 : fread()
char ch = fgetc(fp);
char str[128] = "";
fgets(str, sizeof(str), fp); //개행 문자까지 받아들인다.
char str2[128] = "";
fscanf(fp, "The name of the queen : %s", str2, sizeof(str2));
printf("읽어들인 문자 : %c\\n", ch);
printf("읽어들인 문자열 : %s\\n", str);
printf("퀸은 누구? : %s\\n", str2);
fclose(fp);
--------------------------
바이너리 파일
--------------------------
if (0 != fopen_s(&fp, "Metaverse2", "wb"))
{
printf("오류 발생했다.");
return 1;
}
struct Student
{
int Age;
enum { A, B, O, AB } BloodType;
char Name[24];
};
struct Student s = { 20, A, "ChoiSeonMun" };
if (1 != fwrite(&s, sizeof(s), 1, fp))
{
printf("오류 발생했다!");
fclose(fp);
return 1;
}
fclose(fp);
if (0 != fopen_s(&fp, "Metaverse2", "rb"))
{
printf("오류 발생생.");
return 1;
}
struct Student s2 = { 0 };
if (1 != fread(&s2, sizeof(s2), 1, fp))
{
printf("오류 발생송");
fclose(fp);
return 1;
}
printf("나이 : %d, 혈액형 : %d, 이름 : %s\\n", s2.Age, s2.BloodType, s2.Name);
fclose(fp);
return 0;
}*/
문자열 입출력
/*int main(void)
{
const char* input = "퀸은 누구인가? 퀸균지";
char str[128] = "";
sscanf_s(input, "퀸은 누구인가? %s", str, sizeof(str));
char str2[128] = "";
sprintf(str2, "그렇다. 퀸은 %s였다.", str);
puts(str2);
return 0;
}*/
동적 할당
int main(void)
{
10
int[10]
printf("필요한 공간 개수 입력 : ");
int n;
scanf_s("%d", &n);
메모리 누수
/* while (1)
{
malloc(sizeof(int) * n);
Sleep(100);
}*/
메모리는 자원(Resource)이다.
자원이라는 것은 시스템으로 부터 빌려와서 사용이 끝나면 돌려줘야 하는 것들.
사용이 끝난 메모리를 돌려주지 않으면 메모리 누수(Memory Leak가 발생
int* p = malloc(sizeof(int) * n);
for (int i = 0; i < 10; ++i)
{
p[i] = i;
}
free(p); // 힙에 메모리를 반환.
p = NULL; // 해제가 됐다면 꼭 NULL 포인터로 만들어 줄 것
*p;
free(p);
메모리를 수동으로 관리할 때 문제점
1. 언제 사용이 끝나는지 불명확함. -> 반환이 안될 수 있음. -> 메모리 누수 발생
2. 반환이 됐음에도 불구하고 접근하는 경우
3. 반환이 됐음에도 불구하고 또 반환하는 경우 -> 이중 해제(Double Free)
return 0;
}
typedef : 타입을 재정의 하는 것.어떤 타입에 별명을 지어주는 것
typedef type identifier;
/*typedef char byte;
typedef struct tagA
{
int n
}A;
int main(void)
{
byte a;
va_list args;
A a;*/
}
// 매크로는 기호 상수처럼 사용할 수 있다.
#define SPEED_OF_LIGHT 299792458
// 함수처럼 사용할 수도 있다.
// 함수처럼 사용할 때는 매개변수에 꼭 ()를 사용하자.
#define MIN(a, b) ((a) < (b) ? 1 : 0)
int main(void)
{
printf("빛의 속도는 %d m/s이다.\\n".SPEED_OF_LIGHT);
// 전처리 과정 때 SPEED_OF_LIGHT 매크로는 299792458로 대체 된다.
if (MIN(10, 20)
{
printf("10은 20보다 작다.\\n")
;
}
return 0;
}
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
#include <float.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
//주소연산
//
//
//// 1. Type : 데이터를 해석하는 방법
//// 2. Memory : 데이터를 저장하는 공간
//// 3. Object : 데이터를 저장하는 영역 -> Memory
//
//int main()
//{
// int a;
// a = 10; // 왜 이게 되는 것일까?
//
// // 연산자는 피연산자를 동반한다.
// // a + b
// // a = b : 할당 연산자는 피연산자가 2개 필요하다.
// // 피연산자에 조건. => 타입.
// // 모든 연산자는 피연산자의 조건(타입)이 있다.
//
// int* p;
// p = &a;
//
// int arr[5];
// arr[2];
// *(arr + 2);
// (arr + 2); // 배열 + 정수 => 포인터 + 정수 => 주소 연산
// // int* + int;
// // int*
// //*(int*) => int
//
// // a[b] == *(a + b);
// // 1. 왜 a + b는 주소 연산일까? => 피연산자의 타입 때문에 주소 연산이란 걸 알게 됨. => a의 타입은 pointer고, b의 타입은 int
// // 2. *연산자는 오직 pointer 타입에만 적용할 수 있음. => (a + b)의 타입은 pointer
// // 3. 역참조한 값의 타입은? pointer가 가리키고 있는 타입.
//
// (p + 2); //
// *(arr + 2); // arr(value) + sizeof(type) * int
// // &arr[0] + sizeof(int) * 2;
// //
//
// int arr2[2][3];
// *(*(arr2 + 2) + 3);
// arr2 + 2; // arr2 : int(*)[3];
// // 주소 연산
// // &arr2[0] + sizeof(int[3]) * 2;
// // 첫 번째 원소로부터 24바이트 뒤에 있는 것을 참조.
// // arr2 + 2 : int(*)[3];
// *(arr2 + 2); // int[3]
// *(int*);
// int;
// arr[2][3];
//
// enum { A, B, C } a = -1;
//}
//
//
//printf
//
//
//#include <stdio.h>
//#include <stdarg.h>
//
////void myprintf(int count, ...)
////{
//// // char* == va_list
//// // char의 크기는? 1바이트
//// // byte*
//// va_list args; // 가변 인자를 다룰 객체를 만든다.
//// va_start(args, count); // 가변 인자의 시작 위치를 알려준다.
////
//// printf("My Variadic Function :");
//// for (int i = 0; i < count; ++i)
//// {
//// int number = va_arg(args, int); // 인자를 빼서 사용한다.
//// printf(" %d,", number);
//// }
////
//// va_end(args); // 끝낸다.
////}
//
//
///// <summary>
///// printf와 유사하게 동작하나 기능이 제한됨.
///// %d / %c / %s
///// </summary>
///// <param name="format">형식 문자열</param>
///// <param name="">가변 인자값</param>
//void myprintf(const char* format, ...);
//
//int main(void)
//{
// // -14
// // 14 : 0000 0000 0000 0000 0000 0000 0000 1110
// // ~14 : 1111 1111 1111 1111 1111 1111 1111 0001
// // +1 : 1111 1111 1111 1111 1111 1111 1111 0010
// myprintf("My Printf : %d, %c, %s\\n", -14, 'A', "Hello");
//
// return 0;
//}
//myprintf
/*void printNumber(int n) //숫자입력
{
// 1000 0000 0000 0000 0000 0000 0000
// 8 0 0 0 0 0 0
const int isNegative = n & (1 << 31);
if (isNegative)
{
putchar('-');
n -= 1;
n = ~n;
}
char numberString[16] = "";
int digitCount = 0;
do
{
int digit = n % 10;
numberString[digitCount] = digit + '0';
++digitCount;
n /= 10;
} while (n != 0);
for (int i = digitCount - 1; i >= 0; --i)
{
putchar(numberString[i]);
}
}
void printString(const char* str) //글자입력
{
while (*str != '\\0') //참조건 : str이 널이 아닐경우
{
putchar(*str);
++str;
}
}
void myprintf(const char* format, ...)
{
va_list args;
va_start(args, format);
int n, ch;
const char* str;
while (*format != '\\0')
{
if (*format == '%')
{
++format;
if (*format == '\\0')
{
break;
}
switch (*format)
{
case 'd':
n = va_arg(args, int);
printNumber(n);
break;
case 'c':
ch = va_arg(args, int);
putchar(ch);
break;
case 's':
str = va_arg(args, const char*);
printString(str);
break;
}
++format;
continue;
}
putchar(*format);
++format;
}
va_end(args);
}
int main(void)
{
myprintf("HELLO : %d, %c, %s", 123, 'A', "HELLO");
return 0;
}
//양의 정수 n에 대해서 d(n) = n + (n / 10 + n % 10)
//양의 정수 n이 주어졌을 때, n, d(n), d(d(n)), d(d(d(n)))..
//결과값이 n으로 바뀐다.
//1,3,5,7,9,20,31,42,53,64,75,86,97...9993
*/
//assert (오류를 찾는 언어)
//void CreateUser(const char* nickname)
//{
// int n = strlen(nickname);
// assert(n <= 10); //반드시 만족하려면
//
// if (n <= 10) //선택적 이라면
// {
//
// }
//}
//int main(void)
//{
// int n = 1;
// assert(n == 10);
//}
//int IsSame(float a, float b)
//{
// if (a - b < FLT_EPSILON)
// {
// return 1;
// }
// else
// {
// return 0;
// }
//}
//isSame
//int main(void)
////{
//// printf("float의 유효 숫자 : %d\\n", FLT_MIN); //f를 사용하면 너무 작은값이라 출력이 안나와서 e 사용
//// printf("double의 유효 숫자 : %d\\n", DBL_MIN);
//// printf("long double의 유효 숫자 : %d\\n", LDBL_MIN);
////}
//{
// float f = 1.0 - 0.7;
// if (f == 0.3)
// {
// printf("출력 되니?");
// }
//
// if (IsSame(f, 0.3))
// {
// printf("같음");
// }
//}
//
//div_t result = div(a, b)
//int main(void)
//{
// // 사용자로부터 두 수를 입력 받고
// int a, b;
// printf("두 수를 입력해 : ");
// scanf("%d %d", &a, &b);
// // 몫과 나머지를 출력해보세요.
//
// div_t result = div(a, b);
// printf("몫 : %d, 나머지 : %d\\n", result.quot, result.rem);
//
//}
//int main(void)
//{
// time_t result = time(NULL);
// printf("현재 시간 : %s\\n", asctime(gmtime(&result)));
// //asctrime_s(str, sizeof(str), gmtime(&result))
// //printf("현재 시간 : %s\\n , str); -> 그리니치천문대 기준
//}
//파일 입출력
int main(void)
{
// 1. 파일을 다루기 위한 객체 생성
FILE* fp = NULL;
// 2. 파일을 연다.
// 1) 텍스트 파일 : 텍스트 에디터로 열 수 있는 파일로 우리가 읽을 수 있는 문자로 구성
// 2) 바이너리 파일 : 그 외의 모든 파일
//fopen_s(&fp, "Metaverse.t", "w"); // 확장자는 안 적어도 된다 : .txt
if (0 != fopen_s(&fp, "Metaverse.txt", "w"))
{
printf("오류 발생.");
return 1;
}
// 3. 컨텐츠를 작성한다. (파일을 조작한다.)
//
// 텍스트 파일에 작성할 수 있는 함수 : fputs() / fputc() / fprintf()
// 바이너리 파일에 작성할 수 있는 함수 : fwrite()
fputs("Hello File!", fp);
fputc('J', fp);
fprintf(fp, "\\nThe name of the queen : %s\\n", "퀸균지"); //멀티바이스 방식(한글)
// 4. 파일을 닫는다.
fclose(fp);
if (0 != fopen_s(&fp, "Metaverse.txt", "r"))
{
printf("오류 발생함.");
return 1;
}
// 텍스트 파일에서 읽어들일 수 있는 함수 : fgets() / fgetc() / fscanf()
// 바이너리 파일에서 읽어들일 수 있는 함수 : fread()
char ch = fgetc(fp);
char str[128] = "";
fgets(str, sizeof(str), fp); //개행 문자까지 받아들인다.
char str2[128] = "";
fscanf(fp, "The name of the queen : %s", str2, sizeof(str2));
printf("읽어들인 문자 : %c\\n", ch);
printf("읽어들인 문자열 : %s\\n", str);
printf("퀸은 누구? : %s\\n", str2);
fclose(fp);
// --------------------------
// 바이너리 파일
// --------------------------
if (0 != fopen_s(&fp, "Metaverse2", "wb"))
{
printf("오류 발생했다.");
return 1;
}
struct Student
{
int Age;
enum { A, B, O, AB } BloodType;
char Name[24];
};
struct Student s = { 20, A, "ChoiSeonMun" };
if (1 != fwrite(&s, sizeof(s), 1, fp))
{
printf("오류 발생했다!");
fclose(fp);
return 1;
}
fclose(fp);
if (0 != fopen_s(&fp, "Metaverse2", "rb"))
{
printf("오류 발생생.");
return 1;
}
struct Student s2 = { 0 };
if (1 != fread(&s2, sizeof(s2), 1, fp))
{
printf("오류 발생송");
fclose(fp);
return 1;
}
printf("나이 : %d, 혈액형 : %d, 이름 : %s\\n", s2.Age, s2.BloodType, s2.Name);
fclose(fp);
return 0;
}