BOJ[백준] - 2569 - 짐정리

Posted by ceyx
2017. 7. 13. 01:27 Algorithm 문제풀이/BOJ [백준] 문제풀이

https://www.acmicpc.net/problem/2569

 

(1) Graph로 해결하려 했는데 정렬하기 전과 정렬하고 후에 자리가 똑같은 정점(vertex)을 빼고 나머지 정점들 가지고만 MST(최소신장트리)를

만들어 볼까? 하는 생각을 했었습니다.

4 2 1 3 을 입력 받으면 정렬 했을 때, 1 2 3 4 이고 2는 그대로 있으면 되는 것이죠..

따라서 cyclic 정점 set이 (2)와 (1, 3, 4)로 분리되니  (1, 3, 4) 로만 가지고 MST를 구성해 봤습니다.

이 그림 처럼. 총 합이 9가 나오지 뭡니까 ?? 

이대로 끝인줄 알았습니다 ㅎ..

 

 

 

 

(2) 1 8 9 7 6 을 입력으로 받으면,  정렬 후 1 6 7 8 9 가 되고,  1은 그 자리에 있으면 되니..  (1)과 (6, 7, 8, 9)로 분리를 해서 앞서 적용한 것처럼

계산을 했더니 !??  (6+7) + (6+8) + (6+9) = 42 가 나왔습니다.

BUT!! 저 경우엔 정답이 41이네요...

1 8 9 7 6 -> 6 8 9 7 1 (1+6) -> 6 8 1 7 9 (1+9) -> 6 8 7 1 9 (1+7) -> 6 1 7 8 9 (1+8) ->

 1 6 7 8 9 (1+6) = 41 입니다.

 case 2번은 생각을 못하고 있었는데 결국 뛰어난 PS블로거님에게서 힌트를 얻었습니다. 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <cstdio>
 
#define MIN(a,b)  ((a)<(b) ? (a):(b))
typedef struct vertex
{
   int data, index;
} V;
 
const int MXN = 1000;
V a[MXN + 1];
char chk[MXN + 1];
 
void swap(V *v1, V *v2)
{
   V t = *v1;
   *v1 = *v2, *v2 = t;
}
 
