※ 함수포인터

함수포인터는 프로그램을 간결하게 작성하기 위해 사용한다.

 

 

 

§  구조체 안에 함수를 넣을 수 있을까?

 

 

 

 

 

※ void 포인터

- type이 불분명할 때 사용 (ex malloc, calloc, realloc)

- 포인터의 type은 메모리(byte)를 얼마나 건너뛸 것인가를 결정

∴ 주소를 담는 것 이외에는 아무것도 할 수 없음

 

 

 

 

 

 

 

 

 

 

※ main함수로의 인자전달

 

 

 

 

 

 

※ 구조체 (struct) => 하나의 "자료형"처럼 사용, 다른 언어의 class와 비슷.

§ 구조체의 형태

struct 구조체이름 {
    해당 type이
    가졌으면 하는 멤버
};

struct의 크기는 멤버의 크기와 동일하다.

struct Point {
    int age; // 4 byte
    char name[20]; // 20 byte
    int x[20]; // 80 byte
}; // 총 104 byte

 

 

§ 구조체와 배열

#include <stdio.h>

struct Person{
    char name[20];
    char phone[20];
    int age;
};

int main(){
    struct Person arr[3];
    int i;
    for (int i = 0; i < 3; i++) {
        scanf("%s %s %d", arr[i].name, arr[i].phone, &arr[i].age);
    }
    for (int i = 0; i < 3; i++) {
        printf("%s %s %d \n", arr[i].name, arr[i].phone, arr[i].age);
    }
}

 

 

§ 구조체와 동적배열

 

 

 

 

 

 

※ 구조체와 포인터

 

 

 

 

 

 

 

※ 구조체와 typedef 선언

§ typedef 형식과 특징

typedef를 선언함으로 인해 struct 뒤의 이름을 생략할 수 있다.

 

 

 

 

 

※ 함수의 구조체 전달

- 함수는 항상 1개의 값만 return 할 수 있다. 따라서 값을 여러개 return 받고 싶을 때! 사용한다.

 

 

 

 

 

 

 

 

※ 구조체를 이용한 추상화

 

 

 

 

 

 

 

 

※ 공용체 (Union)

 

 

[ Mini Project ]

1. 프로그램 사용자로부터 int형 정수를 하나 입력받음

2. 입력받은 정수의 상위 2바이트와 하위 2바이트를 양수로 출력

3. 상위 1바이트와 하위 1바이트에 저장된 ASCII문자를 출력

 

 

 

[정답 코드]

#include <stdio.h>

typedef struct {
    unsigned short upper;
    unsigned short lower;
}DBShort;

typedef union {
    int iBuf;
    char cBuf[4];
    DBShort sBuf;
}icDBuf;

int main(){
    icDBuf buf;
    scanf("%d", &(buf.iBuf));
    
    printf("상위 2byte: %u \n", buf.sBuf.upper);
    printf("하위 2byte: %u \n", buf.sBuf.lower);

    printf("상위 1byte ASCII: %c \n", buf.cBuf[0]);
    printf("하위 1byte ASCII: %c \n", buf.cBuf[3]);
}

 

 

 

 

 

 

 

