{"id":6022,"date":"2023-09-09T00:01:04","date_gmt":"2023-09-09T07:01:04","guid":{"rendered":"https:\/\/c-for-dummies.com\/blog\/?p=6022"},"modified":"2023-09-16T08:22:00","modified_gmt":"2023-09-16T15:22:00","slug":"reading-and-writing-to-memory-files","status":"publish","type":"post","link":"https:\/\/c-for-dummies.com\/blog\/?p=6022","title":{"rendered":"Reading and Writing to Memory-Files"},"content":{"rendered":"<p>Opening and closing a memory-file is just academic. To make the whole shebang work, you must be able to read and write data.<br \/>\n<!--more--><br \/>\nTo continue from <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=6013\">last week&#8217;s Lesson<\/a>, I introduce the <em>mem_getc()<\/em> and <em>mem_putc()<\/em> functions. Both use the <em>mem_file<\/em> structure and rely upon the <em>mem_file<\/em> pointer being allocated. They follow the format of the <em>fgetc()<\/em> and <em>fputc()<\/em> functions, which are the basic file I\/O functions for cooked data. (The <em>fread()<\/em> and <em>frwite()<\/em> functions deal with raw data.)<\/p>\n<p>Here is the <em>mem_putc()<\/em> function:<\/p>\n<pre class=\"screen\">\r\n<span class=\"comments\">\/* put a character to a memory file\r\n   input- single character, memory file handle\r\n   output- character written or\r\n           EOF on failure\r\n *\/<\/span>\r\nint mem_putc(int c, struct mem_file *m)\r\n{\r\n    int *index;\r\n\r\n    if( m-&gt;address==NULL )\r\n        return(EOF);\r\n\r\n    index = m-&gt;address+m-&gt;size;\r\n    *index = c;\r\n\r\n    m-&gt;size++;\r\n    <span class=\"comments\">\/* check for overflow *\/<\/span>\r\n    if( (m-&gt;size % DEFAULT_SIZE) == 0 )\r\n    {\r\n        m-&gt;address=realloc(m-&gt;address,m-&gt;size-1+DEFAULT_SIZE);\r\n        if( m-&gt;address==NULL )\r\n            return(EOF);\r\n    }\r\n\r\n    return(c);\r\n}<\/pre>\n<p>The first test is to ensure that the <em>mem_file<\/em> structure passed is allocated. If not, the <code>EOF<\/code> constant is returned. This return value is consistent with the <em>fputc()<\/em> function.<\/p>\n<p>Variable <code>index<\/code> serves as a reference into the memory-file&#8217;s storage. It&#8217;s set to reference the end of the used portion of the memory-file&#8217;s allocated space: <code>index = m-&gt;address+m-&gt;size;<\/code> This function always appends data unless the memory-file <code>size<\/code> value has been otherwise manipulated.<\/p>\n<p>The character passed, <code>c<\/code>, is appended to the memory-file: <code>*index = c;<\/code><\/p>\n<p>The <code>size<\/code> offset is incremented: <code>m-&gt;size++;<\/code><\/p>\n<p>Immediately after incrementing the <code>size<\/code> value, a test is made to ensure that allocated storage hasn&#8217;t been exceeded: <code>if( (m-&gt;size % DEFAULT_SIZE) == 0 )<\/code> If the result is TRUE, another <code>DEFAULT_SIZE<\/code> chunk is allocated for the memory-file, along with appropriate error-checking.<\/p>\n<p>The function returns the character added, <code>c<\/code>.<\/p>\n<p>Here is the <em>mem_getc()<\/em> function:<\/p>\n<pre class=\"screen\">\r\n<span class=\"comments\">\/* fetch a character from a memory file\r\n   input- memory file handle\r\n   output- character retrieved or\r\n           EOF on failure\r\n *\/<\/span>\r\nint mem_getc(struct mem_file *m)\r\n{\r\n    int *index;\r\n\r\n    if( m-&gt;address==NULL )\r\n        return(EOF);\r\n\r\n    if( m-&gt;offset&gt;m-&gt;size )\r\n        return(EOF);\r\n\r\n    index = m-&gt;address+m-&gt;offset;\r\n    m-&gt;offset++;\r\n\r\n    return( *index );\r\n}<\/pre>\n<p>If the <code>address<\/code> is <code>NULL<\/code>, the function returns immediately with an EOF.<\/p>\n<p>Next a check is done to ensure that the function isn&#8217;t reading beyond the end of the memory-file: <code>if( m-&gt;offset&gt;m-&gt;size )<\/code> If so, the function returns <code>EOF<\/code>.<\/p>\n<p>When everything is kosher, the value of <code>index<\/code> is set to the current <code>offset<\/code> in the file, where data is being read: <code>index = m-&gt;address+m-&gt;offset;<\/code><\/p>\n<p>The value of <code>offset<\/code> is incremented in anticipation of the next read operation: <code>m-&gt;offset++;<\/code><\/p>\n<p>Finally, the value refenced at the buffer&#8217;s original <code>offset<\/code> is returned to the caller: <code>return( *index );<\/code><\/p>\n<p>You can view the full code <a href=\"https:\/\/github.com\/dangookin\/C-For-Dummies-Blog\/blob\/master\/2023_09_09-Lesson.c\" rel=\"noopener\" target=\"_blank\">on GitHub<\/a>. In the <em>main()<\/em> function, <code>'A'<\/code> is written to the created and opened memory-file, which is then read back in:<\/p>\n<p><code>Memory file 'memory file' created<br \/>\nTimestamp = Sat Sep&nbsp;&nbsp;9 12:29:03 2023<\/p>\n<p>Put character 'A' to file 'memory file'<br \/>\nFetched character 'A' from file 'memory file'<\/p>\n<p>Memory file 'memory file' closed<\/code><\/p>\n<p>One concern I have is with the memory reallocation when the original allocated chunk size (<code>DEFAULT_SIZE<\/code>) is surpassed. I wrote a test that sent 8K of data to the memory-file, which was read back and output with no problems. Still, I&#8217;d want to do more tests to ensure that everything works properly. And if I encounter problems as this project progresses, I&#8217;ll mention them in a future post.<\/p>\n<p><a href=\"https:\/\/c-for-dummies.com\/blog\/?p=6029\">Next week&#8217;s Lesson<\/a> covers moving the memory-file offset pointer in preparation for reading and writing chunks of data &mdash; random memory-file access.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Reading and writing to anything first requires basic character I\/O. <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=6022\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-6022","post","type-post","status-publish","format-standard","hentry","category-main"],"_links":{"self":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/6022","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=6022"}],"version-history":[{"count":4,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/6022\/revisions"}],"predecessor-version":[{"id":6042,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/6022\/revisions\/6042"}],"wp:attachment":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=6022"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=6022"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=6022"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}