int main()
{
   int n;
   scanf("%d"&n);
   for(int i = 0; i < n; i++)
   {
      scanf("%d"&a[i].data);
      a[i].index = i;
   }
 
   // bubble sort in ascending order of a[].data
   for (int i = 0; i < n - 1; i++)
      for (int j = 0; j < n - i - 1; j++)
         if (a[j].data > a[j + 1].data)
            swap(&a[j], &a[j + 1]);
 
   long long ans = 0;
   for(int i = 0; i < n; i++)
   {
      if(chk[i])
         continue;
      int cycle = 0;
      // loop 1 cycle, cycle = the # of vertices in a cycle
      for(int j = i; !chk[j]; j = a[j].index)
      {
         cycle++;
         ans += a[j].data;
         chk[j]++;
      }
      // case 1 : check only non-sorted cyclic vertices
      //          4 2 1 3 -> check (1,3,4) -> (1+3) + (1+4) = 9
      // case 2 : check a vertex having minimum value in the graph and non-sorted cyclic vertices
      //          1 8 9 7 6 -> check (1) and (8,9,7,6) -> (1+6) + (1+9) + (1+7) + (1+8) + (1+6) = 41
      ans += MIN( (cycle-2* a[i].data , a[i].data + (cycle+1* a[0].data );
   }
   printf("%lld", ans);
   return 0;
}
cs

 

 

 

 

Algorithm classification (알고리즘 분류)

Posted by ceyx
2017. 7. 12. 13:20 Algorithm/Algorithm 상세분류

알파벳 순으로 작성했습니다. 제 마음대로~ 공부하고 있는대로~ 작성한 것이기 때문에 정중한 태클은 환영입니다

기본부터 시작해서 점점 늘려갈 것 입니다ㅎㅎ

 

 

1. Bit manipulation

(1) Binary representation of a given number
(2) Count number of bits to be flipped to convert A to B
(3) Count total set bits in all numbers from 1 to n
(4) Find Next Sparse Number
(5) Find the element that appears once
(6) Magic Number 

(7) Maximum Subarray XOR
(8) Rotate bits of a number

(9) Sum of bit differences among all pairs
(10) Swap All Odds And Even Bits

 

2. Data structure (자료구조)

(1) Linear structure (선형구조)

- Array (배열)

- Deque (덱)

- Linked List (연결리스트)

- Stack (스택)

- Queue (큐)

(2) Nonlinear structure (비선형구조)

- Graph (그래프)

- Tree (트리)

(3) Simple structure (단순구조)

- Character, Float, Integer, String (문자, 실수, 정수, 문자열)

 

3. Dynamic Programming (다이나믹 프로그래밍)

(1) 0-1 Knapsack

(2) Longest Common Subsequence

(3) Longest Increasing Subsequence

 

4. Graph (그래프)

(1) Boggle

(2) Breadth First Search(BFS, 너비우선탐색)

(3) Depth First Search (DFS, 깊이우선탐색)

(4) Shortest Path (최단거리)

- Dijkstra (다익스트라)

- Bellman-Ford (벨만-포드)

- Floyd-Warshall (플로이드-와샬)

- Shortest Path Faster Algorithm (SPFA)

(5) Minimum Spanning tree (최소신장트리)

- Kruskal (크루스칼)

- Prim (프림)

(6) Topological Sort (위상정렬)

 

5. Geometry & Number theory (기하와 정수론)

(1) Convex Hull

 

8. Searching & Sorting (탐색과 정렬)

(1) Binary Search

(2) Bubble Sort

(3) Heap Sort 

(4) Insertion Sort

(5) Merge Sort

(6) Quick Sort

 

9. String (문자열)

(1) Palindrome (회문)

 

10. Tree (트리)

(1) Binary Search Tree

(2) Fecwick Tree

(3) Lowest Common Ancestor

(4) Perfect Binary Tree

(5) Segment Tree

 

 

 

 

Reference (출처) 

1. https://simple.wikipedia.org/wiki

2. http://www.geeksforgeeks.org/top-10-algorithms-in-interview-questions/

 

BOJ[백준] - 2593 - 엘리베이터

Posted by ceyx
2017. 7. 9. 01:27 Algorithm 문제풀이/BOJ [백준] 문제풀이

 

https://www.acmicpc.net/problem/2593

(1) BFS를 사용한 해결 방법입니다.

(2) 아시다시피 BFS는 모든 정점간의 가중치가 1이거나 모두 똑같은 경우에 사용하기 좋습니다.

각 엘리베이터내에서는 몇층이든 관계없이 그냥 한 번에 이동하는 설정입니다. 따라서 층을 정점 번호로 하여

관계를 설정해 줍시다..

(3) 자세한 설명은 코드안에 주석으로 써놓았습니다. (각 엘리베이터마다 1개씩 dummy 정점 만든 부분을 보시기 바랍니다..)

(4) 문제에서는 출력에 엘리베이터 번호를 요구하고 있지만 엘리베이터 번호가 필요없다면, dummy 정점을 만들 필요가 없습니다.

(5) 또한 path를 요구하는게 아니라면 경로찾기를 거꾸로 b부터 시작할 필요도 없겠지요 ^^

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// Elevator problem : resolved with BFS, only <cstdio>
#include <cstdio>
 
// instead of vector
typedef struct node
{
   int d;
   struct node *next;
} NODE;
 
const int MXN = 100100;
int go[MXN + 1], dist[MXN + 1], q[MXN + 1], h, t;
NODE adj[MXN + 1];
 
void add(int idx, int a)
{
   NODE *= &adj[idx];
   while(t->next != NULL)
      t = t->next;
 
   if(t->== 0)
   {
      t->= a;
      t->next = NULL;
   }
   else
   {
      t->next = new NODE;
      t->next->= a;
      t->next->next = NULL;
   }
}
 
/* in this given example,
 elevator   no1 - 4, 7, 10
            no2 - 7, 12
            no3 - 4, 8, 12
 
let's add a dummy node for every evelator as follows
 elevator   no1 13(1+n) - 4, 7, 10
            no2 14(2+n) - 7, 12
            no3 15(3+n) - 4, 8, 12
then, you can make a linked list array for BFS (the last array index will be n + m)
Please note that all the stroies must be conneted with only dummy node.
It means..  the path of (10 to 8) will be 10 - (13) - 4 - (15) - 8.
[4] 13 -> 15
[7] 13 -> 14
[8] 15
[10] 13
[12] 14 -> 15
[13] 4 -> 7 -> 10
[14] 7 -> 12
[15] 4 -> 8 -> 12
if a = 10 and b = 8, it would be better to start with b because it's easier way to track the path.
(Path tree)
           8         depth 1 (dist in the code)
           |
           15        depth 2
          / | 
         4  12       depth 3
       /     |
      13     14      depth 4
     / |
    7  10            depth 5
Also, go[] array has the index of their parent,
go[10] = 13, go[13] = 4, go[4] = 15, go[15] = 8, go[8] = 0
*/
int main()
{
   int n, m;
   scanf("%d %d"&n, &m);
   for(int i = 1, x, y; i <= m; i++)
   {
      scanf("%d %d"&x, &y);
      for(int j = x; j <= n; j += y)
         add((n + i), j), add(j, (n + i));
   }
 
   int a, b;
   scanf("%d %d"&a, &b);
   for(int i = 1; i <= n + m; i++
      dist[i] = -1;
 
   dist[b] = 0;
   q[t++= b;
   while(h != t) 
   {
      NODE *node = &adj[q[h]];
      while(1)
      {
         if(dist[node->d] == -1)
         {
            q[t++= node->d;
            dist[node->d] = dist[q[h]] + 1;
            go[node->d] = q[h];
         }
         if(node->next != NULL)
            node = node->next;
         else
            break;
      }
      h++;
   }
   printf("%d\n", dist[a] / 2);
   for(int i = go[a]; i; i = go[go[i]])
      printf("%d\n", (i - n));
   return 0;
}
cs

 

문제해결 아이디어를 다른 블로그들 구경하다가 봤는데 어느 블로그인지 다시 찾지를 못하여.. 출처를 남기지 못했습니다. ㅜ

티스토리 코드 하이라이트(Color Scripter)

Posted by ceyx
2017. 7. 5. 21:58 Tips/Blogging

앞선 포스팅에서 말씀드렸지만 제가 지금까지 찾은..티스토리에서 코드하이라이트에 쓰는 방법이 3가지 정도 있는 것 같습니다. !!

1. SyntaxHighlighter

2. Highlight JS

3. Color Scripter (유일하게 네이버에서 사용가능)

 

2번을 쓰다가 !  갑자기 3번으로 갈아타는 이유는??   Line number를 보여주는 기능이 없네요 ㅜ_ㅜ

(+게다가 네이버 블로그 쓰시는 분들은 script 태그를 맘대로 못쓰기 때문에 Color Scripter가 더욱 좋을듯 합니다)

따라서 Color Scripter를 써보기로 했습니다 !

2번과는 달리 한국분이 개발하신 것 같아 더욱 친근하네요 ㅎㅎ

 

역시 Highlight JS처럼 웹버전으로 링크로 갖다쓰는 버전과 직접 설치해서 쓰는 버전이 있네요 ㅎ

Color Scripter는 더 많은 테마를 편리하게 적용하게 사용하려면 .. 웹버전을 추천드립니다 ~

 

step 1. https://colorscripter.com/ 에 접속합니다. (저는 크롬으로 ^^)

step 2. 좋아하는 언어와 스타일패키지(일종의 테마)를 선택했습니다.

step 3. 아래와 같이 웹 브라우저에 직접 코드를 씁니다 ~

 

 

step 4. "클립보드에 복사" 버튼을 클릭 ! (오른쪽 아래에 있네요)

step 5. 블로그에 글 쓰실 때, Ctrl + V 로 붙여넣고 글쓰기 완료 하시면 됩니다 !

1
2
3
4
5
6
7
#include <stdio.h>
 
int main()
{
    printf("Hello world");
    return 0;
}
cs

 

클립보드에 복사하는 순간 코드 하이라이트 한 것을 html 태그들로 구성한 코드를 복사해 주네요 ^^

정말 좋습니다~

 

'Tips > Blogging' 카테고리의 다른 글

티스토리 코드 하이라이트(Hightlight JS)  (0) 2017.06.22

C언어 강의 목차

Posted by ceyx
2017. 6. 24. 23:10 C 언어/강의

- 강의에 앞서.. -

(1) 실습 위주의 강의, (2) 서술식 표현은 어렵기 때문에 지양 하겠습니다.

 

1. C언어의 기본을 이해해 보자

(01) C언어란 ? 컴파일이란 ?

(02) 실습환경 준비

(03) 변수, 상수

(04) 연산자, 자료형

(05) 입력, 출력

(06) 조건문, 분기문

(07) 반복문

 

 

 

 

---- 편집중..

'C 언어 > 강의' 카테고리의 다른 글

변수, 상수, 정수, 실수, 진수, 데이타 단위  (0) 2017.09.29

티스토리 코드 하이라이트(Hightlight JS)

Posted by ceyx
2017. 6. 22. 23:23 Tips/Blogging

티스토리에서 코드하이라이트에 쓰는 방법이 3가지 정도 있는 것 같습니다.

1. SyntaxHighlighter

2. Highlight JS 

3. Color Scripter

 

1번은 과거에 몇번 써봤는데 괜찮았네요ㅎㅎ 하지만 2번이 떠오르는 샛별 ! 지원 언어도 더 많은 것 같고 ~!

스킨도 좀 더 깔끔한 느낌이 있습니다~ 따라서 Hightlight JS 로 결정!

 

자자.. 따라해봅시다.

 

step 1. https://highlightjs.org/  로 접속

step 2. Get version XXXXX  버튼 클릭

step 3. highlight 하고 싶은 language들을 고른 후, Download 버튼 클릭 (많이 선택해도 용량이 굉장히 적으니 별 상관없네요 ㅎㅎ)

step 4. 다운받은 file의 압축을 풀어봅니다.

 

step 5. 자..이제 티스토리에 적용해 볼까요? 관리자모드에서 (HTML/CSS 편집 -> 파일업로드) 로 가서,

다운받은 file들을 업로드 추가하고 저장합니다.

저는 styles 폴더 밖에 있는 file 5개와..(readme file은 그냥 추가 했습니다..)  styles 폴더 안에서 제가 사용할 맘에드는 스킨 하나만(androidstudio.css) 추가했습니다.

추가하고나니 경로는 images/ 로 시작하게 되었네요.. -0-

 

step 6.  HTML 탭으로 가서.. (파일업로드 옆에 있음) 살짝 편집하고 저장해 줍니다.

저는 아래와 같이 4줄을 넣었네요,  이 때, 경로는 아까 파일업로드에서 올린것과 같은 경로로 반드시 바꿔주시길 !!

저는 ./images/ 로 시작하겠죠 당연히 ~ 우후훗

 

step 7. 이제.. 글만 포스팅하면 됩니다..  우선 글쓰기 할 때 오른쪽 위에 HTML 모드를 선택한 다음,

아래처럼 pre와 code태그를 써줍니다. class는 programming language 이름이겠죠?

 

step 8. 그런 다음 HTML 모드를 끄고 다시 정상적으로(?) 글을 쓰게 되면 빈 박스가 하나 나타날 테고, 여기에 포스팅 하실 source code를 붙여넣기 해주시면??

아래 그림처럼 !  코드를 써놓았습니다 ! 이제 글쓰기를 완료해주시면 되겠군요.

 

 

step 9. 실제로 c언어 코드 하이라이트가 완성된 모습입니다.

#include <stdio.h>

int main()
{
printf("Hello world!");
}

 

 

- 참고 링크

스킨(테마) 구경 : https://highlightjs.org/static/demo/

공식 사용법 : https://highlightjs.org/usage

관련 Docs : http://highlightjs.readthedocs.io/en/latest/

 

'Tips > Blogging' 카테고리의 다른 글

티스토리 코드 하이라이트(Color Scripter)  (0) 2017.07.05

C언어 시큐어 코딩 #1 입력 데이터 검증 및 표현

Posted by ceyx
2017. 5. 23. 11:59 C 언어/Coding

시큐어 코딩은 SW 개발과정에서 개발자 실수, 논리적 오류 등으로 인해 SW에 내포될 수 있는 보안취약점의 원인, 즉 보안약점을 최소화하는 한편, 사이버 보안위협에 대응할 수 있는 일련의 보안활동을 의미한다..

 

 

1자원 삽입

  • 정의
    • 외부 입력값을 검증하지 않고 시스템 자원(resource)에 대한 식별자로 사용하는 경우, 공격자는 입력값 조작을 통해 시스템이 보호하는 자원에 임의로 접근하거나 수정할 수 있다.
  • 해결방법
    • 외부의 입력을 자원(파일, 소켓의 포트 등) 식별자로 사용하는 경우, 적절한 검증을 거치도록 한다.
  • 안전하지 않은 코드 예제

                   


  • 안전한 코드 예제

              

 

2. 상대 디렉터리 경로 조작

  • 정의
    • 외부 입력을 통하여 디렉터리 경로 문자열을 생성하는 경우, 결과 디렉터리가 제한된 디렉터리여야 할 때, 악의적인 외부입력을 제대로 변환시키지 않으면 예상 밖 영역의 경로 문자열이 생성될 수 있다. 이 취약점을 이용하여 제한된 디렉터리 영역 밖을 공격자가 접근할 수 있게 된다. 가장 많이 쓰이는 것이 ".."을 사용하여 공격하는 것이다. 대부분의 시스템에서 ".."은 상위 디렉터리를 의미하기 때문에 제한된 디렉터리의 상위를 접근할 수 있는 경로를 생성하는 것이다.

  • 해결방법
    • 파일 접근 함수의 파일 경로 인수 일부를 외부 입력으로부터 조합하여 사용하지 않는다.
  • 안전하지 않은 코드 예제
    • void f() {

          char* rName = getenv("reportName");

          char buf[30];

          strncpy(buf, "/home/www/tmp/", 30);

          strncat(buf, rName, 30);

          unlink(buf);

      }

  • 안전한 코드 예제
    • void f() {

          char buf[30];

          strncpy(buf, "/home/www/tmp/", 30);

          strncat(buf, "report", 30);

          unlink(buf);

      }

 

 

3. 정수 오버플로우

  • 정의
    • 정수 연산 시에 정수형 변수가 취할 수 있는 범위를 초과할 때 발생하는 경우이다. 이러한 상황이 발생한 후에 순환문의 조건이나 메모리 할당, 메모리 복사 등에 쓰이거나 이 값에 근거해서 보안 관련 결정을 하는 경우 보안 취약점이 발생된다.
  • 해결방법
    • Signed 정수 타입의 경우, 오버플로우 발생시 양수 음수가 변할 수 있다. 이를 위해, 메모리 할당 함수에서는 할당량을 표시하는 파라미터를 unsigned 타입으로 전달해야 잘못된 값이 사용되는 것을 방지할 수 있으며 배열등의 인덱스를 외부에서 입력받을 경우에는 인덱스의 크기를 검사한다. 
  • 안전하지 않은 코드 예제
    • #include <stdlib.h>

      void* intAlloc(int size, int reserve) {

          void *rptr;

          size += reserve;

          rptr = malloc(size * sizeof(int));

          if (rptr == NULL)

              exit(1);

          return rptr;

       }

  • 안전한 코드 예제
    • #include <stdlib.h>

      void* intAlloc(int size, int reserve) {

          void *rptr;

          unsigned s;

          size += reserve;

          s = size * sizeof(int);

          if (s < 0)

              return NULL;

          rptr = malloc(s);

          if (rptr == NULL)

              exit(1);

          return rptr;

       } 

 

 

4. 스택에 할당된 버퍼 오버플로우

  • 정의
    • 스택에 할당되는 버퍼들 (지역변수로 선언되거나 함수의 인자)이 문자열 계산 등에 의해서 정의된 버퍼의 한계치를 넘는 경우 버퍼 오버플로우 발생
  • 해결방법
    • 입력에 대한 경계 검사를 한다.
    • strcpy()와 같이 버퍼 오버플로우에 취약한 함수를 사용하지 않는다.
  • 안전하지 않은 코드 예제

                   

  

  • 안전한 코드 예제

                  

 

4. 힙에 할당된 버퍼 오버플로우

  • 정의
    • 힙에 할당되는 버퍼들 (예, malloc() 함수를 통해 할당된 버퍼들)에 문자열 등이 저장되어 질 때, 최초 정의된 사이즈를 초과하여 문자열 등이 저장되는 경우
  • 해결방법
    • 입력에 대해 경계 검사를 한다.
    • strlcpy와 같이 버퍼 오버플로우 위험이 없는 함수를 사용한다.
  • 안전하지 않은 코드 예제

                  

 

 

  • 안전한 코드 예제

                   

 

 

 

5. 버퍼 시작 지점 이전에 쓰기

  • 정의
    • 포인터나 인덱스를 통해서 버퍼 시작 지점 이전에 데이터를 기록하는 오류이다. 배열인 경우 인덱스의 최저 위치 보다 적은 위치에 데이터를 기록하는 경우 발생하며 루프 내에서 점검 없이 포인터 감소 연산을 계속했을 경우 발생한다.
  • 해결방법
    • 버퍼에 인덱스나 포인터를 사용해 데이터를 기록할 경우 인덱스가 음수 값이 되거나 포인터 연산의 결과가 버퍼 이전의 값을 가지지 않도록 점검 후 사용한다.
  • 안전하지 않은 코드 예제
    • #include <stdio.h>

      void inverseWordOrder(char * string) {

          const int MAX_WORD_COUNT = 256;

          int wordIndex = MAX_WORD_COUNT - 1;

          char * words[MAX_WORD_COUNT]

          memset(words, NULL, MAX_WORD_COUNT * sizeof(int));

          char * token = strtok(string, " \t");

          while (token != NULL) {

              words[wordIndex] = token;

              token = strtok(NULL, " \t");

              wordIndex--;

          }

       

      }

  • 안전한 코드 예제
    • #include <vector>

      #include <stdio.h>

      using namespace std;

       

      void inverseWordOrder(char * string) {

          const int MAX_WORD_COUNT = 256;

          vector<char *> words(MAX_WORD_COUNT, NULL);

          int wordIndex = MAX_WORD_COUNT - 1;

       

          try

          {

              char * token = strtok(string, " \t");

              while (token != NULL) {

                  words.at(wordIndex) = token;

                  token = strtok(NULL, " \t");

                  wordIndex--;

              }

          }

      catch(const std::exception & exception)

      {

          // out_of_range exception 처리

      }

      }


 

 

6. 널 종료 문제

  • 정의
    • C에서 문자열의 끝을 나타내는 것이 널 문자이자. 개발자의 의도와 상관없이 널 문자가 붙지 않은 문자열이 생성될 수 있는데, 1) 문자열이 필요한 크기보다 작은 배열에 복사하는 경우, 2) 문자열을 strncpy() 함수를 이용해 복사할 때 실제 문자열보다 지정 크기가 작은 경우 등에 발생한다. 널 문자로 종료되지 않은 문자열을 다른 문자열에 복사할 때, 많은 양의 메모리가 복사되어 버퍼 오버플로우가 발생 가능하다.
  • 해결방법
    • read(), redline()로 읽을 문자열에 strcpy(), strcat(), strlen() 함수를 적용하지 않는다.
    • strlcpy()나 strcat() 과 같은 버퍼 오버플로우 위험이 없는 함수를 사용한다.
  • 안전하지 않은 코드 예제

               

 

  • 안전한 코드 예제

                

 

 

7. 의도하지 않은 부호 확장

 

 

  • 정의
    • 큰 수를 표현하는 데이터 형으로 값이 변환될 때 음수 값이 큰 양수 값으로 변환될 수 있다. 숫자형 데이터를 처리 할 때 해당 데이터 형보다 큰 데이터 형으로 복사되는 경우, 부호 확장이 수행된다. 특히, 음수 값을 unsigned로 복사하는 경우 잘못된 부호의 확장으로 엄청난 큰 숫자가 발생 할 수 있다.
  • 해결방법
    • 큰 사이즈의 변수와 작은 사이즈의 변수 사이의 값 교환 시 타입 체크를 통하여 잘못된 부호 확장이 일어나지 않도록 해야 한다.
  • 안전하지 않은 코드 예제
    • extern int info[256];

      int signed_overflow(int id) {

          short s;

          unsigned sz;

       

          s = id;

          if (s > 256)

              return 0;

          sz = s;

          return info[sz];

      }

  • 안전한 코드 예제
    • extern int info[256];

      int signed_overflow(int id) {

          int s;

          unsigned sz;

          s = id;

          if (s > 256 || s < 0)

              return 0;

          sz = (unsigned) s;

          return info[sz];

      }

 

 

 

8. 무부호 정수를 부호 정수로 타입 변환 오류

  • 정의
    • 무부호 정수 (unsigned integer)를 부호 정수 (signed integer)로 변환하면서 큰 양수가 음수로 변환될 수 있다. 이 값이 배열 인덱스로 사용되는 경우 프로그램 오동작이 발생된다.
  • 해결방법
    • 타입체크를 통해서 signed int를 묵시적으로 unsigned int로 변환되지 않도록 한다.
  • 안전하지 않은 코드 예제

#include <stdlib.h>

#include <string.h>

extern int initialized, chunkSize;

int chunkSz() {

    if (!initialized)

        return -1;

    return chunkSize;

}

void* chunkCpy(void *dBuf, void *sBuf) {

    unsigned size;

    size = chunkSz();

    return memcpy(dBuf, sBuf, size);

}

 

       

                

  • 안전한 코드 예제

#include <stdlib.h>

#include <string.h>

extern int initialized, chunkSize;

int chunkSz() {

    if (!initialized)

        return -1;

    return chunkSize;

}

void* chunkCpy(void *dBuf, void *sBuf) {

    int size;

    size = chunkSz();

    if (size < 0)

        return NULL;

    return memcpy(dBuf, sBuf, (unsigned) size);

}

 

                           

 

작성자 : mds 백정현

출처 : C 시큐어코딩 가이드 (행정안전부)

 

함수포인터를 사용하여 바이너리 파일 크기를 줄여보자.

Posted by ceyx
2017. 5. 23. 11:39 카테고리 없음
프로그램의 기능이 많아지면 #define 등의 지시문을 통해 해당 기능의 활성화를 설정합니다.

보통은 소스코드에  a, b, c 라는 기능을 다 구현해 놓고 릴리즈 할때 조건에 따라 a 기능을 활성화 할지, b 기능을 활성화 할지 또는 전부 활성화/비활성화 할지 여부를 결정하게 되는데요.

사용하지 않는 기능은 빼고 바이너리 파일을 만든다면 크기가 줄어 들겠지요.
이번 글은 함수 포인터를 이용해서 바이너리 파일의 크기를 줄일수 있는 방법에 대해 설명하겠습니다.

일반적으로 소스코드를 빌드하면 object 파일이 만들어지고 
링커스크립트를 통해 바이너리 파일과 ELF 파일이 생성됩니다. 

아래 그림은 ARM 기반으로 이와 같은 과정을 보여줍니다.

 


오브젝트 파일은 소스코드가 다 빌드되어 포함되지만 실제 사용하는 기능들은 링커스크립트가 동작하면서
선별하여 bin 파일이 만들어집니다.
보통은 직접 호출하는 함수들은 어김없이 들어갑니다만...
함수 포인터를 사용하여 해당 함수를 간접 호출 함으로써 필요없는 기능은 bin파일에 포함되지 않도록 할수 있습니다. 

다음과 같이 필요한 기능을 구현한 함수가 있습니다.

 

함수가 호출되면 코드상의 printf()를 통해 "Call testFunction1" 이라는 문구가 출력 되겠지요.


일반적으로 이 함수를 testFunction1(); 이렇게 호출하면 해당 함수가 수행 합니다.
여기서는 직접 호출하지 않고 함수 포인터에 등록 해봅시다.

 

먼저 함수 포인터를 선언합니다.

 

 

Function 은 다음과 같이 선언됩니다.

 


리턴값이 있는 함수는 Function 이라는 이름으로, 리턴값이 없는것은 VoidFunction이라고 지정합니다.
그럼 이제 함수포인터 nDTestFunction 에 해당 함수를 할당하는 함수를 만들어 봅니다.

 

 

이 함수의 호출 여부로 함수포인터에 함수를 할당 할지 여부를 결정할수 있습니다. 
이 함수가 수행되지 않으면 당연히 함수포인터는 NULL로 유지 되겠지요.

이제 해당 기능의 활성화 여부를 결정하는 #define CONFIG_TEST_FUNC 가 활성화 되었을때만 
DASetActivate() 함수를 호출 하면 되겠네요.

 

 

#define CONFIG_TEST_FUNC가 선언되지 않으면 nDTestFunction은 NULL 상태일 겁니다.

맨 처음 만들었던 필요한 기능을 수행 하는 함수 testFunction1 의 호출은 
다음과 같이 함수 포인터를 호출하는걸로 대신 할수 있습니다.

 

 

위와 같이 nDTestFunction이 NULL 이 아닐때,

즉 DASetActivate() 함수가 호출되어 함수 포인터에 testFunction1() 함수가 할당 되었을때만 수행하도록 합니다.

위와 같이 구현하고 빌드한 후 map 파일을 열어보면 testFunction1의 존재 여부가 달라집니다.

#define CONFIG_TEST_FUNC 활성화

 

 

 
중간에 testFunction1이 있습니다.

#define CONFIG_TEST_FUNC 비활성화

 

 
testFunction1 함수가 있던 곳은 다른 함수들로 채워져 있습니다.

활성화 후 실행 하면 다음과 같이 정상적으로 수행됩니다.

이와 같이 함수 포인터를 사용하여

필요없는 기능은 포함시키지 않고 바이너리 파일을 생성함으로써 크기가 그만큼 작게 만들어집니다.

감사합니다.

히말라야 도서관

Posted by ceyx
2011. 3. 1. 15:38 책/문학

히말라야도서관세계오지에3천개의도서관,백만권의희망을전한한사나?
카테고리 시/에세이 > 나라별 에세이 > 영미에세이
지은이 존 우드 (세종서적, 2008년)
상세보기

첫 책은 역시 "히말라야 도서관"
글쓴이가 前 MS직원이여서 그런지 왠지 더 동질감 느끼던 책이였다..

 네팔, 베트남, 캄보디아로 이어지는 존 우드의 활약을 잊을 수 없을 것이다..

 

보장된 안정적인 인생을 버리고, 새로운 길을 찾아 도전하는 자세야말로
진정 우리 젊은이들에게 필요한 정신이 아닐까 ?!

그 길을 언제 선택하느냐의 문제인 것이였다.
"일회용 반창고를 떼어네는데는 두 가지 방법이 있다.
 천천히 고통스럽게 떼어내는 것. 빠르고 고통스럽게 떼어내는 것.  선택은 나의 몫 !! "

 

 

 

- 2010년 2월 7일

우선순위를 고려한 사칙연산 (스택이용)

Posted by ceyx
2011. 1. 29. 18:15 카테고리 없음

스택을 이용하여, 우선순위를 고려한 사칙연산을 수행해주는 source입니다. 임의로 우선순위 숫자를 부여하고, 그에 따라 스택을 이용하여 postfix 로 변환한 후,연산을 수행하게 됩니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
import java.lang.String;
import java.util.StringTokenizer;
import javax.swing.JOptionPane;
 
class StackArray     // 스택 클래스
{
    Object firstStack[];
    
    int top;
    
    StackArray(int size) // 생성자
    {
        firstStack = new Object[size];
        top = -1// empty로 초기화
    }
    
    Object getItem(int index)  // index번째의 원소 리턴
    {
        return firstStack[index];
    }
    
    void push(Object ele)      // top에 원소 집어넣기
    {
        firstStack[++top] = ele;
    } 
 
    Object peek()            // top의 원소 보기
    {
        return firstStack[top];
    }
    
    Object pop()             // top의 원소 빼오기
    {
        return firstStack[top--];
    }
}
 
 
class Priority    // 우선순위 알려주는 클래스
{
    int getPri(Object ob)     // 우선순위를 리턴해 주는 메소드
    {
        String operator = (String)ob;
        int pri = -1
        
        if ( operator.equals("+") ) pri = 12;
        if ( operator.equals("-") ) pri = 12
        if ( operator.equals("*") ) pri = 13
        if ( operator.equals("/") ) pri = 13
        if ( operator.equals("%") ) pri = 13
        if ( operator.equals("^") ) pri = 14;
        
        return pri;
     }
}
 
 
 
public class toPostArith
{
    static StackArray mainStack;  //postfix 형태로 변형시킨 식이 들어가 있음.
    static StackArray rStack; // 최종결과가 들어있는 스택 
 
    public static void main(String args[])
    {
        String s1 = JOptionPane.showInputDialog("수식을입력하세요.."); // infix형태의 수식 inputData
        String ConvertPost = makePostFix(s1); // postfix형태로 만드는 메소드 호출. 
        makeFinal();
        JOptionPane.showMessageDialog(null,"PostFix로 전환하면 = "+ConvertPost+"\n"+"최종결과"+rStack.pop());
        System.exit(0);
    }
 
    static String makePostFix(String s2)
    {
        String inputData = s2;
        String nToken; // 토큰을 하나씩 받아와서 저장
        StringTokenizer parser;
        
        parser = new StringTokenizer(inputData,"+-*/^%",true);
        
        int num = parser.countTokens();    // 각 원소 갯수를 알아냄.
        mainStack = new StackArray(num);  // 실제로 필요한 스택자료저장 
 
        StackArray tempStack = new StackArray(num);  // +-/ 등(연산자)을 임시 저장하기위해 
 
          // 스택 사이즈로 num을 쓴 이유는 스택에는 각 원소(변수와 연산자)가 들어가므로 
          // 최대 사이즈가 그 원소의 총 개수와 같거나 작을뿐이기에 여유있게 잡아줌..
        
        String operators = "+-*/^%"// nToken의 값이 연산자인지 구별 
 
        while (parser.hasMoreTokens())      // 토큰이 없을때까지 실행
        {
            nToken = parser.nextToken(); 
 
            boolean isOperator = false;
                        // 연산자인지 아닌지 판별. 기본적으로 false. 즉 연산자 아님을 뜻함. 
 
            for ( int i=0 ; i < operators.length() ; i++ )
            {
                if ( nToken.equals(operators.substring(i,i+1)) ) // 만약 nToken이 연산자이면 true 
                { isOperator = true; } // 연산자일경우만 isOperator에 true를 넣어줌. 
            } 
 
            if ( isOperator == true )   // 연산자일경우 , 연산자 우선순위에 따라 처리..
            {
                Priority p = new Priority(); //  우선순위 관련 클래스를 만든다. 
 
                while ( (tempStack.top >= 0 && p.getPri(nToken) <= p.getPri(tempStack.peek())) )
                {
                    /* nToken의 우선순위와 스택 top에 있는 연산자의 우선순위를 비교하여 
                                             스택 top의 것이 같거나 클때, 반복수행됨. 
                                              연산자가 저장된 스택(tempStack)의 top의 것을 pop하여 
                                              다른 스택에 아래와 같이 push한다.중요!  */ 
                    
                    mainStack.push(tempStack.pop());  // 변수가 저장되는 스택에 pop한것을 push한다. 
                }
                
                tempStack.push(nToken);  // nToken의 우선순위가 스택 top에 있는 연산자 우선순위보다 
                  //큰것을 만족할때 nToken(연산자가 들어가있음)을 연산자가 들어가는 스택에 push한다. 
            }
            
            if ( isOperator == false// 일반 숫자일 경우는 그냥 push한다. 
            {   mainStack.push(nToken);   } 
        }
        
        while ( tempStack.top >= 0 )
        { 
 // 일단 모든 parser에 관해 처리를 했다면 남아있는 것(tempStack)들을 모두 pop해서 mainStack에 push한다. 
            mainStack.push(tempStack.pop());
        }
        
        String userView="";
        
        for (int i=0; i<=mainStack.top ;i++ )
        {
            userView = userView + mainStack.getItem(i);
                // 화면에는 pop을 이용해서 보이게 할수 없으므로..처음부터 get.. 
        }
        
        return userView;
    }
    
    static void makeFinal()
    {
        rStack = new StackArray(mainStack.top+1);
          // 만약 3개가 들어있으면 top은 2라는 값을 가지므로 +1 해 줘야 
          // 안전하게 스택사이즈 결정할수 있다.
        
        for ( int i=0; i <= mainStack.top ; i++ )
        {
            Object t = mainStack.getItem(i);  //i 번째 원소를 리턴해서 t에 대입.
            
            if ( t.equals("+")||t.equals("-")||t.equals("*")||t.equals("/")||t.equals("%")||t.equals("^"))
            {              // 연산자일경우.   아래와 같이 두번 팝(pop)한다.
                double latter = Double.valueOf((String)rStack.pop()).doubleValue(); 
                      //pop는 뒤에서부터 가져오는것이므로  먼저가져온것이 실제로 후자.
                double former = Double.valueOf((String)rStack.pop()).doubleValue();
                double temp = -1// 계산결과를 저장하는 변수,일단 임의의 값 -1대입. 
                
                if ( t.equals("+") )  { temp = former+latter; }
                if ( t.equals("-") )  { temp = former-latter; }
                if ( t.equals("*") )  { temp = former*latter; }
                if ( t.equals("/") )  { temp = former/latter; }
                if ( t.equals("%") )  { temp = former%latter; }
                if ( t.equals("^") )  { temp = getSquare(former,latter); }
                
                rStack.push(temp+"");  // 계산결과(temp)를 push해 준다.
            }
            else   // 연산자가 아닐경우
            {
                rStack.push(t); // 그냥 push해줌.
            }
        }
    }
    
    static double getSquare(double x,double exp)       // 거듭제곱
    {
        int i;
        double temp=1;
        
        for (i=1 ; i<=exp ; i++ )
        {   temp = temp * x;   }
        
        return temp;
    }
cs

 

 

자바 배운지 얼마 안됐을 때라.. 기억도 가물가물하고.. 지금보니 뭔가 ㅎㅎㅎㅎ