{"id":7182,"date":"2025-10-04T00:01:12","date_gmt":"2025-10-04T07:01:12","guid":{"rendered":"https:\/\/c-for-dummies.com\/blog\/?p=7182"},"modified":"2025-09-27T11:04:33","modified_gmt":"2025-09-27T18:04:33","slug":"coding-a-better-stringcopy-function","status":"publish","type":"post","link":"https:\/\/c-for-dummies.com\/blog\/?p=7182","title":{"rendered":"Coding a Better <em>stringcopy()<\/em> Function"},"content":{"rendered":"<p>From <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=7166\">last week&#8217;s Lesson<\/a>, the task is to code a safer, better version of the <em>strcpy()<\/em> function. The goals are to check buffer size, report an overflow or underflow (buffer is too big or too small), and potentially confirm whether data is overwritten. Such a program is often used as a test when applying for a C programming job.<br \/>\n<!--more--><br \/>\nMy solution is the <em>stringcopy()<\/em> function with this prototype:<\/p>\n<p><code>int stringcopy(char *dest, size_t dsize, const char *src, size_t ssize)<\/code><\/p>\n<p>This function uses two arguments found in <em>strcpy()<\/em>: the address of the string to copy, pointer <code>src<\/code>, and the address of the buffer where the string is to be copied, pointer <code>dest<\/code>. Two additional arguments are the size of each buffer: <code>dsize<\/code> for the destination buffer&#8217;s size and <code>ssize<\/code> for the source buffer&#8217;s size. This approach parallels the many alternative, or &#8220;safe,&#8221; <em>strcpy()<\/em> function variations.<\/p>\n<p>I&#8217;ve also added a return value to my <em>stringcopy(<\/em>) function. The value is negative for an overflow, meaning that not every character is copied. It&#8217;s positive for an underflow, meaning that unused space (or characters) remain in the destination buffer. The return value is zero when both buffers match.<\/p>\n<p>Here is my code:<\/p>\n<h3><a href=\"https:\/\/github.com\/dangookin\/C-For-Dummies-Blog\/blob\/master\/2025_10_04-Lesson.c\" rel=\"noopener\" target=\"_blank\">2025_10_04-Lesson.c<\/a><\/h3>\n<pre class=\"screen\">\r\n#include &lt;stdio.h&gt;\r\n\r\n<span class=\"comments\">\/* arguments determine buffer sizes\r\n   return value:\r\n   negative for overflow, chars cut\r\n   positive for underflow, chars left in the buffer\r\n   zero for a perfect copy, no wasted space\r\n *\/<\/span>\r\nint stringcopy(char *dest, size_t dsize, const char *src, size_t ssize)\r\n{\r\n    int flow,x;\r\n\r\n    <span class=\"comments\">\/* test the buffer fit *\/<\/span>\r\n    flow = dsize-ssize;\r\n\r\n    <span class=\"comments\">\/* if overflow, copy only dsize characters *\/<\/span>\r\n    if( flow&lt;0 )\r\n    {\r\n        for( x=0; x&lt;dsize-1; x++ )\r\n            *(dest+x) = *(src+x);\r\n        *(dest+x) = '\\0';\r\n    }\r\n    <span class=\"comments\">\/* if underflow, copy the entire string *\/<\/span>\r\n    <span class=\"comments\">\/* same condition apples to equal buffer size *\/<\/span>\r\n    else\r\n    {\r\n        for( x=0; x&lt;ssize; x++ )\r\n            *(dest+x) = *(src+x);\r\n        *(dest+x) = '\\0';\r\n    }\r\n\r\n    return(flow);\r\n}\r\n\r\nint main()\r\n{\r\n    const char size=16;\r\n    char dest[size];\r\n    char src[] = \"The string is the thing\";\r\n    int r;\r\n\r\n    <span class=\"comments\">\/* copy the string *\/<\/span>\r\n    r = stringcopy(dest,size,src,sizeof(src)-1);\r\n    <span class=\"comments\">\/* test result *\/<\/span>\r\n    if( r&lt;0 )\r\n    {\r\n        puts(\"String overflow\");\r\n        printf(\"'%s' copied to '%s'\\n\",src,dest);\r\n    }\r\n    else if( r&gt;0 )\r\n    {\r\n        puts(\"String underflow\");\r\n        printf(\"'%s' copied to '%s'\\n\",src,dest);\r\n    }\r\n    else\r\n    {\r\n        puts(\"String fully copied\");\r\n        printf(\"'%s' copied to '%s'\\n\",src,dest);\r\n    }\r\n\r\n    return 0;\r\n}<\/pre>\n<p>The <em>stringcopy()<\/em> function first calculates integer variable <code>flow<\/code> as the difference between the destination buffer&#8217;s size and the source buffer&#8217;s size. The result determines overflow or underflow.<\/p>\n<p>An <em>if-else<\/em> decision is made depending on the value of <code>flow<\/code>. When <code>flow<\/code> is less than zero, meaning that the buffer would otherwise overflow, only <code>dsize-1<\/code> characters are copied into buffer <code>dest<\/code>. The final character is the null character, creating the string.<\/p>\n<p>The <em>else<\/em> condition handles underflow, in which case the entire string is copied. This condition also handles when the <code>dest<\/code> buffer is larger than necessary, with flow containing the number of characters remaining in the buffer.<\/p>\n<p>No matter which decision is made, the value of <code>flow<\/code> is returned, indicating underflow or overflow as well as reporting characters cut off or remaining in the buffer.<\/p>\n<p>The <em>main()<\/em> function copies a source string that&#8217;s too long to fit in the destination buffer. Variable <code>r<\/code> captures the return value from the <em>stringcopy()<\/em> function, with an <em>if else-if else<\/em> structure handling the various conditions possible.<\/p>\n<p>Here&#8217;s output from a sample run:<\/p>\n<p><code>String overflow<br \/>\n'The string is the thing' copied to 'The string is t'<\/code><\/p>\n<p>I&#8217;m not certain whether this code will land me a job, but it doesn&#8217;t accomplish the task at hand. In the future I may explore the variety of string copying functions and how they deal with various conditions. Just about anything is better than the standard <em>strcpy()<\/em> function, which can easily be exploited.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This task may be presented when you apply for a C programming job. <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=7182\">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-7182","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\/7182","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=7182"}],"version-history":[{"count":3,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/7182\/revisions"}],"predecessor-version":[{"id":7188,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/7182\/revisions\/7188"}],"wp:attachment":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=7182"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=7182"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=7182"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}