2016년 4월 11일 월요일

알파벳 대소문자 변환 하는 법

일단 대문자를 소문자로
소문자를 대문자로 고치는 방법은 많이 있겠지만 (함수도 있다)
나는 2가지 방법을 쓰겠다.

우선 문자를 입력받아서 거기서 32를 더하거나 빼주면 된다.

A는 아스키코드값이 65이고
a는 97이다.
둘의 차이는 32. 그래서 32를 빼주면 대문자가 되고 더하면 소문자가 된다.
귀찮다.

두번째 방법은 비트 연산을 이용하는것

A는 비트로 0100 0001 이다(65니까)
a는 비트로 0110 0001 이다(97이니까)
(참고로 비트 맨 마지막이 0이냐 1이냐로 홀수 짝수 구분됨.)
이 비트들을 ^32 해준다.
32는 비트로 0010 0000이다.
A로 예를 들면
0100 0001
0010 0000
0110 0001이 된다.
a도 마찬가지이다.
이걸 코드로 짜면
#include<stdio.h>
int main(){
    char a='a';
    char A='A';
    printf("%c %c\n",a^32,A^32);
}

Perl 기본

perl 언어 기초

linux 환경에서는 perl이 기본적으로 설치되어있다.
perl로 간단하게 출력하는 프로그램을 짜보면 다음과 같다.
print "hello, world\n";
이 프로그램을 실행하려면, 인터프리터인 perl의 1번째 argument로 파일명을 넘겨준다.
$ perl main.pl
우리는 C로 짠 프로그램을 실행시킬떄 아래와 같이 한다.
$ ./a.out
perl도 마찬가지로 이렇게 실행시킬 수 있다.
먼저 실행권한옵션을 준다.
$ chmod +x main.pl
그리고 프로그램 소스 최상단에
다음과 같이 작성한다.
#!/usr/bin/perl
print "hello, world\n";
그러면 다음과 같이 실행이 가능하다.
$ ./main.pl

2016년 4월 8일 금요일

포인터에 기본 개념

포인터(Pointer)

-어렵게 생각할거 없이 그냥 말 그대로 포인터 즉 가르키고 있는거다. 
음...교수가 레이저로 화면 쏘면서 가르키고 있는것마냥

근데 이걸로 멀 하냐? - 코딩 하는 놈이 메모리의 일부를 직접 조작하고 컨트롤 할 수 있게 해줌.
이걸 터득하면? 동적메모리 할당, 배열이랑 포인터 관계(2차원 배열 동적할당 할때 난 소름 돋음),
                        연결리스트,트리 같은 자료구조 개념, 함수포인터 등등 이해하기 ㅅㅌㅊ

자 개념을 보장
int c='a'; 라고 딱 메모리 할당 하고 초기화도 이쁘게 시켜둠. 
그러면 메모리 상에서 어케 생겼냐면

이케 생김. 밑에 1 2 3 은 주소값이라고 가정하고 보셈.
그럼 c의 주소는 2임. 고럼 &c? 2 인거지 (&는 주소연산자다)
아 참고로 한 블록당 1Byte이고 어떤 메모리에 쓸지는 컴터가 알아서 지정해줌.
이케 주소도 알면 나중에 다시 찾아서 수정하거나 연산 할때 용이하겠지?
이게 배열에서도 통하는건데 만약에 내가
char arr[3]={10,20,30}을 입력했다고 치자.(arr[0] 주소 1이라고 생각하고)
그럼 내가 arr[2]의 주소까지 알아야 되나? 머 지금 처럼 크기가 작으면 상관없겠지
근데 존나 크면 개에바잖수. 해결책은?
걍 맨 처음 배열의 주소값만 알면되지.
arr[2]라고 해봤자 arr[0]의 주소값에서 계산하면 되잖아.
(이거 어케 주소값 접근하는지는 이따 밑에서 쓸거임.)
이걸 이쁘게 말하면
=>데이터가 들어있는 곳의 처음 주소는 1이고, 데이터 크기는 3Byte 구나. 

결국 변수명이 아닌 그 변수의 주소값으로 접근했을때 편의성은 무궁무진하다 이 말임.

예를 하나 더 들자면
int i=3;
int *p=&i;
이라고 치자. i의 주소가 101012이면 
p에는 101012가 저장되있는거야. 
그림으로 표현하면 이렇게 되지. 화살표로 걍 가르키면서 할 수 있지만 기본 개념잡는데는
이게 더 이해하기 쉬운거 같음. 



