(참고로 IDE 는 Integrated Development Environment로 우리가 쓰는 Visual studio code, Pycharm, Intellij 같은 것들을 의미합니다)

 

각 언어별로 구글에 cheatsheet(컨닝페이퍼)를 이미지 검색하시면, 각종 단축키와 문법들이 정리된 자료들이 많습니다.

 

처음부터 배울 때 이걸로 배워봤자, 아무런 하등 도움되지 않지만...

 

복습겸, 몰랐던 단축키들을 새로 알게 되면서, 좀 더 해당 코드와 IDE를 접하는데 부담감이 덜 하실 것입니다.

 

사람들마다 한번에 보고 기억하는 분들도 있지만, 저는 금방 잊어버려서, 계속 써봐야 기억이 남더라구요.

 

그래서 시험보는 것도 아니니, 코딩하면서 까먹은 것들은 컨닝 페이퍼라도 써서 한 번 더 타이핑 해보는 게 좋다고 생각합니다. :D

 

이것만 믿고 방심, 방만은 절대 금물입니다!

 

 

VS code cheat sheet

Visual Studio Code Tips and Tricks

Visual Studio Code Tips and Tricks for power users.

code.visualstudio.com

 

 

Bootstrap cheat sheet

Bootstrap Cheat Sheet

 

감사합니다.

 

'언어' 카테고리의 다른 글

StarUML 소개 [2023-06-02 학습일지]  (0) 2023.06.02

 

 

한글로 저장된 텍스트 문서를 불러와 출력하는 건 가능했다.

 

그리하여, 오늘 C언어 콘솔로 한글을 입력을 받으면 그대로 파일로 저장하는 것을 시도했으나, 결과는 대참패였다.

 

#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <locale.h>

int main()
{
	FILE *file;
	char str[100] = "\0";
	char ch;

	file = fopen("wtext.txt", "w");
	scanf("%s", str);
	printf("%s", str);

	int i = 0;
	while (i < 100)
	{
		if (str[i] == NULL)
		{
			break;
		}
		putc(str[i], file);
		i++;
	}

	fclose(file);
	return 0;
}
 

 

# wtext.txt file
# "hi" 입력 시..
hi
# "안녕" 입력 시.. in UTF-8 디코딩 시
�� 
# "안녕" 입력 시.. in EUC-KR 디코딩 시
薛
 

char도 써보고, wchar_t 구조체도 써보고 함수도 바꿔보고,

system("chcp 65001");
 

코드에 삽입하여 Window cmd 인코딩 방식도 바꿔보았다.

 

하지만, 돌아오는건 "��" 거나, 비정상적 종료뿐..

 

한글로 입력하면, ANSI 로 읽고, 이를 다시 ANSI로 저장하려고 해서 그런 것 같은데, 배열로 미리 포인터로 저장된 값은 저장이 잘된다.

 

하지만, 동적으로 한글 입력을 받고자하는 것이 목표였기 때문에, 오늘의 조사와 공부는 실패했다.

 

그나마 관련된 힌트로 마소에 정리된 자료를 발견하여 갖고왔다.

UTF의 약자가 Unicode Transform Format이다. 아무래도, scanf가 스트림(버퍼)형식이고 이것의 입력을 일부러 막아둔 듯하다.

 

StackOverFlow에서 console의 값을 복사하는 방법도 찾았는데, 막상 적용되진 않아서, 이것도 실패했다.

 

내일은 김밥천국 POS를 코딩할 예정이므로, 오늘은 수업시간에 작성한 로또 번호 생성기로 마무리하겠다.

 

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int get_rand_num()
{
    return rand() % 45 + 1;
}

int main()
{
    int num_1;
    int num_2;
    int num_3;
    int num_4;
    int num_5;
    int num_6;

    srand(time(NULL));

    while (1)
    {
        num_1 = get_rand_num();
        num_2 = get_rand_num();
        num_3 = get_rand_num();
        num_4 = get_rand_num();
        num_5 = get_rand_num();
        num_6 = get_rand_num();

        if (num_1 == num_2)
            continue;
        if (num_1 == num_3)
            continue;
        if (num_1 == num_4)
            continue;
        if (num_1 == num_5)
            continue;
        if (num_1 == num_6)
            continue;

        if (num_2 == num_3)
            continue;
        if (num_2 == num_4)
            continue;
        if (num_2 == num_5)
            continue;
        if (num_2 == num_6)
            continue;

        if (num_3 == num_4)
            continue;
        if (num_3 == num_5)
            continue;
        if (num_3 == num_6)
            continue;

        if (num_4 == num_5)
            continue;
        if (num_4 == num_6)
            continue;

        if (num_5 == num_6)
            continue;

        break;
    }

    int change_count;

    do
    {
        change_count = 0;
        int temp;
        if (num_1 > num_2)
        {
            temp = num_1;
            num_1 = num_2;
            num_2 = temp;
            change_count++;
            continue;
        }
        if (num_2 > num_3)
        {
            temp = num_2;
            num_2 = num_3;
            num_3 = temp;
            change_count++;
            continue;
        }
        if (num_3 > num_4)
        {
            temp = num_3;
            num_3 = num_4;
            num_4 = temp;
            change_count++;
            continue;
        }
        if (num_4 > num_5)
        {
            temp = num_4;
            num_4 = num_5;
            num_5 = temp;
            change_count++;
            continue;
        }
        if (num_5 > num_6)
        {
            temp = num_5;
            num_5 = num_6;
            num_6 = temp;
            change_count++;
            continue;
        }
    } while (change_count > 0);

    printf("My Lotto nums are %d, %d, %d, %d, %d, %d\n", num_1, num_2, num_3, num_4, num_5, num_6);

    return 0;
}
 

