What is the difference between IF and ELSE IF clauses? - c

I'm on the path of learning C with K&R. Besides the exercises in the book, I'm also doing some by myself. I wrote the following code, what it does is, it counts your input, gives you feedback how many words are left to reach the "goal" of 10 words and congratulates you as soon as you reach the 10 words.
#include <stdio.h>
main()
{
/* This programm will read your input, check the number of words,
and will congratulate when you reach a value of 10 words*/
int c, nw, counter;
nw = 0;
counter = 0;
while (nw < 10)
{
c = getchar();
if (c == ' ' || c == '\t' || c == '\n')
{
counter = 0;
}
else if (c != ' ' || c != '\t' || c != '\n')
{
if (counter == 0)
{
counter = 1;
++nw;
}
printf("Only %d words left\n", 10-nw );
}
}
}
Ok, in this version the code will not count blanks as words, resulting in the correct output of words left.
At first I wrote the code with only "if" instead of "else if". What it did was it also counted the blanks as words.
The question I am asking is why ? Wheres the difference in using if or else if.
As I understand is, that compiler will check whether a condition is met or not met. This should also be the case when only using if. As everything is the same expect else if instead of if, I can't figure out what the problem is.

It looks like this might be a case of overthinking a problem. The logic you've ended up with, aside from being wrong, is overly complicated. Your question of the difference between if and else if is fair, and I promise I will address it in my answer.
First, let me restate what you are trying to do:
Read input, count number of words, and congratulate you when you reach 10 words
From your code, I believe your intention is to split words based on spaces, tabs, and newlines. There are many ways to split words, but for the purposes of this question, your intended method is fine.
The problem, of course, is that your logic doesn't work. You have a condition that can never be false:
else if (c != ' ' || c != '\t' || c != '\n')
Think about it (hint: the else doesn't change the condition itself). Say it out loud if that helps: You are looking for a condition where c isn't a space, or c isn't a tab, or c isn't a newline. Remember that logical or (||) is an inclusive or, in other words, the expression is true if any of the conditions are true. For example, let's suppose c is a space. The first condition (c != ' ') fails, but the 2nd one, c != '\t' is true because a space is not a tab. Thus, the entire expression is true. In fact, that expression will be true for any value of c.
But what about else?
As I said, the else part of the else if doesn't make a difference here. The only thing else if does differently is essentially tack itself on as a new condition to your if statement. Let's look at a simpler example:
if (a == 1) {
/* a is 1 */
}
if (a != 1 && b == 2) {
/* a isn't 1, but b == 2 */
}
That's an example of two completely independent if statements. It's a perfect example of where to use else, because as you probably noticed, the 2nd if statement tests for the inverse of the 1st. (a != 1). So, the above can be simplified as follows:
if (a == 1) {
/* a is 1 */
else if (b == 2) {
/* a isn't 1 and b is 2 */
}
In the else if block, we needn't test for a != 1, as that's implied because we only evaluate the else statement if the 1st if conditional was false.
Note also that else if is actually a combination of two separate keywords. It is equivalent to:
else {
if (b == 2) { ... }
}
However, by convention we omit the optional braces and write it as:
else if (b == 2) { ... }
In fact, in some cases we don't need that 2nd if at all:
if (a == 1) {
printf("a is 1!\n");
} else {
printf("a isn't 1. In fact, it's %d.\n", a);
}
Simplified Version
So, now there's no need to get caught up in else if. Focus on your logic, and do your best to simplify it. I will simplify it for you, however I encourage you to skip over this part and try it on your own first:
char c;
int in_word = 0;
while (nw < 10) {
c = getchar();
if (c == ' ' || c == '\t' || c == '\n') {
/* If we were in a word, then count that word! */
if (in_word) {
nw++;
printf("You only have %d words to go!", 10 - nw);
}
in_word = 0; /* We are not in a word now */
} else {
in_word = 1; /* Now we're in a word
}
}

Not sure if this is the answer you are looking for. But two separate if statements are both evaluated no matter what. With "if" and "else if", first if is evaluated if it is true, else if is skipped. When "if" is not true "else if" is evaluated.

else if (c != ' ' || c != '\t' || c != '\n')
This line of code is probably not doing what you intended. It works fine as an else if, but in fact it doesn't really check anything (you could actually replace it with a simple else)! For any conceivable character, it's will always be either not a space, or not a tab, or not a newline. What you really want is the conjunction of those statements, rather than the current disjunction:
else if (c != ' ' && c != '\t' && c != '\n')
This checks that the character is neither a space, a tab, nor a newline. It would work even with else removed, as a separate if-statement. However, you really should just go with a simple else.

In your if condition, if you use simple if .. else construct, it will be equivalent to
if (c == ' ' || c == '\t' || c == '\n')
{
...
}
else if (c != ' ' && c != '\t' && c != '\n') //Notice &&.
//Apply De-morgan's law over if conditio.
{
...
}
In the above case else if is not required, if else is suffice to use. Using if .. else would be more efficient than the given code.
However, logically it may have same effect as your given code.
As per logic, else if is not required.
The difference you will get in terms of number of comparison operation as explained below.
Current code:
For any non-space character such as 'a', it will perform 4 comparisons (|| and && are short-circuited).
For any space character, there will be max 3 comparisons.
In if-else code, max of 3-comparison will be performed.
This difference is not so significant. And can only be noticed when code is run billions of times.
if else has extra advantage of maintenance. In the above code in OP, if there is any change in if part, it should be reflected in else if part also.
Hence, to me it seems it will be beneficial to go with just if else rather if else if.

Related

Proper way to write 'one but not both' situation?

This question is really arbitrary so I'll try to explain it as best as I can. I'm looping through two strings of unknown size.
bool check(char *str1, char *str2)
{
char special = 'k';
for (int size_t i = 0; ; i++)
{
}
}
I want the terminating condition of the for loop to be the following:
Leave the loop only if either str1[i] == special OR str2[i] == special, but not both.
For this question, ignore the fact that I might segment fault since I know neither the size nor am I checking for 0x00.
I know how to write this but it's always really messy and involves using ternary conditional operators. What is a better way to write it?
You could use (str1[i] == special) != (str2[i] == special), as suggested here.
This works because in c, == can only return one of the int values 0 or 1 (reference).
You want the XOR operator written as ^ use it like you would and && or or ||. It is true only if one but not both arguments are true.
Oops: now see OP said "For this question, ignore the fact that I might segment fault since I know neither the size nor am I checking for 0x00."
So my concern below is moot. Leaving as a reference.
Since code is working with strings, the loop must terminate on 3 conditions:
Leave the loop if either (str1[i] == special) != (str2[i] == special), but not both.
str1[i] == 0.
str2[i] == 0.
Code code be
for (int size_t i = 0;
((str1[i] == special) != (str2[i] == special)) && str1[i] && str2[i]);
i++) {
...
}
Perhaps a simplification could be had.

How do curly braces and scope wоrk in C?

I'm currently trying to learn some C in my spare time. I have some experience in Java, and I'm therefore used to limit scoping of i.e. variables with curly braces. But I'm a bit confused, as it seems like Brian W. Kernighan/Dennis M. Ritchie's book "The C Programming Language" doesn't use a lot of curly braces, where I would assume it's normal to use them (from a Java perspective). E.g. 1.6 in the book where the code is:
while((c = getchar())) != EOF)
if (c >= '0' && c <= '9')
++ndigit[c-'0'];
else if() /*and so forth...*/
++nwhite;
else
++nother;
From a Java perspective I'm used to that only the first statement would be run then, because of the lack of curly braces, but the indentation suggests that everything will run (if, else if and else).
So what I'm asking is: What would run here, and why would it run? Are if, else if and else all in the scope of the while loop? Are there any conventions to refer to, that I can read to try to understand it better? Thanks in advance.
The while, if, else if, and else are followed by a single statement. This statement can be an actual line of C, or a block statement (surrounded by braces). The if, else if, and else are considered as one block.
So using braces, this would be the equivalent:
while((c = getchar())) != EOF) {
if (c >= '0' && c <= '9') {
++ndigit[c-'0'];
}
else if() { /*and so forth...*/
++nwhite;
}
else {
++nother;
}
}
In C, as in Java, an ìf and a while has one statement as its body, and if can have an optional else clause with one statement as its body. And in most places where you can have one statement, you can have a statement block, which is a list of statements surrounded by curly braces. This is not different in C than in Java.
In order to avoid ambiguity, if there are two ifs and one else, the else is defined to refer to the last one.
I. e.
if(a) x if(b) y else z
is defined to mean
if(a) x { if(b) y else z }
and not
if(a) x { if(b) y } else z
Here, x, y, and z are statements - which can be statement blocks as well.
However, having said all this, it is error prone to leave off the braces, and hence many coding guidelines suggest to always use the curly braces.
You may just treat if/else if/else instructions as one block - they can't really be divided, else cannot exist on it's own.
On the side note, it's sometimes confusing when you have a situation like
if(something)
if (somethingOther)
....
else
.....
If your code is long enough, you might get confused where to attach this else, so it's good to always use braces. As stated in comment, else always attaches to the "nearest" if.
If an if statement does not contain a curly brace, you can inline up to one semi colon after, and it will automatically assume the curly braces as such:
while((c = getchar())) != EOF){
if (c >= '0' && c <= '9')
{
++ndigit[c-'0'];
}
else if() /*and so forth...*/
{
++nwhite;
}
else
{
++nother;
}
}
So this is valid:
while(true) i++;
And this should not be valid:
while(true) i++; break; printf("hello");
if(true) printf("Hello"); break;

C ambiguity problem

While coding very simple program for removing blanks, tabs, newlines I came across something I don't actually catch on first; even though if condition is true only when tab, space or newline doesn't exist it's still executed with the mentioned for some reason.. here is the code
#include <cstdio>
#include <cstring>
#include <stdio.h>
#include <string.h>
#define LGT 100
void rem(char s[])
{
int i;
for(i=(strlen(s)-1);i>=0;i--)
if(s[i]!=' ' || s[i]!='\t' || s[i]!='\n')
break;
s[i+1]='\0';
}
int main(void)
{
char v[LGT]={"sdsfg\t"};
rem(v);
printf("%s\n",v);
getchar();
}
s[i]!=' ' || s[i]!='\t' || s[i]!='\n' is always true. A character can't be equal to both a space, a tab and a newline.
The problem is that
  if(s[i]!=' ' || s[i]!='\t' || s[i]!='\n')
Is always true. If s[i] is a space, then the latter two checks are true. If it's not a space, them the first check is true.
To fix this, change these ors to ands:
if(s[i]!=' ' && s[i]!='\t' && s[i]!='\n')
Or, even better, use isspace:
if(isspace(s[i])
s[i] != x || s[i] != y is true for all different values of x and y.
You probably want &&.
If you think about it, any expression like the following is suspect...
a != x || a != y
Whatever a is, it will always not be one thing OR not be another. So this is always true. The equivalent mistake with and is always false rather than always true, and it looks like:
a == x && a == y
It's a little easier to see, right? Thing a can't possibly be both x AND y at the same time. And in fact these statements are related by De Morgan's laws.
Update: So, typically what you want is a != x && a != y. For the second case: a == x || a == y.
try changing
if(s[i]!=' ' || s[i]!='\t' || s[i]!='\n')
break;
with
if(s[i]!=' ' && s[i]!='\t' && s[i]!='\n')
break;
As others already pointed out, your boolean expression is a tautology (ie always true). You might also want to use the function strpbrk() instead of duplicating functionality provided by the standard library:
#include <stdio.h>
#include <string.h>
// …
char text[] = "foo\tbar\n";
char *tail = strpbrk(text, " \t\n");
if(tail) *tail = 0;
printf("<%s>", text); // prints <foo>
Also, when including <c…> headers, you should prefix identifiers with std:: or add a using directive. Alternatively, use <….h> instead.
Using functionality not inherited from the C standard library, more idiomatic C++ code would look like this:
#include <iostream>
#include <string>
// …
std::string text = "foo\tbar\n";
std::size_t pos = text.find_first_of(" \t\n");
if(pos != std::string::npos)
text.erase(pos);
std::cout << '<' << text << '>'; // prints <foo>

K&R Exercise 1-21 - Mental incomprehension

The "impossible" K&R exercise.
"Write a program entab that replaces
strings of blanks by the minimum
number of tabs and blanks to achieve
the same spacing. Use the same tab
stops, say every n columns. Should n
be a variable or a symbolic
parameter?"
The problem I'm having is, I'm unsure about how to even do this correctly. I know it's not very explanatory, but that's pretty much the problem here. Most of the examples I've seen have counted a number of blanks, and replaced those series with a tab, but this isn't what its asking, I reckon I understand what its asking, but currently feel unable to do this.
Could anyone help :)
Edit: The code I've written so far can be found here.
If your question is "What is this asking me to do?" I think I can help by paraphrasing the original question (posing the same question in a different way).
Write a program that takes as input text with spaces and produces as output visually equivalent text using tabs to the maximum extent possible.
For example, with tabstops every 8 characters, and showing spaces as '.' and tabs as '-';
input;
".foo:...bar;......#comment"
output;
".foo:-bar;-..#comment"
input;
".......-foo:.....bar;......#comment"
output;
"-foo:-.bar;-...#comment"
Write the program so that tabstop parameter n can be varied, i.e. allow values of n other than 8. Be prepared to justify your decision to make n a constant, or alternatively a variable.
Edit I had a look at your code and I think it is more complex than it needs to be. My advice is to do it a character at a time. There's no need to buffer a whole line. Maintain a column count as you read each character ('\n' resets it to zero, '\t' bumps it by 1 or more, other characters increment it). When you see a space (or tab), don't emit anything right away, start your entabbing process, emit zero or more tabs and then spaces later (at '\n' or a non whitespace character, whichever comes first).
A final hint is that a state machine can make this kind of algorithm a lot easier to write, validate, test and read.
Edit 2 In a shameless attempt to get the OP to accept my answer, I have now gone ahead and actually coded a solution myself, based on the hints I offered above and my comment 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;
}
I'm a bit late, but here's how I solved it myself. It's a different approach than what has been shared above, so please share any comments/feedback if you have any.
Check out my public gist on Github for the source code. There's comments on the code, and the approach is explained on the top of the file, but I'll copy and paste it here just so that the logic is clear from the get-go.
Approach:
We'll keep track of number of spaces encountered (between nontab/nonspace characters)
We'll keep track of characters (that aren't tabs/blanks/newlines) per input line
We'll evaluate the "gaps" generated by spaces by:
Evaluating whether the number of spaces in between those characters.
A gap will be "big enough" when the number of spaces is >= TABSIZE
Then, for all the left over spaces in our "buffer", we'll print them out individually
Finally, we print out the character that was read in (which was not a tab/blank)
As well as updating space count and character count if necessary.
I'm still a novice programmer in all senses, so I am not sure of how it would compare vs the other solutions posted in here, but the logic seems easier to follow (at least for me).
Hope this helps someone later on!
I agree with your assessment. It won't be enough to replace every n blanks with a tab; for example, if n == 4, "hi blank blank blank blank" should not be replaced by "hi tab", but rather by "hi tab blank blank".
It sounds like what you need to do is keep track of the current position as you're reading in each line, and use this information to determine how many tabs you need. Does this help? Please let me know if you need more details!
As for the "variable vs. symbolic parameter" part, either would definitely be viable, but I can think of one significant advantage to using a variable: you can run the program for different values of n without recompiling.
My understanding is that you don't really have to know what the problem is or how to solve it in order to answer this question. The question seems to asking whether you understand when to use variables instead of "symbolic parameters". I'm not actually sure what is meant by "symbolic parameter"; it seems to be outdated nomenclature.
Having said that, solving the first part of the question (replacing spaces with tabs) is rather straight forward. Think division and remainders.
I took a very cursory look at your code, and nothing is jumping out at me as blatantly wrong.
So my advice would be to either single-step through a few input examples in a debugger, examining variable values as you go, or add a whole bunch of debugging print statements. In either case, your goal is to find the point where the state of the program starts to deviate from what you expected or intended.
I am currently plowing KnR and came across this page:
Answers to Exercises
Your exercise are located under:
Solutions
Chapter 1 - A Tutorial Introduction
Ex No 21 Pg No 34
users.powernet.co.uk/eton/kandr2/krx121.html
Hopefully you find this useful.
Sincerely,
Morpfh
1: http://users.powernet.co.uk/eton/kandr2/index.html "The C Programming Language", 2nd edition, Kernighan and Ritchie - Answers to Exercises
In the top rated answer above, the program is overly complex.
In an attempt to simplify that part of the answer, I've attached a much simpler code hopefully written in the style of K&R (mostly by incrementing inline with ++).
include
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;
}
There is an even more concise solution, although it does not employ the best code practices available (abusing short circuit evaluation, awkward control flow via continue, somewhat weird "space" loop).
#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;
}
Except for blanks, every character that is read is printed verbatim. Blanks are counted instead. If the program encounters a non-blank character, it prints as many blanks as it has counted before, resetting that counter afterwards. If it encounters a blank, it checks via a second counter (printed characters since the beginning of the line/last tabstop) if the cursor is on a tabstop. If it is, a tab is printed, otherwise the blank is just counted.
A tab in the input is dealt with resetting the space counter and outputting the tab, eliminating any superfluous blanks in the process.

