Optimizing My Code

One of the burdens of being a programmer is that few people are witness to your brilliance. You can write the keenest code since the Countess of Lovelace and it’s likely no one will ever appreciate your genius. But don’t let this limitation stop you!

I’m always looking for clever ways to improve my code. Some of this obsession borders on obfuscation, but the process always beings with the bulky way to code a problem. Work continues as I try to add efficiency and elegance.

I wrote the following code to measure tab stops on the terminal screen. In Linux, you use the tabs command to set the stops. The default is eight spaces, though you can set the interval to any amount or even set discrete tab stops at specific positions. My program shows where they’re set:

2024_07_27-Lesson-a.c

#include <stdio.h>

int main()
{
    int x;

    /* output header */
    for( x=0; x<79; x++ )
    {
        if( x%10==0 )
            putchar('|');
        else
            printf("%d",x%10);
    }
    putchar('\n');

    /* show tab stops */
    printf("Zero\n");
    printf("\tOne\n");
    printf("\t\tTwo\n");
    printf("\t\t\tThree\n");
    printf("\t\t\t\tFour\n");
    printf("\t\t\t\t\tFive\n");
    printf("\t\t\t\t\t\tSix\n");
    printf("\t\t\t\t\t\t\tSeven\n");

    return(0);
}

Here’s sample output:

|123456789|123456789|123456789|123456789|123456789|123456789|123456789|12345678
Zero
        One
                Two
                        Three
                                Four
                                        Five
                                                Six
                                                        Seven

To me, this program provides a useful tool, but I don’t like the repetitive printf() statements. Further, it would help if the header were output between each line to better gauge the tab stop positions.

The first improvement I made to the code is to extract the header into its own function. I then put the tab output routine into a loop. This change didn’t make the code tighter, but it improved the output:

2024_07_27-Lesson-b.c

#include <stdio.h>

/* output header */
void header(void)
{
    int x;

    for( x=0; x<79; x++ )
    {
        if( x%10==0 )
            putchar('|');
        else
            printf("%d",x%10);
    }
    putchar('\n');
}

int main()
{
    int x,t;
    char *count[8] = {
           "Zero", "One", "Two", "Three",
        "Four", "Five", "Six", "Seven"
    };

    /* show tab stops */
    for( x=0; x<8; x++ )
    {
        header();
        for(t=0; t<x; t++ )
            putchar('\t');
        printf("%s\n",count[x]);
    }

    return(0);
}

Here is the updated output:

|123456789|123456789|123456789|123456789|123456789|123456789|123456789|12345678
Zero
|123456789|123456789|123456789|123456789|123456789|123456789|123456789|12345678
        One
|123456789|123456789|123456789|123456789|123456789|123456789|123456789|12345678
                Two
|123456789|123456789|123456789|123456789|123456789|123456789|123456789|12345678
                        Three
|123456789|123456789|123456789|123456789|123456789|123456789|123456789|12345678
                                Four
|123456789|123456789|123456789|123456789|123456789|123456789|123456789|12345678
                                        Five
|123456789|123456789|123456789|123456789|123456789|123456789|123456789|12345678
                                                Six
|123456789|123456789|123456789|123456789|123456789|123456789|123456789|12345678
                                                        Seven

I remained unhappy with this update. The output is crowded. So I added a toggle to the header() function. An on/off value is read to determine whether the digits are output between the pipe characters. Two defined constants, ON and OFF, determine when to output the digits:

2024_07_27-Lesson-c.c

#include <stdio.h>

#define ON 1
#define OFF 0

/* output header */
void header(int a)
{
    int x;

    for( x=0; x<79; x++ )
    {
        if( x%10==0 )
            putchar('|');
        else
        {
            if(a)
                printf("%d",x%10);
            else
                putchar(' ');
        }
    }
    putchar('\n');
}

int main()
{
    int x,t;
    char *count[8] = {
           "Zero", "One", "Two", "Three",
        "Four", "Five", "Six", "Seven"
    };

    /* show tab stops */
    for( x=0; x<8; x++ )
    {
        x==0 ? header(ON): header(OFF);
        for(t=0; t<x; t++ )
            putchar('\t');
        printf("%s\n",count[x]);
    }

    return(0);
}

Here is the updated and final output:

|123456789|123456789|123456789|123456789|123456789|123456789|123456789|12345678
Zero
|         |         |         |         |         |         |         |        
        One
|         |         |         |         |         |         |         |        
                Two
|         |         |         |         |         |         |         |        
                        Three
|         |         |         |         |         |         |         |        
                                Four
|         |         |         |         |         |         |         |        
                                        Five
|         |         |         |         |         |         |         |        
                                                Six
|         |         |         |         |         |         |         |        
                                                        Seven

I’m pleased with the result. Further, I think I’m clever for devising some interesting solutions. My goal wasn’t to make the code more compact (which would have been sweet), but to make it more efficient. Regardless, the final program is the point. As long as it’s doing the job and doesn’t pose an unintended risk to the system, I’m good.

3 thoughts on “Optimizing My Code

  1. I donʼt know how you do it, but the challenges you come up with on a weekly basis is really impressive and I like this one.

    The only thing that could probably be improved would be to use ioctl(STDIN_FILENO, TIOCGWINSZ, &winsize); to determine the terminals width and height and to also use the "\x1B[6n\n" ANSI escape sequence to get the cursors position after outputting "\r\t", thereby determining the systems TAB width size at runtime.

    That being said I realize why you didnʼt go this route—all the necessary code to do this would only distract from the main idea and blow up the the programs LOC to probably twice or even thrice of the current solution.

  2. Thank you!

    I like your thoughts on obtaining a tab stop. Using the window size would be good – and relevant today as a mouse swipe can easily change a terminal window’s size.

    The ANSI sequence is cool, but keep in mind that the tabs command can set tab stops at irregular intervals. Of course, all this dust is silly because the tabs command option -d coughs up the current tab stops anyway:

    ----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8
    *-------*-------*-------*-------*-------*-------*-------*-------*-------*-------
    *       *       *       *       *       *       *       *       *       *

    It even adjusts the output width to match the window, so there’s some magic in there!

    Still, it’s a fun exercise and something I’ve used in the past.

  3. Interesting, I didn’t know that you could set varying TAB positions (like on an electronic typewriter).

    Then again, I must admit that I have never really played with the tabs command.

Leave a Reply