배열을 쓰지 않고, 라이브러리에 sorting을 지원하는 함수가 없었다.

 

그래서 개별적으로 변수 선언을 하고, 비교해서 틀리면 다시 뽑게 했는데..

 

만약 배열을 썼으면, 뽑힌 숫자를 표시하기 위한 용으로 배열을 하나 더 작성하여 애초에 뽑을 때 겹치지 않게 뽑았을 것 같다.

 

또한, sorting방식은 bubble sorting을 사용헀다. 개별 변수를 사용하다보니, for문과 index 사용이 제한되어 있던 터라 while을 통해 구현했고, 종료 조건으로 변경할 것이 없을 때로 두었다.

 

그랬더니 잘 나왔다. 하지만 bubble sorting은 그다지 효율적인 방법은 아니다.

 

6자리 개별 변수이니, 큰 차이 없어 이렇게 알고리즘을 구성하였다.

감사합니다.

 

 

C 언어로 한글 파일 출력하기

 

콘솔화면에 printf함수를 사용하면 우리가 원하는 텍스트를 출력할 수 있다.

 

하지만, 점점 표현하고 싶은 것들이 많아지고 다양해질수록, 한 소스코드에서 관리하기 어려워진다.

 

객체지향적인 프로그래밍을 하기 위해 지켜야할 SOLID, 5가지 원칙 첫번째 SRP가 있다.

 

Single Responsibility Principle

 

이것이 의미하는 것은 한 소스코드엔 하나의 책임만 존재해야하는 것이다.

 

만들기는 어렵지만, 객체지향적인 코드를 작성하면, 소스 코드의 재활용성이 올라가고, 읽기 쉬워지니 유지보수성이 올라가, 생산성이 올라간다.

 

그래서 나는 소스코드에 매번 텍스트를 넣게 하는 것보다, txt file로 저장한 것을 불러올 수 있도록 하고 싶었다.

 

찾아보니 다음과 같이 쓸 수 있었다.

 

#include <stdlib.h>
.... 중략 ...
void paint_old()
{
    FILE *ptr;
    char ch;

    ptr = fopen("rabbit.txt", "r");

    if (NULL == ptr)
    {
        printf("cannot read the file. error! \n");
    }
    do
    {
        ch = fgetc(ptr);
        printf("%c", ch);
    } while (ch != EOF);
    printf("\n");
    fclose(ptr);
    return 0;
}
.... 중략 ...
 

old버전의 내가 만든 paint함수이다.

소스코드를 간략히 소개하자면, FILE 구조체의 포인터를 이용해 fopen으로 주소를 받고,

읽지 못하면 에러 메세지를, 읽을 수 있으면 한 글자씩 char로 받아 화면에 출력한다.

EOF를 읽으면 fclose로 포인터를 반환하도록 했다.

 

     / \
    / _ \
   | / \ |
   ||   || _______
   ||   || |\     \
   ||   || ||\     \
   ||   || || \    |
   ||   || ||  \__/
   ||   || ||   ||
    \\_/ \_/ \_//
   /   _     _   \
  /               \
  |    O     O    |
  |   \  ___  /   |
 /     \ \_/ /     \
/  -----  |  -----  \
|     \__/|\__/     |
\       |_|_|       /
 \_____       _____/
       \     /
       |     |
 

그러면 이런 아스키 이미지를 그려넣을 수 있었다.

 

하지만, 여기서 부족했다. 나는 함수 하나로 여러가지 파일을 접근하고 싶은데??

 

