Reputation: 41
Im trying to work my way through the C programming Language book and im on exercise 1-21, where you have to replace blocks of blank spaces with the right amount of tabs and spaces to equal the same space,I was able to get everything to run and compile correctly but it keeps putting the wrong amount of tabs and spaces in the output.
The actual question from the book:
Write a program entab that replaces string of blanks by the minimum number of tabs and blanks to achieve the same spacing. Use the same tab stops as for detab. When either a tab or a single blank would suffice to reach tab stop, which should be given preference?
Again Guys im still really new to programming so please be as descriptive as possible.
if I input something like asdf asdf asdf
i get something like----- asdf asdf asdf back out.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_BUFFER 1024
#define SPACE ' '
#define TAB '\t'
#define TabSize 4
int main()
{
int c, i, j, spaces = 0, size, tempspaces, x, y, z;
int tabs = 0;
char arrayPrimary[MAX_BUFFER];
char arraySecondary[MAX_BUFFER];
/* ********************************************************************** */
for(i = 0;(c = getchar()) != EOF && c != '\n'; i++)
{
arrayPrimary[i] = c;
}
arrayPrimary[i] = '\0';
size = i;
printf("%s\n", arrayPrimary);
/* ********************************************************************** */
for(i = 0, j = 0, tempspaces = 0; i < size; i++)
{
if(arrayPrimary[i] == SPACE)
{
tempspaces++;
}
else
{
arraySecondary[j] = arrayPrimary[i];
j++;
}
if(tempspaces > 0 && arrayPrimary[i + 1] != SPACE)
{
spaces = tempspaces % TabSize;
printf("Spaces %i\n", spaces);
tabs = ((tempspaces - spaces)/TabSize);
printf("Tabs %i\n", tabs);
for(y = 0; y <= spaces; y++)
{
arraySecondary[j] = SPACE;
j++;
}
for(x = 0; x <= tabs; x++)
{
arraySecondary[j] = TAB;
j++;
}
tabs = 0;
spaces = 0;
tempspaces = 0;
}
}
arraySecondary[j + 1] = '\0';
printf("%s\n", arraySecondary);
return 0;
}
Upvotes: 1
Views: 1307
Reputation: 21
Taking a stab at the algorithm for solving this problem. Here goes.
Define the tab size. Create and null out an 'input' array and an 'output' array. Initialize index variables for the arrays and other variables as required.
First, collect the entire input line into an array called 'input'. Then, starting from the beginning of 'input', read each character till the end of the array and check whether it is a 'space' character or not. If it is not a 'space' character, copy it into the 'output' array and continue with next character. If it is a 'space' character, then remember the index in 'input' where we found the 'space' and look ahead into 'input' for any contiguous 'space' characters and increment a counter for each 'space' character we encounter. When we reach the next non-'space' character, check whether the number of 'space' characters we have just read is greater than the tab size. If it is greater than tab size, then call a function to entab the number of spaces as combination of tabs and spaces equal to the number of spaces and insert into 'output'. If it is not greater than the tab size, then we can't put 'tab' characters, so we just copy all the spaces into 'output'. If we were able to call the entab function, we need to resume reading 'input' from the index which we have remembered, but we have to skip all the spaces by adding the number of 'space' characters we encountered to the remembered index.
The entab function would have to calculate the number of tabs and spaces that can be combined to achieve the actual spacing. We calculate the distance to the next tab stop using the below mentioned formula:
x = tabSize - (currentInputIndex mod tabSize);
If the above result is non-zero, then we are x characters away from the next tab stop. Now insert one 'tab'. Then recalculate the remaining number of spaces by subtracting x from the original number of spaces. Recalculate the number of tabs and spaces required by using the below mentioned formulae:
nTabs = spacesRemaining / tabSize; nSpaces = spacesRemaining mod tabSize;
Insert nTabs 'tab' and nSpaces 'space' characters into 'output' in sequence. The entab function should return the index in the output array back to the main program so that it can continue processing the rest of the input array.
Upvotes: 2
Reputation: 42159
At the very least you are inserting one extra space and one extra tab every time:
for(y = 0; y <= spaces; y++)
for(x = 0; x <= tabs; x++)
Both of these loops run from 0 to the number of spaces/tabs, i.e., if you have 1 each, the loops will run twice (0 <= 1
, 1 <= 1
). Remove the =
from the conditions.
Secondly, most terminals and editors do not simply treat a tab as equal to a certain number of spaces, but rather the tab is of variable width, taking the cursor to the next tab stop. So, for example, if tabs stops are four spaces apart, the strings "123\tx"
and "\tx"
both cause the x
to end up at the same tab stop in column 4 – in the first the tab is equivalent to one space, whereas in the second it is equivalent to four spaces… Your program does not take this into account.
To implement tab stops correctly, you need to keep track of the current column - the width of the tab at that position will then be TabSize - (column % TabSize)
.
It also looks to me like you are not terminating arraySecondary
correctly:
arraySecondary[j + 1] = '\0';
You always increment j
after assigning to the array inside the loop, so this should be
arraySecondary[j] = '\0';
In addition to this, make sure the TabSize
defined in the program matches the tab size of the terminal you run the program in, otherwise the output will not visually match even if your program is correct.
Upvotes: 1