# C program to print a vertical english ruler whose length is given by the user

In this source code, i have writena program, using for loops, to print an english ruler whose length is given by the user. So what i want to know is that is it possible to modify this program, to print the ruler in a more logical way And if so, how can it be done, without applying reculsions ?

This is the program to print ruler vertically.

#include <stdio.h>
int main()
{

int q, num, x;
int y, p, n;
printf( "Enter height of central dashes \n" );
scanf( "%d", &n );
printf( "Enter number of inches \n" );
scanf( "%d", &num );
for( x=0; x < num ; x++ )
{
for( q=0; q<n; q++ )
{
printf( "-" );
}
printf( "%d\n", x );
for( p=0; p < n-3; p++ )
{
printf("-");
}
printf( "\n" );
for( p=0; p < n-2; p++ )
{
printf( "-" );
}
printf( "\n" );
for( p=0; p < n-3; p++ )
{
printf( "-" );
}
printf("\n");
for( p = 0; p < n-1; p++)
{
printf( "-" );
}
printf( "\n" );
for( p = 0; p < n-3; p++)
{
printf( "-" );
}
printf( "\n" );
for( p = 0; p < n-2; p++)
{
printf( "-" );
}
printf( "\n" );
for( p = 0; p < n-3; p++)
{
printf( "-" );
}
printf( "\n" );
}
for( y = 0; y < n; y++ )
{
printf( "-" );
}
printf( "%d", x );
printf( "\n" );
return 0;
}


• @aghast Please do not edit code in the question. Reviewers can comment on any aspect of the code including whitespace. By editing the code you can either give reviewer more points to talk about or depriving the reviewer of points to talk about, either way the OP becomes disadvantaged. Please read our editing meta for more information. May 4 at 7:57

First up: Single Responsibility Principle (SRP)

You've basically got all your code in one big long main function. That's not outright terrible for code like this, but... it's a bad habit to get into. If you've never heard of SRP before, spend a good few hours googling it, and read 'Clean Code' by Robert "Uncle Bob" Martin - it's one of the best ways to improve as a programmer.

Second: variable names.

About the only place you should ever use a one-letter variable name is in a Lambda Expression or a 1-2 line loop. You should never use one for a loop that has scope over dozens of lines of code.

Plus, good variable names help document what your code is doing. Most of the time you'll spend in code isn't writing the code, but maintaining the code. The code should be readable, not merely decipherable.

Next up: Indentation.

Partly just OCD, but partly because troubleshooting/reading code with incorrect indentation is dangerous. You've got an overarching loop for the inch counter, but your inner contents aren't indented to signal that.

Finally: Don't Repeat Yourself (the 'DRY' principle.)

Take a skim over your code - how similar does it look throughout, how many lines of code look like duplication? That's a good way to get a sense of whether you're violating DRY.

Repeating yourself sucks. Not because it's hard to Copy-Paste (it's not!) but because... it's very easy to bug-fix or augment one section... but miss another that does the same thing.

Anyway, here's what I'd do for something like this (caveat: not at a C compiler at the moment, so this code might not be 100% correct)

int main()
{
int baselineDashCount = GetNumberOfInchesToPrint();
char[200] baselineDashes;
GetBaselineDashesToPrint(baselineDashes, sizeof(baselineDashes)-1);
PrintInchDividerLine(0, baselineDashes);
for (int inchNum = 1; inchNum <= numberOfInchesToPrint; inchNum++)
{
}
}
int GetNumberOfInchesToPrint()
{
int retVal;
printf( "Enter number of inches \n" );
scanf("%d", &retVal);
// todo: do some validation of the input here
return retVal;
}
void GetBaselineDashesToPrint(char * buffer, int maxSize)
{
int numOfDashes;
printf( "Enter number of inches \n" );
scanf( "%d", &retVal );
// todo : do some validation on the input here, especially numOfDashes <= maxSize
if (numOfDashes > maxSize) numOfDashes = maxSize; // or we can be lazy like this
if (numOfDashes < 0) numOfDashes = 0;
for (int charPos = 0; charPos < numOfDashes; charPos++)
{
buffer[charPos] = '-';
}
buffer[numOfDashes] = 0; // null terminate our string.
}

void PrintInchDividerLine(int inchNum, char * baselineDashes)
{
printf("%s--- %d\n", baselineDashes, inchNum);
}
void PrintAdditionalInch(int inchNum, char * baselineDashes);
{
printf("%s\n", baselineDashes);
printf("%s-\n", baselineDashes);
printf("%s\n", baselineDashes);
printf("%s--\n", baselineDashes);
printf("%s\n", baselineDashes);
printf("%s-\n", baselineDashes);
printf("%s\n", baselineDashes);
PrintInchDividerLine(inchNum, baselineDashes);
}


The code here has been streamlined greatly. If you don't like the additional complexity of the 'baselineDashes' bit which skips having to do for() loops for every time you want to print dashes (geez, I'd forgotten how much I hate string handling in C), you could always modify that part to something like:

void PrintInchDividerLine(int inchNum, int baselineDashCount)
{
DashPrinter(baselineDashCount + 3, false);
printf("%d\n", inchNum);
}
{
DashPrinter(baselineDashCount, true);
DashPrinter(baselineDashCount+1, true);
DashPrinter(baselineDashCount, true);
DashPrinter(baselineDashCount+2, true);
DashPrinter(baselineDashCount, true);
DashPrinter(baselineDashCount+1, true);
DashPrinter(baselineDashCount, true);
PrintInchDividerLine(inchNum, baselineDashCount);
}
void DashPrinter(int dashCount, bool sendNewline)
{
for (int i = 0; i < dashCount; i++) { printf("-"); }
if (sendNewline) printf("\n");
}


Big Takeaways from the code:

Look at how short each function is. Look at how the function name documents what it's doing. Look at how, if you needed to change how the program operated, that it makes modification very simple (you generally just need to tweak one small function, not manipulate a long overarching function.)

• Thank you very much, this is exactly what i needed to know. May 6 at 4:57

The task you are solving is quite simple. So I don't think there's any great change possible. Here are a few things:

1. You might want to consider accepting command-line parameters (argc and argv) to determine the number of dashes and the dash height.

2. Your variables are poorly named, and not initialized. You have not specified an old version of C, so I'm assuming that you can write to at least the 1999 C standard (known as "C99").

3. You don't validate your user's input.

4. You don't need to return 0 from main(). Just "fall off the end" of the function and it will do that automatically.

5. Your last two calls to printf should be merged.

6. You might want to write functions (or preprocessor macros) to make the various fractional gradations more clear:

#define DRAW_1_8(HEIGHT) for (int i = 0; i < (HEIGHT) - 3; ++i) printf("-")

then your main loop becomes a series of named statements:

for (int inch = 0; inch < length; ++inch) {
DRAW_INCH(height, inch);
DRAW_1_8(height);
DRAW_1_4(height);
DRAW_1_8(height);
DRAW_1_2(height);
DRAW_1_8(height);
DRAW_1_4(height);
DRAW_1_8(height);
}
DRAW_INCH(height, length);


This does serve to make the code a bit clearer, but mainly it serves to reduce repetition. I'll bet there were a few mistakes early on as you adjusted all the n - K parameters, and macros or functions address that issue.

• I personally disagree with implicit-return-zero. It's one of those quirks of C that doesn't greatly improve terseness or usability, and hinders uniformity of syntax. May 5 at 2:32

Instead of a series of for loops for each mark, you could have a single string with as many marks as you need for the longest mark, and use fwrite or some other primitive function to write the specified number of bytes.

And then encapsulate a function to draw a mark of the desired length.