// main function
int main(){
    ...
    paint_old_add_path("src/rabbit.txt");
    paint_old_add_path("src/two-birds.txt");
    ...
    return 0;
}
// 함수 정의
void paint_old_add_path(char* path)
{
    FILE *ptr;
    char ch;

    ptr = fopen(path, "r");

    if (NULL == ptr)
    {
        printf("cannot read the file. error! \n");
    }
    do
    {
        ch = fgetc(ptr);
        printf("%c", ch);
    } while (ch != EOF);
    printf("\n");
    fclose(ptr);
    return 0;
}
 
     / \
    / _ \
   | / \ |
   ||   || _______
   ||   || |\     \
   ||   || ||\     \
   ||   || || \    |
   ||   || ||  \__/
   ||   || ||   ||
    \\_/ \_/ \_//
   /   _     _   \
  /               \
  |    O     O    |
  |   \  ___  /   |
 /     \ \_/ /     \
/  -----  |  -----  \
|     \__/|\__/     |
\       |_|_|       /
 \_____       _____/
       \     /
       |     |
  (o o)   (o o)
 (  V  ) (  V  )
/--m-m- /--m-m-
 

함수에 경로를 인자로 전달했더니, 부엉이가 생겼다!

 

 

그럼 배너 텍스트도 따로 관리하고 싶어졌다.!

    // main 함수 내
    paint_old_add_path("src/intro.txt");
 
??꽑 泥쒖옣?대떎.

"?ш릿 ?대뵒?멸?.."
 

이런.. 한글이 다 깨져버렸다. txt 는 UTF-8 로 인코딩을 했는데, fopen 의 기본 디코딩 방식이 ANSI이다.

 

그리하여 찾아본 바로,

    FILE *fp = fopen(file_name, "r, ccs=UTF-8");
    wchar_t c;
 

ccs의 정확한 의미는 구글링해도 찾을 수 없었다. 유력한 건 "const char set(?)" 하지만 다음과 같은 추가 설정으로 UTF-8 인코딩 방식의 파일을 읽을 수 있었고,

r
읽기 모드
w
쓰기 모드
a
append 모드
b
binary 모드
t
text 모드 (binary로 된 것을 읽을 때)
+
update 모드 (read + write 둘 다 가능)

 

모드 설정을 다음과 같이 할 수 있는 걸 알게 되었다.

 

또한, UTF-8은 다양한 언어를 표현할 수 있어, 용량이 더 커야했다. 그래서 사용하는 자료형이

wchar_t 를 사용한다.

 

그렇게 ch를 담았더니..

 

낯선 천장이다.

여긴 어디인가.................................................................. (무한 반복 됨)
 

EOF를 인식하지 못하고 while문 밖으로 나오지 못하고 있었다.

 

그래서 찾아봤지만, wchar_t로 명확히 EOF를 인식할 수 있는 방법을 못찾았고, @를 읽으면 내가 정의한 EOF다.

 

라고 코드를 수정했다. 또한 <Windows.h> 의 Sleep함수를 사용해서 마치 텍스트가 타이핑 되는 것처럼 만들어보았다.

void paint(char *file_name, int ms)
{
    FILE *fp = fopen(file_name, "r, ccs=UTF-8");
    wchar_t c;
    wchar_t end = '@';
    setlocale(LC_CTYPE, "");
    while (c != end)
    {
        fwscanf(fp, L"%lc", &c);
        if (c != end)
        {
            Sleep(ms);
            wprintf(L"%lc", c);
        }
    }
    printf("\n");
    fclose(fp);
    return;
}
 
 

 감사합니다.

 

 

空手來 空手去(공수래 공수거)

빈손으로 와서 빈손으로 간다

 

우리의 삶도 공수래 공수거인 것처럼, 프로그램도 마찬가지다.

 

운영체제의 허락을 받으면, RAM 공간 속에 자리 잡고 자기 일이 끝나면 홀연이 사라진다.

 

자신을 기리듯 결과물을 화면을 통해 보여주거나, File 형태로 HDD, SDD 에 저장한다.

 

 

그런데, C언어는 메모리를 할당 받으면 어떻게 쓸까?

 

위키에 나온 설명으로는, RAM의 일정 영역을 할당 받으면, 거기서

 

[Code Memory] - [Data Memory] - [BSS] - [Heap Memory] - [Stack Memory] 로 구분한다.

 

Ram Cell들은 Row 와 Column으로 구성된 2차원 배열로 알고 있다. 결국 풀어서쓰면 이런 List 형태의 선형 구조로 바뀔 수 있다.

 

 

프로그램을 실행시키는 행위는 다음과 같이 풀어 쓸 수 있다.

 

* 운영체제에 프로그램 구동을 요청한다.

 

* 운영체제는 허가된 프로그램인가 확인하고, 이상이 없으면 RAM 에 자리를 만든다.

 

* SDD에 저장된 파일을 RAM에 복사한다.

 

* 요청한 파일을 동작시킨다.

 

* 계산이 필요하면 CPU를 쓴다.

 

* 저장이 필요하면 SSD에 저장한다.

 

