diff --git a/Z-Data.cabal b/Z-Data.cabal
--- a/Z-Data.cabal
+++ b/Z-Data.cabal
@@ -1,5 +1,5 @@
 name:                       Z-Data
-version:                    0.1.0.0
+version:                    0.1.1.0
 synopsis:                   array, vector and text
 description:                This package provides array, slice and text operations
 license:                    BSD3
diff --git a/Z/Data/CBytes.hs b/Z/Data/CBytes.hs
--- a/Z/Data/CBytes.hs
+++ b/Z/Data/CBytes.hs
@@ -46,8 +46,8 @@
   , null , length
   , empty, append, concat, intercalate, intercalateElem
   , toBytes, fromBytes, toText, toTextMaybe, fromText
-  , fromCStringMaybe, fromCString, fromCStringN
-  , withCBytes
+  , fromCString, fromCString', fromCStringN
+  , withCBytes, allocCBytes
   -- helpers re-export
   , V.w2c, V.c2w
   -- * exception
@@ -101,21 +101,35 @@
 
 -- | Create a 'CBytes' with IO action.
 --
+--
 -- User only have to do content initialization and return the content length,
--- 'create' takes the responsibility to add the '\NUL' ternimator.
+-- 'create' takes the responsibility to add the @\NUL@ ternimator. If the
+-- initialize function write @\NUL@ terminator(most FFI functions for example),
+-- you should use 'allocCBytes'.
+--
+-- If (<=0) capacity is provided, a 'nullPtr' is passed to initialize function and
+-- 'empty' will be returned. other than that, if length returned is larger than (capacity-1),
+-- a 'NULLTerminatorNotFound' will be thrown.
 create :: HasCallStack
