What does the for loop condition (str1[i] && str2[i]) mean? - c++

for (int i = 0; str1[i] && str2[i]; i++)
What does str1[i] && str2[i] mean? I have known the middle part of a for loop to be a condition but how is that a condition? What is it checking?

This loop keeps going until either one of the values is falsy. Most likely, both of them are C-style strings (which are simple char arrays or pointers, terminated with a NUL character, '\0'), and the loop is intended to continue until it's reached the end of the shortest string (the first one in which it finds NUL).

This expression:
str1[i] && str2[i]
Is equivalent to
(str1[i] != '\0') && (str2[i] != '\0')
The for loop terminates when either str1[i] or str2[i] is the end of the string.
In other words, when the for loop terminates, i is the length of the shorter of str1 and str2. (Although by then, i is out scope).

str1 and str2 are probably c strings (char *, char []) so the for loop iterates till either str1[i] or str2[i] are \0 which is the string terminator. The string "hi" is a more convenient way to write { 'h', 'i', '\0' }.

Related

Replacing a substring with a space character

I am given a string and I have to remove a substring from it. Namely WUB, and replace it with a space character.
There are 2 WUB's between ÁRE' and 'THE'. SO the first condition in if statement is for not printing two blank spaces but on executing the code two blank spaces are being printed.
Input: WUBWEWUBAREWUBWUBTHEWUBCHAMPIONSWUBMYWUBFRIENDWUB
Output: WE ARE THE CHAMPIONS MY FRIEND
Here is my code so far:
#include <iostream>
using namespace std;
int main()
{
const string check = "WUB";
string s, p;
int ct = 0;
cin >> s;
for (int i = 0; i < s.size(); i++)
{
if (s[i] == 'W' && s[i+1] == 'U' && s[i+2] == 'B')
{
i += 2;
if (p[ct] == '32' || p.empty())
{
continue;
}
else
{
p += ' ';
ct++;
}
}
else
{
p += s[i];
ct++;
}
}
cout << p;
return 0;
}
Why is the first if statement never executed?
2 things are going to break your code:
you are doing a for loop like this int i=0;i<s.size() but reading (s[i]=='W' && s[i+1]=='U' && s[i+2]=='B')
and here: if(p[ct]=='32') you mean for sure if(p[ct]==32) or if(p[ct]==' ')
This condition
if(p[ct]=='32')
should read either
if(p[ct]==32)
or
if(p[ct]==' ')
that is, compare to the numeric value of the space character or to the space character itself.
Additionally, when your i grows close to the string's length, the subexpressions s[i+1] and s[i+2] may reach non-exiting characters of the string. You should continue looping with a i<s.length()-2 condition.
EDIT
For a full solution you need to fully understand the problem you want to solve. The problem statement is a bit vague:
remove a substring ("WUB") from (a given string). And put a space inplace of it if required.
You considered the last condition, but not deeply enough. What does it mean, 'if required'? Replacement is not required if the resulting string is empty or you appended a space to it already (when you encounter a second of further consecutive WUB). It is also not necessary if you are at WUB, but there is nothing more following it - except possibly another WUBs...
So, when you find a "WUB" substring it is too early to decide if a space is needed. You know you need a space when you find a non-WUB text following some WUB (or WUBs) and there was some text before those WUB(s).
There are actually three bugs here, so it's probably worth to conclude them in one answer:
The first condition:
if (s[i] == 'W' && s[i+1] == 'U' && s[i+2] == 'B')
is out of bounds for the last two characters. One fix would be to check the length first:
if(i < s.length() - 2 && s[i] == 'W' && s[i+1] == 'U' && s[i+2] == 'B')
There's a multicharacter-literal in
if (p[ct] == '32' || p.empty())
Use ' ' or 32 or std::isspace instead. IMO the last one is the best.
In the same condition
p[ct] == '32'
is always out of bounds: ct is equal to p.length(). (Credits to Some programmer dude, who mentioned this in the comments!) The variable ct is also redundant, since std::string knows it's length. I suggest to use std::string::back() to access the last character and reorder the condition as so:
if (p.empty() || std::isspace(p.back()))
The algorithm to this program is on the right track.
However, there is a few issues..
The for loop goes out of index. A way to solve this issue is substracting the size -3. Something like this.
for (int i=0; i<s.size()-3; i++) {
}
I do not suggest using other variables as counters like ct. In this case ct can reach an index out of bound error by using p[ct] inside the for loop.
Creating a string and using append() function will be a better solution. In this case, we iterate through each character in the string and if we find "WUB" then we append a " ". Otherwise, we append the character.
I highly recommend to write the first if() statement using substring() from C++.
This makes the code easier to read.
Substring creates and returns a new string that starts from a specific position to an ending position. Here is the syntax
syntax: substr(startingIndex, endingIndex);
endingIndex is exclusive
#include <string>
#include <iostream>
int main() {
string s, p;
cin >> s;
for(int i=0;i<s.size()-3;i++) {
if (s.substr(i, i+3) == "WUB") {
p.append(" ");
} else {
p.append(s.substr(i,i+1));
i++;
continue;
}
i+=3;
}
}

