K & R Exercise 1-21 - Mental Misunderstanding

Impossible exercise K & R.

“Write an entab program that replaces spaces with a minimum number of tabs and spaces to achieve the same interval. Use the same tab to stop, say, every n columns. If n be a variable or symbolic parameter?”

The problem I am facing is that I am not sure how to do this correctly. I know this is not very explanatory, but this is pretty much the problem here. Most of the examples that I saw counted a few spaces, and replaced these series with a tab, but that’s not what she’s asked, I think I understand what she’s asking, but currently I can’t do it.

Can anyone help :)

Edit: the code that I wrote so far can be found here .

+6
c kr-c
source share
8 answers

If your question is: “What is it asking me to do?” I think I can help by paraphrasing the original question (asking the same question in a different way).

Write a program that takes spaces as input and produces as output the visually equivalent text using tabs as much as possible.

For example, with tabstops every 8 characters and showing spaces as '.' and tabs like '-';

input; ".foo:...bar;......#comment" output; ".foo:-bar;-..#comment" input; ".......-foo:.....bar;......#comment" output; "-foo:-.bar;-...#comment" 

Write the program so that the tabstop n parameter can change, i.e. allow n values ​​other than 8. Be prepared to justify your decision to make n a constant or, alternatively, a variable.

Edit I looked at your code, and I think it is more complicated than necessary. My advice is to make this a character at a time. There is no need to buffer an entire line. Count the columns when reading each character ('\ n' resets it to zero, '\ t' hits it by 1 or more, other characters increase it). When you see a space (or tab), don't emit anything right away, start the entabbing process, emit zero or more tabs, and then spaces later (in "\ n" or a character without spaces, whichever comes first).

The final hint is that a state machine can make such an algorithm much easier to write, validate, validate, and read.

Edit 2 In a shameless attempt to get the OP to accept my answer, I now went ahead and actually coded the solution myself, based on the hints I suggested above and my comments in the discussion.

 // K&R Exercise 1-21, entab program, for Stackoverflow.com #include <stdio.h> #define N 4 // Tabstop value. Todo, make this a variable, allow // user to modify it using command line int main() { int col=0, base_col=0, entab=0; // Loop replacing spaces with tabs to the maximum extent int c=getchar(); while( c != EOF ) { // Normal state if( !entab ) { // If whitespace goto entab state if( c==' ' || c=='\t' ) { entab = 1; base_col = col; } // Else emit character else putchar(c); } // Entab state else { // Trim trailing whitespace if( c == '\n' ) { entab = 0; putchar( '\n' ); } // If not whitespace, exit entab state else if( c!=' ' && c!='\t' ) { entab = 0; // Emit tabs to get close to current column position // eg base_col=1, N=4, col=10 // base_col + 3 = 4 (1st time thru loop) // base_col + 4 = 8 (2nd time thru loop) while( (base_col + (N-base_col%N)) <= col ) { base_col += (N-base_col%N); putchar( '\t' ); } // Emit spaces to close onto current column position // eg base_col=1, N=4, col=10 // base_col -> 8, and two tabs emitted above // base_col + 1 = 9 (1st time thru this loop) // base_col + 1 = 10 (2nd time thru this loop) while( (base_col + 1) <= col ) { base_col++; putchar( ' ' ); } // Emit buffered character after tabs and spaces putchar( c ); } } // Update current column position for either state if( c == '\t' ) col += (N - col%N); // eg col=1, N=4, col+=3 else if( c == '\n' ) col=0; else col++; // End loop c = getchar(); } return 0; } 
+14
source share

I'm a little late, but here's how I decided it myself. This is a different approach than what was circulated above, so please share any comments / feedback if you have any.

Check out my public entity on Github for source code. It comments on the code, and this approach is explained at the top of the file, but I will copy it and paste it here only so that the logic is clear from the moment it is released.

an approach:

  • We will track the number of spaces traversed (between nontab / nospace characters)

  • We will track characters (which are not tabs / spaces / newlines) on the input line

  • We will evaluate the “spaces” generated by spaces as follows:

    • An estimate of the number of spaces between these characters.

    • The gap will be "large enough" when the number of spaces is> = TABSIZE

    • Then for all remaining spaces in our "buffer" we will print them individually

