파일에 든 바이트를 눈으로 살펴보려고 덤프 표를 찍는다.
첫 줄에 바이트의 수 n, 한 줄에 놓는 바이트의 수 w, 첫 바이트의 주소 s가 주어진다.
둘째 줄에 바이트 n개가 차례로 주어진다.
바이트를 앞에서부터 w개씩 묶어 한 줄씩 쓴다. 마지막 줄은 w개보다 적을 수 있다.
0부터 세어 k번째 바이트의 주소는 s + k이다.
한 줄은 다음 네 부분을 차례로 이어 쓴다.
첫째, 그 줄 첫 바이트의 주소를 16진수 소문자 여덟 자리로 쓰고 쌍점(:)을 붙인다. 자리가 모자라면 앞을 0으로 채운다.
둘째, 바이트마다 빈칸 하나를 쓰고 그 바이트를 16진수 대문자 두 자리로 쓴다(10은 0A).
셋째, 그 줄의 바이트가 w개보다 적으면 모자란 바이트 하나마다 빈칸 세 개를 쓴다.
넷째, 빈칸 두 개와 | 를 쓰고, 바이트마다 글자 하나를 쓴 뒤 | 로 닫는다. 바이트의 값이 32 이상 126 이하이면 그 코드의 ASCII 글자를 쓰고, 아니면 마침표(.)를 쓴다.
바이트의 개수와 값이 바로 앞 묶음과 모두 같은 묶음은 줄을 쓰지 않는다.
이렇게 쓰지 않은 줄이 잇달아 있으면, 몇 줄이든 그 자리에 * 하나만 있는 줄을 한 번 쓴다.
맨 끝에 n bytes, sum S 꼴의 줄을 쓴다. n과 S는 10진수이고, S는 모든 바이트의 값을 더한 수다.
입력
1 ≤ n ≤ 6000, 1 ≤ w ≤ 16, 0 ≤ s, s + n ≤ 4294967296. 바이트는 0 이상 255 이하의 정수이고 빈칸 하나로 띄워 주어진다
실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).
$ 준비됐어요
코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.
다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이
수를 16진수로, 자리 수까지 맞춰 쓰는 방법이 언어마다 달라요. Python은 f"{b:02X}"와 f"{a:08x}", C는 printf("%02X", b)와 printf("%08llx", a), Java는 String.format("%02X", b)와 String.format("%08x", a), C#은 b.ToString("X2")와 a.ToString("x8")처럼 서식 하나로 진법·자리 수·대소문자를 함께 정해요. JS·TS의 b.toString(16)은 소문자이고 자리도 맞춰 주지 않아서 toUpperCase()와 padStart(2, "0")를 이어 써요. C++은 std::cout << std::hex << std::setfill('0') << std::setw(2) << b처럼 조작자를 걸어요. 크레이콘에는 16진수 서식이 없어서 남은 % 16으로 한 자리를 고르고 수학.몫(남은, 16)으로 줄여 가며 직접 만들고, 글자는 글자.글자로변환(b)로 얻어요. 함정 하나: 0 채우기를 빼면(Python {b:X}) 16보다 작은 바이트가 한 자리가 돼요. 첫째 예시의 10이 0A가 아니라 A로 나오고 그 뒤가 한 칸씩 당겨져요. 함정 둘: JS의 toString(16)은 소문자라서 toUpperCase()를 빼면 6C가 6c로 나와요. 주소는 소문자, 바이트는 대문자예요. 함정 셋: C++의 std::hex, std::setfill, std::uppercase는 한 번 걸면 계속 남아요(std::setw만 바로 다음 값 하나에 걸려요). std::dec으로 되돌리지 않으면 첫째 예시의 맨 끝 줄이 13 bytes, sum 621이 돼요. 함정 넷: 마지막 줄이 짧을 때 모자란 바이트마다 빈칸 세 개를 채우지 않으면 |가 앞으로 당겨져요(첫째 예시의 셋째 줄). 함정 다섯: 글자로 쓰는 것은 126까지예요. 127(DEL)은 보이는 글자가 아니에요. b <= 127로 쓰면 첫째 예시 둘째 줄에 . 대신 127번 글자가 그대로 들어가요. 함정 여섯: 같은 묶음이 여러 번 이어져도 *는 한 번만 써요. 둘째 예시에서 쓰지 않은 줄은 둘이지만 *는 한 줄이에요. 함정 일곱: 주소가 4294967295까지라서 32비트 int(약 21억까지)에 담기지 않아요. C#에서 주소를 int.Parse로 읽으면 OverflowException으로 멈춰요. C·C++은 long long, Java·C#은 long에 담아요. 이 경우는 예시에 없어요(s가 2147483648 이상일 때 드러나요).
Pythonmain.py · 22 줄
n, w, s = map(int, input().split())data = list(map(int, input().split()))out = []prev = None # 바로 앞 줄의 바이트들starred = False # 생략 표시 *를 이미 썼는가for i in range(0, n, w): row = data[i:i + w] if row == prev: if not starred: out.append("*") starred = True continue prev = row starred = False # 바이트는 대문자 16진수 두 자리, 모자란 칸은 빈칸 세 개 hexes = "".join(f" {b:02X}" for b in row) + " " * (w - len(row)) text = "".join(chr(b) if 32 <= b <= 126 else "." for b in row) # 주소는 소문자 16진수 여덟 자리 out.append(f"{s + i:08x}:{hexes} |{text}|")out.append(f"{n} bytes, sum {sum(data)}")print("\n".join(out))
JavaScriptmain.js · 26 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");const [n, w, s] = lines[0].trim().split(/\s+/).map(Number);const data = lines[1].trim().split(/\s+/).map(Number);const out = [];let prev = ""; // 바로 앞 줄의 바이트 부분(주소 뺀 문자열)let starred = false; // 생략 표시 *를 이미 썼는가let sum = 0;for (let i = 0; i < n; i += w) { const row = data.slice(i, i + w); for (const b of row) sum += b; // 바이트는 대문자 16진수 두 자리, 모자란 칸은 빈칸 세 개 const hexes = row.map((b) => " " + b.toString(16).toUpperCase().padStart(2, "0")).join("") + " ".repeat(w - row.length); if (hexes === prev) { if (!starred) out.push("*"); starred = true; continue; } prev = hexes; starred = false; const text = row.map((b) => (b >= 32 && b <= 126 ? String.fromCharCode(b) : ".")).join(""); // 주소는 소문자 16진수 여덟 자리 out.push(`${(s + i).toString(16).padStart(8, "0")}:${hexes} |${text}|`);}out.push(`${n} bytes, sum ${sum}`);console.log(out.join("\n"));
TypeScriptmain.ts · 29 줄
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const [n, w, s]: number[] = lines[0].trim().split(/\s+/).map(Number);const data: number[] = lines[1].trim().split(/\s+/).map(Number);const hex = (value: number, width: number): string => value.toString(16).padStart(width, "0");const out: string[] = [];let prev = ""; // 바로 앞 줄의 바이트 부분(주소 뺀 문자열)let starred = false; // 생략 표시 *를 이미 썼는가let sum = 0;for (let i = 0; i < n; i += w) { const row: number[] = data.slice(i, i + w); for (const b of row) sum += b; // 바이트는 대문자 16진수 두 자리, 모자란 칸은 빈칸 세 개 const hexes: string = row.map((b) => " " + hex(b, 2).toUpperCase()).join("") + " ".repeat(w - row.length); if (hexes === prev) { if (!starred) out.push("*"); starred = true; continue; } prev = hexes; starred = false; const text: string = row.map((b) => (b >= 32 && b <= 126 ? String.fromCharCode(b) : ".")).join(""); // 주소는 소문자 16진수 여덟 자리 out.push(`${hex(s + i, 8)}:${hexes} |${text}|`);}out.push(`${n} bytes, sum ${sum}`);console.log(out.join("\n"));
JavaMain.java · 45 줄
import java.io.*;import java.util.*;public class Main { public static void main(String[] args) throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(in.readLine()); int n = Integer.parseInt(st.nextToken()); int w = Integer.parseInt(st.nextToken()); long s = Long.parseLong(st.nextToken()); // 주소는 2^31을 넘을 수 있어 long st = new StringTokenizer(in.readLine()); int[] data = new int[n]; long sum = 0; for (int i = 0; i < n; i++) { data[i] = Integer.parseInt(st.nextToken()); sum += data[i]; } StringBuilder out = new StringBuilder(); boolean starred = false; // 생략 표시 *를 이미 썼는가 for (int i = 0; i < n; i += w) { int len = Math.min(w, n - i); // 바로 앞 줄(i - w부터 w개)과 바이트가 모두 같은가 if (i > 0 && len == w && Arrays.equals(data, i, i + w, data, i - w, i)) { if (!starred) out.append("*\n"); starred = true; continue; } starred = false; out.append(String.format("%08x:", s + i)); // 소문자 16진수 여덟 자리 for (int j = 0; j < w; j++) { if (j < len) out.append(String.format(" %02X", data[i + j])); // 대문자 두 자리 else out.append(" "); } out.append(" |"); for (int j = 0; j < len; j++) { int b = data[i + j]; out.append(b >= 32 && b <= 126 ? (char) b : '.'); } out.append("|\n"); } out.append(n).append(" bytes, sum ").append(sum).append('\n'); System.out.print(out); }}
C#Main.cs · 43 줄
using System;using System.Text;class Program{ static void Main() { string[] head = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries); int n = int.Parse(head[0]); int w = int.Parse(head[1]); long s = long.Parse(head[2]); // 주소는 2^31을 넘을 수 있어 long int[] data = Array.ConvertAll(Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries), int.Parse); var output = new StringBuilder(); bool starred = false; // 생략 표시 *를 이미 썼는가 long sum = 0; for (int i = 0; i < n; i += w) { int len = Math.Min(w, n - i); var row = new ReadOnlySpan<int>(data, i, len); foreach (int b in row) sum += b; // 바로 앞 줄(i - w부터 w개)과 바이트가 모두 같은가 if (i > 0 && row.SequenceEqual(new ReadOnlySpan<int>(data, i - w, w))) { if (!starred) output.Append("*\n"); starred = true; continue; } starred = false; output.Append((s + i).ToString("x8")).Append(':'); // 소문자 16진수 여덟 자리 for (int j = 0; j < w; j++) { if (j < len) output.Append(' ').Append(data[i + j].ToString("X2")); // 대문자 두 자리 else output.Append(" "); } output.Append(" |"); foreach (int b in row) output.Append(b >= 32 && b <= 126 ? (char)b : '.'); output.Append("|\n"); } output.Append($"{n} bytes, sum {sum}\n"); Console.Write(output); }}
C++main.cpp · 45 줄
#include <algorithm>#include <iomanip>#include <iostream>#include <vector>int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int n, w; long long s; // 주소는 2^31을 넘을 수 있어 long long std::cin >> n >> w >> s; std::vector<int> data(n); long long sum = 0; for (int& b : data) { std::cin >> b; sum += b; } bool starred = false; // 생략 표시 *를 이미 썼는가 for (int i = 0; i < n; i += w) { int len = std::min(w, n - i); // 바로 앞 줄(i - w부터 w개)과 바이트가 모두 같은가 if (i > 0 && len == w && std::equal(data.begin() + i, data.begin() + i + w, data.begin() + i - w)) { if (!starred) std::cout << "*\n"; starred = true; continue; } starred = false; // hex, setfill, uppercase는 한 번 걸면 계속 남고, setw는 바로 다음 값 하나에만 걸린다 std::cout << std::hex << std::setfill('0'); std::cout << std::nouppercase << std::setw(8) << s + i << ':'; std::cout << std::uppercase; for (int j = 0; j < w; j++) { if (j < len) std::cout << ' ' << std::setw(2) << data[i + j]; else std::cout << " "; } std::cout << " |"; for (int j = 0; j < len; j++) { int b = data[i + j]; std::cout << (b >= 32 && b <= 126 ? static_cast<char>(b) : '.'); } std::cout << "|\n"; } std::cout << std::dec << n << " bytes, sum " << sum << '\n'; // 10진수로 되돌린다}
Cmain.c · 42 줄
#include <stdio.h>#include <string.h>static unsigned char data[6000];int main(void) { int n, w; long long s; /* 주소는 2^31을 넘을 수 있어 long long */ scanf("%d %d %lld", &n, &w, &s); long long sum = 0; for (int i = 0; i < n; i++) { int b; scanf("%d", &b); data[i] = (unsigned char)b; sum += b; } int starred = 0; /* 생략 표시 *를 이미 썼는가 */ for (int i = 0; i < n; i += w) { int len = n - i < w ? n - i : w; /* 바로 앞 줄(i - w부터 w개)과 바이트가 모두 같은가 */ if (i > 0 && len == w && memcmp(data + i, data + i - w, (size_t)w) == 0) { if (!starred) puts("*"); starred = 1; continue; } starred = 0; printf("%08llx:", (unsigned long long)(s + i)); /* 소문자 16진수 여덟 자리 */ for (int j = 0; j < w; j++) { if (j < len) printf(" %02X", data[i + j]); /* 대문자 두 자리 */ else printf(" "); } printf(" |"); for (int j = 0; j < len; j++) { unsigned char b = data[i + j]; putchar(b >= 32 && b <= 126 ? b : '.'); } puts("|"); } printf("%d bytes, sum %lld\n", n, sum); return 0;}
Craykonmain.cray · 65 줄
// 수를 16진수 문자열로 바꾼다(자리 수만큼 앞을 0으로 채움)십육진수(값, 자리, 숫자들){ 결과 = ""; 남은 = 값; 반복 (k = 0; k < 자리; k++) { 결과 = 숫자들[남은 % 16] + 결과; 남은 = 수학.몫(남은, 16); } 돌려주기 결과;}첫줄 = 콘솔.수들읽기();n = 첫줄[0];w = 첫줄[1];s = 첫줄[2];data = 콘솔.수들읽기();이전 = ""; // 바로 앞 줄의 바이트 부분(주소 뺀 문자열)별표씀 = 거짓; // 생략 표시 *를 이미 썼는가합 = 0;out = "";반복 (i = 0; i < n; i += w){ 바이트들 = ""; 글자들 = ""; 반복 (j = 0; j < w; j++) { 만약 (i + j < n) { b = data[i + j]; 합 += b; 바이트들 = 바이트들 + " " + 십육진수(b, 2, "0123456789ABCDEF"); 만약 (b >= 32 && b <= 126) { 글자들 = 글자들 + 글자.글자로변환(b); } 아니면 { 글자들 = 글자들 + "."; } } 아니면 { 바이트들 = 바이트들 + " "; } } 만약 (바이트들 == 이전) { 만약 (!별표씀) { out = out + "*\n"; } 별표씀 = 참; } 아니면 { 이전 = 바이트들; 별표씀 = 거짓; out = out + 십육진수(s + i, 8, "0123456789abcdef") + ":" + 바이트들 + " |" + 글자들 + "|\n"; }}out = out + n + " bytes, sum " + 합 + "\n";콘솔.이어쓰기(out);