C++ for loop terminated automatically safely for char * when index cross its length

Consider the following for loop.
char temp[100];
char *str = "abab";
int i, j;
for (i = 0, j = 0; temp[i] = str[j];j++)
{
if (str[j] == temp[i])
i++;
else
i--;
}
It does not have terminating condition but still it manages to terminates after traversing "str".
Please explain.
The assignment expression temp[i] = str[j] has a value, which is the value that was assigned.
Since str is \0 terminated (character value 0), when the loop reaches it and assigns it to temp, the expression evaluates to 0. And the loop condition becomes false.
The loop does have a terminating condition, namely
temp[i] = str[j]
As the value of that is str[j], the loop condition boils down to
for (j = 0; str[j]; j++)
This certainly traverses str exactly once since str[j] evaluates to false in this context if and only if str[j] == '\0'. '\0' is a special character that terminates all string literals and is used to terminate C style strings.
In the "real world", i.e. outside of toy programs, you should avoid "clever" code like this, even if it works.
Also note that the conversion from string literals to char* is deprecated and that every attempt to modify a string literal invokes undefined behavior. Use
const char *str = "abab";
instead.
The condition is temp[i] = str[j]. That assigns and returns the assigned value. Therefore it will be evaluated to true for everything different to \0 and false, when the terminating \0 has been reached.
#include <iostream>
using namespace std;
int main()
{
char temp[100];
const char *str = "abab";
int i, j;
for (i = 0, j = 0; temp[i] = str[j]; j++)
{
if (str[j] == temp[i])
i++;
else
i--;
}
cout << (temp[4] ? "true" : "false") << endl;
}
Printing shows that the condition of the last iteration evaluates to false because it's zero ('\0' as end of string).
from the looks of it, the loop run it course as its scan the whole word "abab" and the condition for the loop to end is str = temp, the final output of those variables are 4 = 4

strcmpi integer without a cast error