Counting Syllables one char at a time [C]

I'm writing a program which reads text from a file, and determines the number of sentences, words, and syllables of that file. The trick is, it must only read one character a time, and work with that. Which means it can't just store the whole file in an array.
So, with that in mind, heres how my program works:
while(character != EOF)
{
check if the character is a end-of-sentence marker (?:;.!)
check if the character is whitespace (' ' \t \n)
(must be a letter now)
check if the letter is a vowel
}
Using a state-machine approach, each time the loop goes through, certain triggers are either 1 or 0, and this effects the count. I have had no trouble counting the sentences or the words, but the syllables are giving my trouble. The definition for syllable that I am using is any vowel or group of vowels counts as 1 syllable, however a single e at the end of a word does not count as a syllable.
With that in mind, I've created code such that
if character = 'A' || 'E' ... || 'o' || 'u'
if the last character wasnt a vowel then
set the flag for the letter being a vowel.
(so that next time through, it doesnt get counted)
and add one to the syllable count.
if the last character was a vowel, then dont change the flag and don't
add to the count.
Now the problem i have, is my count for a given text file, is very low.
The given count is 57 syllables, 36 words, and 3 sentences. I get the sentences correct, same with the words, but my syllable count is only 35.
I also have it setup so that when the program reads a !:;.? or whitespace it will look at the last character read, and if that is an e, it will take one off the syllable count.
This takes care of the e being at the end of a word not counting as a vowel.
So with this in mind, I know there must be something wrong with my methodology to get such a vast difference. I must be forgetting something.
Does anyone have some suggestions? I didn't want to include my entire program, but I can include certain blocks if necessary.
EDIT: Some code...
I have if ( end-of-sentence marker), then else if (whitespace), then the final else which entails that only letters which can form words will be in this block. This is the only block of code which should have any effect on the counting of syllables...
if(chrctr == 'A' || chrctr == 'E' || chrctr == 'I' || chrctr == 'O' || chrctr == 'U' || chrctr == 'a' || chrctr == 'e' || chrctr == 'i' || chrctr == 'o' || chrctr == 'u')
{
if(chrctr == 'E' || chrctr == 'e')
{
isE = 1;
}
else
{
isE = 0;
}
if(skipSylb != 1)
{
endSylb = 1;
skipSylb = 1;
}
else
{
endSylb = 0;
skipSylb = 1;
}
}
else
{
endSylb = 0;
skipSylb = 0;
}
So to explain... endSylb if 1, later in the program will add one to the count of syllables. skipSylb is used to flag if the last character was also a syllable. If skipSylb = 1, then this is a block of vowels and we only want to add one to the counter. Now I have an isE variable, which just tells the program next time around that the last letter was an E. This means, next time through the while loop, if it is an end of sentence, or whitespace, and the last letter was E (so isE = 1), then we have added one too many syllables.
Hopefully that helps.
Since the value is actually lower then what it should be, i thought perhaps the statements where i minus from the count are important too.
I use this if statement to decide when to minus from the count:
if(isE == 1)
{
countSylb --;
}
This statement happens when the character is whitespace, or an end of sentence character.
I can't think of anything else relevant, but i still feel like im not including enough.
Oh well, let me know if something is unclear.
I also have it setup so that when the program reads a !:;.? or whitespace it will look at the last character read, and if that is an e, it will take one off the syllable count.
This sounds wrong. What about words like "die" and "see"?
Obviously you can only decrement the count if the word counted for more than one syllable.
In your case decrementing if the 'e' at the end was not part of a vowel group might suffice.
If that doesn't help: Maybe you don't clear the vowel flag after reading a consonant? I can't tell from your code.
What could really help you is debugging outputs. Let the program tell you what it is doing like:
"Read a vowel: e"
"Not counting the vowel e because [...]"
You need a Finite State Machine
In a sense, every program is a state machine, but typically in the programming racket by "state machine" we mean a strictly organized loop that does something like:
while (1) {
switch(current_state) {
case STATE_IDLE:
if (evaluate some condition)
next_state = STATE_THIS;
else
next_state = STATE_THAT;
break
case STATE_THIS:
// some other logic here
break;
case STATE_THAT:
// yet more
break;
}
state = next_state;
}
Yes, you can solve this kind of program with general spaghetti code. Although legacy spaghetti code with literal jumps isn't seen any more, there is a school of thought which resists grouping lots and lots of conditionals and nested conditionals in a single function, in order to minimize cyclomatic complexity. To mix metaphors, a big rat's-nest of conditionals is kind of the modern version of spaghetti code.
By at least organizing the control flow into a state machine you compress some of the logic into a single plane and it becomes much easier to visualize the operations and make individual changes. A structure is created that, while rarely the shortest possible expression, is at least easy to modify and incrementally alter.
Looking at your code, I suspect some of the logic has gotten lost in the excessive size. Your main snippet appears equivalent to something like this:
chrctr = tolower(chrctr);
if (strchr(chrctr, "aeiou")) {
isE = (chrctr == 'e');
endSylb = !skipSylb;
skipSylb = 1; // May not be you want, but it's what you have.
}
else {
skipSylb = endSylb = 0;
}
Personally, I think trying to count syllables algorithmically is nearly hopeless, but if you really want to, I'd take a look at the steps in the Porter stemmer for some guidance about how to break up English words in a semi-meaningful way. It's intended to strip off suffixes, but I suspect the problems being solved are similar enough that it might provide at least a little inspiration.

Resources