* 프로그램을 종료하면, 운영체제는 RAM의 점유를 뺐는다.

 

 

그럼 이제 오늘의 주제다. 우리가 선언하는 변수는 어디에 저장되는가?

 

프로그램이 동작할 때, 전역 변수냐, 지역 변수냐에 따라 저장되는 공간이 다르다.

 

Scope에 대한 개념을 이해해야 하는데, 메모리에 요청하는 방식에 따라 다르다.

 

"이 A라는 변수는 코드 전반에 걸쳐서 쓸 예정이야. 날라가지 않게 따로 저장해줘." => 전역 변수

 

"이 B라는 변수는 여기 부분만 잠깐 쓰는거야. 쓰고나면 지워져도 돼." => 지역 변수

 

 

용도에 맞게 전역변수 Data Memory에 저장되고, 지역변수 Stack Memory에 저장된다.

 

그럼 코드로 테스트해보자.

( ※ 아직 포인터와 배열이 뭔지 모르면, 그냥 이런게 있구나 하고 나중에 다시 와서 보는걸 추천한다 ※)

 

#include <stdio.h>

int main(){
        static int A = 0;
        int B = 0;
        const int C = 0;
        static const int LUCKYNUM = 7;
        char* hello = "Hello";
        int arr[10];
        static int arr2[10];
        static const char chars[10];


        printf("static int              memory address : %p\n", &A);
        printf("int                     memory address : %p\n", &B);
        printf("const int               memory address : %p\n", &C);
        printf("static const int        memory address : %p\n", &LUCKYNUM);
        printf("char*                   memory address : %p\n", &hello);
        printf("int array               memory address : %p\n", &arr);
        printf("static int array        memory address : %p\n", &arr2);
        printf("static const char array memory address : %p\n", &chars);
        return 0;
}
 

다양한 방법으로 변수를 정의하고, 각각의 메모리 위치를 출력하도록 해보았다.

static int              memory address : 0x5572f6ece040
int                     memory address : 0x7ffca6b85b50
const int               memory address : 0x7ffca6b85b54
static const int        memory address : 0x5572f6ecc150
char*                   memory address : 0x7ffca6b85b58
int array               memory address : 0x7ffca6b85b60
static int array        memory address : 0x5572f6ece060
static const char array memory address : 0x5572f6ecc158
 

결과값은 0x557.... 어쩌고와 0x7ff... 저쩌고 두 분류로 나왔다.

 

낮은 메모리 주소값부터

 

[Code Memory] - [Data Memory] - [BSS] - [Heap Memory] - [Stack Memory]

 

를 Upload하기 때문에, static 이라는 조건이 붙으면 Data Memory로 분류되어 0x557....의 낮은 메모리 주소값에 저장되고,

 

그 외엔 0x7ff...로 시작하는 걸로 보아 Stack Memory로 저장되고 있음을 유추할 수 있다.

 

또한 선언의 순서에 따라, int와 const int를 보면 딱 4만큼의 차이가 있음을 볼 수 있는데,

64bit를 사용하는 Window의 int의 크기는 4byte이다.

 

 

※ 그럼 왜 자료형이 중요할까?

4byte int값 '10'은 메모리에 다음과 같이 저장될 것이다.

00000000 00000000 00000000 00001010
 

ASCII code로 인코딩 된 2byte char값 'A'는 메모리에 다음과 같이 저장될 것이다.

00000000 01000001
 

만약 이것을 문자가 아닌, 정수로 착오해서 메모리가 읽는다면?

65라고 읽을 것이다.

 

그럼 우리가 예상하는 결과와 크게 달라질 것이다.

 

자료형은 똑같이 0과 1로 이루어진 숫자들의 나열을 어떻게 해석할 것인가를 명명해주기 때문에, C를 배우고 있는 상황에선 중요하다.

 

고급 언어를 주로 사용하는 프로그래밍 시대에 굳이 알 필요가 있을까 하지만,

언젠가 도움이 되겠지 라는 마음에 글로 정리하여 공유합니다.

 

감사합니다.

 

 

C 언어를 공부 중이다.

 

포인터에 대해 어느정도 알고 있었지만, 오랜만에 볼 때마다 헷갈리는 부분들이 있어서 다시 이해를 바로잡고자 정리 글을 써본다.

 

우선 포인터에 대해 이해하기 앞서 배경 지식이 필요하다.

 

0과 1로 컴퓨터는 어떻게 계산을 하는가? and, or, not, xor, nand, xnor, nor의 논리회로를 이용하여 계산하고 결과값을 저장한다.

이런걸 누적 시키면?

 
작은 논리회로, ALU(Arithmatic Logic unit)가 된다. 저 다리에 신호를 어떻게 주느냐 따라서 output 신호가 달라진다.