3가지 결론을 내리자면

1. 포인터는 변수이다.(단, 다른 변수의 주소값을 저장하는 변수)

2. 포인터는 오직 주솟값만 저장해서 8Byte이다.(void*,char* 모두 8바이트)
                         ->이건 64bit컴퓨터 기준으로 말한거임.

3. 포인터 변수로 어떤 연산할려면 *필요. (주소값으로 찾아간 후 변수 값 조정)
           

cf)*는 star 연산자(간접참조 연산자)이다. 
       - 포인터가 가르키고 있는 주소로 가서 그곳에 데이트럴 읽어 오거나 
        그곳에 있는 값을 변경하여 저장함.




아 참고로 포인터 연산도 쓰겠다.

위에 그림처럼 i라는 변수의 주소가 101012이고
p가 i의 주소를 담고 있다고 치자.
이때 p=p+1; 하면 p의 값은 어케 될까?
101013? 답은 노우다.

왜 그런지 그림을 한번 보장.

일단 기본적인 메모리 구조를 보자
(내가 그림 그리긴 힘들어서 퍼옴. 뿌잉) 
i라는 변수에는 지금 30이 저장되있고, 그 변수의 주소는 현재 4인거다.
p라는 변수는 i의 주소값을 저장하고 있는 상태이다. 
(저 p는 지금 32bit컴 기준으로 그린거)

이따 p=p+1을 했을때 p가 5라고 가정해보자. 그렇게 되면 그림으로





이렇게 된다. 무슨 일이 일어났는지 짐작이 가나? 
i의 메모리를 침범해버린다. 좆된거다.
제대로 된 그림을 보자.


얼마나 깔끔하고 이쁜가?
(p 주소값은 그림 상 안 겹치게 할려고 뒤로 밀어낸거임)

이걸로 유추할수 있는것은

->포인터 변수의 연산은 그 포인터 변수의 타입의 크기만큼 증감한다.

그렇다고 p=p+4라고 입력하라는게 아니다. (형변환을 생각해보자)

더 많은 예를 들어보자.


int i=10;
double d=40.0;
char c='c';

int *pi=&i;             //  i의 주소값 10으로 가정
double *pd=*d;  // d의 주소값 20으로 가정
char *pc=&c;      // c의 주소값 31로 가정

pi++;                  //int는 4바이트 -> 14
pd+=3;              //double은 8바이트 -> 44
pc-=9;               //char는 1바이트->22



굳!
다음은 포인터랑 배열 관계를 써보겠다.



SORT(버블,선택,삽입)


버블정렬(Bubble sort)

-인접한 데이터끼리 비교
-시간복잡도 O(n^2) => 최고:이미 정렬된 상태
                                => 최악:역순으로 정렬된 상태



ex)
#include<stdio.h>
#include<malloc.h>
int main(){
    int* arr;
    int i,j,n,temp;
    scanf("%d",&n);
    arr=(int*)calloc(n,sizeof(int));
    for(i=0;i<n;i++){
        scanf("%d",arr+i);
    }
    for(i=0;i<n-1;i++){
        for(j=0;j<n-1;j++){
            if(arr[j]>arr[j+1]){
                temp=arr[j];
                arr[j]=arr[j+1];
                arr[j+1]=temp;
            }
        }
    }
    for(i=0;i<n;i++){
        printf("%d",arr[i]);
    }
    printf("\n");
    
}

입력: 5 
         9 2 3 5 1
결과: 1 2 3 5 9




선택정렬(Selection sort)

- 배열 첫번째 위치부터 기준키로 설정
=>2~n번째 값과 비교 =>가장 작은 값과 기준키를 교환

-시간복잡도 O(n^2) => 최고:이미 정렬된 상태
                                => 최악:역순으로 정렬된 상태
ex)
#include<stdio.h>
int main(){
    int arr[10]={5,3,2,1,4,6,8,7,10,9};
    int i,j,temp,curr;
    for(i=0;i<9;i++){
        curr=i;
        for(j=i+1;j<10;j++){
            if(arr[curr]>arr[j]){
                curr=j;
            }
        }       
        if(arr[i]>arr[curr]){
            temp=arr[i];
            arr[i]=arr[curr];
            arr[curr]=temp;    
        }
    }
    for(i=0;i<10;i++){
        printf("%d ",arr[i]);
    }
    printf("\n");
    return 0;
}