-       => Int  -- ^ capacity n, including the '\NUL' terminator
-       -> (CString -> IO Int)  -- ^ initialization function,
+       => Int  -- ^ capacity n, including the @\NUL@ terminator
+       -> (CString -> IO Int)  -- ^ initialize function
                                -- write the pointer, return the length (<= n-1)
        -> IO CBytes
 {-# INLINE create #-}
-create n fill = do
+create n fill | n <= 0 = fill nullPtr >> return empty
+              | otherwise = do
     mba <- newPinnedPrimArray n :: IO (MutablePrimArray RealWorld Word8)
     l <- withMutablePrimArrayContents mba (fill . castPtr)
-    writePrimArray mba l 0 -- the '\NUL' ternimator
+    when (l+1>n) (throwIO (NULLTerminatorNotFound callStack))
+    writePrimArray mba l 0 -- the @\NUL@ ternimator
     shrinkMutablePrimArray mba (l+1)
     CBytesOnHeap <$> unsafeFreezePrimArray mba
 
+-- | All exception can be throw by using 'CBytes'.
+data CBytesException = NULLTerminatorNotFound CallStack
+                    deriving (Show, Typeable)
+instance Exception CBytesException
+
 instance Show CBytes where
     show = unpack
 
@@ -185,6 +199,9 @@
     lenA = length strA
     lenB = length strB
 
+-- | 'empty' 'CBytes'
+--
+-- Passing 'empty' to C FFI is equivalent to passing a @NULL@ pointer.
 empty :: CBytes
 {-# NOINLINE empty #-}
 empty = CBytesLiteral (Ptr "\0"#)
@@ -277,7 +294,7 @@
 
 -- | Pack a 'String' into null-terminated 'CBytes'.
 --
--- '\NUL' is encoded as two bytes @C0 80@ , '\xD800' ~ '\xDFFF' is encoded as a three bytes normal UTF-8 codepoint.
+-- @\NUL@ is encoded as two bytes @C0 80@ , '\xD800' ~ '\xDFFF' is encoded as a three bytes normal UTF-8 codepoint.
 pack :: String -> CBytes
 {-# INLINE CONLIKE [1] pack #-}
 pack s = runST $ do
@@ -327,7 +344,7 @@
 -- | /O(1)/, (/O(n)/ in case of literal), convert to 'V.Bytes', which can be
 -- processed by vector combinators.
 --
--- NOTE: the '\NUL' ternimator is not included.
+-- NOTE: the @\NUL@ ternimator is not included.
 toBytes :: CBytes -> V.Bytes
 {-# INLINABLE toBytes #-}
 toBytes cbytes@(CBytesOnHeap pa) = V.PrimVector pa 0 l
@@ -338,7 +355,7 @@
   where l = length cbytes
 
 -- | /O(n)/, convert from 'V.Bytes', allocate pinned memory and
--- add the '\NUL' ternimator
+-- add the @\NUL@ ternimator
 fromBytes :: V.Bytes -> CBytes
 {-# INLINABLE fromBytes #-}
 fromBytes (V.Vec arr s l) =  runST (do
@@ -363,38 +380,35 @@
 toTextMaybe = T.validateMaybe . toBytes
 
 -- | /O(n)/, convert from 'T.Text', allocate pinned memory and
--- add the '\NUL' ternimator
+-- add the @\NUL@ ternimator
 fromText :: T.Text -> CBytes
 {-# INLINABLE fromText #-}
 fromText = fromBytes . T.getUTF8Bytes
 
 --------------------------------------------------------------------------------
 
--- | Copy a 'CString' type into a 'CBytes', return Nothing if the pointer is NULL.
+
+-- | Copy a 'CString' type into a 'CBytes', return 'empty' if the pointer is NULL.
 --
 --  After copying you're free to free the 'CString' 's memory.
---
-fromCStringMaybe :: HasCallStack => CString -> IO (Maybe CBytes)
-{-# INLINABLE fromCStringMaybe #-}
-fromCStringMaybe cstring =
+fromCString :: CString -> IO CBytes
+{-# INLINABLE fromCString #-}
+fromCString cstring = do
     if cstring == nullPtr
-    then return Nothing
+    then return empty
     else do
         len <- fromIntegral <$> c_strlen cstring
         mpa <- newPinnedPrimArray (len+1)
         copyPtrToMutablePrimArray mpa 0 (castPtr cstring) len
         writePrimArray mpa len 0     -- the \NUL terminator
         pa <- unsafeFreezePrimArray mpa
-        return (Just (CBytesOnHeap pa))
-
+        return (CBytesOnHeap pa)
 
--- | Same with 'fromCStringMaybe', but throw 'NullPointerException' when meet a null pointer.
+-- | Same with 'fromCString', but throw 'NullPointerException' when meet a null pointer.
 --
-fromCString :: HasCallStack
-            => CString
-            -> IO CBytes
-{-# INLINABLE fromCString #-}
-fromCString cstring = do
+fromCString' :: HasCallStack => CString -> IO (Maybe CBytes)
+{-# INLINABLE fromCString' #-}
+fromCString' cstring =
     if cstring == nullPtr
     then throwIO (NullPointerException callStack)
     else do
@@ -403,18 +417,15 @@
         copyPtrToMutablePrimArray mpa 0 (castPtr cstring) len
         writePrimArray mpa len 0     -- the \NUL terminator
         pa <- unsafeFreezePrimArray mpa
-        return (CBytesOnHeap pa)
+        return (Just (CBytesOnHeap pa))
 
 -- | Same with 'fromCString', but only take N bytes (and append a null byte as terminator).
 --
-fromCStringN :: HasCallStack
-            => CString
-            -> Int
-            -> IO CBytes
+fromCStringN :: CString -> Int -> IO CBytes
 {-# INLINABLE fromCStringN #-}
 fromCStringN cstring len = do
-    if cstring == nullPtr
-    then throwIO (NullPointerException callStack)
+    if cstring == nullPtr || len == 0
+    then return empty
     else do
         mpa <- newPinnedPrimArray (len+1)
         copyPtrToMutablePrimArray mpa 0 (castPtr cstring) len
@@ -432,6 +443,26 @@
 {-# INLINABLE withCBytes #-}
 withCBytes (CBytesOnHeap pa) f = withPrimArrayContents pa (f . castPtr)
 withCBytes (CBytesLiteral ptr) f = f ptr
+
+-- | Create a 'CBytes' with IO action.
+--
+-- If (<=0) capacity is provided, a 'nullPtr' is passed to initialize function and
+-- 'empty' will be returned. Other than that, User have to make sure a @\NUL@ ternimated
+-- string will be written, otherwise a 'NULLTerminatorNotFound' will be thrown.
+allocCBytes :: HasCallStack
+       => Int  -- ^ capacity n, including the @\NUL@ terminator
+       -> (CString -> IO a)  -- ^ initialization function,
+       -> IO (CBytes, a)
+{-# INLINABLE allocCBytes #-}
+allocCBytes n fill | n <= 0 = fill nullPtr >>= \ a -> return (empty, a)
+                   | otherwise = do
+    mba <- newPinnedPrimArray n :: IO (MutablePrimArray RealWorld Word8)
+    a <- withMutablePrimArrayContents mba (fill . castPtr)
+    l <- fromIntegral <$> withMutablePrimArrayContents mba (c_strlen . castPtr)
+    when (l+1>n) (throwIO (NULLTerminatorNotFound callStack))
+    shrinkMutablePrimArray mba (l+1)
+    bs <- unsafeFreezePrimArray mba
+    return (CBytesOnHeap bs, a)
 
 --------------------------------------------------------------------------------
 
diff --git a/Z/Data/Text/Base.hs b/Z/Data/Text/Base.hs
--- a/Z/Data/Text/Base.hs
+++ b/Z/Data/Text/Base.hs
@@ -692,10 +692,6 @@
 if it is unstable. If the result is MAYBE, the string does not necessarily
 have to be normalized.
 
-If the result is unstable, the offset parameter is set to the offset for the
-first unstable code point. If the string is stable, the offset is equivalent
-to the length of the string in bytes.
-
 For more information, please review [Unicode Standard Annex #15 - Unicode
 Normalization Forms](http://www.unicode.org/reports/tr15/).
 -}
diff --git a/Z/Data/Vector/Base.hs b/Z/Data/Vector/Base.hs
--- a/Z/Data/Vector/Base.hs
+++ b/Z/Data/Vector/Base.hs
@@ -134,6 +134,12 @@
 --
 -- Instead of providing a generalized vector with polymorphric array field, we use this typeclass
 -- so that instances use concrete array type can unpack their array payload.
+--
+-- Vector types, e.g. 'Vector','PrimVector'... are obivious instances, with O(1) 'toArr' and
+-- 'fromArr', which convert slices to (array, offset, length) tuple back and forth.
+--
+-- Array types can also be instances of this class, e.g. 'Array', 'PrimArray'..., in this case
+-- 'toArr' will always return offset 0 and whole array length, and 'fromArr' is O(n) 'copyArr'.
 class (Arr (IArray v) a) => Vec v a where
     -- | Vector's immutable array type
     type IArray v :: * -> *
@@ -1299,6 +1305,7 @@
 {-# INLINE defaultInitSize #-}
 defaultInitSize = 30
 
+-- | All exception can be throw by using 'Vec'.
 data VectorException = IndexOutOfVectorRange {-# UNPACK #-} !Int CallStack
                      | EmptyVector CallStack
                     deriving (Show, Typeable)