ALU가 모이면 CPU가 된다.

비약이 심했지만, 결론은 CPU 는 계산기다. 어디선가 데이터를 불러오고 어디론가 저장을 할 수 있어야한다.

그 어디서가? 어디인가?

CPU는 빠르게 데이터 처리를 하기 때문에 빠른 접근과 저장이 가능한 Cache(캐시)를 이용한다.

요즘은 CPU가 멀티 코어를 지원함으로써 각 코어에 가까운 작고 빠른 캐시(Cache L1)를 붙이고, 공유 개념의 L2, L3 Cache를 설계한다.

결국 이런 캐시 메모리들의 용량은 너무 작기 때문에, 데이터들을 오래 들고 있을 수 없다.

 

주기억장치 RAM으로 이동해야한다.

 

RAM은 Random Access Memory의 약자로, 저 수많은 금니들을 통해 각 검정칩에 저장된 데이터에 빠른 접근이 가능하다.

 

저장할 수 있는 용량이 CPU가 가진 용량보다 훠얼씬 많다.

 

그래서 우리는 프로그램을 RAM에 띄워놓고 필요한 부분만 CPU에서 계산하면 된다.

 

.....

 

포인터 이야기를 하다가 왜 여기까지 왔느냐 하면..

 

포인터는 이 RAM의 주소를 저장하기 떄문이다.

 

#include <stdio.h>
int main(){
    int a = 10;
    int* ptr = &a;
    *ptr = 5;
    printf("%d", *ptr);
    return 0;
}
 
5
 

포인터를 이용해 변수의 값을 변경한 간단한 코드다.

 

여기서부턴 개인적으로 이해하기 위한 주관적 해석입니다.

본디 변수(variable)는 2가지의 정보를 갖고 있다. Stored Data와 Memory Address 이다.

int a;
 

이 상태는 Stored Data는 Garbage data, Memory Address는 받아둔 상태라고 볼 수 있다.

 

10;
 

상수(constant)는 변수가 아니다. 따라서 저장할 수 없다.

 

int a = 10;
 

이 행위는 a 변수에 Garbage data 대신 10이라는 수가 이진수로 저장될 것이다.

00000000 00000000 00000000 00001010 (2)
 
 

 

감사합니다.

 

올해 3월 정보처리기사 필기를 통과하고, 4월 말 중에 실기 시험을 예정하고 있다.

 

대부분의 문제가 실무 위주의 코딩 + DB 위주의 문제라고 하니 직접 타이핑하면서 공부해보고자 한다.

 

꼭 그럴 필요는 없지만, linux 상에서 db 환경을 조성하기 위해..

 

저는 실습실 Windows 에 WSL 을 설치하고, Ubuntu 상에서 mysql 을 설치하여 진행했습니다.

 

(WSL : 윈도우 기본 배포로 리눅스 가상환경을 간편하게 설치해줌)

(Ubuntu : Microsofts 에서 기본 제공하는 유명한 무료 리눅스 운영체제)

(mysql : Oracle사의 무료 DB)

 

Ubuntu logo image
MySQL logo image

(설치 방법은 검색으로 쉽게 찾을 수 있으니, 학우분들 중에 혹시나 안되면 설치 도와드리겠습니다)

 

https://www.mysqltutorial.org/

MySQL Tutorial – A comprehensive MySQL Tutorial

MySQL Tutorial website provides a comprehensive MySQL tutorial that helps you master MySQL fast, easy & fun.

www.mysqltutorial.org

 

Window 커맨드창에서 '''wsl'''을 명령하면, linux 가상 환경으로 접속된다.

C:\Users\KDT107>wsl
 

그러면, sudo 명령어를 통해 mysql을 실행시킨다.

user@DESKTOP-R7GJ6RM:/mnt/c/Users/KDT107$ sudo mysql
 
 
사진 삭제

사진 설명을 입력하세요.

그럼 다음과 같은 화면으로 정상접속 되는 것을 확인해볼 수 있다.

 

혹시나 다시 안들어가지는 경우가 있는데, 다음 명령어를 한 번 실행시키면 접속 가능해진다.

$ sudo service mysql restart
 

 

 

===========================================

 

 

※ SQL 은 무엇인가?

Structured Query Language 의 약자이다. 해석하면 구조화된 질의 언어.

 

결론은 구조가 정해진 구문을 만들어 전달하면 DB가 이를 대답하는 것이다.

 

 

※ 왜 SQL, DB를 사용하는가?

SQL을 사용하는 이유는 DB를 조작하기 위해 있는 것. DB는 Database의 약자로 데이터를 저장하는 곳이란 의미이다.

