When is the condition of this for loop will becomes false? - c++

I'm working on my C++ practice question to prepare for my upcoming test and I'm struggling with a for loop condition that I have never seen before.
for (int i = 0; s[i]; i++)
The string s that has been sent from the main is "Two roofs to fix"
The question is when is the for loop's condition will become false?

The loop condition becomes false, when the string's terminating zero '\0' is hit. (if (0) evaluates to false)
Please note: this form of test is a possible error waiting to happen if the string isn't null terminated.

Just to clarify #MitchWheat's answer, if an expression used as a condition specifies only a value, like if (x), then it's essentially equivalent to if (x != 0). If the value is a pointer type, then it's equivalent to if (x != NULL) instead (though that's not really an "instead", since NULL == 0).

#include<iostream>
#include<string>
using namespace std;
int main()
{
string s = "Two roofs to fix";
int i;
for (i = 0; s[i]; i++);
cout<<"i = "<<i<<endl;
}
I test the problem with the above code. It returns an error "string subscript out of range". So if the length of string s is Len, s[Len] is illegal.
In your code, s is not a pointer char*, but a string. So it is unappropriate to code like this.

Related

When to return from a function?

Sorry in advance if the question sounds naive. I am writing a simple bool function to check if all digits of a number are same. The following works, however the one after, gives me an error of
17:1: warning: control reaches end of non-void function [-Wreturn-type]
What I am doing wrong with the second one?
Working:
# include <iostream>
# include <string>
using namespace std;
bool samedigits (int number){
bool result = true;
std::string snumber = to_string (number);
for (int i=0; i < snumber.size(); i++){
if (snumber[i] != snumber[0]){
result = result and false;
break;
}
}
return result;
}
int main()
{
cout << samedigits (666);
return 0;
}
Non working:
# include <iostream>
# include <string>
using namespace std;
bool samedigits (int number){
std::string snumber = to_string (number);
for (int i=0; i < snumber.size(); i++){
if (snumber[i] != snumber[0]){
return false;
break;
}
return true;
}
}
int main()
{
cout << samedigits (666);
return 0;
}
Your algorithm is incorrect, you are only checking if the first character is equal to itself, and returning true for every input. Instead, you should move the return true outside the loop, so that you check all the characters first.
Unfortunately, the warning is a false positive. The compiler fails to realize that std::to_string is guaranteed to return a non-empty string when passed an int. This means that the for loop body will be entered, and the function will return a value.
The compiler is right. There is a code path in your second snippet that won't return.
for (int i=0; i < snumber.size(); i++){
Here, the std::string size function can return 0 according to its contract. When it does happen, then your function won't enter the loop. After that, you exit the function without returning.
The second version of your function (combined with some information obtained via comments) indicates a misunderstanding of what return does. The second version would work (here is the misunderstanding) if a return statement were to simply store the indicated value for use when the function eventually ends. However, this is not how return works. A return statement stores the indicated value for use when the function ends and immediately ends the function. In the second version of your function, the for statement might as well be an if and the break is never executed as it comes right after a return.
To demonstrate, let's do a code walk-through for a call to samedigits(123).
bool samedigits (int number){
As we enter the function, number is set to 123.
std::string snumber = to_string (number);
The string snumber is set to "123".
for (int i=0; i < snumber.size(); i++){
The loop initializes by setting i to 0 then checks if 0 < 3 (the size of snumber is 3). This is true, so we enter the loop. Note that the result of entering the loop depends only on snumber not being empty.
if (snumber[i] != snumber[0]){
We check to see if snumber[0] does not equal snumber[0]. This is a bit trivial, but the computer is willing to do it. The result, of course, is false (independent of what the input was – this part might be more interesting if the loop started at 1 instead of 0). So skip to the statement after the if.
return true;
The function immediately ends, returning true.
And that's it. There is no second iteration of the loop. No other code is executed during this function call. Since to_string never returns an empty string, the second version of your function is functionally equivalent to the following:
bool samedigits (int /*number*/){
return true;
// Execution ends with the return statement, so nothing after
// this comment ever executes.
std::cout << "This is dead code. It will never execute.\n";
std::cout << "You will never see this output.\n";
}
To fix the second version, you need to return inside the loop only when the if condition is true. Move return true; to be after the loop so that the loop can iterate multiple times. You do not want to end the function and tell the caller that all the digits are the same (which is what return true; does) until after you've checked all the digits. (If your loop finds a mismatch, execution will reach the return false; inside the loop. At that point, the function ends, so code after the loop has no effect on that function call.)
A smaller (cosmetic) fix is to get rid of the break. Suppose the loop did iterate enough times to find a mismatch. Execution would go into the if statement body and encounter return false. At that point, not only is the loop stopped, but the function as a whole ends, before the break statement is seen. The break statement is dead code, meaning code that can never be executed. In order to get to the break, execution has to go through a return. Execution may arrive at a return statement, but it never goes through one.
Also, be sure to thank your compiler for finding this error, as it does point to a bug in your code. It's not the exact bug the compiler reported, but then again, compilers are not exactly the best thinkers in the world. :)

isPalindromic Function [duplicate]

This question already has answers here:
What is a debugger and how can it help me diagnose problems?
(2 answers)
Closed 5 years ago.
I wrote this function isPalindromic for my compsci class where the professor wants us to better understand how library functions work. So he asked us to write a function isPalindromic and mine isn't working as well. Because there are so many parts, I will paste the whole function, so bear with me. Sorry!
The function always returns false for some reason. The word passed is "HELLO ". My first loop checks for the size of the word without spaces or null characters so I can use it as a parameter in my second loop. This returns false, which is correct, but when I pass "HELLEH " or "HELLEH", they both return false. I've rewritten this at least 5 times, and I can't figure out why it's returning false.
char* isPalindromic(char inputCheck[]){
int actWord;
int sizeCheck = myStrLen(inputCheck);
char tempWord[actWord];
for(int check = 0; check < sizeCheck; check++){
if(inputCheck[check] = ' ' || inputCheck[check] == '\0')
actWord = check;
}
for(int replace = 0; replace < actWord; replace++){
tempWord[replace] = inputCheck[actWord - replace];
}
tempWord == inputCheck ? inputCheck = "True" : inputCheck = "False";
return inputCheck;
}
char tempWord[actWord];
actWord at this point is uninitialised. Your entire program therefore has undefined behaviour.
tempWord == inputCheck ? inputCheck = "True" : inputCheck = "False";
This is also a problem; you cannot compare two character arrays with == like this; you're just comparing their locations in memory. You'll have to use reimplement strcmp for that (although, actually, a much simpler version of your algorithm will not require such logic).
You don't need any of this extra buffer space. All you need to do is iterate from front and back simultaneously, comparing characters.
const char* isPalindromic(const char inputCheck[])
{
const int size = myStrLen(inputCheck);
for (size_t i1 = 0, i2 = size-1; i1 < i2; i1++, i2--)
if (inputCheck[i1] != inputCheck[i2])
return "False";
return "True";
}
(live demo)
Also I would strongly consider returning a bool, not "True" or "False".

bubble sort algorithm for loop statement warning

I saw a piece of bubble sort code and initially I thought the code is wrong. But after compile and run, it surprised me that it actually works. I want to know how come second statement in the first for loop is not a condition but an assignment. In addition, how come this code will not go into infinitely loop?
PS: It will generate an warning: "suggest parentheses around assignment used as truth value [-Wparentheses]" complaining about the first for loop. Surprisingly it's not an error.
#include <iostream>
void bubblesort(int A[], int n)
{
for (bool sorted = false; sorted = !sorted; n--)
{
for (int i = 1; i < n; ++i)
{
if (A[i-1] > A[i])
{
int tmp = 0;
tmp = A[i];
A[i] = A[i-1];
A[i-1] = tmp;
sorted = false;
}
}
}
}
int main()
{
int a[5] = {1,4,5,2,3};
bubblesort(a, 5);
for (unsigned int i = 0; i < 5; ++i)
{
std::cout << a[i] << std::endl;
}
return 0;
}
The result of an assignment is the left operand, so the condition
sorted = !sorted
is using sorted as the condition after it's assigned a new value. The warning is there to give you a notice that using assignment as condition is sometimes not what you expected. You can use
(sorted = !sorted) == true
to silence the warning.
It's one of the quirks of C and C++ that they allow an assignment in the middle of a statement. Usually it's an error (= instead of ==) so a good compiler will warn you about it.
The value of such an expression is the same as the assigned value.
In this case it's a very tricky optimization; if the value was false it's reset to true and the loop continues, if it was true then it becomes false and the loop termination condition is met. I would never use this in code that anybody was expected to maintain.
An explanation for the code. Basically, if sorted ever is true before the condition the loop will stop.
1st loop: sorted is true
Within the second for loop, it basically checks if the array is sorted. If it isn't sorted -> false and the loop continues. If it is, sorted-> true and execution stops.
The comparision normally is as follows:
sorted != sorted
Of course, this does not make any sense. But instead, you have the following:
sorted = !sorted
By doing this, you just negate the condition for sorting, meaning that the array, which is unsorted, is assumed to be sorted. Then, if you traverse the complete array without making any swap, the left side of the assignment is taken as a condition (which in this case is true).

in visual c++, warning comes but program doesnt runs furthers, is there any way to igonre it?

I have written some code, here is a snippet of it is:
int num[8],n=0;
for (n = 0; n<8; n++)
{
char temp = binnum[n];
num[n] = atoi(&temp);
cout << num[n];
}
It doesn't gives any error, but I do get a warning. When I run it on C++, it gives Run Time Check Failure - The variable n is being used without being initialized.
After that, it doesn't run any further and the program closes. Is there any way to ignore this error? Because if I initialize n, it gives the wrong answer. For example, if answer is 101011, it will give 10101100, which is wrong.
Initialize n as #anthares pointed out and increment it at the end of the loop so your loop actually works.
int number[8];
int n = 0;
do
{
char temp = binnum[n];
number[n] = atoi(&temp);
cout << number[n];
n++;
} while (n<8);
Your main problem (after all the edits) is that atoi takes a null-terminated char array (C-style string). The address of a single char variable does not make a C-style string.
To convert a single character in range ['0'...'9'] to a corresponding number use:
number[i] = temp - '0';
possibly having checked that temp contains a digit character.
Give a value to your vairable n before using it int number [8], n=0 for example. Otherwise, it is "not defined behavior" what is the value of n and how many iterations you will do in your cycle.
Also, As it is written your loop will go forever since you never change the value of n ...
You are using n before it is assigned a value. You need to ensure that n is initialized (to 0, maybe) before you begin to reference it in your code. You do not want to ignore this error.
Try something like this:
const int count = 8;
int number[count];
for (int i=0; i < count; i++)
{
char temp = binnum[i];
number[i] = atoi(&temp);
cout << number[i];
}
what? you never assign any value to n.
and even if you will for example do int number[8],n=0; you never change n's value you you will end up with an infinite loop.
You should really initialize n (and also increment it, for that matter).
You are probably running a debug build of your application. In this case, the variable is probably always initialized with the same value. This is why you see the result you expect. It seems to behave correct purely by accident.
As soon as your application is built in release mode, n may have a different value each time the program is run and thus the output will be unpredictable.
This is what happens when you have undefined behavior in your program.

Accepting a grammar in C++

This is a lab assignment I am stuck on.
I need to accept this grammar (ab)*b, which basically means any number of "ab" and ending with b.
I have written this code but somehow, it checks only the first 2 letters.
#include <iostream.h>
#include <conio.h>
#include <string.h>
enum track {true, false};
void main()
{
clrscr();
char*str;
enum track track_pos, track_pos_2;
cout<<"enter the string: ";
cin>>str;
int len=strlen(str);
cout<<"length of the string is "<<len;
getch();
int i;
for(i=0;i<len; i++)
{
++str;
cout<<"loop"<<i;
if(*str=='a' && i%2==0)
{
cout<<"\nchecking a...";
track_pos=true;
cout<<"\na.check";
++str;
if (*str=='b')
{
cout<<"\nchecking b...";
track_pos=true;
cout<<"\nb.check";
}
else{
track_pos=false;
cout<<"\nb.uncheck";
}
}
}
if(*str=='b')
track_pos_2=true;
else
track_pos_2=false;
if(track_pos==true && track_pos_2==true)
cout<<"\nThe string is accpeted.";
else
cout<<"\nThe string is rejected.";
getch();
cout<<"\n\nDo you want to continue (Y/N)? ";
char ch;
cin>>ch;
if(ch=='y' || ch=='Y')
main();
}
I'm going to regret this, but each time I look at this question I see something else wrong with your code. Here is the line by line. I've probably missed a lot.
The correct name for this header is "iostream", not "iostream.h" - the ".h" version is deprecated. Similarly, use "string", not "string.h" in modern C++, and use the modern STL string classes.
#include <iostream.h>
#include <conio.h>
#include <string.h>
As pointed out, don't do this. You have redefined the standard bool type to have the opposite value from the standard types. I don't even know that this is legal.
enum track {true, false};
The return value of the main function is int, not void.
void main()
{
clrscr();
Do you know what a buffer overflow is? You have defined str as a pointer here, with no allocated memory, and you write to that undefined bit of memory a bit later on. This is undefined behaviour, and you are pretty much guaranteed to crash. I recommend, you should defined str as a std::string - this will nicely avoid the buffer overflow, and it has many useful methods that you can use in your program.
char*str;
enum track track_pos, track_pos_2;
cout<<"enter the string: ";
This is the buffer overflow right here. You are writing to who knows what area of memory.
cin>>str;
If str was a std::string - you would do size_t len=str.length();
int len=strlen(str);
cout<<"length of the string is "<<len;
It's probably not a good idea to mix console IO functions like this with iostreams functions - there are some buffering issues that can lead to difficulties.
getch();
Declare i in the body of the loop, since you aren't using it again. Like so:
for (int i=0; i<len; i++) etc...
int i;
for(i=0;i<len; i++)
{
Instead of using poiter arithmetic, since you are keeping track of the index of the current character in i, just use that and treat str as an array. This way, you don't have to keep str in synch with i all of the way through. This is the cause the bug you are reporting, by the way.
++str;
cout<<"loop"<<i;
You should change this to:
if (str[i]=='a' && i%2==0)
(That works even if str is a std::string by the way, unlike the pointer arithmetic version).
if(*str=='a' && i%2==0)
{
You really should drop out at some point, if you figure out that the string doesn't match, then there is no point going on to the end of the string.
cout<<"\nchecking a...";
I don't favour status flags like this - your code is partly hard to understand because of the proliferation of these flags, you cannot keep track of the proper behaviour. The name track_pos is not mnemonic, that makes it hard to work out what it is meant to signify without detailed study of the code.
I would recommend that you would refactor your code inside the body of the for loop to call a function, the purpose of which is simply to match a single group of "ab" - this function could return true if it did, and false if it did not.
track_pos=true;
cout<<"\na.check";
Note that since we are dealing with the buffer overflow mentioned before, you are iterating undefined memory. Also note that you did not increment i here.
++str;
if (*str=='b')
{
cout<<"\nchecking b...";
track_pos=true;
cout<<"\nb.check";
}
else{
track_pos=false;
cout<<"\nb.uncheck";
}
}
}
When we get to here, according to your for loop, we have iterated the whole string, so we must be looking past the end of the string (even ignoring the buffer overflow) so there is no possible way this test can succeed. In short, your for loop must be going too far.
if(*str=='b')
track_pos_2=true;
else
track_pos_2=false;
if(track_pos==true && track_pos_2==true)
Should I mention the spelling mistake?
cout<<"\nThe string is accpeted.";
else
cout<<"\nThe string is rejected.";
getch();
cout<<"\n\nDo you want to continue (Y/N)? ";
char ch;
cin>>ch;
If you refactor your code into appropriate sub-routines, you will find the structure of the program takes care of itself. Note that calling main recursively is not strictly illegal, but it is kind of weird and has an obvious vulnerability that will lead to an eventual stack overflow, if the program never exits.
if(ch=='y' || ch=='Y')
main();
}
Implement a simple state machine. It has these states:
0 = start
1 = 'received a of (ab)'
2 = 'received b of (ab)'
3 = 'received final b'
-1 = error, invalid grammar
Then you just need a function like this:
int nextState(int currentState, char inputChar) {
if (currentState == 0 && inputChar == 'a') return 1; // handled string is "a"
if (currentState == 0 && inputChar == 'b') return 3; // handled string is "b"
if (currentState == 1 && inputChar == 'b') return 2; // handled string is "ab", or "abab", or ...
if (currentState == 2 && inputChar == 'a') return 1; // handled string is "aba", or "ababa", or ...
if (currentState == 2 && inputChar == 'b') return 3; // handled string is "abb", or "ababb", or ...
return -1;
}
Iterate this "state machine" over your input chars, starting with state 0, and if you end up in state 3, your input is valid.
int isValid(char* inputString) {
int state = 0;
for(int i=0; i<str_len(inputString); i++) {
state = nextState(state, inputString[i]);
}
return (state == 3);
}
Things wrong with your code:
#include <iostream.h>
should be:
#include <iostream>
The following is a non-standard (and very old) header:
#include <conio.h>
The following is illegal - true and false are reserved words.
enum track {true, false};
In C and C++, main must return an int:
void main()
Non standard function:
clrscr();
No memory allocated to this pointer:
char*str;
which is then used here - result undefined behaviour:
cin>>str;
Illegal call to main:
main();
I suspect you are using a very old and obsolete C++ compiler. You should replace it with something like MinGW.
Don't do this!
enum track {true, false};
Here your true is equal to 0 and false is equal to one! When you later assign track_pos, you may get the wrong value! (Because when converting bool to int, true converts to 1 and false converts to 0.)
That's only a guess though. Maybe it's something else that matters.