{"id":6029,"date":"2023-09-16T00:01:45","date_gmt":"2023-09-16T07:01:45","guid":{"rendered":"https:\/\/c-for-dummies.com\/blog\/?p=6029"},"modified":"2023-09-23T08:29:20","modified_gmt":"2023-09-23T15:29:20","slug":"enabling-random-memory-file-access","status":"publish","type":"post","link":"https:\/\/c-for-dummies.com\/blog\/?p=6029","title":{"rendered":"Enabling Random Memory-File Access"},"content":{"rendered":"<p>The two types of file access are sequential and random. Sequential access means the file&#8217;s data is read from beginning to end, one byte after the other. Random access isn&#8217;t random in the sense that it&#8217;s haphazard. No, random access means you can read data from any position in the file: beginning, middle, or end.<br \/>\n<!--more--><br \/>\nFor example, if you know the data chunk you want is at offset 100 bytes from the start of the file, you can position a file pointer (I don&#8217;t like using the term &#8220;pointer&#8221;) at offset 100 and start reading. The <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=1572\">fseek() function<\/a> is responsible for this manipulation.<\/p>\n<p>Continuing with my memory-file implementation in <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=6022\">last week&#8217;s Lesson<\/a>, I sought to write a <em>mem_seek()<\/em> function to parallel <em>fseek()<\/em>. This function moves a position indicator in the memory-file to enable random memory-file access:<\/p>\n<pre class=\"screen\">\r\n<span class=\"comments\">\/* move the memory offset index\r\n   input- memory file handle, offset, whence\r\n   output- current offset or -1\r\n   whence:  SEEK_SET (start)\r\n               SEEK_CUR (current)\r\n            SEEK_END (end)\r\n *\/<\/span>\r\nint mem_seek(struct mem_file *m, long position, int whence)\r\n{\r\n    <span class=\"comments\">\/* return -1 on various errors *\/<\/span>\r\n    if( m-&gt;address==NULL )\r\n        return(-1);\r\n\r\n    <span class=\"comments\">\/* adjust m-&gt;offset value *\/<\/span>\r\n    if( whence==SEEK_SET )\r\n    {\r\n        if( position&lt;0 )\r\n            return(-1);\r\n        <span class=\"comments\">\/* no negative offsets! *\/<\/span>\r\n        if( position&gt;m-&gt;size )\r\n            return(-1);\r\n        <span class=\"comments\">\/* set offset from the start *\/<\/span>\r\n        m-&gt;offset = position;\r\n        return(m-&gt;offset);\r\n    }\r\n    else if( whence==SEEK_CUR )\r\n    {\r\n        if( m-&gt;offset+position&lt;0 || m-&gt;offset+position &gt; m-&gt;size )\r\n            return(-1);\r\n        m-&gt;offset+=position;\r\n        return(m-&gt;offset);\r\n    }\r\n    else if( whence==SEEK_END )\r\n    {\r\n        if( position&lt;0 || m-&gt;size-position&lt;0 )\r\n            return(-1);\r\n        m-&gt;offset = m-&gt;size-position;\r\n        return(m-&gt;offset);\r\n    }\r\n    else\r\n        return(-1);\r\n}<\/pre>\n<p>The three operations are based on the three defined constants shared with the <em>fseek()<\/em> function:<\/p>\n<p><code>SEEK_SET<\/code> to move the pointer offset from the memory-file&#8217;s start<br \/>\n<code>SEEK_CUR<\/code> to move the pointer offset from the current position<br \/>\n<code>SEEK_END<\/code> to move the pointer offset from the end of the memory-file<\/p>\n<p>The offset values for <code>SEEK_SET<\/code> and <code>SEEK_END<\/code> must be positive. These are offsets from the start and end of the file and calculated that way in the code.<\/p>\n<p>For the <code>SEEK_CUR<\/code> argument the position change can be positive or negative. Math in the code works to prevent an overflow, where the position indicator leaps below zero or beyond the end of the file, <code>m-&gt;size<\/code>. I&#8217;m unsure how the <em>fseek()<\/em> function is coded, but these are the rules I implemented.<\/p>\n<p>To test my <em>mem_seek()<\/em> function, I modified the <em>main()<\/em> function to write the 26 letters of the alphabet to a memory file. These letters are then read back using specific options in the <em>mem_seek()<\/em> function:<\/p>\n<pre class=\"screen\">\r\n<span class=\"comments\">\/* test the memory file functions *\/<\/span>\r\nint main()\r\n{\r\n    static char name1[] = \"memory file\";\r\n    struct mem_file *mfp1;\r\n    int a,r;\r\n\r\n    mfp1 = mem_open(name1);\r\n    if( mfp1==NULL )\r\n    {\r\n        fprintf(stderr,\"Unable to create %s\\n\",name1);\r\n        exit(1);\r\n    }\r\n    printf(\"Memory file '%s' created\\n\",name1);\r\n\r\n    <span class=\"comments\">\/* write the alphabet to the memory-file *\/<\/span>\r\n    for( a='A'; a&lt;='Z'; a++ )\r\n        mem_putc(a,mfp1);\r\n\r\n    <span class=\"comments\">\/* read back in the entire alphabet *\/<\/span>\r\n    printf(\"Reading the entire file: \");\r\n    r = mem_seek(mfp1,0,SEEK_SET);\r\n    if( r==-1)\r\n    {\r\n        fprintf(stderr,\"Position error\\n\");\r\n        exit(1);\r\n    }\r\n    for( a=0; a&lt;26; a++ )\r\n        putchar( mem_getc(mfp1) );\r\n    putchar('\\n');\r\n\r\n    <span class=\"comments\">\/* read the last ten characters *\/<\/span>\r\n    printf(\"Reading the last ten characters: \");\r\n    r = mem_seek(mfp1,10,SEEK_END);\r\n    if( r==-1)\r\n    {\r\n        fprintf(stderr,\"Position error\\n\");\r\n        exit(1);\r\n    }\r\n    for( a=0; a&lt;10; a++ )\r\n        putchar( mem_getc(mfp1) );\r\n    putchar('\\n');\r\n\r\n    <span class=\"comments\">\/* read the middle ten characters *\/<\/span>\r\n    printf(\"Reading the middle ten characters: \");\r\n        <span class=\"comments\">\/* position is at the end of the file *\/<\/span>\r\n    r = mem_seek(mfp1,-18,SEEK_CUR);\r\n    if( r==-1)\r\n    {\r\n        fprintf(stderr,\"Position error\\n\");\r\n        exit(1);\r\n    }\r\n    for( a=0; a&lt;10; a++ )\r\n        putchar( mem_getc(mfp1) );\r\n    putchar('\\n');\r\n\r\n    mem_close(mfp1);\r\n    printf(\"Memory file '%s' closed\\n\",name1);\r\n\r\n    return(0);\r\n}<\/pre>\n<p>The bulk of the <em>main()<\/em> function deals with error-checking, to ensure that when I&#8217;m moving the file position pointer that I&#8217;m not accessing unallocated memory. The program reads all characters in the memory-file, then the last ten, finally the middle ten. Here is a sample run:<\/p>\n<p><code>Memory file 'memory file' created<br \/>\nReading the entire file: ABCDEFGHIJKLMNOPQRSTUVWXYZ<br \/>\nReading the last ten characters: QRSTUVWXYZ<br \/>\nReading the middle ten characters: IJKLMNOPQR<br \/>\nMemory file 'memory file' closed<\/code><\/p>\n<p>The full code is 205 lines long, which is too much to list in this post. <a href=\"https:\/\/github.com\/dangookin\/C-For-Dummies-Blog\/blob\/master\/2023_09_16-Lesson.c\" rel=\"noopener\" target=\"_blank\">Click here<\/a> to view the full code on Github.<\/p>\n<p>For <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=6037\">next week&#8217;s Lesson<\/a>, I present how to split up this code into multiple modules for easier implementation of new features.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Reading and writing to a file isn&#8217;t always sequential. <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=6029\">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-6029","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\/6029","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=6029"}],"version-history":[{"count":5,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/6029\/revisions"}],"predecessor-version":[{"id":6049,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/6029\/revisions\/6049"}],"wp:attachment":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=6029"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=6029"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=6029"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}