현재엔 컴퓨터 과학의 발전으로 많은 데이터들을 구조화하여 빠르게 저장하고 불러올 수 있는 능력을 가지고 있다. 또한, 연결의 가지(connection pool)를 조절함으로써 다중 접속이 가능하게 정보에 접근할 수 있다. 이 이후로는 너무 깊어지므로 이정도만 정리한다.

 

※ RDBMS?

relational database management system의 약어로 DB들 중에서, 중복을 줄이고 속도를 올리기 위해 관계형 데이터베이스란 것이 있다. 일단 RDBMS 타입이 현재 주류를 이루고 있으며, 오늘 사용할 MySQL도 RDBMS이다. 조작한다는 건, 표도 만들고 지우고 수정하고, 정보(row)를 추가하고, 롤백(?)하고 할 수 있어야한다.

 

※ 트랜잭션? (Transaction)

한 번 내뱉은 말은 수정할 수 있나? 없다. 그러기 때문에 신중해야한다.

DB는 중요한 정보가 담긴 곳이며, 여러 사람이 볼 수 있는 곳이다.

만약 정보를 쓰다가 중간에 에러가 발생하면 어떻게 해야하는가? 그대로 놔두어도 될까? 안된다.

이런 일을 방지하기 위해 DB에는 트랜잭션이라는 일련의 과정을 거쳐, 수정할 테이블을 잠깐 복사해서 입력 처리를 마무리하고, 이상이 없으면 본체에 합본(commit) 시킨다. 만약 중간에 에러가 발생하면 없던 일로 되돌리기 위해 롤백(rollback) 한다. 이런 과정을 Transaction 이라 한다.

 

 

※ 배우면 좋은 점?

모든 RDBMS SQL syntax에 대해 알 필요는 없다. SQL자체가 ISO 국제 공통 기준으로 어느정도 비슷하며, 요즘은 ORM(Object-Relational Mapping) 이라고 해서 자동으로 테이블 생성도 해준다. 그래도 기본은 알면, 원하는 만큼 DB를 직접 다룰 수 있게 된다.

 

더군다나 우린 데이터 기반 AI SW개발자이다. 데이터 기반이면, DB와 친해질 수 밖에 없다!

 

===========================================

 

※ SQL은 크게 네 가지로 분류한다. DDL, DCL, DML, TCL

DDL : Database Definition Language

DCL : Database Control Language

DML : Database Manipulation Language

TCL : Transaction Control Language

 

쉽게 생각한다. 만드는 말, 정보 접근에 대해 통제하는 말, 정보를 추가/삭제/수정하는 말, 트랜잭션을 조작하는 말들로 분류해놓고, 모두 RDBMS 롤 조작하므로 SQL이라고 통칭한다.

 

감사합니다.

 

오늘 C언어 역사에 대해 배웠다. C언어를 처음 배우는게 아니기 때문에, 이전에 무심코 지나쳤던 부분에 대해 알아보고자, 주제를 선정해보았다. [2탄]

 

이것은 무엇일까? from https://en.wikipedia.org/wiki/Punched_card

 

1940년대, 세계 전쟁 중 주류를 이루던 컴퓨터들이다.

 

2차대전 중에는 독일군은 내부적으로 암호를 사용하기 위해 <애니그마>를 발명하여 자기네 통신을 암호화했다.

애니그마, 독일군 암호화 장치. 그날의 암호표를 보고 선과 내부 톱니바퀴를 셋팅하면, 해독하기 어려운 언어로 변환된다.

이를 해독하기 위해, 영국 첩보국은 "앨런 튜링"이라는 미국 프리스턴 박사를 고용하여 이 암호들의 해독을 지시했다. 그리고 그 해독의 끝에 완벽하진 않지만

 

"튜링 봄브" 라는 해석기를 만들었다. 거의 독일군의 암호를 풀어낸 와중에 전쟁이 끝나버렸다고 한다.

아직은 프로그래밍 언어보단 전자, 전기에 더 관련있어 보인다.

그러던 중, 최초로 프로그래밍 가능한 컴퓨터가 발명된다 in 1941, German

뮌헨 국립 독일 박물관에 전시된 추제 Z3 모형. from https://upload.wikimedia.org/wikipedia/commons/4/4c/Z3_Deutsches_Museum.JPG

천공 카드(punch card)를 통해 데이터 연산을 했다고 한다.

 

이런 타입의 기계들이 계속 발전을 거쳐 많은 컴퓨터들이 발명되었고, Mark1, ENIAC, UNIVAC.. 그런 것들이다.

 

필연적으로 만들 수 있는 프로그램들의 크기가 작을 수 밖에 없었다..

 

 

 

이를 해결하기 위해 작은 프로그램들을 모아 큰 프로그램을 만든다는 뜻으로 1949년 어셈블리어가 등장한다.

section	.text
   global _start     ;
	