I'm trying to create a program that removes vowels from a string, add them into a vector and then give the user the possibility of having the original code again.
In my code i have this:
char s[20];
And soon after i have this comparison:
for(j=0;j<tam;j++)
{
if(strcmpi(s[j],"a")==1 ||
(strcmpi(s[j],"e")==1 ||
(strcmpi(s[j],"i") ==1||
(strcmpi(s[j],"o") ==1||
(strcmpi(s[j],"u")==1))
{
So if the array is char and the vowels are char(""), why the compiler give me this error?:
[Warning] passing arg 1 of `strcmpi' makes pointer from integer without a cast
EDIT
As someone said the correct is s[j] == 'a', but that result in wrong way. If a put car the result is still car. Don't know why.
if(s[j] == 'a' ||
s[j] == 'A' ||
s[j] == 'e' ||
s[j] == 'E' ||
s[j] == 'i' ||
s[j] == 'I' ||
s[j] == 'o' ||
s[j] == 'O' ||
s[j] == 'u' ||
s[j] == 'U')
{
s[j] = s[j++]; }
Strcmpi is for comparing strings. The first argument to strcmpi is of type char, when it expects a char*.
In order to compare single chars, s[j]=='e' is enough, or tolower(s[j])=='e' if you need it to be case insensitive. You'll need to include ctype.h. for tolower.
The arguments to strcmpi must be strings, but s[j] is just a single character, not a string. You can use == to compare characters directly. To get case-insensitive comparisons, get the lowercase version of the character first and compare it.
for (j = 0; j < tam; j++) {
char lower = tolower(s[j]);
if (lower == 'a' || lower == 'e' || lower == 'i' || lower == 'o' || lower == 'u') {
...
}
}
You don't want to use strcmp or any of its variants.
Because you want to know whether the string contains vowels or not, you may want to use a substring search using strstr.
You use function strcmpi incorrectly. It first parameter has type const char * while you pass an argument of type char. That is the function expects a string while you pass only one character.
Moreover this function is not a standard C/C++ function. So it should not be used.
You could achieve the same result using the following approach
char vowels[] = "aeiou";
//...
if ( strchr( vowels, tolower( s[j] ) )
{
std::cout << s[j] << " is a vowel" << std::endl;
}
You have already been told that strcmpi is not the right way to check single characters. This is an answer to the edit to your question, where you ask about actually stripping the vowels.
If you want to retain the original string, you need extra memory for the string without consonants. You also need two indices, because once you have skipped a vowel in the original string, the indices are out of sync. Here's an example implementation:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
char orig[] = "Jackdaws love my big sphinx of quartz.";
char cons[sizeof(orig)]; // Make new char buffer as big
// as the original
int i, j;
j = 0;
for (i = 0; orig[i]; i++) {
if (strchr("AEIOUaeiou", orig[i]) == NULL) {
cons[j++] = orig[i];
}
}
cons[j] = '\0'; // Terminate consonant string
printf("was: '%s'\n", orig);
printf("is: '%s'\n", cons);
return 0;
}
The expression strchr checks whether a character is in a string. You can use it as a shortcut to spelling out all vowels in explicit comparisons.

Why is my program not reading all of characters in the string?

I need to input a string, if the string is just a whole string and not with spaces, the codes is fine, if the input is a string with spaces, the string only copys the first set of strings and not the whole strings? I'm an noob, please help.
#include <stdio.h>
#include <string.h>
int main() {
char again = 0;
do {
char str[60], s[60];
int i, j = 0;
printf("Enter any string->");
scanf("%s", str);
printf("The string is->%s", str);
for (i = 0; i <= strlen(str); i++) {
if (str[i] == 'a' || str[i] == 'e' || str[i] == 'i' ||
str[i] == 'o' || str[i] == 'u' || str[i] == 'A' ||
str[i] == 'E' || str[i] == 'I' || str[i] == 'O' ||
str[i] == 'U') {
str[i] = ' ';
} else {
s[j++] = str[i];
}
}
s[j] = '\0';
printf("\nThe string without vowel is->%s", s);
NSLog(#"Do you want to enter another string to be edit? (y/n) ");
scanf("%s", &again);
} while (again != 'n');
}
Your code stops reading at a space because that's how scanf works with the %s format. It reads a sequence of non-whitespace characters.
If you're really using C++, then you'd be wise to switch to std::string and std::getline, which will read all input up to the end of the line. Your code doesn't appear to use any C++ features, though, so maybe you're really using C. In that case, consider fgets instead. It will read the whole line, too (up to a specified size, which generally corresponds to the size of your buffer).
This code is a mess.
C++ features like std::string are not used at all.
You're mixing printf/scanf and NSLog for no reason.
Modifying str in the if branch makes no sense, as it won't be read later.
You probably want to use i < strlen(str) instead of <=, or you'll copy that terminating zero character twice.
Your scanf("%s", &again); specifies to read a string, but you only have memory for a character, thus you probably end up writing into some random memory position.
While some of these points are more severe than others, I suggest fixing those issues and see what happens. If you experience unexpected output, then please do give your example input and output as well.
You are allocating an array of 60 chars long (str). You can't expect to read a lot into it. Here are a few tips:
Don't use such buffers, they are dangerous. The C++ library provides you std::string.
Never omit the curly braces {}.
There are an easier way to check for chars than this horribly long if. Hint: std::string::find_first_of

Comparing chars in a character array with strcmp

I have read an xml file into a char [] and am trying to compare each element in that array with certain chars, such as "<" and ">". The char array "test" is just an array of one element and contains the character to be compared (i had to do it like this or the strcmp method would give me an error about converting char to cons char*). However, something is wrong and I can not figure it out. Here is what I am getting:
< is being compared to: < strcmp value: 44
Any idea what is happening?
char test[1];
for (int i=0; i<amountRead; ++i)
{
test[0] = str[i];
if( strcmp(test, "<") == 0)
cout<<"They are equal"<<endl;
else
{
cout<<test[0]<< " is being compare to: "<<str[i]<<" strcmp value= "<<strcmp(test, "<") <<endl;
}
}
strcmp() expects both of its parameters to be null terminated strings, not simple characters. If you want to compare characters for equality, you don't need to call a function, just compare the characters:
if (test[0] == '<') ...
you need to 0 terminate your test string.
char test[2];
for (int i=0; i<amountRead; ++i)
{
test[0] = str[i];
test[1] = '\0'; //you could do this before the loop instead.
...
But if you always intend to compare one character at a time, then the temp buffer isn't necessary at all. You could do this instead
for (int i=0; i<amountRead; ++i)
{
if (str[i] == "<")
cout<<"They are equal"<<endl;
else
{
cout << str[i] << " is being compare to: <" << endl;
}
}
strcmp wants both strings to be 0 terminated.
When you have non-0 terminated strings, use strncmp:
if( strncmp(test, "<", 1) == 0 )
It is up to you to make sure that both strings are at least N characters long (where N is the value of the 3rd parameter). strncmp is a good functions to have in your mental toolkit.