[카테고리:] 컴퓨터

  • 고유값, 고유벡터 구하기

    내가 이걸 왜 만들었지.

    아무튼, 복소수로 3차 정사각형 행렬의 eigenvalue와 eigenvector 찾는 프로그램 소스다. 사용법은 각자 공부해 보시길. 정 모르겠으면 댓글로 문의바람. 임의의 n차 행렬이었으면 어딘가에 올렸을지도 모르지만, 그냥 3차 행렬로 고정되어 있음. 포인터같은거 전혀 없이 전부 변수로만 넘겨줌. 언젠가 포인터로 변수 넘겨주는 프로그램으로 바꾸고 싶음.

    혹시 버그 발견하게 되면 알려주시기 바람.

    산수 공부하는데 도움이 될까 하여, 연구와 관련된 부분을 빼고 올림. 빼는 과정에서 뭔가 이상해질수도 있음.

    gcc로 컴파일 할 때는 -lm(link math)옵션이 필요함.

    라이센스는 GPL이며, 특별히 문의해도 좋음.


    *최적화같은거 전혀 신경쓰지 않았음.


    eigenvector.h

  • 이뭐병

    이거야 원…피해망상이라도 걸릴 것 같은 일이 일어났다.

    지난주까지, gcc에 math.h에서 연결해서 쓰던 atan



    [각주:

    1

    ]



    하고 log



    [각주:

    2

    ]



    함수들이, 갑자기 정신을 잃고 나한테 헛소리를 한다. nan



    [각주:

    3

    ]



    이라든가, inf



    [각주:

    4

    ]



    라든가.

    그럼 대체 지지난주까지 잘 작동했던 그 함수는 어디갔는데…

    결국 나만 교수님한테 개갈굼 받게 생겼네. “넌 정신이 있는거니?”

    내가 지금까지 환상을 봤나? Maple 결과랑 잘 맞춰봤었는데…

    미치겠다. 젠장.

    추가

    square root, cubic root, log, arc tan, arc cos함수를 전부 새로 코딩했다. 미쳤지. 애초에 시작하는게 아니었는데 -_-;

    그러나 결과에는 별다른 영향이 없다는 거.

    산수공부는 많이 하게 되었다. C언어에서 연산자 여러개 겹쳐쓰면 빡(=nan)난다는 것도 알았고

    추가2

    전에는 나눗셈 때문에 골치아팠는데.

    Maple은 왜 지맘대로 3차방정식 근의 순서를 바꾸는 것일까.

    아무튼, 내 코드에서 3차방정식도 제대로 풀리는 것으로 보인다.

    추가3

    문제의 원인은 놀랍게도 #include를 빼먹어서였다. 왜? 왜 빠져 있었지??

    그러나 atan이 가진 부호 문제때문에 그냥 내가 직접 작성한 함수를 쓰기로 했다. log는 math.h에 있는걸로 쓴다. 제곱근은 괜찮은데, 세제곱근에 문제가 있어서, 세제곱근도 직접 작성했다. 에휴. 삽질.

    추가4

    atan의 부호 문제를 해결한 함수가 atan2더라. 역시 난감하다 -_-;

    아무튼, 그럭저럭 괜찮은 결과가 나왔으니, 이제 오늘만 밤새면 된다. 결국 직접 만든 함수 쓰는건 세제곱근 뿐.

    1. arc tangent, 탄젠트의 역함수

      [본문으로]
    2. 지수함수의 역함수

      [본문으로]
    3. Not A Number. “이건 숫자가 아닌겨”

      [본문으로]
    4. infinity. “이건 숫자가 아닌것도 아닌겨”

      [본문으로]

  • 블로그에서 수식이 된다.


    http://php.chol.com/~pobi1969/tt/12

    이곳에서 보았다.



    수식표현이 된다.

    $d/dx x^n = n x^{n-1}$

    $\frac{n^2}{n+n^2}$

    TeX의 문법을 대충 다 지원하는 것 같다. 이것으로, 내 블로그의 표현력이 한층 늘어나게 되었다.

    사실은 블로그가 아니라 html 에 위에서 설명된 자바스크립트 파일을 넣기만 하면 된다.

    참고로 파이어폭스에서는 그냥 보이고 익스플로러에서는 mathplayer를 설치해야 한다고 한다.


    http://www.dessci.com/en/products/mathplayer/download.htm?src=mplogo


    ileshy

    님의 조언에 따라 LaTeX을 쓰는 걸로 바꿔봤다.

    이건 TeX의 문법을 다 지원한다고 한다. 괜찮은 것 같다.

  • C로 배우는 산수

    C언어를 이용해서 산수를 처음부터 해보자. 오늘의 주제는 복소수로 사칙연산 하기다.

    예제로 나온 코드는 전부 내가 직접 작성한 코드이다. 뭐 복사하나 새로 만드나 비슷비슷할테니 코드의 저작권을 따지지는 않도록 하겠다.

    더불어, 어차피 복소수를 사용할 수 있는 방법은 아주 다양하고, 기존에 잘 쓰고 있는 방법이 많이 있을 거라고 생각한다. 내가 이걸 만든 이유는 배우는 것 보다 새로 짜는게 더 빠를 거라는 착각에 빠져서 만든 거였다. 다른 사람들은 그냥 기존에 있는 좋은 방법들을 사용하기를 바란다.

    일단, 복소수가 어떤건지 먼저 정해줘야 한다.

    //the type definition of complex number

    typedef struct {

    double x;

    double y;

    } cnumber;

    typedef a b; 라고 쓰면 a라는 형식을 b라는 이름을 갖는 형식으로 쓰겠다는 뜻이다.

    예를들어 typedef double merong; 으로 쓰면, 변수를 선언할 때 double a; 로 안하고 merong a; 로 해도 된다.

    struct는 구조체를 선언한 것이고, cnumber라는 이름을 줬다. cnumber는 안에 x와 y를 멤버로 가지는데, 불러올때는 점을 찍거나 화살표 연산자로 불러오면 된다.

    이제 덧셈을 해보자.

    //The addition of two complex numbers z and w

    cnumber add_cnum(cnumber z, cnumber w){

    cnumber a={z.x+w.x,z.y+w.y};

    return a;

    }

    일단, 이 함수가 하는 일은 두개의 복소수 z와 w를 받아서 복소수 값을 되돌려 주는 것이다. 그러므로 이 함수의 형식은 cnumber가 된다. 물론 cnumber는 앞에서 내부에 x와 y를 가지는 구조체형식이라고 미리 선언했으므로 쓸 수가 있다. 만약 이 선언을 안하게 되면 컴파일 할 때 “헛소리하지 마슈, cnumber라는게 대체 어딨냐?”고 에러를 내뱉는다.

    내부적으로는 새로운 cnumber a를 선언해서 단순히 초기화 시킨다. 복소수의 덧셈은 그냥 실수부분과 허수부분을 각각 더해서 새로운 실수부분과 허수부분으로 나타내는 것이므로, 아주 간단하게 처리된다. 그리고 함수값을 되돌려 주기 위해서 return a;를 불러오면 된다.

    사실 더 짧게 쓸 수도 있다.

    //The addition of two complex numbers z and w

    cnumber add_cnum(cnumber z, cnumber w){

    z.x+=w.x;

    z.y+=w.y;

    return z;

    }

    여기서 += 이라는 연산자가 하는 일은, +=의 오른쪽에 있는 녀석을 왼쪽에 있는 녀석에게 더해준다는 뜻이다.

    즉 a+=b라고 쓰는건 a=a+b라고 쓰는 것과 같다는 뜻이다. 이 +=연산자의 쓸모는 아주 많으므로 잘 알아두자. 물론 -=으로 쓴 것도 작동한다. 이 경우는 오른쪽에 있는 녀석을 왼쪽에 있는 녀석으로부터 빼게 된다.

    덧셈을 잘 했으니, 뺄셈을 정의하려고 하는데, 뺄셈을 정의하려면 위와 마찬가지로 a.x=z.x-w.x로 해도 될 것이다. 하지만 뺄셈의 원래 정의인 a-b=a+(-b)를 실현하기 위해서 일단 복소수 z를 입력받아서 -z를 되돌려주는 함수를 만든다.

    //The negative number of the given complex number z

    cnumber minus_cnum(cnumber z){

    z.x=-z.x;

    z.y=-z.y;

    return z;

    }

    이 함수가 하는 일은 뻔하므로 설명하지 않겠다. 단지 =-는 -=가 아니라는 점만 주의하자.

    그리고, -를 붙이는 함수를 굳이 만든 이유는, 앞으로 유용하기 때문이다.

    //Subtracting w from z

    cnumber sub_cnum(cnumber z, cnumber w){

    cnumber a;

    a=add_cnum(z,minus_cnum(w));

    return a;

    }

    드디어 뺄셈이다. 덧셈 함수를 실제로 응용한 함수가 될 것이다.

    덧셈과 뺄셈을 잘 했다. 복소수는 그 자체로 체를 이루기 때문에 사칙연산이 모두 가능하다. 이제 사칙연산중 나머지 두개인 곱셈과 나눗셈을 정의해 주자.

    //Multiplication of z by w

    cnumber mul_cnum(cnumber z, cnumber w){

    cnumber a;

    a.x=z.x*w.x-z.y*w.y;

    a.y=z.x*w.y+z.y*w.x;

    return a;

    }

    복소수를 공부해본 사람은 알겠지만, 위의 함수가 복소수 z와 w를 받아서 새로운 복소수의 실수부분과 허수부분을 각각 정의하고 있다는 걸 알 수 있을 것이다.

    문제는 나눗셈이다. 나눗셈을 정의하려고 하면 계산이 꽤 복잡해 지는데, 나눗셈 함수는 더 작은 함수로 쪼갤 수가 있다. 먼저, 켤레 복소수를 만드는 함수를 만든다.

    //Complex conjugate of the given complex number z

    cnumber conj_cnum(cnumber z){

    cnumber a;

    a.x=z.x;

    a.y=-z.y;

    return a;

    }

    비결은 -를 붙이는 함수랑 같다. 단지 허수 부분만 -가 붙어서 나온다는 점.

    //The norm of the given complex number z

    double norm_cnum(cnumber z){

    double a;

    a=sqrt(z.x*z.x+z.y*z.y);

    return a;

    }

    절대값을 되돌리는 함수도 만든다. 절대값은 실수이므로 double형이 된다. 그리고 애초에 난 이걸 z와 z의 켤레복소수를 곱해서 그 실수부분의 제곱근을 취하는 함수로 만들 생각이었는데, 만들고나니까 이렇게 되어 있었다.

    //z is divided by w

    cnumber div_cnum(cnumber z, cnumber w){

    cnumber a;

    a=mul_cnum(z,conj_cnum(w));

    a.x=a.x/(norm_cnum(w)*norm_cnum(w));

    a.y=a.y/(norm_cnum(w)*norm_cnum(w));

    return a;

    }

    이제 나눗셈을 정의할 수 있다. z를 w로 나누는데, z에 w의 켤레 복소수를 곱한 다음, w의 절대값의 제곱으로 나눠준다. 이 계산이 왜 나눗셈과 같은 계산인지는 직접 생각해 보면 되겠다.

    이제 사칙연산을 모두 해봤으니, 복소수를 갖고 노는 다른 연산들을 정해볼 수도 있다. 가령, 위상각 돌리기가 된다.

    //complex phase transformation of the given complex number z by k

    cnumber phase_cnum(cnumber z, double k){

    cnumber x={cos(k),sin(k)};

    cnumber m=mul_cnum(z,x);

    return m;

    }

    복소수 위상phase은 크기1인 복소수를 곱해주는 것과 같고, 결국 그 실수부분은 cos함수로, 허수부분은 sin으로 표현되므로, k라디안만큼 돌리고 싶으면 cos(k), sin(k)를 성분으로 가지는 복소수를 곱해주면 된다.

    이건 복소수의 위상각을 구해주는 함수이다. 위상각은 복소수를 극형식으로 표현했을 때 나오는 각도를 얘기하는데, 그냥 허수부분을 실수 부분으로 나누면 복소수의 절대값은 서로 약분되고, 탄젠트 함수 부분만 남게 된다. 따라서 각도를 구하려면 그 숫자의 아크탄젠트 값을 구하면 된다. 아크탄젠트는 C언어의 math.h에서 제공하므로, 아래의 함수를 쓰려면 #include를 쓰고 컴파일 할 때 -lm옵션을 붙여야 할 것이다.

    //The argument of the given complex number z

    double arg_cnum(cnumber z){

    if(z.x==0.0){

    return PI/2.0;

    }

    else{

    double a=atan(z.y/z.x);

    return a;

    }

    }

    자, 간단한 복소수 사용법을 알아보았다. 정통 C에서 복소수를 어떻게 하는지는 모르겠고, C++은 다음 페이지에서 소개하는 것과 같이

    아주 쉽게

    되는 것 같다.


    http://insar.yonsei.ac.kr/~tkhong/complex.html


  • TeX 에디터

    WinEdt

    윈에딧이라고 부르는 편집기. WinEdit과 절대 혼동하지 말길 바란다.

    홈페이지 : http://www.winedt.com/

    일단 무료로 다운로드 받아서 사용할 수 있다.

    상용 라이센스이므로, 라이센스를 구입하면 되는데, 해외에서 쓸 수 있는 신용카드를 이용해서 결제하면 된다. 학생용이 30$, 교육용이 40$, 회사/정부 기관용이 70$라고 하니까, 용도에 맞게 구해서 쓰면 되겠다.

    난 교수님이 연구비로 결제해 주셔서 공짜로 얻었다.

    일단 MiKTeX을 설치하고서, 설치 경로를 지정해주면 된다. 뭐 자세한건 사용설명서를 참고하시기를.

    TeXmaker

    WinEdt과 나름 비슷한 편집기이다.

    홈페이지 : http://www.xm1math.net/texmaker/

    GPL로 풀려있으므로 자유롭게 사용할 수 있다. 개인적으로는 그냥 공짜로 구할 수 있는 이걸 사용하고 싶지만, 교수님께서 사주신게 있으므로 그냥 WinEdt을 쓰게 된다. 윈에딧이랑 비교한다면, 그냥 비슷한 수준인 것 같다.

    TeXmacs

    이건 TeX을 위한 편집기는 아니지만, 너무나 편리하게 TeX같은 편집을 할 수 있는 편집기이다.

    홈페이지 : http://www.texmacs.org

    개인적인 생각으로는, 세계 최고의 수식 입력기이고 TeX편집기라고 생각한다. 물론 TeX편집기도 아니고 세계 최고수준이라고 하기엔 아직 한참 부족하지만, TeXmacs가 없으면 수식 편집을 불편해서 못할 것 같다.

    vi나 gEdit같은 것들도 TeX의 구문 강조는 해 주기 때문에 쓸만하겠지만, 위의 전문적인 편집기를 사용한다면 아무래도 편리할 것이다.

    * MiKTeX은 http://www.ktug.or.kr에서 잘 찾아보면 받을 수 있다.

  • TeX4PPT

    TeX4PPT

    download :

    http://www.ecs.soton.ac.uk/~srg/softwaretools/presentation/TeX4PPT/

    위의 사이트에서 다운받으면 된다. 일단, 만든 사람에 따르면, MS Powerpoint 2002 이상의 버전에서 잘 작동하는 것을 확인했으며, MS PPT 2007에서 작동하는지 여부는 새 물건을 받아봐야 안다고 했다. 또한 MiKTeX이 설치되어 있어야 되며, 다른 TeX에서 어떻게 작동하는지는 모른다고 한다.

    MiKTeX은 다음 사이트를 참고하여 설치하기 바란다.

    KTUG :

    http://faq.ktug.or.kr/faq/MiKTeX

    잘 설치되었으면, MS PPT를 실행시켜보자.

    메뉴중에 TeX4PPT라는 항목이 추가되었을 것이다. 거기에는 Configure, fonts, helps라는 세개의 하위 메뉴가 있다. 그중 Helps를 선택하면 꽤 쓸만한 정보를 얻을 수 있을 것이다.

    기본적인 사용방법은 다음과 같다.

    1. 글상자를 새로 만든다.

    2. TeX 문법으로 필요한 내용을 입력한다.

    3. 입력한 부분 위에서 오른쪽 단추를 누르고 TeXify를 고른다.

    4. 크기조절을 하거나 적당히 편집할 때마다 TeXify를 해 줘야 한다.

    5. TeXify한 상태에서 다시 편집하고 싶으면, 필요한 수식을 왼쪽 더블클릭을 하면 원래대로 돌아간다. 물론 다시 TeXify를 하면 수식으로 변신한다.

  • 자기 참조 구조체

    VIPS를 쏜다는 말에 혹해서, 친구의 C언어 프로그래밍 숙제를 해주다가, 재미난걸 알아버렸다.

    변수를 이용할 때, 구조체 안에 있는 특정 변수의 값만 필요하다면 .연산자를 쓰면 된다는 건 알고 있다. 구조체 포인터에서 그 안에 있는게 필요하면 ->연산자를 쓰면 된다.

    그런데, 구조체를 이용해서 배열을 이용하면, 배열 각각의 요소를 처리하는건 쉽지만 배열의 순서나 배열을 중간에 추가하는 작업같은건 아주 어려운 작업이 된다. 이 작업을 자기참조구조체라는 개념을 이용하면 쉽게 해결할 수 있다.

    선언은 간단하다. 구조체를 하나 선언하는데, 다음과 같이 선언하면 된다

    struct mania

    {

    int a;

    struct mania *next;

    }

    그러고나면, next라는 포인터는 mania라는 구조를 구조체를 가리키게 된다. 그럼 next는 다시 그 안에 next를 갖고 있다. 물론 이 next와 앞의 next는 내부변수이므로 서로 구별되고, 다른 주소를 가리키게 되므로 아무 문제 없다. 문제는 가장 마지막 변수에서 생기는데, 마지막 변수는 next가 없으므로 에러가 난다. 따라서, 최초에 선언할 때 next를 NULL로 초기화를 해 두면 괜찮다.

    우선, 제일 처음 구조체를 선언할 때 다음과 같이 해 준다.

    struct mania dummy; //임시 시작점이다.

    struct mania *start=&dummy; //시작점의 주소를 start라는 포인터에 넣는다. struct mania *sequence; //실제로 우리가 사용할 포인터이다.

    struct mania *work; //작업용 포인터

    그럼, 이제 첫 세팅을 해보자.

    start=&dmy;

    start->next=NULL;

    처음엔 당연히 아무것도 없으므로 NULL이다.

    여기에 뭘 넣기 전에, 일단 next에 해당하는 녀석의 메모리를 확보를 해 둘 필요가 있다. 메모리의 확보는 malloc, calloc같은 함수로 한다.



    [각주:

    1

    ]



    sequence=(struct mania *)malloc(sizeof(struct mania));

    이렇게 하면 sequence라는 이름의 mania구조를 가진 포인터에 sizeof(struct mania)만큼의 크기를 가진 메모리가 할당된다. 그런데, 이건 딱 한개만 확보하는 것이므로 체인의 고리를 만들어 나갈 때는 만들 때마다 메모리를 할당해야 한다. 이 점에 주의해서 문제를 잘 해결해 보기 바란다.

    아무튼, 이걸 이용하는 개념은 다음과 같다.

    제일 처음에 start포인터를 사용한다.



    [각주:

    2

    ]




    start->next는 start포인터 뒤에 있는 녀석이다.

    물론 start->next->next는 start포인터의 뒤에뒤에 있는 녀석이다.

    sequence는 체인의 가장 끝에 있는 녀석이다.

    이제, next의 포인터를 적당히 지정해주기만 하면 체인을 이리저리 연결할 수 있다.

    가령, 두번째 체인을 세번째 체인과 바꾸고 싶다면?

    적당한 mania구조를 가진 temp를 지정하고

    struct mania temp;

    temp=start->next->next;

    start->next->next=start->next;

    start->next=temp;

    이런식으로 하면 두번째와 세번째가 바뀐다.

    자, 나머지는 잔머리다! (무책임 -_-;)

    1. 난 말록, 콜록, 뭐 이렇게 읽는다. calloc은 “씨-얼록”으로 읽는게 맞다는데, 뭐 알아들으면 되지 않겠는가.

      [본문으로]
    2. start, sequence, next등은 그냥 임의로 붙인 이름일 뿐이다!

      [본문으로]

  • 함수

    C언어는 함수형 언어이다. 모든것이 함수로 이루어져 있다는 뜻이다. 자세히 알아보자.

    함수는 수학적으로는 집합A와 집합B가 정해져 있을 때, 다음과 같이 정의한다.

    A의 원소에 B의 원소를 짝지어서 (a,b)로 쓴다. 이 경우, 모든 (a,b)의 집합의 어떤 부분집합 f는 함수이다.

    만약, B의 임의의 원소 b에 대해서 (a,b)가 존재하면 f는 전사함수(surjective function, surjection)라고 부른다. 만약, B의 원소 b가 결정되었을 때, (x,b)를 만족하는 x를 모아둔 A의 부분집합의 원소가 1개뿐이면 f는 단사함수(injective function, injection)이다. 그리고 전사함수이면서 단사함수이면 전단사 함수(bijection)라고 부른다. 이건 고등학교때 배우는 쉬운 내용이므로 넘어가자.

    수학적으로는 그런데, 좀 어렵다. 따라서, 좀 쉽게 정해보자. 위와 똑같은 얘기를 아래와 같이 쉽게도 할 수 있다.

    a는 A의 원소이고 b는 B의 원소라고 하자. 만약 a를 결정했을 때 그와 관련된 b를 알 수 있으면, 그런 규칙은 함수라고 부른다.

    만약 모든 B의 원소가 A에 있는 적어도 한 원소와 관련되는 함수는 전사함수이다. 만약 B의 어떤 한 원소로 오는 A의 원소가 유일하게 결정된다면, 그런 함수는 단사함수이다. 둘 다 되면 전단사 함수이다.

    여전히 어려운가? 상관없다. C언어의 함수를 배우는데는 아무런 문제가 되지 않는다. C언어에서의 함수는 아주 간단하다.

    type 함수이름(변수1, 변수2…){

    함수가 할 일

    return 되돌려줄 변수;

    }

    이런식으로 함수를 만든다. type은 int, float, double, char, void 등이 있으니 맘대로 골라쓰자. void는 return할게 없을 경우에 사용한다. 물론 입력받을게 없는 함수도 만들 수 있다. 변수에 아무것도 쓰지 말고 void만 써주면, void는 “아무것도 없다”는 걸 알게 해준다. 이런식으로 기능을 함수로 쪼개는 것은 상당히 재미있다.

    내가 이 얘기를 하는 이유는, 함수라고 부르는 대상이 상당히 재미있는 일을 해주기 때문이다. 가령, 숫자 두개를 받아서 더하여 출력하는 함수가 있다고 해 보자. 그럼 함수는 변수 2개를 입력받고, 내부적으로 적당히 처리해서, 출력을 해주면 된다. 이 사실을 알려주는 것을 선언이라고 한다. 선언은 함수의 정의와는 다른데, 정의는 함수가 무슨 일을 하는지 정확히 다 알려주는 것이지만, 선언은 그냥 변수를 무엇을 받고 결과를 어떻게 내보내는지만 말해준다. 그리고, 선언과 정의를 동시에 할 수도 있다. 중요한 것은, 함수의 정의는 어디에 있어도 상관 없지만, 선언은 그 함수가 최초로 쓰이기 전에 반드시 존재해야 한다는 점이다.

    이것은 솔직히 말하면 귀찮은 작업이긴 하다. 하지만 귀찮은 것을 신경쓰지 않는다면, 재미난 것을 해볼 수가 있다.

    double add(double,double);

    이런 식으로 선언을 했다고 하자. add라는 함수는 실수 두개를 받아서 실수를 출력하는 함수가 된다. 그럼 정의는?

    double add(double a, double b){

    double c=a+b;

    return c;

    }

    이런식으로 쓸 수가 있다. 중요한건, return해주는 변수 c는 처음에 add를 정의할때 사용한 double과 같은 타입을 갖고 있어야 한다는 점이다. 이것만 주의하면 된다. 만약 add를 좀 다른 방법으로 계산하고 싶다면, 다르게 정의하면 된다.

    double add(double a, double b){

    double c=a+2*b+3.0;

    return c;

    }

    이렇게 하면 우리가 원하는대로 add라는 함수가 정의된다. 아무 상관 없다.

    C언어에서 알고리즘은 그래서 함수가 어떤 기능을 하는지, 그리고 그 함수를 이용해서 또다른 함수를 어떻게 만들지 고민하는 과정이라고 보면 되겠다. 그런점에서 C언어는 상당히 수학적으로 구성할 수 있는 언어라고 생각한다.

    수학은 최초에 무정의 용어와 그 무정의 용어의 사용법에 대한 공리Axiom가 있어야 한다. 그리고 그 공리와 무정의 용어를 이용해서 다른 정리들을 증명해 간다. C언어는 함수가 사용되기 전에 선언되지 않으면 사용할 수 없다. 그리고 선언되기만 하고 정의되지 않으면 사용할 수 없다. 수학에서도 알려지지 않은 정리는 사용할 수 없으며, 추측으로 그럴듯해 보이더라도 기존의 정리들로부터 증명되지 않으면 사용할 수 없다. C언어에서 무정의 용어와 공리계에 해당하는 것은 standard C의 문법 체계와 기본적인 라이브러리에 해당할 것이다.

  • 포인터와 구조체

    그냥 구조체를 쓴다고 해 보자.

    struct 구조{

    int 수;

    int 열;

    };

    이제, 구조체를 하나 정의하자.

    struct 구조 아싸;

    이래놓고서 아싸의 수를 참조하고 싶으면 다음과 같이 하면 된다는건 알려져 있다.

    아싸.수

    그런데, 구조체라고 포인터로 선언하지 말란 법은 없다. 이렇게 하면 된다

    struct 구조 *메롱;

    이러면 메롱은 구조라는 형태를 가진 변수를 가리키는 포인터가 된다. 그럼 메롱의 수를 참고하고 싶으면 어떻게 할까?

    원래는

    (*메롱).수

    라고 해야 한다.

    *메롱.수

    라고 하면 안되는 이유는, 이건

    *(메롱.수)

    로 해석되어버리기 때문이다. 즉,

    메롱.수

    라는 포인터가 가리키는 곳으로 가버리기 때문에,

    메롱

    이 가리키는 곳의 수로 가지를 않는다. 귀찮다. 그래서 새로운 연산자가 있다. 바로 ->이다.

    메롱->수

    라고 쓰면, 이것은

    (*메롱).수

    와 동등하다.

    자, 오늘도 신기한거 하나 배웠다.

  • 변수

    C언어에서 변수형은 대단히 중요하다. 왜냐하면, 자동으로 처리를 못하기 때문에 항상 그 변수가 어떤 형태를 가지고 있는지 처음에 정해놓고, 그것에 맞춰서 사용해야만 하기 때문이다.

    기본적으로 정수, 실수, 문자열 변수가 있다. 그리고 각각 그냥 쓰는 것과 긴(long) 형식이 있다. 또한, 부호를 붙인 것과 붙이지 않은 것이 있다 따라서, 다음과 같이 쓰면 된다

    int

    long int

    unsigned int

    unsigned long int

    float

    long float

    unsigned float

    unsigned long float

    char

    만약, long이 아니라는 것을 굳이 강조하고 싶다면 short int처럼 쓰면 된다. 이건 아무말 하지 않은 int와 똑같다.

    여기서, 흥미로운건 double형이다. double은 long float이랑 똑같다. 그리고 여기에long double형이 있다는 것. 따라서 long double형은 정말 정말 큰 숫자를 표시할 수 있다. long double은 자칫 잘못 쓰면 너무 긴 숫자가 나오므로 조심해서 쓰도록 하자. 출력할때는 long이 붙으면 %lf, %ld 등으로 l을 붙여줘야 한다는 점을 까먹지 말자.

    여기에, 굳이 뭔가 더 쓰자면 포인터 형이 있다. 포인터는 주소를 가르쳐 주는 변수형인데, 그건 다른 글에서 알아보도록 하겠다.

    이러한 변수들을 만약 한두개가 아니라 여러개를 쓰고 싶다면 어떻게 해야 할까? 가령, 100개정도의 변수가 있고, 그것들을 번호를 매겨서 관리하려면? 여기에 쓰는게 바로 배열(array)이다. 배열은 다음과 같이 선언하면 된다.

    int arrayname[100];

    그럼 정수형을 가지며 arrayname이라는 이름을 가진 공간 100칸이 메모리에 예약된다. 우린 이 예약된 공간을 마음대로 갖고 놀 수가 있게 되는 것이다. 사용할 때는 arrayname[번호] 형식으로 사용한다

    참고로, 번호는 0번부터 시작한다는 것을 절대 까먹지 말자. 정의할때는 arrayname[100]을 쓸 수 있지만, 어디서 실제로 사용할때 a=arrayname[100]처럼 쓰면 기어이 에러가 발생하고야 말 것이다.

    참고로, 배열명은 포인터 이름과 같다는 것만 일러두고 끝낸다. 따라서 arrayname은 포인터 이름이 된다.