_start:	            ;
   mov	edx,len     ;
   mov	ecx,msg     ;
   mov	ebx,1       ;
   mov	eax,4       ;
   int	0x80        ;
	
   mov	eax,1       ;
   int	0x80        ;

section	.data
msg db 'Hello, world!', 0xa  ;
len equ $ - msg     ;
 

무슨 프로그램을 실행시키기 위한 것일까? 실행 결과를 보자.

Hello, world!
 

아직 무슨 뜻인지는 모르겠지만, 맨 밑단에 msg 와 중간 _start 의 ecx,msg 가 뭔가 관련있어 보인다.

 

그정도까지만 알고, 일단 넘어가도록 한다.

 

 

이후 Auto Code 라는 프로그래밍 언어가 나왔고,

c@VA t@IC x@½C y@RC z@NC
INTEGERS +5 →c           # Put 5 into c
      →t                 # Load argument from lower accumulator
                         # to variable t
   +t     TESTA Z        # Put |t| into lower accumulator
   -t
          ENTRY Z
SUBROUTINE 6 →z          # Run square root subroutine on
                         # lower accumulator value
                         # and put the result into z
  +tt →y →x              # Calculate t^3 and put it into x 
  +tx →y →x
+z+cx   CLOSE WRITE 1    # Put z + (c * x) into
                         # lower accumulator
                         # and return
 

Mark1 을 돌리기 위한 최초의 컴파일 언어라고 하는데 아직도 무슨 뜻인지 전혀 감도 안온다.

 

 

이후, 1957년 Fortran 이라는 언어가 나오게 된다. IBM에서는 자신들의 최신 컴퓨터를 사용하기 위해 컴파일 언어를 만들었다.

 

program hello
  ! This is a comment line; it is ignored by the compiler
  print *, 'Hello, World!'
end program hello
 

이 소스코드를 컴파일을 거치면,

$> gfortran hello.f90 -o hello
 
Hello, world!
 

드디어, 뭔가 눈에 보이는 프로그래밍 언어의 계보가 보인다.

 

 

 

이후 1년 뒤 Algol이라는 언어가 나오게 되는데, Algorithm language란 뜻이다.

BEGIN
FILE F (KIND=REMOTE);
EBCDIC ARRAY E [0:11];
REPLACE E BY "HELLO WORLD!";
WHILE TRUE DO
  BEGIN
  WRITE (F, *, E);
  END;
END.
// 이상은 'hello world' 출력, 이하는 문자 비교 코드
BEGIN
INTEGER p, q;
y := 0; i := k := 1;
     for p := 1 step 1 until n do
         for q := 1 step 1 until m do
             if abs(a[p, q]) > y then
                 begin y := abs(a[p, q]);
                     i := p; k := q
                 end
 END Absmax
 

 

배열이나 변수, 반복, 분기 모습이 보이기 시작한다.

 

실제로 ALGOL은 이후로 나오는 PHASCAL, BC에 영향을 주었다.

 

 

이후엔 우후죽순 늘어나는 프로그래밍 언어를 통합 대체하기 위해 1959년 COBOL이란 단어가 등장하였고, 상업용으로 광범위하게 쓰였고, 비교적 최근까지 이용했다고 한다.

IDENTIFICATION DIVISION.
PROGRAM-ID. HELLOWRD.

PROCEDURE DIVISION.
DISPLAY "SIMPLE HELLO WORLD".
STOP RUN.
 

같은 연도, MIT에서는 LISp (list proccessing) 라는 언어를 발표한다.

(format t "Hello, World!")

(list 1 5 2 1)
(lambda (arg) (* arg 2))
 

주목할 것은 리스트의 사용과 람다의 사용이다. 어? python? 이 생각나게 한다. 인공지능에 영향을 주었다고 한다.

 

 

1964년엔 BASIC이라는 언어가 나왔다. 우리가 C 이전에 부르는 B를 의미한다.

BASIC의 의미는 무엇인가?

 

이 시기엔 개인용 컴퓨터가 속속 등장하면서, 선풍적인 인기를 끌었고, Microsoft 사에서 주력 언어로 사용하게 된다.

PRINT "Hello World!"
 

간단한 코드를 보라.

 

이후 1970년, 포트란보다 익히기 쉬운 교육용 언어 PASCAL이란 코드도 나오고 이는 나중에 구조적 프로그래밍, 모듈화에 영향을 주었다고 한다.

 

1972년, smalltalk-80 이란 코드의 등장은 OOP(객체지향 프로그래밍), python같은 dynamic typing, GUI, IDE에 영향을 끼쳤다고 한다.

당시 사용되었던 SMALLTALK-80

그리고 같은 연도, Bell 연구소에서 C 언어를 발표하게 된다.

 

 

 

