Thank you for putting your work out there, it's brave of you!
That is how we improve.
The motivation for CHARMAX / LINEMAX is unclear,
given that they are not part of the problem specification.
Gold star for giving each
magic number
a manifest constant name.
The usual motivation for CHARMAX (or MAX_LINE_LENGTH, to distinguish
from total document length) would be to allow a get_line()
function
to get away with static allocation instead of having to malloc().
The LINEMAX just kind of mystifies me.
I mean, what if $ yes | entab
processes
an unbounded number of lines?
Is it somehow "correct" to bail after a while?
Or should the pipeline have looked like $ yes | head -${LINEMAX} | entab
if we wanted finite output?
size_t charCount = 0; // running total of characters
size_t lineCount = 1; // running total of lines
size_t space_count = 0; // running count of spaces
Pick a coding standard.
There's lots to choose from, maybe GNU or Google.
And then stick with it.
In particular, avoid arbitrarily mixing camelCase with snake_case.
Kudos, the identifiers are wonderfully descriptive.
Consider deleting the // comments
, as they don't really
tell us anything we didn't already know.
} else {
while ((ch = getchar()) != '\n') {
;
}
tiny style nit: The ;
semicolon on a line by itself is great,
it calls attention to "this is a no-op!". But it's maybe a bit
weird within {
}
braces. Use one or the other. This comes
back to: pick a style guide, write down which one, and adhere to it.
Which is a lot easier if you routinely use a linter or a
code reformatter which implements that guide.
Bigger item: We're discarding characters till end-of-line?
I don't find that in the original spec. Ok, fine, maybe,
write down the revised spec that you are implementing.
One can only report a code defect ("bug") with respect
to a spec. Missing specs cause endless misery.
Again, the usual motivation for such line truncation
would revolve around static allocation for a line buffer.
But your code makes no such allocation, so it just kind
of seems like gratuitous data deletion.
Here's a bigger critique.
Your loop features four if
clauses, some with dependent clauses.
And there's quite a lot of mutation going on, the most
important being consuming input characters.
I don't find it especially easy to reason about
invariants
in this code.
Consider introducing a helper function that is responsible
for processing exactly one line of input text.
(For one thing, that makes writing unit tests way easier.)
Let's define a term.
def: We are at start-of-line when at start of input file,
and also right after we've seen a \n
newline input character.
The outer loop invariant would be "we are at start-of-line each
time the while loop begins again", and helper would have
its own inner loop which is responsible for making the invariant true.
That is, it's responsible for consuming a full line and
returning control to the outer loop.
Here's an example document for a unit test.
sp16 = " " * 16
doc = f"{sp16}A{sp16}B"
expected_output = "\t\tA\t\t B"
I don't find it especially easy to reason about space_count
OBOB
issues given the current structure.
Maybe the input is specified as having no TAB characters?
If so, we should signal an error upon encountering one.
If not, maybe reset space_count
to zero?
// When either a tab or a single blank would suffice to reach a tab stop, which should be given preference?
It seems the problem author was inviting an explicit response to this,
perhaps in the form of a comment.
Overall?
You seem to have adopted some novel requirements that don't appear
in the problem statement.
Running with those new requirements, the code appears to implement
them correctly.
There is an opportunity to structure the code into smaller chunks,
each having greater clarity for future maintainers who will
attend to bug fixes and feature enhancements.