{"id":5850,"date":"2024-06-16T03:00:00","date_gmt":"2024-06-16T07:00:00","guid":{"rendered":"https:\/\/www.both.org\/?p=5850"},"modified":"2024-06-12T20:49:43","modified_gmt":"2024-06-13T00:49:43","slug":"5-common-c-programming-bugs-and-how-to-avoid-them","status":"publish","type":"post","link":"https:\/\/www.both.org\/?p=5850","title":{"rendered":"5 common C programming bugs (and how to avoid them)"},"content":{"rendered":"<div class=\"pld-like-dislike-wrap pld-template-1\">\r\n    <div class=\"pld-like-wrap  pld-common-wrap\">\r\n    <a href=\"javascript:void(0)\" class=\"pld-like-trigger pld-like-dislike-trigger  \" title=\"\" data-post-id=\"5850\" data-trigger-type=\"like\" data-restriction=\"cookie\" data-already-liked=\"0\">\r\n                        <i class=\"fas fa-thumbs-up\"><\/i>\r\n                <\/a>\r\n    <span class=\"pld-like-count-wrap pld-count-wrap\">    <\/span>\r\n<\/div><\/div>\n<p>Programming in C can provide a lot of flexibility to writing your own command line programs. I like writing in C because I find it easier to write most of my programs. The trade-off to writing in C is that you need to be more careful. In \u201chigher level\u201d programming languages like Rust, Go, or Java, the language helps to protect the programmer from certain common mistakes. But in C, you need to watch for these pitfalls yourself.<\/p>\n\n\n\n<p>Here are five common C programming bugs, and how you can avoid them:<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"using-variables-without-initializing-them\">1. Using variables without initializing them<\/h2>\n\n\n\n<p>The C programming language doesn\u2019t initialize variables to zero before you use them; that\u2019s the job of the programmer. What happens \u201cbehind the scenes\u201d is that the operating system will give the program some memory to use, but it\u2019s not guaranteed to have any particular value. It\u2019s just random bits. So any values you try to read from that area could be completely random. If you forget this important detail, you can wind up with some very strange behavior.<\/p>\n\n\n\n<p>Here\u2019s a sample program that uses a few integer variables, an integer array, and a pointer to an integer array. Note that the program immediately prints the values from those variables <em>without giving them a value<\/em> so the values are just some weird bit patterns that were in memory at the time.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;stdio.h&gt;\n\nint main()\n{\n    int a, b, c, d;\n    int numbers&#91;5];\n    int *array;\n\n    puts(\"These variables are not initialized:\");\n    printf(\"a, b, c, d = %d, %d, %d, %d\\n\", a, b, c, d);\n\n    puts(\"This array is not initialized:\");\n\n    for (a = 0; a &lt; 5; a++) {\n        printf(\"numbers&#91;%d] = %d\\n\", a, numbers&#91;a]);\n    }\n\n    puts(\"This array is not allocated or initialized:\");\n\n    for (a = 0; a &lt; 5; a++) {\n        printf(\"array&#91;%d] = %d\\n\", a, array&#91;a]);\n    }\n\n    puts(\"Ok\");\n\n    return 0;\n}<\/code><\/pre>\n\n\n\n<p>If we save this as <code>uninit.c<\/code> and compile it, we can see the program generates some unpredictable values:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ gcc -o uninit uninit.c\n$ .\/uninit \nThese variables are not initialized:\na, b, c, d = 32767, -154530776, 0, 0\nThis array is not initialized:\nnumbers&#91;0] = 0\nnumbers&#91;1] = 0\nnumbers&#91;2] = 0\nnumbers&#91;3] = 0\nnumbers&#91;4] = 0\nThis array is not allocated or initialized:\narray&#91;0] = -98693133\narray&#91;1] = -284203435\narray&#91;2] = -443987776\narray&#91;3] = -1991682239\narray&#91;4] = 1096172031\nOk<\/code><\/pre>\n\n\n\n<p><em>Programming tip: If you need a variable to start with some initial value, assign a value to it when you declare the variable. Or add an extra step to store a value (like zero) to the variable before you use it.<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"going-outside-array-boundaries\">2. Going outside array boundaries<\/h2>\n\n\n\n<p>When you\u2019re writing programs that involve arrays, it can be tempting to assume the size of the array will never change. Unfortunately, that rarely remains true.<\/p>\n\n\n\n<p>Here\u2019s a typical example: In \u201cversion 1\u201d of your program, the array is ten elements long. For \u201cversion 2,\u201d you make a few changes, and realize you don\u2019t need the array to be quite as long, maybe only five elements. You update the program &#8211; but you forget to make the same change everywhere. Your array is defined as five elements, but later you try to store ten elements. Here\u2019s one example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;stdio.h&gt;\n\nint main()\n{\n    int i;\n    int array&#91;5];\n    char a = 'a', b = 'b';\n    int zero = 0;\n\n    \/* show starting values *\/\n\n    printf(\"a, b = %c, %c\\n\", a, b);\n    printf(\"zero = %d\\n\", zero);\n\n    \/* initialize the array *\/\n\n    for (i = 0; i &lt; 10; i++) {\n        array&#91;i] = 0;\n    }\n\n    \/* show ending values *\/\n\n    printf(\"a, b = %c, %c\\n\", a, b);\n    printf(\"zero = %d\\n\", zero);\n\n    puts(\"Ok\");\n\n    return 0;\n}<\/code><\/pre>\n\n\n\n<p>This goes outside the array boundaries, and can lead to unpredictable behavior. That\u2019s because the memory for the array was only five elements; the memory at what would be \u201celement six\u201d is actually some other variable. In the worst case, your program might overwrite some important value and cause the program to hang or crash. When I saved this program as <code>outside.c<\/code> and compiled and ran it, the program hung and I had to use control-c to terminate the program and return to the command prompt.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ gcc -o outside outside.c\n$ .\/outside \na, b = a, b\nzero = 0\n^C<\/code><\/pre>\n\n\n\n<p><em>Programming tip: Use a constant value using<\/em> <code>#define<\/code> <em>and use that for the size of your array. That\u2019s one place to change the program when you later decide the array should be some other size.<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"overflowing-a-string\">3. Overflowing a string<\/h2>\n\n\n\n<p>Related to going outside array boundaries is overflowing a string. A string is really just an array of <code>char<\/code> values, usually terminated by a zero value called the \u201cnull terminator.\u201d<\/p>\n\n\n\n<p>One easy way to overflow a string is when the program asks the user to input something. The old-style <code>gets<\/code> function will get a string value from the terminal, but without consideration to the array size. If your string variable can hold only eight letters, but the user enters nine or more letters, the program will overflow the string. And as with going outside an array\u2019s boundaries, that will overwrite some part of memory elsewhere in the program.<\/p>\n\n\n\n<p>Fortunately, <code>gets<\/code> has been deprecated in the C programming language, so programs that use it will fail to compile.<\/p>\n\n\n\n<p>So let\u2019s look at another example of overflowing a string. You can copy one string into another using the <code>strcpy<\/code> function. This assumes that the destination string is large enough to store the full value, which may not always be true; Here\u2019s one example that naively copies a longer string into a string variable that\u2019s not large enough:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;stdio.h&gt;\n#include &lt;string.h&gt;                    \/* strcpy *\/\n\nint main()\n{\n    char str&#91;4];\n    char hello&#91;] = \"Hello world!\";\n\n    puts(hello);\n\n    strcpy(str, hello);\n    puts(str);\n\n    puts(\"Ok\");\n\n    return 0;\n}<\/code><\/pre>\n\n\n\n<p>If I save this program as <code>string.c<\/code> and compile it, we\u2019ll see that the program doesn\u2019t just fail &#8211; it fails <em>hard<\/em> with a core dump.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ gcc -o string string.c\n$ .\/string\nHello world!\nHello world!\nOk\nSegmentation fault (core dumped)<\/code><\/pre>\n\n\n\n<p><em>Programming tip: C programmers should always take care to keep track of how long each string is, and make sure there\u2019s enough room to copy data into it.<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"using-invalid-file-pointers\">4. Using invalid file pointers<\/h2>\n\n\n\n<p>C makes it easy to read and write data to files. You open a file with the <code>fopen<\/code> function, and close it with <code>fclose<\/code> when you\u2019re done with the file. But don\u2019t assume the program was able to open the file. You might encounter any number of reasons that the program couldn\u2019t open a file, from file permissions, file locking, or simply the fact that the file doesn\u2019t exist. Here\u2019s one program that make the too-simple assumption that it could open a file before printing it:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;stdio.h&gt;\n\nint main()\n{\n    FILE *pfile;\n    char ch;\n\n    \/* open the file *\/\n\n    pfile = fopen(\"file.dat\", \"r\");\n\n    \/* show the file *\/\n\n    while ((ch = fgetc(pfile)) != EOF) {\n        putchar(ch);\n    }\n\n    \/* close the file *\/\n\n    fclose(pfile);\n\n    puts(\"Ok\");\n    return 0;\n}<\/code><\/pre>\n\n\n\n<p>The program is supposed to read data from <code>file.dat<\/code> and print it to the terminal, but this will fail if the file does not exist. And in my case, that file isn\u2019t there. If I save this program as <code>showfile.c<\/code> and compile it, we can see the file fails hard with a core dump:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ gcc -o showfile showfile.c\n$ ls file.dat\n\/bin\/ls: cannot access 'file.dat': No such file or directory\n$ .\/showfile\nSegmentation fault (core dumped)<\/code><\/pre>\n\n\n\n<p><em>Programming tip: Check the return value of<\/em> <code>fopen<\/code> <em>to be sure that your program could actually open the file.<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"freeing-memory-more-than-once\">5. Freeing memory more than once<\/h2>\n\n\n\n<p>The C programming language has a flexible system to allocate memory for a program. <code>malloc<\/code> can allocate an entire block of memory at once, while the related <code>calloc<\/code> function allocates memory based on the number of elements that you need to store. If you need to change the amount of memory that\u2019s reserved for you, the <code>realloc<\/code> will do that for you.<\/p>\n\n\n\n<p>When you\u2019re done with the memory, usually at the end of the program, the program needs to release that memory back to the operating system with the <code>free<\/code> function. However, you must only free memory once. That\u2019s because <code>malloc<\/code> returns a <em>pointer<\/em> to an area of memory that\u2019s been made available to the program; after this region has been freed, you shouldn\u2019t use that memory again. Freeing the memory a second time is invalid. Here\u2019s a simple program to show what I mean:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;stdio.h&gt;\n#include &lt;stdlib.h&gt;                    \/* malloc *\/\n\n#define SIZE 5\n\nint main()\n{\n    int i;\n    int *array;\n\n    \/* allocate memory *\/\n\n    array = malloc(SIZE * sizeof(int));\n\n    if (array == NULL) {\n        puts(\"cannot allocate memory\");\n        return 1;\n    }\n\n    \/* store values *\/\n\n    for (i = 0; i &lt; SIZE; i++) {\n        array&#91;i] = i;\n        printf(\"array&#91;%d] = %d\\n\", i, array&#91;i]);\n    }\n\n    \/* free *\/\n\n    free(array);\n    free(array);                       \/* oops, we did it again *\/\n\n    puts(\"Ok\");\n    return 0;\n}<\/code><\/pre>\n\n\n\n<p>At first, this seems like a normal program, allocating five elements in the array and initializing a value before using it. But when the program is done with the memory, it frees the array twice. This can happen if you use a function to do a bunch of cleanup in your program, including freeing memory used by arrays, and forget that your <code>main<\/code> program also frees the same array on its own. In this case, the program aborts:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ gcc -o free2 free2.c\n$ .\/free2 \narray&#91;0] = 0\narray&#91;1] = 1\narray&#91;2] = 2\narray&#91;3] = 3\narray&#91;4] = 4\nfree(): double free detected in tcache 2\nAborted (core dumped)<\/code><\/pre>\n\n\n\n<p><em>Programming tip: I recommend only using<\/em> <code>free<\/code> <em>in the same function that allocates memory. If your<\/em> <code>main<\/code> <em>program allocates the memory, it should also be the unit that frees it.<\/em><\/p>\n\n\n\n<p><em>Bonus programming tip: You can also assign the<\/em> <code>NULL<\/code> <em>value to a pointer after you free it. The<\/em> <code>free<\/code> <em>function takes no action if the array pointer is already<\/em> <code>NULL<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"we-all-make-mistakes\">We all make mistakes<\/h2>\n\n\n\n<p>Programming bugs happen to the best of programmers. But if you follow these guidelines and add a little extra code to check for these five types of bugs, you can avoid the most serious C programming mistakes. A few lines of code up front to catch these errors may save you hours of debugging later.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Add a little extra code to your next program to avoid these common C programming mistakes.<\/p>\n","protected":false},"author":33,"featured_media":5230,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_lmt_disableupdate":"","_lmt_disable":"","footnotes":""},"categories":[98,150],"tags":[439,152],"class_list":["post-5850","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-code","category-programming","tag-bugs","tag-programming"],"modified_by":"David Both","_links":{"self":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/5850","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/users\/33"}],"replies":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=5850"}],"version-history":[{"count":1,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/5850\/revisions"}],"predecessor-version":[{"id":5851,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/5850\/revisions\/5851"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/media\/5230"}],"wp:attachment":[{"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=5850"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=5850"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=5850"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}