취업 준비
언제나 그렇듯이 먼저 터미널 창을 열고 명령을 실행하세요.update50
귀하의 신청서가 이미 최신 상태인지 확인하십시오. 시작하기 전에 cd ~ / workspace
wget http://cdn.cs50.net/2015/fall/psets/4/pset4/pset4.zip
이 작업의 ZIP 아카이브를 다운로드하려면 다음 단계를 따르세요. 이제 ls를 실행하면 ~/workspace 디렉토리 에 pset4.zip 이라는 파일이 있는 것을 볼 수 있습니다 . 다음 명령을 사용하여 추출합니다. ls 명령을 다시 실행하면 다른 디렉터리가 나타나는 것을 볼 수 있습니다. 이제 아래와 같이 zip 파일을 삭제할 수 있습니다. pset4 디렉토리를 열고 ls 를 실행한 후 디렉토리에 다음이 포함되어 있는지 확인하세요. unzip pset4.zip
rm -f pset4.zip
cd pset4
bmp / jpg / questions.txt
whodunit 또는 "누가 그랬어?"
기본 Windows XP 데스크톱(https://en.wikipedia.org/wiki/Bliss_(image))(언덕과 푸른 하늘)을 본 적이 있다면 BMP를 본 것입니다. 웹페이지에서 GIF를 본 적이 있을 것입니다. 디지털 사진을 보셨나요? 그래서 우리는 JPEG를 보는 기쁨을 누렸습니다. Mac에서 스크린샷을 찍어본 적이 있다면 PNG를 본 적이 있을 것입니다. 인터넷에서 BMP, GIF, JPEG, PNG 형식에 대해 읽고 다음 질문에 답하세요.-
각 형식은 몇 가지 색상을 지원합니까?
-
애니메이션을 지원하는 형식은 무엇입니까?
-
손실 압축과 무손실 압축의 차이점은 무엇입니까?
-
다음 중 손실 압축을 사용하는 형식은 무엇입니까?
-
FAT 파일 시스템에서 파일이 삭제되면 기술적인 관점에서 어떤 일이 발생합니까?
-
삭제된 파일을 복구할 수 없도록 (높은 확률로) 어떻게 해야 합니까?
xxd -c 24 -g 3 -s 54 smiley.bmp
아래에 표시된 내용이 표시되어야 합니다. 0000ff의 모든 인스턴스를 빨간색으로 다시 강조 표시했습니다. 가장 왼쪽 열의 이미지에서 파일의 첫 번째 바이트로부터의 오프셋에 해당하는 파일의 주소를 볼 수 있습니다. 모두 16진수 체계로 제공됩니다. 16진수 00000036을 10진수로 변환하면 54가 됩니다. 따라서 smiley.bmp 의 54번째 바이트를 보고 있는 것입니다 . 24비트 BMP 파일에서 처음 14 + 40 = 54바이트는 메타데이터로 채워집니다. 따라서 메타데이터를 보려면 다음 명령을 실행하십시오. smiley.bmp 에 ASCII 문자가 포함되어 xxd -c 24 -g 3 smiley.bmp
있으면 모든 점 대신 xxd의 가장 오른쪽 열에 해당 문자가 표시됩니다. 따라서 Smiley는 크기(해상도)가 8x8 픽셀인 24비트 BMP(각 픽셀은 24 ¼ 8 = 3바이트로 표시됨)입니다. 따라서 각 라인(또는 "스캔라인"이라고도 함)은 (8픽셀) x (픽셀당 3바이트) = 24바이트를 차지합니다. 이 숫자는 4의 배수이며 행의 바이트 수가 4의 배수가 아닌 경우 BMP 파일이 약간 다르게 저장되므로 중요합니다. 따라서 폴더에 있는 또 다른 24비트 BMP 파일인 small.bmp에서 녹색 3x3 픽셀 상자를 볼 수 있습니다. 이미지 뷰어에서 열면 아래 이미지와 비슷하지만 크기가 더 작은 것을 볼 수 있습니다. 따라서 small.bmp 의 각 줄은 (3픽셀) × (픽셀당 3바이트) = 9바이트를 차지하며 이는 4의 배수가 아닙니다. 4의 배수인 줄 길이를 얻으려면 추가로 0으로 채워집니다. 0에서 3바이트 사이의 각 줄을 24비트 BMP 형식으로 채웁니다(이유가 무엇인지 추측할 수 있습니까?). small.bmp 의 경우 (3픽셀) x (픽셀당 3바이트) + (3바이트 패딩) = 12바이트이므로 실제로는 4의 배수이므로 3바이트의 0이 필요합니다. 이 패딩을 "확인"하려면, 다음을 수행하십시오. -c 에는 smiley.bmp 와 다른 값을 사용하므로 xxd는 이번에는 4개의 열만 출력합니다(녹색 사각형에 3개, 패딩에 1개). 명확성을 위해 00ff00의 모든 인스턴스를 녹색으로 강조 표시했습니다. 대조적으로, Large.bmp 파일 에는 xxd를 사용하겠습니다 . small.bmp 와 정확히 동일해 보입니다.xxd -c 12 -g 3 -s 54 small.bmp
, 해상도만 12x12 픽셀, 즉 4배 더 큽니다. 아래 명령을 실행하세요. 전송을 방지하려면 창을 확장해야 할 수도 있습니다. xxd -c 36 -g 3 -s 54 large.bmp
다음과 같은 내용이 표시됩니다. 이 BMP에는 여담이 없습니다. 결국 (12픽셀) × (픽셀당 3바이트) = 36바이트이며 이는 4의 배수입니다. xxd 16진수 편집기는 BMP 파일의 바이트를 보여주었습니다. 프로그래밍 방식으로 어떻게 얻을 수 있습니까? copy.c 에는 BMP의 복사본을 하나씩 생성하는 것이 유일한 목적인 프로그램이 하나 있습니다. 예, 이에 대해 cp를 사용할 수 있습니다 . 그러나 CP는 Boddy 씨를 도울 수 없습니다. copy.c 가 이를 수행하기를 바랍니다 . 이제 ls를./copy smiley.bmp copy.bmp
실행하면 (적절한 플래그와 함께) smiley.bmp 와 copy.bmp 가 실제로 동일한 크기임을 알 수 있습니다 . 이것이 실제로 사실인지 다시 확인해 볼까요? 이 명령이 화면에 아무것도 표시하지 않으면 파일이 실제로 동일하다는 의미입니다(중요: Photoshop과 같은 일부 프로그램에는 일부 VMP 끝에 후행 0이 포함됩니다. 우리 버전의 복사본에서는 이를 삭제하므로 하지 마십시오). 테스트를 위해 다운로드했거나 생성한 다른 BMP를 복사하는 경우 복사본이 원본보다 몇 바이트 더 작아질 수 있으니 걱정하세요. Ristretto의 이미지 뷰어에서 두 파일을 모두 열어(더블 클릭) 이를 시각적으로 확인할 수 있습니다. 하지만 diff는 이 비교를 바이트 단위로 수행하므로 그녀의 시력은 귀하의 시력보다 더 예리합니다! 이 사본은 어떻게 만들어졌나요? copy.c는 bmp.h 와 관련이 있는 것으로 나타났습니다 . 확인하자: bmp.h를 엽니다.diff smiley.bmp copy.bmp
. 여기서는 이미 언급한 헤더의 실제 정의를 Microsoft 자체 구현에서 적용한 내용을 볼 수 있습니다. 또한 이 파일은 Win32(예: Windows) 프로그래밍 세계에서 일반적으로 발견되는 데이터 유형인 BYTE, DWORD, LONG 및 WORD 데이터 유형을 정의합니다. 이는 본질적으로 여러분에게 이미 친숙한 기본 요소에 대한 별칭입니다. BITMAPFILEHEADER 및 BITMAPINFOHEADER가 이러한 유형을 사용하고 있는 것으로 나타났습니다. 이 파일은 RGBTRIPLE이라는 구조체도 정의합니다. 이는 3바이트(파란색, 녹색, 빨간색) 3바이트를 "캡슐화"합니다(이는 디스크에서 RGB 삼중항을 찾는 순서입니다). 이 구조체는 어떻게 유용합니까? 요약하자면, 파일은 단순히 디스크에 있는 일련의 바이트(또는 궁극적으로 비트)입니다. 그러나 이러한 바이트는 일반적으로 처음 몇 개가 무언가를 나타내고 다음 몇 개가 다른 것을 나타내는 식으로 순서가 지정됩니다. 파일 "형식"은 바이트의 의미를 정의하는 표준 또는 규칙이 있기 때문에 존재합니다. 이제 디스크에서 RAM으로 파일을 하나의 큰 바이트 배열로 간단히 읽을 수 있습니다. 그리고 위치 [i]에 있는 바이트는 한 가지를 나타내고 위치 [j]에 있는 바이트는 다른 것을 나타낸다는 것을 기억합니다. 하지만 메모리에서 더 쉽게 검색할 수 있도록 이러한 바이트 중 일부에 이름을 지정하는 것은 어떨까요? 이것이 바로 bmp.h의 구조가 우리에게 도움이 되는 것입니다. 파일을 하나의 긴 바이트 시퀀스로 생각하는 대신 파일을 더 이해하기 쉬운 블록, 즉 구조 시퀀스로 분류하는 것을 볼 수 있습니다. smiley.bmp 의 해상도 는 8x8픽셀이므로 디스크에서 14 + 40 + (8 × 8) × 3 = 246바이트를 차지합니다(ls 명령을 사용하여 확인할 수 있습니다). Microsoft에 따르면 디스크에서의 모습은 다음과 같습니다. 구조체 멤버의 경우 순서가 중요하다는 것을 알 수 있습니다. rgbtBlue가 RGBTRIPLE에 먼저 정의되었기 때문에 바이트 57은 rgbtBlue(rgbtRed가 아님)입니다. 그건 그렇고, pack 속성을 사용하면 clang이 멤버를 "단어 정렬"(각 멤버의 첫 번째 바이트 주소가 4의 배수인 상태)하려고 시도하지 않도록 하여 결과에 구멍이 생기지 않도록 합니다. 디스크에는 전혀 존재하지 않는 구조입니다. 계속 진행합시다. bmp.h의 설명에 따라 BITMAPFILEHEADER 및 BITMAPINFOHEADER와 일치하는 URL을 찾으세요. 주목하세요. 좋은 순간입니다. MSDN(Microsoft Developer Network)을 사용하기 시작하셨습니다! copy.c 를 더 스크롤하는 대신 몇 가지 질문에 답하여 코드 작동 방식을 이해하세요. 언제나 그렇듯이 man 명령은 진정한 친구이며 이제 MSDN이기도 합니다. 답을 모른다면 구글에 검색해서 생각해 보세요. https://reference.cs50.net/에서 stdio.h 파일을 참조할 수도 있습니다.
-
메인에 중단점을 설정합니다(메인 라인 번호가 있는 눈금자의 왼쪽을 클릭하여).
-
터미널 탭 에서 ~/workspace/pset4/bmp 로 이동 하고 make를 사용하여 copy.c를 복사 프로그램으로 컴파일합니다.
-
debug50 copy smiley.bmp copy.bmp 를 실행하면 오른쪽에 디버거 패널이 열립니다.
-
오른쪽 패널을 사용하여 프로그램을 단계별로 살펴보세요. 참고 bf 및 bi . ~/workspace/pset4/questions.txt 에서 다음 질문에 답하세요.
-
stdint.h 는 무엇입니까 ?
-
프로그램에서 uint8_t , uint32_t , int32_t 및 uint16_t 를 사용하는 이유는 무엇입니까 ?
-
BYTE , DWORD , LONG 및 WORD 는 각각 몇 바이트를 포함합니까 (32비트 아키텍처 가정)?
- BMP 파일의 처음 2바이트는 무엇(ASCII, 10진수 또는 16진수)이어야 합니까? (파일 형식을 식별하는 데 사용되는 선행 바이트(확률 높음)를 종종 "마법의 숫자"라고 합니다).
-
bfSize와 biSize의 차이점은 무엇입니까?
-
음수 biHeight는 무엇을 의미합니까?
-
BITMAPINFOHEADER의 어떤 필드가 BMP의 색상 심도(즉, 픽셀당 비트 수)를 정의합니까?
-
copy.c 37에서 fopen 함수가 NULL을 반환할 수 있는 이유는 무엇입니까?
-
코드에서 fread의 세 번째 인수가 1인 이유는 무엇입니까?
-
bi.biWidth가 3인 경우 copy.c 70의 어떤 값이 패딩을 정의합니까?
-
fseek는 무엇을 합니까?
-
SEEK_CUR이 무엇인가요?
Mr. Boddy에게 돌아가세요. 운동:
Mr. Boddy의 그림을 보여주는 whodunit.c 라는 파일에 whodunit 이라는 프로그램을 작성하세요 . 흠, 뭐? 복사와 마찬가지로 프로그램은 정확히 두 개의 명령줄 인수를 취해야 하며, 아래와 같이 프로그램을 실행하면 결과가 verdict.bmp에 저장되므로 Boddy 씨의 그림이 시끄럽지 않게 됩니다. 아래 명령을 실행하여 이 미스터리 해결을 시작해 보세요. Mr. Boddy를 돕기 위해 작성해야 하는 코드 라인이 얼마나 많은지 보면 놀랄 것입니다. smiley.bmp 에는 불필요한 숨겨진 내용이 없으므로 이 파일에서 프로그램을 자유롭게 테스트해 보세요. 이것은 작으며 개발 중에 프로그램의 출력과 xxd의 출력을 비교할 수 있습니다(아니면 smiley.bmp 에 뭔가 숨겨진 것이 있을 수도 있습니까 ? 실제로는 그렇지 않습니다). 그런데 이 문제는 다양한 방법으로 해결될 수 있습니다. 일단 Boddy 씨의 그림을 확인하시면, 그는 편히 쉬실 것입니다. whodunit은 다양한 방법으로 구현될 수 있으므로 check50을 사용하여 구현의 정확성을 확인할 수 없습니다 . 그리고 그것이 당신의 재미를 망치게 놔두십시오. 그러나 추리 문제 에 대한 보조자의 솔루션도 사용할 수 없습니다 . 마지막으로 ~/workspace/pset4/questions.txt 파일에서 다음 질문에 답하세요../whodunit clue.bmp verdict.b
cp copy.c whodunit.c
Whodunit? //ктоэтосделал?
크기 조정
자, 이제 다음 테스트입니다! resize.c에 resize 라는 프로그램을 작성해 보겠습니다 . 압축되지 않은 24비트 BMP 이미지의 크기를 n단계로 조정합니다. 애플리케이션은 정확히 3개의 명령줄 인수를 허용해야 합니다. 첫 번째(n)는 100보다 크지 않은 정수, 두 번째는 수정될 파일의 이름, 세 번째는 수정된 파일의 저장된 버전의 이름입니다. 파일.Usage: ./resize n infile outfile
이러한 프로그램을 사용하면 아래와 같이 Small.bmp의 크기를 4로 조정하여(즉, 너비와 높이에 4를 곱하여) Large.bmp를 만들 수 있습니다. 단순화를 위해 copy.c를./resize 4 small.bmp large.bmp
다시 복사 하고 복사본 이름을 resize.c 로 지정하여 작업을 시작할 수 있습니다 . 그러나 먼저 다음 질문에 답해 보십시오. BMP 크기를 변경한다는 것은 무엇을 의미합니까(infile 크기의 n배는 232-1을 초과하지 않는다고 가정할 수 있습니다) . BITMAPFILEHEADER 및 BITMAPINFOHEADER에서 변경해야 할 필드를 결정합니다. 주사선 필드를 추가하거나 제거해야 하는지 고려하십시오 . 그리고 네, 0에서 1까지 n의 가능한 모든 값을 고려하라고 요청하는 것이 아니라는 사실에 감사하세요! (하지만 관심이 있으시다면 이것은 해커의 책에 나오는 문제입니다 ;)). 그러나 n = 1인 경우 프로그램은 올바르게 작동하고 출력 파일 outfile은 원래 infile과 동일한 크기라고 가정합니다. check50을 사용하여 프로그램을 확인하시겠습니까? 다음 명령을 입력하십시오. ~cs50/pset4/resize
예를 들어, (xxd 가 허용하는 것보다 더 사용자 친화적인 형식으로)
Large.bmp 헤더 를 보려면 다음 명령을 실행해야 합니다.
~cs50/pset4/peek large.bmp
CS50 보조 파일의 헤더와 헤더.
~/workspace/pset4/bmp 디렉터리 내에서 명령을 실행할 수 있습니다 (각 명령의 기능을 생각해 보세요).
malloc 을 사용한 경우 메모리 누수를 방지하려면
free 를 사용하세요 . 누출 여부를 확인하려면
valgrind를 사용해 보십시오 .
./resize 4 small.bmp student.bmp
~cs50/pset4/resize 4 small.bmp staff.bmp
~cs50/pset4/peek student.bmp staff.bmp
어떻게 결정하나요?
-
확대해야 할 파일을 열고 확대된 이미지가 기록될 새 파일을 만들어 엽니다.
-
출력 파일의 헤더 정보를 업데이트합니다. 이미지가 BMP 형식이고 크기를 변경 중이므로 새 크기로 새 파일의 헤더를 작성해야 합니다. 무엇이 바뀔까요? 파일 크기와 이미지 크기 - 너비와 높이.
-
우리는 나가는 파일을 한 줄씩, 한 픽셀씩 읽습니다. 이를 위해 다시 파일 I/O 라이브러리와 fread 함수를 사용합니다. 읽은 바이트 수, 읽을 단일 요소의 크기, 해당 요소의 수 및 읽을 파일에 대한 포인터를 포함하는 구조에 대한 포인터를 사용합니다.
-
지정된 스케일에 따라 각 라인을 수평으로 늘리고 그 결과를 출력 파일에 씁니다.
파일을 어떻게 작성하나요? 파일에 쓸 데이터가 있는 구조, 요소의 크기, 요소 수 및 출력 파일에 대한 포인터에 대한 표시기를 전달하는 fwrite 함수가 있습니다. 루프를 구성하려면 이미 익숙한 for 루프를 사용할 수 있습니다 .
-
부족한 부분을 채워보세요! 한 줄의 픽셀 수가 4의 배수가 아닌 경우 "정렬"(0바이트)을 추가해야 합니다. 정렬 크기를 계산하려면 공식이 필요합니다. 출력 파일에 널 바이트를 쓰려면 fputc 함수를 사용하여 쓰려는 문자와 출력 파일에 대한 포인터를 전달할 수 있습니다.
이제 문자열을 가로로 늘이고 출력 파일에 정렬을 추가했으므로 정렬을 뛰어넘어야 하므로 출력 파일에서 현재 위치를 이동해야 합니다.
-
세로 크기를 늘립니다. 더 복잡하지만 copy.c 의 샘플 코드를 사용할 수 있습니다(copy.c는 출력 파일을 열고, 출력 파일에 헤더를 쓰고, 소스 파일에서 이미지를 한 줄씩, 픽셀 단위로 읽고 이를 씁니다. 출력 파일에). 이를 바탕으로 가장 먼저 할 수 있는 일은 다음 명령을 실행하는 것입니다: cp copy.c resize.c
이미지를 세로로 늘린다는 것은 각 줄을 여러 번 복사하는 것을 의미합니다. 이를 수행하는 방법에는 여러 가지가 있습니다. 예를 들어, 다시 쓰기를 사용하면 한 줄의 모든 픽셀을 메모리에 저장하고 이 줄을 필요한 만큼 루프의 출력 파일에 쓸 수 있습니다. 또 다른 방법은 다시 복사하는 것입니다. 나가는 파일에서 한 줄을 읽고 이를 출력 파일에 쓰고 정렬한 후 fseek 함수 를 나가는 파일의 줄 시작 부분으로 되돌리고 모든 것을 여러 번 다시 반복합니다.
-
메모리 카드의 내용이 담긴 파일을 엽니다.
-
JPEG 파일의 시작 부분을 찾습니다. 이 카드의 모든 파일은 JPEG 형식의 이미지입니다.
다시 덮다
4주차 문제지를 예상하면서 지난 며칠 동안 디지털 카메라로 1GB CompactFlash(CF) 메모리 카드에 JPEG 형식으로 저장된 사진을 살펴보았습니다. 대신 제가 실제로 지난 며칠 동안 페이스북에서 시간을 보냈다고 말하지 마세요. 불행하게도 제 컴퓨터 실력이 많이 부족해서 저도 모르게 실수로 사진을 모두 삭제하게 되었어요! 다행스럽게도 컴퓨터 세계에서 "삭제"는 일반적으로 "죽음"을 의미하지 않습니다. 내 컴퓨터는 이제 메모리 카드가 비어 있다고 주장하지만 나는 그것이 거짓말이라는 것을 알고 있습니다. 과제: ~/workspace/pset4/jpg/recover.c 에 이 사진을 복구할 프로그램을 작성하세요 . 흠. 좋습니다. 한 가지 더 설명하겠습니다. JPEG 형식은 BMP보다 복잡하지만 JPEG에는 다른 파일 형식과 구별하는 데 도움이 되는 바이트 패턴인 "서명"이 있습니다. 대부분의 JPEG 파일은 다음과 같은 3바이트로 시작합니다.0xff 0xd8 0xff
첫 번째 바이트부터 세 번째 바이트까지, 왼쪽에서 오른쪽으로. 네 번째 바이트는 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,0xe8, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef 조합 중 하나일 가능성이 높습니다. 즉, JPEG 파일의 네 번째 바이트의 처음 4비트는 1110입니다. 사진이 저장된 드라이브(내 메모리 카드 등)에서 이러한 패턴 중 하나를 발견하면 이것이 JPEG 파일의 시작이 될 가능성이 있습니다. 물론 어떤 디스크에서 우연히 이런 일이 발생할 수 있으며 데이터 복구는 정확한 과학이라고 할 수 없습니다.
GO TO FULL VERSION