※ 열거형 (사실 #define 전처리기를 더 많이 사용함)

#include <stdio.h>

typedef enum{
    Do=1, Re=2, Mi=3, Fa=4, So=5, La=6, Ti=7
}Syllable;

void song(Syllable s){
    switch(s){
        case Do:
            puts("도는 도라지"); return;
        case Re:
            puts("레는 레코드"); return;
        case Mi:
            puts("미는 미나리"); return;
        case Fa:
            puts("파는 파랑새"); return;
        case So:
            puts("솔은 솔방울"); return;
        case La:
            puts("라는 라디오"); return;
        case Ti:
            puts("시는 시냇물"); return;
    }
}

int main(){
    Syllable tone;
    for (tone = Do; tone <= Ti; tone++) {
        song(tone);
    }
}

process 관련 설명: https://chan4im.tistory.com/33

 

this->OS.code(2)

OS Architecture: monolithic kernel과 micro kernel 두 종류가 있다. monolithic kernel micro kernel 단일체(monolithic)여서 OS 실행속도가 빠르다. 또한 Kernel 내부에 구현되어 있어서 내부함수로 call이 진행된다. 예: UNIX

chan4im.tistory.com

 

※ 프로세스 (process)

실행되는 프로그램으로 메모리가 할당된다.

 

Ex. Stack 과정

 

§ 왜? heap 영역을 사용하게 된 것일까?

그림 1.

 

 

 

 

 

 

※ malloc, calloc, realloc  /  free(ptr)

heap영역에 할당해야 하므로 포인터에 대한 연산으로 진행하는 경우가 대부분이다.

malloc: 인자가 1개이다. (memory allocation의 줄임말)

int **arr;
int X, Y;
arr = (int**) malloc (sizeof(int*) * Y);
for(int i = 0; i < Y; i++){
    arr[i] = (int*) malloc(sizeof(int) * X);
}

for(int i=0; i < Y; i++){
    free(arr[i]);
}
free(arr);

calloc:  인자가 2개이다. (clear allocation의 줄임말로 할당된 메모리가 0으로 초기화된다.)

int **arr;
int X, Y;
arr = (int**) calloc (sizeof(int*), Y);
for(int i = 0; i < Y; i++){
    arr[i] = (int*) calloc(sizeof(int), X);
}

for(int i=0; i < Y; i++){
    free(arr[i]);
}
free(arr);


realloc:
인자가 2개이다. (re allocation의 줄임마로 포인터의 크기를 재조절한다.)

int *ptr = (int*) malloc (sizeof(int) * 4);
for (int i = 0; i < 4; i++) {
    ptr[i] = i+1;
}
ptr = (int*)(realloc(ptr, 6 * sizeof(int)));
ptr[4] = 4;
ptr[5] = 5;

 

[할당 과정 설명]

 

왼쪽 코드는 그림1의 문제를 해결한 코드이다.

 

 

 

 

 

※ 포인터배열 & 배열의 포인터

포인터 배열: 포인터 변수를 모아놓은 배열

int *parr[3] = arr;

배열의 포인터: 배열을 가리킬 수 있는 포인터 [2차원 배열로 활용 가능]

int (*parr)[3] = arr;

 

다음 예시에 대해 살펴보자.

int arr[30];  => 배열 arr는 int형 포인터
int *arr[30]; => int형 포인터 배열 arr

 

 

 

 

 

 

 

 다차원 배열 & 포인터

 

 

 

 

 

 

 배열이름기반 포인터연산

 배열에 대한 포인터 연산

 

 

 

 

 

 

 

 포인터의 포인터 응용

 

※ 배열&포인터에 의한 문자열 표현

다음 예시에 대해 살펴보자.

char str1 [] = "My String";
char *str2 = "Your String";

Q. 이때, 각각에 저장된 문자열 "My String"과 "Your String"을 바꿀 수 있을까?

 

이와 관련된 코드를 좀 더 자세히 풀어보면 아래와 같다.

 

 

 

 

 

※ C언어의 인자전달방식은 "무.조.건!" 값의 복사(Call-By-Value)이다!

 

 

 

 

※ 포인터와 함수인자 전달 (Call-by-Value 방식!)

 

 

Ex. Swap함수와 함수 인자 전달

 

cf. Swap 함수 인자 전달 (feat. 이중포인터)

 

 

 

 

 

 

 

※ 포인터와 상수화(const)

 

 

※ 배열에 대한 기본 개념

https://chan4im.tistory.com/19

 

this.code(1).DS_ Array & Vector (STL) (★★★★★★)

※ Array (배열) ※ 1차원 배열 배열은 주로 여러 개의 동일한 자료형의 데이터를 한꺼번에 만들 때 사용된다. 예를 들어 a0, a1, a2, a3, a4, a5라는 6개의 정수형 변수를 A[6]으로 간단하게 선언할 수 있

chan4im.tistory.com

 

 

※ 1차원 배열

자료형  배열이름  [배열길이] 형태로 사용한다.

§ n개의 수를 입력받는 프로그램

int arr[n];
for (int i = 0; i < n; i++) {
    scanf("%d", &arr[i]);
}

 

Ex. 배열에 담기 (feat. 약수구하기)

#include <stdio.h>

int main(){
    int arr[100];
    int cnt = 0, N = 0;
    scanf("%d", &N);

    for (int i = 1; i <= N; i++) {
        if (N % i == 0){
            arr[++cnt] = i;    //cnt++;    //arr[cnt] = i;
        }
    }
    for (int i = 1; i <= cnt; i++) {
        printf("%d ", arr[i]);
    }
}

 

 

※ 배열을 이용한 문자열 변수 표현

 

 

 

 

 

※ 포인터

포인터는 주소를 "꺼내는" 연산이기에 포인터는 값과 그 값의 type을 알아야 한다!

* 연산자를 붙이면 주소를 따라가게 되며 &연산자는 주소를 꺼내는 연산자이다.

 

§ 직접접근과 간접접근을 이용한 값 변화

int a = 10;
int *ptr = &a;

a++;       // 직접접근
*ptr = 20; // 간접접근

 

ptr           // 포인터

*ptr         // 포인터가 가리키는 값

*ptr++     // 포인터가 가리키는 값을 가져온 후, 포인터를 한 칸 증가

(*ptr)++   // 포인터가 가리키는 값을 증가

 

 

 

 

 

 

※ 포인터 = 배열

명확히 말하자면 둘은 다르다. (https://chan4im.tistory.com/21 Case 3. 참조)

 

[Effective Modern C++ item 1]: template 형식 연역 규칙을 숙지하라!

※ 형식연역 (type deduction) 형식연역이 일어나는 방식을 확실히 이해하지 않는다면 Modern C++에서 효과적인 프로그래밍은 불가능하다. 1장에서는 이런 형식연역의 작동방식과 형식연역에 기초한 au

chan4im.tistory.com

배열과 포인터를 구분하지 않고 사용가능하지만, 배열형식은 포인터 형식과 다르다는 사실!

 

다만, 포인터는 연속된 메모리값을 사용하는데, 이때 배열이 포인터로 붕괴하기에 배열과 포인터가 같다 이해하고 사용하는 것이다.

 

 

 

 

 

 

 

※ 다차원 배열

 

 

 

 

※ switch 문

보통 if문 대신 사용하며 case를 나눌 필요가 있을 때, if-else를 여러번 쓰기 힘들 때 사용한다.

switch (n) // n은 정수형 변수로 전달되는 인자정보, n에 지정된 값에 따라 case 영역 실행
{
    case 'M':
        // 조건 입력
        break;
    case 2:
        // 조건입력
        break;
    default:
        // else문과 비슷한 역할
}

이때, break를 하지 않으면 다음 break가 있는 case문까지 같이 실행되기에 적는 것이 좋다.

§ break와 continue

break: 가장 가까운 반복문을 탈출한다.
continue: 실행위치와 상관없이 반복문의 조건검사위치로 이동한다.
          이때, 이후부터는 continue는 생략하고 재실행한다.

 

 

 

※ while 문 vs for 문

보통 while문은 특정 종료조건이 나타나기 전까지의 지속적인 실행을 위해,

보통 for문은 반복횟수가 정해져 있는 경우에 많이 사용된다.

 

※ 비트 연산자

메모리에 할당된 정수값을 bit단위로 논리연산을 실행하기 위해 사용한다.

 

 

 

 

 

 

 

 

※ 함수 선언

[함수 return 타입] [함수 이름] (인자) {
    /*
     * 
     */
}

인자 (argument): 함수 호출 시 전달되는 "값"

매개변수(parameter): 그런 인자를 받는 "변수"

 

 

 

 

 

 

※ 지역변수와 전역변수, static과 block scope

지역변수(local variable): 중괄호에 의해 형성되는 영역안에 존재, "스택"이라는 메모리 영역에 할당
전역변수(global variable): 초기화를 하지 않으면 0으로 초기화되며 많이 사용하면 효율이 떨어진다.

 

§ 지역변수와 Block Scope

특정함수, 명령문의 블록안에 선언된 변수는 블록범위(Block Scope)밖에서는 사용이 불가능하다!

int a = 1;

{
    a = 2; // a는 2로 초기화 됨
}

{
    int a = 5; // 앞선 a와는 전혀 다른 a
    // Block scope가 끝나면 사라짐
}

{
    a++; // 여기까지 a값은 2, 아래줄 실행 시 a=3으로 증가
}

printf("%d", a); // 3 출력

 

 

§ static: "한 함수 내"에서 "지역변수의 전역변수화"를 해주는 tool

선언된 함수내에서만 접근 가능 (지역변수의 특징)
1회만 초기화, 종료전까지 메모리 공간에 저장 (전역변수 특징)
★ 전역변수와 달리 Block Scope 내부에서만 접근 가능

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

※ 입출력 방식

scanf("%d", &num); // 입력
printf("%d", num); // 출력

이때, 입력의 &num은 변수 num에 입력한 내용을 저장한다는 뜻이며

printf에서는 num에 저장된 입력값을 출력한다는 뜻이다.

 

물론 %d이외에 다른 방법으로도 입력받을 data type을 정할 수 있다.

%d // 부호가 있는 "10진수 정수" (int, short, char)
%c // 값에 대응하는 "문자" (char, int, short)
%s // "문자열" (char*)
%p // "포인터 주소값" (void*)

이때, char는 정수형임을 주의!

char는 문자형처럼 보이지만 "실제로는 char형 변수에 저장되는 것은 정수이다."

 

※ 복합대입연산자

a += b  // a = a + b
        // b가 1이면 a++로도 사용

l-value에 저장하는 것! (l-value: https://chan4im.tistory.com/11)

 

this.code(1)_ C++, based by C

※ C++의 입출력 연산자, [>>, (istream&, Coord&);와 ostream& operator (b) ? (a) : (b)) ... int x = 5, y = 0; CALL_MAX(++x, y); // a가 2번 증가 CALL_MAX(++x, y+10); // a가 1번 증가 위의 경우, (++a>b) ? ++a : b 로 해석되기에 a가 2

chan4im.tistory.com

 

 

※ 전위, 후위 증감연산자

전위연산: ++a // a값 1 증가 후 실행         [선증가, 후연산]
후위연산: a++ // 속한문장 진행 후 값 1증가   [선연산, 후증가]

즉, 후위연산의 경우 "다음문장으로 넘어가야만!" 비로소 증감연산이 실행된다.

int a = 5;
a++; // 여기서는 아직 a값은 5
printf("%d", a); // 여기서의 a값은 6이됨

 

 

※ NOT 연산자 (with if문)

a가 3의 배수라면? 과 관련된 코드이다.

if (a%3 == 0)
if (!(a%3))

위의 둘은 같은 뜻인데, if(!(a%3))의 경우 생소할 수 있다. 이에 대한 풀이는 아래와 같다,

a가 3의 배수일 떼 => a%3 == 0 즉, 0이 나온다.
if (!0) 즉, 0(거짓)이 아님이란 뜻으로
if (true)와 같은 뜻이다.

 

 

※ main문의 구조와 return 0; 의 의미

int main(){
    /*
     * 
     */
    return 0;
}

여기서, return 0의 의미는 다음 2가지이다.

1. 실행중인 "함수의 종료"
2. 함수 호출영역으로 "값의 반환"

cf. C언어는 boolean 타입이 없어서 0만! false, 0 이외의 값이 true로 간주된다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1972년, 벨 연구소의 데니스 리치가 만든 범용 프로그래밍 언어로 세계적으로 많이 쓰이는 프로그래밍 언어중 하나이다.

 

[사용분야]

- 운영체제 및 디바이스 드라이버

- 마이크로 컨트롤러

- 임베디드 시스템

- 암호학

- CPython 등의 프로그래밍 언어 인터프리터

- 매우 빠른 계산속도가 필요한 프로그램, 라이브러리의 구성

 

위의 예시를 보면 알 수 있듯이 C언어로 짜여진 코드는 속도가 매우 빠르고 바이널 크기도 작아 속도가 매우 빠르다.

따라서 정밀기계 등의 적은 메모리공간에서도 작동할 수 있거나 시시각각 빠른 연산이 필요할 때 많이 사용된다.

 

하드웨어나 컴퓨터 아키텍처를 배우게 된다면, C언어의 특징은 오히려 장점이 된다. Java나 Python 같은 언어들은 일반적인 상황에서 생산성을 높이기는 좋지만 특정한 상황에서 속도를 높이기는 어렵다. 일반적인 개발을 하려면 많은 상황을 처리할 수 있도록 강력하고 복잡하게 만들어야 하기 때문이다.

따라서 고성능이 필요한 특정 목적이 필요할 경우 언어에서 쌓은 추상화의 장벽을 뚫고 저수준(low level) 개념을 이용할 필요가 있는데, 이에 관한 개념을 제대로 이해하려면 처음부터 OS와 기계 제어를 위해 태어난 C언어를 사용하는 것이 가장 효과적이다. 다시 말해, C언어를 공부한다는 말은 곧 하드웨어를 공부한다는 말과 같다고 할 수 있다.

 

특히나 다른 언어에 비해 메모리관리를 할 수 있어서 (java 등의 언어는 garbage collector가 자동으로 메모리 누수(memory leak)을 잡아준다.) 메모리 누수를 모두 잡는다는 가정하에 매우 뛰어난 메모리 관리효과를 기대할 수 있다.

물론 이는 단점이 될 수도 있지만 말이다.

 

단점은 문자와 문자열, 포인터와 배열의 혼동과 범위를 넘어선 배열접근(buffer overflow) 등을 꼽을 수 있다.

 

하지만 이런 여러 단점들에도 C언어는 50여년이 훨씬 지난 지금에도 여전히 자리를 굳건히 지키고 있으니 배워보는것은 추천이 아니라 필수라 생각한다.

※ Supervised learning 과 Unsupervised learning

 Supervised learning (지도학습) _ Classification, Regression, etc.

정답과 오답 등과 같은 답이 있는 train dataset (학습데이터)로 학습시키는 것

 

§ 지도학습 알고리즘

  • 선형 회귀(linear regression)
  • 로지스틱 회귀(logistic regression)
  • k-최근접 이웃(k-NN : k-Nearest Neighbors)
  • 결정 트리(decision trees)
  • 신경망(neural networks), Deep NN
  • 서포트 벡터 머신(SVC : support vector machines)
  • 랜덤 포레스트(randome forests)

 

Unsupervised learning (비지도학습) _ Clustering, PCA, etc.

정답과 오답 등과 같은 답이 없는 train dataset (학습데이터)로 학습시키는 것

 

 

 

 

 

 

 

 

※ (Linear) Regression

장점: 사용하기 쉽고 설명력이 있다. (popular and easy to use, explain with prediction)

단점: 정확도와 linear 관계성을 설명해야 한다. (redundant features, irrelevant features)

 

Examples

▶ 목적:  how to predict y-values (continuous values)

 

 

 

§ β값은 어떻게 찾을 것인가?

1차 직선그래프에 대해 빨간 점과 그래프 사이의 y축과 평행한 거리가 error값이 된다.

 

 

[ β_hat 구하는 방법 증명 ]

 

 

 

 

 

 

 

※ Model evaluation (모델 평가) [ feat.   y,  y_hat ]

Correlation value: 상관계수

 

 

 

 

 

 

 

※ Regularization (규제화)

 

 

 

 

 

 

 

 

※ Nonlinear Regression

- input과 output사이의 관계성이 선형(nonlinear)일 때

 

 

 

 

※ Logistic Regression

 

※ Logistic Function

 

 

 

 

 

※ Logistic Regression 의 해석 방법

 

 

 

 

 

※ (Linear)Regression  vs  Logistic Regression

§ Regression

장점: 사용하기 쉽고 설명력이 있다. (popular and easy to use, explain with prediction)

단점: 정확도와 linear 관계성을 설명해야 한다. (redundant features, irrelevant features)

 

 

§ Logistic Regression

장점: 해석력이 괜찮고 사용하기 편하다. (Interpretability, Easy to use)

단점: 예측력(prediction)이 다른 모델에 비해 뛰어난 편에 속하지는 않는다. (Performance)

 

 

 

 

'A.I > Machine Learning_이론' 카테고리의 다른 글

[Machine Learning].Bayesian Classifier_이론  (0) 2022.11.04

+ Recent posts