made separate API for dictionary management
diff --git a/doc/educational_decoder/harness.c b/doc/educational_decoder/harness.c
index 31e1c29..43d6df7 100644
--- a/doc/educational_decoder/harness.c
+++ b/doc/educational_decoder/harness.c
@@ -106,9 +106,15 @@
         return 1;
     }
 
+    dictionary_t* parsed_dict = create_dictionary();
+    if (dict) {
+        parse_dictionary(parsed_dict, dict, dict_size);
+    }
     size_t decompressed =
         ZSTD_decompress_with_dict(output, decompressed_size,
-                                  input, input_size, dict, dict_size);
+                                  input, input_size, parsed_dict);
+
+    free_dictionary(parsed_dict);
 
     write_file(argv[2], output, decompressed);
 
diff --git a/doc/educational_decoder/zstd_decompress.c b/doc/educational_decoder/zstd_decompress.c
index fe87709..e22df1c 100644
--- a/doc/educational_decoder/zstd_decompress.c
+++ b/doc/educational_decoder/zstd_decompress.c
@@ -357,19 +357,16 @@
 
 size_t ZSTD_decompress(void *const dst, const size_t dst_len,
                        const void *const src, const size_t src_len) {
-    return ZSTD_decompress_with_dict(dst, dst_len, src, src_len, NULL, 0);
+    dictionary_t* uninit_dict = create_dictionary();
+    size_t const decomp_size = ZSTD_decompress_with_dict(dst, dst_len, src,
+                                                         src_len, uninit_dict);
+    free_dictionary(uninit_dict);
+    return decomp_size;
 }
 
 size_t ZSTD_decompress_with_dict(void *const dst, const size_t dst_len,
                                  const void *const src, const size_t src_len,
-                                 const void *const dict,
-                                 const size_t dict_len) {
-    dictionary_t parsed_dict;
-    memset(&parsed_dict, 0, sizeof(dictionary_t));
-    // dict_len < 8 is not a valid dictionary
-    if (dict && dict_len > 8) {
-        parse_dictionary(&parsed_dict, dict, dict_len);
-    }
+                                 dictionary_t* parsed_dict) {
 
     istream_t in = IO_make_istream(src, src_len);
     ostream_t out = IO_make_ostream(dst, dst_len);
@@ -380,9 +377,7 @@
     // parameters which tells the decoder how to decompress it."
 
     /* this decoder assumes decompression of a single frame */
-    decode_frame(&out, &in, &parsed_dict);
-
-    free_dictionary(&parsed_dict);
+    decode_frame(&out, &in, parsed_dict);
 
     return out.ptr - (u8 *)dst;
 }
@@ -1408,6 +1403,16 @@
 /******* END OUTPUT SIZE COUNTING *********************************************/
 
 /******* DICTIONARY PARSING ***************************************************/
+#define DICT_SIZE_ERROR() ERROR("Dictionary size cannot be less than 8 bytes")
+
+dictionary_t* create_dictionary() {
+    dictionary_t* dict = calloc(1, sizeof(dictionary_t));
+    if (!dict) {
+        BAD_ALLOC();
+    }
+    return dict;
+}
+
 static void init_dictionary_content(dictionary_t *const dict,
                                     istream_t *const in);
 
@@ -1416,7 +1421,7 @@
     const u8 *byte_src = (const u8 *)src;
     memset(dict, 0, sizeof(dictionary_t));
     if (src_len < 8) {
-        INP_SIZE();
+        DICT_SIZE_ERROR();
     }
 
     istream_t in = IO_make_istream(byte_src, src_len);
diff --git a/doc/educational_decoder/zstd_decompress.h b/doc/educational_decoder/zstd_decompress.h
index 2ac9030..4100990 100644
--- a/doc/educational_decoder/zstd_decompress.h
+++ b/doc/educational_decoder/zstd_decompress.h
@@ -7,6 +7,13 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  */
 
+/******* EXPOSED TYPES ********************************************************/
+/*
+* Contains the parsed contents of a dictionary
+* This includes Huffman and FSE tables used for decoding and data on offsets
+*/
+typedef struct dictionary_s dictionary_t;
+/******* END EXPOSED TYPES ****************************************************/
 
 /******* DECOMPRESSION FUNCTIONS **********************************************/
 /// Zstandard decompression functions.
@@ -18,7 +25,7 @@
 /// `ZSTD_decompress` but uses the provided dict
 size_t ZSTD_decompress_with_dict(void *const dst, const size_t dst_len,
                               const void *const src, const size_t src_len,
-                              const void *const dict, const size_t dict_len);
+                              dictionary_t* parsed_dict);
 
 /// Get the decompressed size of an input stream so memory can be allocated in
 /// advance
@@ -29,10 +36,10 @@
 
 /******* DICTIONARY MANAGEMENT ***********************************************/
 /*
- * Contains the parsed contents of a dictionary
- * This includes Huffman and FSE tables used for decoding and data on offsets
+ * Return a valid dictionary_t pointer for use with dictionary initialization
+ * or decompression
  */
-typedef struct dictionary_s dictionary_t;
+dictionary_t* create_dictionary();
 
 /*
  * Parse a provided dictionary blob for use in decompression
@@ -43,6 +50,7 @@
  */
 void parse_dictionary(dictionary_t *const dict, const void *src,
                              size_t src_len);
+
 /*
  * Free internal Huffman tables, FSE tables, and dictionary content
  */