Exercises 1-20 of
“The C Programming Language” by Brian
Kernighan and Dennis Ritchie aka K&R
deal with parsing text entered by a user.
Exercise 1-20. Write a program detab that replaces
tabs in the input with the proper number of blanks to space to the next tab
stop. Assume a fixed set of tab stops, say every n columns. Should n be
a variable or a symbolic parameter?
By this point in the book, writing this code, even from
scratch, should be straightforward, but there is some work to figure out tab
stops since a tab moves to fixed stops. It’s not the case that every tab is
replaced with n number of spaces. The number of spaces will vary. Second, to
replace a tab ‘\t’, which is one character, with several spaces, means
stretching the char array. You can avoid this issue by outputting the text
immediately and not storing any data in a character array.
On my computer, a tab takes up 8 characters. Here is an
example.
Column: 1234567891123456789212345678931234567940
Element: 0123456789112345678921234567893123456794
abcdT abcabcT
abcT abc...
The first tab appears at element 4 or position 5 on the
screen. The modulus of 5 and 8 is 5 and the number of spaces to add is 3. The
tab width, 8, less 5 is three.
The tab character has to be replaced with a space so the
number of spaces to add is: 1+ Tab width (8) less (Element position + 1) mod 8.
This equation can be simplified since 1 mod 8 is one and subtracting it from 1
+ Tab width leaves: Tab width less (Element position mod 8). The simplification
of the equation is true for all values of tab width.
As for how to store the value of the tab width, it’s better
to create a variable, TabWidth. If it’s a variable, it can be dynamically
changed based on a user’s system without recompiling the program. If the value
is stored as a symbolic constant, the value can only be changed by recompiling
the program. The symbolic constant (e.g., #DEFINE TABWIDTH 8) is replaced by
its literal value during the pre-compile process.
Sample Code.
I am using Visual C++ 2010 and created the sample code as a
console application.
//
Function prototype.
// The
standard library includes the system function.
#include <cstdlib>
//
Standard I/O library.
#include <cstdio>
int main()
{
int c, i =
0;
char
line[80];
// Get user input
from keyboard.
while ((c =
getchar()) != EOF)
{
// Store
char.
if (c
!= '\n')
{
line[i] = c;
++i;
}
else
{
//
Store null char to mark end.
line[i] = '\0';
//
Parse text to replace tabs w spaces.
detab(line);
//
Output text.
printf("%s\n\n",
line);
//
Reset counter.
i = 0;
}
}
// Keep console
window open.
system("pause");
// Return some
value.
return 0;
} // end main
//
Remove tabs and replace
int detab(char text[])
{
int iFrom,
iTo = 0;
char
temp[80];
int
SpaceCount = 0;
int
TabWidth = 8;
for (iFrom
= 0; text[iFrom]; ++iFrom)
{
// Find
tab.
if
(text[iFrom] == '\t')
{
//
Replace tab with spaces.
//
Calc the number of spaces to fill up to tab stop.
//
SpaceCount = 1 + TabWidth - ((iTo + 1) % TabWidth);
//
Equiv. stmt.
SpaceCount = TabWidth - (iTo %
TabWidth);
for
(; SpaceCount ; --SpaceCount, ++iTo)
temp[iTo] = ' ';
}
else
{
// Not
a tab.
//
Store as is.
temp[iTo] = text[iFrom];
++iTo;
}
}
// Store null
char to mark end.
temp[iTo] = '\0';
// Copy temp to text.
iTo = 0;
while
((text[iTo] = temp[iTo]) != '\0')
++iTo;
// Store null
char to mark end.
text[iTo] = '\0';
// Return
something.
return 0;
}
Output.