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.
Related
In a simplified strcpy(a, b) function I saw such implementation:
for (i = 0; (a[i] = b[i]) != 0; i++) ;
I saw the above statement in a c string copy implementation. I assume it is assigning a[i] to b[i], and then check if a[i] is the termination character?
In which order does the above execute? Does it start with the not equal checking first or the assignment? And is it checking on array a or b?
Is it OK to write code in this compact way as this might cause confusion?
A for loop always checks the condition first
"OK" depends on context of course. If you code like this on a team project, someone is likely to get upset with you. If you do it in your own code and you understand it, then it is OK.
I'm trying to code a function that checks a through a char* a[], and often end up using something like
if(a[i] == 'x'){
i++;
//...
}
Now I would really like to change this to a[i++] instead, but it doesn't seem to work.
Question:
Am I doing something wrong here, or is there a clean alternative to avoid the i++?
Note: Currently 3 of my 13 rows in the function are i++, which makes it look significantly larger than it really is.
if (a[i++] == 'x') by itself is fine in C. It is, however, semantically different: Your original code only increments i if the condition is true, whereas if (a[i++] == 'x') always increments i.
v[i++] is not undefined if v[i] is not undefined and i++ doesn't cause an overflow of signed integer.
if(a[i++] == 'x'){
...
}
if not equivalent to
if(a[i] == 'x'){
i++;
...
}
because the former inclements i every time this is executed,
but the latter inclements i only if a[i] == 'x' is true.
++i is an alternative to avoid i++. Note that the value of ++i differs from i++. (++i)-1 may be useful.
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.
I've been at this for quite some time now and the existing answers offer little to no help. I am new to programming and am trying to write a sub-part of my program which tries to check whether any given input is constituted solely of alphabets.
For this, the idea I have in mind is to pass an entire array through the isalpha function by using a loop which passes each character at a time. The idea makes logical sense but I am having syntactic trouble implementing it. I will greatly appreciate any help!
Below is my code-
printf("Please type the message which needs to be encrypted: ");
string p = GetString();
for (int i = 0, n = strlen(p); i < n; i++)
{
if(isalpha(**<what I'm putting here is creating the problem, I think>**) = true)
{
printf("%c", p[i]);
}
}
You should modify your code as this (assuming you have the string type defined yourself):
printf("Please type the message which needs to be encrypted: ");
string p = GetString();
for (int i = 0, n = strlen(p); i < n; i++)
{
if(isalpha(p[i]) == true) // HERE IS THE ERROR, YOU HAD =, NOT ==
{
printf("%c", p[i]);
}
}
Operator = is for assignment and operator == is for comparison!
So what was happening? The assignment resulted in true, no matter what p[i] was.
As Quentin mentioned:
if(isalpha(p[i]) == true)
could be more elegant and error prune if written like this:
if(isalpha(p[i]))
Here is an example in C:
/* isalpha example */
#include <stdio.h>
#include <ctype.h>
int main(void)
{
int i = 0;
char str[] = "C++";
while (str[i]) // strings in C are ended with a null terminator. When we meet
// the null terminator, while's condition will get false.
{
if (isalpha(str[i])) // check every character of str
printf ("character %c is alphabetic\n",str[i]);
else
printf ("character %c is not alphabetic\n",str[i]);
i++;
}
return 0;
}
Source
Ref of isalpha().
C does not have a string type.
Tip: Next time post your code as it is!
Aslo, as Alter noticed, it would be nice to use:
isalpha((unsigned char)str[i])
and in your code
isalpha((unsigned char)p[i])
for safety reasons.
Your example is here.
I.e. parameter of isalpha() is i-th character of string p. The only question is how to access to i-th character. Usually you can use []. I.e. just use following code: isalpha(p[i]) (I see that you already use [] in call of printf).
Also isalpha(p[i]) = true is wrong condition. It looks like you planned to check isalpha(p[i]) == true (you can skip == true).
Late but:
both other answers say omitting == true is desirable, but don't say it is necessary for portability.
The C core-language operators == != < <= > >= && || which return a 'logical' value use an int value of 1 for true and 0 for false. In C99 and up with stdbool.h and by common convention before that true is 1 and false is 0, so e.g. if( (a < b) == true ) will work correctly, although it is redundant and many (including me) consider it poor style. Language elements that test a logical value, namely if(c) while(c) for(;c;) and the operands to && || and the left operand to ?: consider any value that compares equal to 0 to be false, and any other value to be true.
The character-classification routines in ctype.h as well as some other standard-library routines like feof(f) and ferror(f) are specified to return some nonzero int for true and 0 (an int) for false, and on many implementations the nonzero value used for true is not (always) 1. In those cases isalpha(whatever) == true might result in testing say 4 == 1 and fail even when whatever is an alphabetic character. OTOH isalpha(...) != false or isalpha(...) != 0 does work correctly if you really want to write something explicit.
Our codebase contains a few loops of the form while((*assignment*) *condition*), for example:
while((c = *s++) != '\0') {...}
while((i = getNext()) != NULL) {...}
Unfortunately these are causing the compiler to emit an "assignment in condition" warning, which I would like to get rid of. My plan is to transform the while loops into for loops of the form for(assignment; condition; assignment), for example:
for(c = *s++; c != '\0'; c = *s++) {...}
for(i = getNext(); i != 0; i = getNext()) {...}
Is this transformation valid? Is there a better alternative?
The transformations are valid, yes, but they result in code that's harder to maintain, simply because there are two places you have to change the assignment.
I would be more inclined to figure out how to turn off that particular warning (even if it's localised with something like the gcc #pragma warning pragma) since it is, after all, perfectly valid C code, both syntactically and (in this case) semantically.
Personally, I'd write the first loop like this:
for (char c; (c = *s) != '\0'; ++s)
{
// ...
}
This makes it clear that the s is the thing that's being incremented. You can also omit the != '\0', which is implicit.
I'd keep the second loop as a while loop, or at least leave the assignment-inside-conditional. Maybe like this, to minimize scope pollution:
for (iterator i; i = getNext(); )
{
// ...
}
I personally find it quite acceptable to have part of the per-loop activity happening inside the conditional; that's natural for things like std::cin >> n and std::getline(file, line), too.
You haven't stated what your compiler is, but any compiler of quality allows such a warning to be turned off. But if you can't manage that:
for(;;)
{
c = *s++;
if (c == '\0') break;
...
}
is equivalent and is more general. Likewise:
for(;;)
{
i = getNext();
if (!i) break;
...
}
In many cases, better than the first one (but not equivalent) is:
for(;; s++)
{
c = *s;
if (c == '\0') break;
...
}
These are more verbose and ugly, but they are much better than your transformation that repeats the code, which is fragile and error-prone.
If my understanding of loops is correct your transformation is completely valid, but this transformation seems to be a lot harder to read than the while loop. Just do the initialization before the while loop and then increment at the end of the loop to get rid of the warning.
c = *s++;
while(c != '\0')
{
...
c = *s++;
}