결과값: 1 2 3 4 5 6 7 8 9 10

삽입정렬(Insertion sort)

-pivot을 잡고 그 전에 값들과 비교하면서 pivot보다 클 경우 오른쪽으로 한칸씩 이동한다.

시간복잡도 (http://i-bada.blogspot.kr/2012/05/blog-post_161.html)
- 최적 : 입력 데이터가 정렬하고자 하는 순서대로 배열되어 있는 경우 최소 비교 횟수 : n-1
- 최악 : 입력 데이터가 역순으로 정렬되어 있는 경우 최대 비교 횟수 : (n(n-1))/2
- 각 패스 별로 중간 정도에서 부분적인 정렬이 완료되었을 경우 평균 비교 횟수 : (n(n-1))/4
- n개의 레코드를 정렬한 때 n-1번 삽입이 발생되어 전체 수행시간 : O(n2)



예제

#include<stdio.h>
int main(){
    int arr[7]={7,2,8,1,3,9,4};
    int i,j,pivot;
    for(i=1;i<7;i++){
        pivot=arr[i];
        for(j=i-1;j>=0;j--){
            if(pivot<arr[j]){
                arr[j+1]=arr[j];
            }
            else{
                break;
            }    
        }
        arr[j+1]=pivot;      
    }
    for(i=0;i<7;i++){
        printf("%d ",arr[i]);
    }
    
}
결과값: 1 2 3 4 7 8 9






간단할 수 있지만 많은 생각을 요구함.
이제 자고 일어나서 generatic 하게 짤꺼임.

이 정렬 뿐만 아니라 다른 정렬들 설명 잘 되있는 사이트
http://yujuwon.tistory.com/entry/%EC%82%BD%EC%9E%85%EC%A0%95%EB%A0%ACInsert-Sort

2016년 4월 1일 금요일

2차원 배열 동적할당

<stdlib.h> 호출해도 되긴한데 사이즈 넘 크니 그 하위인 <malloc.h> 호출
1. 일단 1차원 배열 동적할당 하는거

int *arr;
int n;
scanf("%d",&n);
arr=(int*)calloc(n,sizeof(int));

2. 2차원 배열 동적할당하기

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


2016년 3월 16일 수요일

소수판별법 에라테네스체

소수를 판별하는 방법은 2가지다.

첫번째는 입력받은 값을 2부터 입력받은값까지 다 나눠보고 나머지가 0인게 뜨면
그새끼는 소수가 아닌거임. 이걸로 했을땐 시간복잡도 값이 O(n)이 됨.

두번째는 에라테네스체를 사용하는거다.
소수를 판별할때 젤 먼저 보게 되는게 이 새끼가 2의 배수인가? 아니면 3의 배수인가다.
그 담으로는 n에 루트를 취했을때 루트n에 대해서 대칭이 된다.
이때 시간복잡도 값은 O(루트n)이 된다.

1.첫번째 방식으로 풀어보자.

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

int main(){
        int n;
        int i;
        scanf("%d",&n);
        for(i=2;i<n;i++){
                if(n%i==0){
                puts("합성수");
                return 0;
                   }
                else{
                puts("소수");
                return 0;
                   }
                }
        return EXIT_SUCCESS;
        }

2.두번째 방식
isPrime 함수 정의후 사용하기.(말그대로 is Prime? 이거임)

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

int isPrime(int n);
double sqrt(double n);

int main(){
        int n;
        scanf("%d",&n);
        if(isPrime(n)!=0){
                puts("소수");
         }
        else{
                puts("합성수");
        }
        return EXIT_SUCCESS;
}

int isPrime(int n){
        int i;
        int x=(int)sqrt(n);
        if(n%2==0){
                return n==2;
        }
        if(n%3==0){
                return n==3;
        }
        for(i=5;i<=x;i++){
                if(n%i==0){
                 return 0;
                }
        }
        return n!=1;
}


2016년 3월 15일 화요일

부분배열 합

1. 변수 줄임
#include<stdio.h>
#include<string.h>
#include<stdlib.h>


int main(){
        int arr[100];
        int i;
        int n;

        scanf("%d",&n);

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

                }
     
        printf("%d",arr[n-1]);
     
        return EXIT_SUCCESS;


}




2. 


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

int main(){
int arr[100];
int i;
int n;
int sum=0;

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

return EXIT_SUCCESS;
}