얕고 넓게 C 언어 이전의 프로그래밍 언어들에 대해 훑어보았다. 지금 주력으로 사용되는 언어들의 근간이 되는 언어들로 공부하면서 흥미로웠고, 현재는 이전에 비해 프로그래밍 언어의 개발은 많지 않지만, 대신에 framework와 npm 같은 library 들이 무궁무진하게 늘어나면서, 개발 생태계는 다채롭고 풍요로워지고 있어 감사하다.

 

이상으로, 1964년도에 사용하던 체신 컴퓨터의 작동 모습을 보며 안도의 한숨을 쓸어내리며 또 공부하러 가야겠다.

https://youtu.be/YnnGbcM-H8c

"""Random variable generators.

    bytes
    -----
           uniform bytes (values between 0 and 255)

    integers
    --------
           uniform within range

    sequences
    ---------
           pick random element
           pick random sample
           pick weighted random sample
           generate random permutation

    distributions on the real line:
    ------------------------------
           uniform
           triangular
           normal (Gaussian)
           lognormal
           negative exponential
           gamma
           beta
           pareto
           Weibull

    distributions on the circle (angles 0 to 2pi)
    ---------------------------------------------
           circular uniform
           von Mises

General notes on the underlying Mersenne Twister core generator:

* The period is 2**19937-1.
* It is one of the most extensively tested generators in existence.
* The random() method is implemented in C, executes in a single Python step,
  and is, therefore, threadsafe.

"""

이것은 python random.py 모듈의 주석 내용이다.  만들 수 있는 수에 대해서 요약되어 있으며, 오늘 이것들 중 몇 개의 random 함수를 다뤄본다. 

 

< 실수 관련 >

import random

num1 = random.random()
print(f"random() = {num1}") #0.8737351792314224

num2 = random.uniform(1,10)
print(f"uniform(1,10) = {num2}") #5.387622011327463

num3 = random.randint(1, 10)
print(f"randint(1, 10) = {num3}") # 1~10 random int

num4_1 = random.randrange(0, 1000, 5)
print(f"randrange(0, 1000, 5) = {num4_1}") # 0-999까지 간격(step) 5에 해당하는 수 중 rand 추출

num4_2 = random.randrange(0, 10)
print(f"randrange(0, 1000, 5) = {num4_2}") # 0 ~ 9 중 수 1개 뽑기, 이렇게 사용하면 randint와 같다.

num5 = random.randbytes(1)
print(f"randbytes = {num5}") # 8byte (0~255) random byte value 반환

num6 = random.triangular(0, 1)
print(f"triangular = {num6}") # 0~1미만의 삼각함수 값을 반환

(1회차)

random() = 0.625753259433996
uniform(1,10) = 4.993728111936218
randint(1, 10) = 6
randrange(0, 1000, 5) = 365
randrange(0, 1000, 5) = 3
randbytes = b'J'
triangular = 0.8263672948031475

(2회차)

random() = 0.12223894921737943
uniform(1,10) = 3.014724048076995
randint(1, 10) = 6
randrange(0, 1000, 5) = 545
randrange(0, 1000, 5) = 6
randbytes = b'\xaf'
triangular = 0.5225005183685572

 

참고로, rand 함수는 C언어 random 함수처럼 seed를 통해 추출을 결정하므로, 완벽한 함수는 아니라는 걸 명심하자.

# Create one instance, seeded from current time, and export its methods from by random.py

random.seed(1)
num1 = random.random()
print(f"num1 = {num1}") #시드 1로 고정 시킨 상태

random.seed(1)
num2 = random.random()
print(f"num2 = {num2}") # 동일한 값이 나온다..
num1 = 0.13436424411240122
num2 = 0.13436424411240122

 

 

< 경우의 수 관련 >

import random

mylist = list("ABCDEFGH")
string1 = random.choice(mylist)
print(f"choice() = {string1}") # 제공한 list 중에 1글자 추출

string2 = random.choices(mylist,k=3)
print(f"choices() = {string2}") #제공한 list 중에 k만큼 추출(중복 포함)

string3 = random.sample(mylist, k=3)
print(f"sample() = {string3}") #제공한 list 중에 k만큼 뽑기(순열, 중복 없음)

string4 = random.shuffle(mylist)
print(f"shuffle() = {string4}") # return 없음
print(f"mylist = {mylist}") # myList의 변화를 잘 봐보자.
choice() = H
choices() = ['B', 'H', 'B']
sample() = ['D', 'H', 'E']
shuffle() = None
mylist = ['F', 'H', 'B', 'G', 'D', 'A', 'C', 'E']

 

조합과 순열이 편하게 함수로 제공된다는 점에서 알고리즘 문제, 블랙박스 테스트 때 사용할 값 등 여로모로 이용할 수 있을 것 같다. visit 매번 작성해줘야하는 자바보다 편하다!

 

 

+ Recent posts