복기

 

먼저 이 문제는 제가 풀지못한 문제입니다. 결국 다른 사람의 풀이를 보고 풀었죠...ㅜㅜ

 

구슬이 중간에서 터지면 위의 구슬이 떨어져서 밑이랑 색이 같으면 또 터지는 뿌요뿌요 게임처럼 삭제된 문자열 좌우 문자를 붙혀서 A 문자열이 나오면 또 삭제를 해줘야하는 점이 아마 이 문제를 까다롭게 만드는 점인 것 같은데요.

 

먼저, 아래는 다른 사람 풀이를 보고 작성한 코드입니다.

 

더보기

 

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
// 검열
#include <stdio.h>
#pragma warning(disable : 4996)
char A[35], T[300015], s1[300015], s2[300015], b;
int len, l, r, t1, t2;
 
char check(void) {
    if (0 == b) {
        if (t1 < len) return 0;
        for (int i = 1; i <= len; i++) {
            if (s1[t1 - i] != A[len - i]) {
                return 0;
            }
        }
    }
    else {
        if (t2 < len) return 0;
        for (int i = 1; i <= len; i++) {
            if (s2[t2 - i] != A[i - 1]) {
                return 0;
            }
        }
    }
    return 1;
}
int main(void) {
    scanf("%s %s", A, T);
    for (len = 0; A[len]; len++);
    for (r = 0; T[r + 1]; r++);
 
    while (l <= r) {
        if (0 == b) {
            s1[t1++= T[l++];
            if (s1[t1 - 1== A[len - 1]) {
                if (check()) {
                    t1 -= len;
                    b ^= 1;
                }
            }
        }
        else {
            s2[t2++= T[r--];
            if (s2[t2 - 1== A[0]) {
                if (check()) {
                    t2 -= len;
                    b ^= 1;
                }
            }
        }
    }
    b = 0;
    while (t2) {
        s1[t1++= s2[--t2];
        if (s1[t1 - 1== A[len - 1]) {
            if (check())
                t1 -= len;
        }
    }
    s1[t1] = 0;
    return !printf("%s\n", s1);
}// 1
cs

 

위 코드가 제가 맨처음 작성했던 코드와 다른 점은 비교를 앞에서부터 하는가 뒤에서부터 하는가 입니다.

 

글이 좀 애매한데 어떤 의미인가 하면

 

 
 A: aac


 T: aaaaaaccc

 

위의 입력이 주어졌을 때, T의 왼쪽에서부터 A 문자열과 일치하는 문자열을 찾는 상황에서

 

앞에서부터 비교한다는건 (a a c 순으로 비교) 아래와 같이 일치하는 문자열을 찾았을 때 인덱스가 4 가 되는 것이고

 

뒤에서부터 비교한다는건 (c a a 순으로 비교) 인덱스가 6 일 때 아래 상황이 되는 겁니다. 

 

 
 aaaa (aac) cc



별 것 아닌 차이 같지만 앞문자부터 비교하면 삭제후 다음 인덱스부터 앞방향 탐색 범위에 삭제 때문에 끊기고 뒤에 남은 문자들이 포함되지 못합니다. 추가로 뭔 짓거리를 더 해줘야 하는 셈이죠. : aaaa (c->) c

 

반면에 뒷문자부터 비교하면 삭제후 다음 인덱스로 옮겨도 버퍼 안의 내용과 비교하면 탐색하던 방향 그대로 뒤에 남은 문자들을 포함해서 비교할 수 있죠 : aaaa (<-c) c

 

물론 전자처럼 구현해도 관계는 없을 겁니다. 하지만, 확실히 후자가 쉬운 길인 것 같네요.

 

더보기
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
// 검열
#include <stdio.h>
#include <string.h>
#pragma warning(disable : 4996)
volatile char A[33], T[300015];
volatile int len, f, r;
 
struct Stack {
    char data[300015];
    int top;
} s1, s2;
void Push(Stack *ps, char in)    { ps->data[ps->top++= in;    }
char Pop(Stack *ps)                { return ps->data[--(ps->top)];    }
int GetCount(Stack *ps)            { return ps->top; }
 
int main(void) {
    scanf("%s %s", A, T);
    for (len = 0; A[len]; len++);
    for (r = 0; T[r]; r++);
    
    char bSame;
    int n;
    while (r - f >= len) {
        while (r - f >= len) {
            bSame = 1;
            for (int i = 0; i < len; i++) {
                if (T[f + i] != A[i]) {
                    bSame = 0;
                    break;
                }
            }
            if (bSame == 0
                Push(&s1, T[f++]);
            else {
                n = GetCount(&s1);
                n = n < len - 1 ? n : len - 1;
                f += len - n;
                for (int i = n - 1; i >= 0; i--)
                    T[f + i] = Pop(&s1);
            }
            while (GetCount(&s2) > 0 && r - f < len) {
                T[r++= Pop(&s2);
                T[r] = 0;
            }
            if (bSame == 1break;
        }
        while (r - f >= len) {
            bSame = 1;
            n = r - len;
            for (int i = 0; i < len; i++) {
                if (T[n + i] != A[i]) {
                    bSame = 0;
                    break;
                }
            }
            if (bSame == 0
                Push(&s2, T[--r]);
            else {
                n = GetCount(&s2);
                n = n < len - 1 ? n : len - 1;
                r -= len - n;
                T[r] = 0;
                for (int i = n; i > 0; i--)
                    T[r - i] = Pop(&s2);
            }
            while (GetCount(&s1) > 0 && r - f < len) 
                T[--f] = Pop(&s1);
            if (bSame == 1break;
        }
    }
    while (GetCount(&s1) > 0)
        T[--f] = Pop(&s1);
    while (GetCount(&s2) > 0)
        T[r++= Pop(&s2);
    T[r] = 0;
    return !printf("%s\n", T + f);
} // 2
cs

 

 

위 코드는 전자 방법으로 푼 코드이고 문자열 삭제후 뒤에 남은 문자랑 비교하려고 (A 문자열 길이 -1) 개 문자를 저장 버퍼에서 빼는... 쓰잘데기 없이 일을 만들어서 하는 방법입니다. 

 

그리고, 사실 이 코드는 틀린 코드입니다. 이유는 잘 모르겠지만 "출력 초과"로 나오네요.. ㅠ_ㅠ

 

'일단 머리좀 식히고 답을 잊을 때쯤 다시와서 틀린 이유를 찾아보자' 는 의미에서 이 코드도 남깁니다.

 

혹여 지나가던 고수님께서 이유를 집어 주신다면 감사할 따름이고요 ㅎㅎ.

 

복기끝

 

 

사실 지금 든 생각이지만 이 것도 시작 문자 한 개만 버퍼랑 비교하고 나머지는 T랑 비교하면 전자나 후자나 다를게 없겠다는 생각이 드네요............. 

지금까지 쓴 글이... ++'

'개발 > c' 카테고리의 다른 글

[백준] 17825 주사위 윷놀이  (0) 2020.04.24
[백준] 17822 원판 돌리기  (0) 2020.04.22
[백준] 4179 불!  (0) 2018.12.13
winpcap pcap_pkthdr 구조체에서 caplen과 len의 차이  (0) 2018.12.01
ffmpeg 라이브러리 사용법  (2) 2018.11.16



복기



이 전에 이와 비슷한 문제를 푼 적이 있었고 풀면 풀리겠다 생각했습니다. 


네... 방심을 했던거죠. 저의 전략은 이랬습니다.


일단, 불을 BFS로 먼저 퍼뜨립니다.


이 때, 맵의 각 칸에 언제 불이 도달하는지에 대한 값을 써넣습니다.


이후 지훈이를 큐에 넣고 똑같이 BFS를 돌립니다.


큐안에 들어간 지훈이는 현재의 시간값?!을 가졌기 때문에 주위 칸에 도착했을 때


이 칸이 이미 옛날 옛적에 불에 뒤덮힌 칸인지, 아직 불이 오지 않은 칸인지 알 수 있습니다.



사실 위와 같은 풀이는 방문 여부를 check하는 배열을 맵으로 대신해서 메모리를 아껴보고자 하는 욕심에서


비롯된 풀이였습니다만, 이때 저는 지훈이의 방문을 check하지 않는 실수를 범합니다.


지훈이가 시간 값을 가지기 때문에 불이 일찍이 덮친 칸들로 이동하지 못하고 (큐에 들어가지 못하고)


루프가 종료될 것으로 생각했습니다.



하지만, 불이 애초에 가지 못한 곳은 지훈이가 이동하면서 check해주지 않으면 영원히 0의 값을 가지게 됩니다.


큐가 터지게 되는거죠...


런타임 에러를 보고도 여기까지 생각하지 못하고 뭐지? 하며 황당했던 지난 날의 나를 용서합니다. ㅋ


결국 답답함을 이기지 못하고 다지우고 visit 배열을 사용해서 문제를 풀었고


다시 푸는 과정에서 위와 같은 케이스, 예를 들면, 5 5 에서


 #

 #

 #

 #

 #

 #

 .

 .

 .

 #

 #

 .

 J

 .

 #

 #

 .

 .

 .

 #

 #

 #

 #

 #

 #

 

이와 같이 입력이 주어져 지훈이가 벽 안에서 계속 싸돌아 다니게 되는... 경우를 생각하게 됐습니다.


이후 지훈이의 방문 확인도 맵을 이용하면서 결국 visit 배열 메모리를 아껴서 문제를 다시 풀었습니다.


오기로 풀었습니다. ㅋㅋ




코드
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
#include <stdio.h>
 
struct Crd { int x, y; };
int in[1010][1010];
Crd q[1000010];
int f, r;
int main(void) {
    int R, C, sx, sy, x, y, xx, yy, i, j;
    char ct;
    scanf("%d %d"&R, &C); getchar();
    for (i = 0; i < R; i++) {
        for (j = 0; j < C; j++) {
            ct = (char)getchar();
            if (ct == 'J') sx = i, sy = j;
            else if (ct == '#') in[i][j] = -1;
            else if (ct == 'F') in[i][j] = 1, q[r].x = i, q[r++].y = j;
        }
        getchar();
    }
 
    while (f < r) {
        x = q[f].x, y = q[f++].y;
 
        for (i = 0; i < 4; i++) {
            xx = x + "1210"[i] - '1';
            yy = y + "2101"[i] - '1';
 
            if (xx < 0 || R <= xx || yy < 0 || C <= yy || in[xx][yy]) continue;
            in[xx][yy] = in[x][y] + 1;
            q[r].x = xx, q[r++].y = yy;
        }
    }
 
    f = r = 0;
    q[r].x = sx, q[r++].y = sy;
    in[sx][sy] = 1;
    int ans = 0x7fffffff;
 
    while (f < r) {
        x = q[f].x, y = q[f++].y;
        if (x == 0 || y == 0 || x == R - 1 || y == C - 1) {
            ans = in[x][y];
            break;
        }
 
        for (i = 0; i < 4; i++) {
            xx = x + "1210"[i] - '1';
            yy = y + "2101"[i] - '1';
 
            if (xx < 0 || R <= xx || yy < 0 || C <= yy) continue;
            if (in[xx][yy] && in[xx][yy] <= in[x][y] + 1continue;
            in[xx][yy] = in[x][y] + 1;
            q[r].x = xx, q[r++].y = yy;
        }
    }
 
    if (ans == 0x7fffffffprintf("IMPOSSIBLE");
    else                   printf("%d", ans);
    return 0;
}
cs


복기 끝.

'개발 > c' 카테고리의 다른 글

[백준] 17822 원판 돌리기  (0) 2020.04.22
[백준] 3111 검열  (0) 2019.03.05
winpcap pcap_pkthdr 구조체에서 caplen과 len의 차이  (0) 2018.12.01
ffmpeg 라이브러리 사용법  (2) 2018.11.16
ffmpeg 이란?  (1) 2018.11.02

winpcap man page에서 "pcap_pkthdr" 이란 구조체를 봤습니다.

 

확실하진 않지만 winpcap을 사용하면 LAN으로 들어오는 데이터들을 Packet 단위로 읽을 수 있는 것 같습니다.

 

이 때, 각 Packet은 "헤더 + 페이로드" 로 분류가 되고

 

"pcap_pkthdr" (packet capture - packet header) 는 그 이름처럼 헤더에 대한 정보를 받아옵니다.

 

이 구조체에는 아래처럼 딱 세가지 멤버가 있습니다.

 



struct timeval ts;
bpf_u_int32 caplen;
bpf_u_int32 len;

 

여기서 caplen과 len의 차이가 뭘까? 궁금해서 찾아봤습니다. 출처

 

결론만 말하자면 caplen은 captured length 실제 읽은 길이를 뜻하고

 

len은 이번에 capture한 packet의 length를 뜻하는 것 같습니다.

 

 

무슨 말인고... 영어는 잘못하지만 나름 해석을 해보니

 

packet을 받기전에 앞으로 받을 packet의 최대 길이를 설정할 수 있다는 것 같습니다.

 

 

예를 들면, pcap은 packet 단위로 데이터를 가져다 주는데 이번에 들어온 packet은 길이가 100입니다.

 

그런데 처음에 한 번에 읽을 최대 길이를 60으로 설정했다면

 

실제 읽은 데이터 길이 (caplen) 은 60이 되고 capture한 packet의 실제 길이 (len)은 100이 됩니다.

'개발 > c' 카테고리의 다른 글

[백준] 17822 원판 돌리기  (0) 2020.04.22
[백준] 3111 검열  (0) 2019.03.05
[백준] 4179 불!  (0) 2018.12.13
ffmpeg 라이브러리 사용법  (2) 2018.11.16
ffmpeg 이란?  (1) 2018.11.02

문제


Visual Studio 2008 에서 MFC로 코드 작성 중 이상한 일을 겪었습니다.


갑자기 Class View에서 Control과 연결된 변수를 자동 생성하는 기능이 안되더라고요.


MFC를 개인적으로 공부했거나 많이 경험했던게 아니라서 순간, 아 원래 Class View에서 하는 게 아니었나?


하고 한참을 찾아 헤맸더랬죠.


결국 Resource View에서 변수 추가하는 기능을 발견해서 추가해봤지만 아래와 같은 에러만 볼 수 있었습니다.


add/remove operation is impossible because the code element is read only 


알고보니 가끔가다 발생하는 에러더라고요. Visual Studio에 이런 결함이 ... 역시 최신 버전을 써야겠죠



해결 방법


프로젝트 폴더에서 ".suo", ". ncb" 파일을 삭제하고 프로젝트를 리빌드하면 기능이 정상적으로 작동합니다.



출처


 



 저는 입사 4개월차 초보 개발자 입니다.
전문가가 아니기에 작성하는 정보에 오류가 있을 수 있음을 밝힙니다.


오류가 있을 경우 지적해주시면 최대한 고치도록 노력하겠습니다. 
모든 정보는 정확하지 않을 경우 추측성 어조를 사용해 표현했습니다.
또한, 되도록 출처와 관련된 정보를 포함하는 링크 주소를 남기려 노력했습니다.
감사합니다.

 

 

ffmpeg 라이브러리 사용하기 1단계

- 설치 및 예제 컴파일

 

작성일

- 2018-11-16

환경

- windows10 64bit

- visual studio 2017

 

 

 

1. 설치하기

 

 

위 사이트에서 빨간색 네모 박스가 쳐진 선택지를 각각 선택한 후 다운로드 하면 됩니다.

 

저의 경우 Version은 위의 20181114-... 을 선택했고 Architecture은 64bit를 선택했습니다.

 

Linking은 SharedDev 둘 모두 다운받아야합니다.

 

 

설치 후 압축을 풀면 위의 왼쪽 사진과 같게됩니다.

 

여기서 필요한 것은 빨간 화살표가 가리키고 있는 bin, include, lib 폴더입니다.

 

이들만 따로 복사해서 ffmpeg이라는 이름의 폴더 안에 별도로 넣어 관리하면 편리하게 사용할 수 있습니다.

 

 

 

2. 프로젝트에 추가하기

 

visual studio 2017 을 사용해 Test용으로 빈프로젝트를 하나 만들었습니다.

 

프로젝트 폴더 안에 위에서 만든 ffmpeg이라는 이름의 폴더를 복사 붙여넣기합니다.

 

이제 폴더안의 bin, include, lib 각각을 프로젝트에 추가해 주어야합니다.

 

a. bin

동적 라이브러리 (*.dll) 가 들어있는 폴더 입니다.

 

'프로젝트(P) - 프로젝트 속성(P) - 구성 속성 - 디버깅 - 환경' 의 경로에 bin 폴더의 경로를 추가합니다.

 

PATH=원하는 경로;%PATH% 의 형태로 입력하면 됩니다.

 

저의 경우 'PATH=$(SolutionDir)\addition\ffmpeg\bin;%PATH%' 와 같이 경로를 추가했습니다.

 

b. include

헤더 파일 (*.h) 이 들어있는 폴더 입니다.

 

'프로젝트(P) - 프로젝트 속성(P) - 구성 속성 - C/C++ - 일반 - 추가 포함 디렉터리' 의 경로에 include 폴더의 경로를 추가합니다.

 

저의 경우 '$(SolutionDir)\addition\ffmpeg\include' 와 같이 경로를 추가했습니다.

 

c. lib

정적 라이브러리 (*.lib) 가 들어있는 폴더 입니다.

 

'프로젝트(P) - 프로젝트 속성(P) - 구성 속성 - 링커 - 일반 - 추가 라이브러리 디렉터리' 의 경로에 lib 폴더의 경로를 추가합니다.

 

저의 경우 '$(SolutionDir)\addition\ffmpeg\lib' 와 같이 경로를 추가했습니다.

 

정적 라이브러리의 경우 추가적으로

 

'프로젝트(P) - 프로젝트 속성(P) - 구성 속성 - 링커 - 입력 - 추가 종속성' 의 경로에 사용할 lib 파일 이름을 추가합니다.

 

저의 경우 avformat.lib, avcodec.lib, avutil.lib 세 가지를 추가했습니다.

 

이 것으로 프로젝트에 ffmpeg 라이브러리 추가가 끝났습니다.

 

 

 

3. 예제 코드 빌드 및 에러 잡기

 

이제 기본 예제 코드를 빌드해보겠습니다.

 

1
2
3
4
5
6
7
8
9
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/avutil.h>
#include <stdio.h>
 
int main(void) {
    av_register_all();
    return 0;
}
cs

 

여러 가지 에러가 발생합니다. 발생한 에러들과 해결 방법을 정리합니다.

 

 

 

fatal error C1189: #error:  missing -D__STDC_CONSTANT_MACROS / #define __STDC_CONSTANT_MACROS

 

참고

 

libavutil의 common.h 에서 __STDC_CONSTANT_MACROS가 정의되지 않았을 경우 에러가 발생하도록 해놓아서 발생하는 에러입니다.

 

잘 모르겠지만,  

__STDC_CONSTANT_MACROS 를 정의하면 C++프로그램이 C99 표준에 정의된 stdint.h 를 사용할 수 있다고 하는 것 같습니다.

 

ffmpeg 헤더 파일들을 include 하기 전에 아래 코드를 삽입하면 해결됩니다.

 

1
2
3
#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS
#endif
cs
 
error LNK2019: "void __cdecl av_register_all(void)" (?av_register_all@@YAXXZ) 외부 기호(참조 위치: _main 함수)에서 확인하지 못했습니다.

 

참고

 

테스트를 위해 사용한 함수 av_register_all()이 deprecated 이기 때문에 발생하는 에러입니다.

 

예전에는 사용했지만 지금은 또는 이제 머지 않을 미래에는 사용하지 않을 함수이니 다른 방법을 사용하라는 뜻입니다.

 

프로젝트 맨 위에 다음 코드를 작성하면 해결됩니다.

 

1
#pragma warning(disable : 4996)
cs
 
LNK2019 "void __cdecl av_register_all(void)" (?av_register_all@@YAXXZ) 외부 기호(참조 위치: _main 함수)에서 확인하지 못했습니다.

 

참고 참고1

 
ffmpeg library가 c언어로 작성되었기 때문에 이를 c++ 파일에서 불러올 경우 발생하는 문제입니다. (키워드 : Name Mangling)
 
파일의 확장자를 .c로 변경하거나  extern "C" {}  블럭으로 ffmpeg 헤더 파일 선언부를 감싸 해결할 수 있습니다.
 

 

 

빌드를 성공적으로 마쳤습니다.

 

 

이번 글에서는 ffmpeg 라이브러리를 설치하고 예제 코드를 빌드해보았습니다.

 

 

감사합니다.

'개발 > c' 카테고리의 다른 글

[백준] 17822 원판 돌리기  (0) 2020.04.22
[백준] 3111 검열  (0) 2019.03.05
[백준] 4179 불!  (0) 2018.12.13
winpcap pcap_pkthdr 구조체에서 caplen과 len의 차이  (0) 2018.12.01
ffmpeg 이란?  (1) 2018.11.02


먼저, 저는 그저 모 중소 기업의 신입 개발자에 불과함을 밝힙니다.
이는 제가 전문 지식을 가지고 글을 작성하는 것이 아니고 단순히 책이나 인터넷을 참조해서 글을 작성함을 뜻합니다.
따라서, 100% 정확하지 않을 수 있으며 최대한 추측 글과 출처를 밝히도록 노력할 것입니다.
이 글이 기억력이 좋지 않은 제자신과 똑같은 문제로 고민하는 다른 신입 개발자 분들께 도움이 되길 바랍니다.

 

 

 

FFMPEG 이란? - 본인 정의 -

 

동영상과 관련된 여러 처리를 할 수 있는 것 ( Thing ) 입니다. ( 확장자를 변경한다거나 영상을 자르고 붙이고 하는 등의 처리, 편집이 가능합니다. )

 

이용하는 입장에선 프로그램라이브러리 두가지로 나누어 볼 수 있습니다.

 

 

  • 프로그램

프로그램은 다운 받으면 실행 파일을 얻는데 ( ffmpeg.exe )

 

실행 파일이 있는 경로에 동영상 파일을 같이 놓고 cmd나 powershell을 사용해서 영상 관련 처리를 할 수 있습니다.

 

EX )

 

"sample.avi" 를 "sample.mp4"로 변경하고 싶을 경우

 

.\ffmpeg -i sample.avi sample.mp4

 

이와 같이 작성할 수 있습니다.

 

 

  • 라이브러리

ffmpeg 라이브러리는 말 그대로 개발을 위한 라이브러리입니다.

 

따라서 다운 받을 경우

 

 

bin  *.dll 동적 라이브러리가 들어있는 폴더
 include  *.h 헤더 파일이 들어있는 폴더
 lib  *.lib 정적 라이브러리가 들어있는 폴더

 

 

위 세 가지를 얻을 수 있고 프로젝트에 추가해서 사용하면 됩니다.

 

API는 ffmpeg 사이트를 참조할 수 있습니다.

 

 

이상으로 ffmpeg이 어떤 느낌인지 알아 보았습니다.

 

다음 포스트에선 각각의 사용 방법에 대해 알아 보겠습니다.

 

 

'개발 > c' 카테고리의 다른 글

[백준] 17822 원판 돌리기  (0) 2020.04.22
[백준] 3111 검열  (0) 2019.03.05
[백준] 4179 불!  (0) 2018.12.13
winpcap pcap_pkthdr 구조체에서 caplen과 len의 차이  (0) 2018.12.01
ffmpeg 라이브러리 사용법  (2) 2018.11.16

+ Recent posts