Finally, we print the character that was read (which was not a tab / space)

Also, if necessary, updating the number of spaces and the number of characters.

I'm still a newbie programmer in every sense, so I'm not sure how this will compare with the other solutions posted here, but the logic seems easier to execute (at least for me).

Hope this helps someone later!

+1
source share

I understand that you really do not need to know what the problem is or how to solve it in order to answer this question. The question seems to ask if you understand when to use variables instead of "symbolic parameters". I'm not sure what is meant by the "symbolic parameter"; this is apparently an outdated nomenclature.

Having said that, the solution to the first part of the question (replacing spaces with tabs) is quite straightforward. Think division and leftovers.

0
source share

I looked at your code very superficially, and nothing jumps out of me just as sadly wrong.

Thus, my advice would be to either complete one step through a few input examples in the debugger by examining the values ​​of the variables along the way, or add a whole bunch of debug printing applications. In any case, your goal is to find the point at which the state of the program begins to deviate from the expected or expected.

0
source share

I agree with your assessment. This will not be enough to replace all n spaces with a tab; for example, if n == 4, "hin blank blank blank" should not be replaced with "hi tab", but rather, "hi tab blank blank".

It looks like you need to keep track of the current position when you read on each line, and use this information to determine how many tabs you need. Does it help? Please let me know if you need more information!

As for the "variable vs. symbolic parameter" part, it will definitely be viable, but I can come up with one significant advantage of using a variable: you can run the program for different values ​​of n without recompiling.

0
source share

I am currently plowing KnR and stumbled upon this page:

Exercise Answers

Your exercise is located under:

Hope you find this helpful.

Regards, Morpfh

1 : http://users.powernet.co.uk/eton/kandr2/index.html "C Programming Language, 2nd Edition, Kernighan and Ritchie - Exercise Answers

0
source share

In the above answer, the program is too complicated. In an attempt to simplify this part of the answer, I have attached much simpler code, which we hope is written in the K & R style (mainly by increasing inline c ++).

turn on

define TAB 4

int main () {

 char newsentence[255],c; int spacecount = 0, oldsentencepointer = 0, newsentencepointer = 0; printf("Give me a sentence please:\n"); while ((c = getchar()) != '\n') { if ((oldsentencepointer != 0) && (oldsentencepointer % TAB == 0) && (spacecount > 0)) { newsentencepointer -= spacecount; //if at tabstop, and spaces and not first, go back to 1st space, set tab. newsentence[newsentencepointer++] = '\t'; spacecount = 0; } if (c == ' ') { newsentence[newsentencepointer++] = ' '; spacecount++; //keep track of spaces before tab stop } else if (c == '\t') { newsentence[newsentencepointer++] = '\t' ; oldsentencepointer = TAB; //set old pointer to TAB (does not matter if actual, only cadence important) continue; //continue from here so as not to increment old sentence counter. } else { newsentence[newsentencepointer++] = c ; //write whatever was old into new. spacecount = 0; //reset space counter. } oldsentencepointer++; } newsentence[newsentencepointer] = '\0'; //cap it off. puts(newsentence); return 0; 

}

0
source share

There is an even more succinct solution, although it does not use the best methods of using the code (abuse of short-circuit evaluation, inconvenient control flow through the continuation, a somewhat strange “whitespace” cycle).

 #include <stdio.h> #define TS 8 int main(int arg, char *argv[]) { int counter = 0, space_counter = 0, c; while ((c = getchar()) != EOF) { ++counter; if (c == ' ' && ++space_counter && (counter % TS) == 0) { space_counter = 0; c = '\t'; } else if (c == '\t') { counter = space_counter = 0; } else if (c != ' ') { while (space_counter--) putchar(' '); space_counter = 0; if (c == '\n') counter = 0; } else { continue; /* don't call putchar(c) */ } putchar(c); } return 0; } 

With the exception of spaces, each character read is printed verbatim. Instead, spaces are considered. If the program encounters a non-empty character, it prints as many spaces as it counted before, then reset this counter. If it encounters a space, it checks through the second counter (printed characters from the beginning of the line / last tabstop) if the cursor is on the tabletop. If so, a tab is displayed, otherwise the space is counted.

The tab is used to reset the space counter and display the tab, excluding any extra spaces in this process.

0
source share

All Articles