simple for if loop not working correctly - c++

I have a very simple for if loop which takes in an array (a vector of vectors) called data, reads the 0th element of EACH row (i.e. the data[i][0] elements), and outputs the 5th elements of THAT specific row IFF it satisfies the condition that the first element is equal to an integer pid (user defined earlier in the code.) If the row doesn't start with that element, i want it to output nothing.
Here is my code for this loop:
for(int i = 0; i < data.size(); i++) {
if(data[i][0] = pid) {
cout << data[i][5] << endl;
}
}
However, when I run the program, it outputs the 5th element of EVERY row, not just the ones that start with pid. AKA, c++ seems to be completely ignoring my if statement.
Does anyone have an answer to this?
Thank you in advance!

You need to use == instead of = inside the if condition:
if(data[i][0] == pid)
Otherwise you are just assigning the value of pid to the array element and this will be true if pid is not 0.

You are using assignment operator = instead of the comparison operator ==
if(data[i][0] = pid) {
^^^
As for me I would write these loops the following way
for ( size_t i = 0; i < data.size(); i++ )
{
if ( data[i][0] == pid && data[i].size() > 5 )
{
cout << data[i][5] << endl;
}
}

Related

What can I use to stop a loop instead of 'return 0'?

so I made a simple loop that finds out if an array has the elements with the values of 0 and 1.
if the loop indeed finds 0 or 1 inside of the array, it will say "YES", otherwise "NO".
yes, the program works just fine, but at the end of the program it prints out "YES" or "NO" as many times as i put cin>>dim to.
for example if dim which means (dimension[of the array]) is 5 it's going to print either "YESYESYESYESYES" or "NONONONONO"
I have to use return 0 in order to make it print it out like once, but I feel like this is not the right way to do it. Please help me with this. thanks!
#include <bits/stdc++.h>
using namespace std;
int main()
{
int i, dim, v[100];
cin>>dim;
for(i=0;i<dim;i++)
cin>>v[i];
for(i=0;i<dim;i++)
if(v[i]==0 || v[i]==1){
cout<<"YES"; return 0;}
else{
cout<<"NO"; return 0;}
return 0;
}
The break statement can be used to break out of loops. The example from cppreference:
for (int j = 0; j < 2; j++) {
for (int k = 0; k < 5; k++) { //only this loop is affected by break
if (k == 2) break;
std::cout << j << k << " ";
}
}
As the comment suggests, break only breaks the innermost loop.
In your code you always exit from the loop on the very first iteration, hence you do not need the loop in the first place. This will have the same output as your code:
int main() {
int i, dim, v[100];
cin >> dim;
for(i=0; i < dim; i++)
cin >> v[i];
if(v[0] == 0 || v[0] == 1) {
cout << "YES";
} else {
cout << "NO";
}
}
After reading the question again...
I made a simple loop that finds out if an array has the elements with the values of 0 and 1
If you exit the loop after checking the first element then you only check the first element. If you want to see if an array contains only 1 or 0 or it contains at least one element which is 0 or 1 (not 100% clear which one you want), then you rather need this:
bool only_zero_or_one = true;
bool one_zero_or_one = false;
for (int i = 0; i < dim; ++i) {
zero_or_one = ( v[i] == 0 | v[i] == 1);
only_zero_or_one = zero_or_one && only_zero_or_one;
one_zero_or_one = zero_or_one || one_zero_or_one;
}
Only for one_zero_or_one you can break the loop once zero_or_one == true.
Moreover, you should rather use a std::vector. In your code, if the user enters a dim which is greater than 100 you write beyond the bounds of v. This can be avoided easily:
size_t dim;
std::cin >> dim;
// construct vector with dim elements
std::vector v(dim);
// read elements
for (size_t i=0; i < v.size(); ++i) std::cin >> v[i];
// .. or use range based for loop
for (auto& e : v) std::cin >> e;
but I feel like this is not the right way to do it
Returning is an entirely right way to break out from a loop.
Another right way is the break statement, which jumps to after the loop.
Even better, you can actually check if v[i]==0 or 1 inside the input for loop immediately after taking input and set a flag to true. Depending on requirement, you can either break or wait until the entire input is read and then come out and check for flag==true and then print "YES" and print "NO" if flag==false.
This will save you running the loop again to check for 0 or 1.

Indexing issue with a for loop

I have a for loop where I'm using the slide operator as I'm working with unsigned types. Essentially it boils down to
for (std::size_t i = 6; i --> 0;){
cout << i;
}
But it outputs the numbers from 5 to 0 inclusive and omits 6. Why?
Thank you very much for looking at this. I'm quite stuck.
This is a touchstone for
The fact that this so-called "operator" should be used with caution, if at all.
Changing the state of variables within the conditional check of a for loop ought to be done with extreme caution, if at all.
The largest output is 5 simply because i is decremented as a result of the conditional test which also decrements i. The conditional check is ran before program control enters the for loop body.
You really ought to rewrite the loop. Don't set the initial value of i to 7 as that's a dirty hack. Although --> is often used with while (and to emphasise, it's unlikely to win you many friends in your programming review), I've never seen it used with a for loop before.
--> is not a slide operator.
It is understood by the compiler as two different operators -- and >.
So your code look like this to the compiler:
for (std::size_t i = 6; (i--) > 0;){
cout << i;
}
Since the loop condition is checked before entering the loop's body i is decreased before the first execution of the loop's body, hence the produced sequence of numbers is 5 4 3 2 1 0.
For more details see this Stack Overflow question: What is the "-->" operator in C++?
After evaluating this condition in the for statement
i --> 0
i will be equal to 5. So the first iteration of the loop outputs
5
To achieve the effect you want rewrite the loop the following way
#include <iostream>
int main()
{
size_t i = 6;
do
{
std::cout << i;
} while ( i-- > 0 );
return 0;
}
The program output is
6543210
Another way is the following
#include <iostream>
int main()
{
for ( size_t i = 6; std::cout << i && i != 0; i-- )
{
//
}
return 0;
}
Of course you could write the loop like this
const size_t N = 6;
for ( size_t i = N + 1; i-- > 0; )
// ^^^^^^^
{
std::cout << i;
}
However in general this approach does not work when the initial value of i is equal to std::numeric_limits<size_t>::max() Because if to add 1 to this value you will get 0.
A general approach using a for loop can look the following way
#include <iostream>
int main()
{
const size_t N = 6;
for ( size_t i = N, j = N; j != 0; j = i-- )
{
std::cout << i;
}
return 0;
}
Its output is
6543210

how can I delete the elements of array after read it in C++?

Array<Personne> personnes;
while (in) {
Personne newPersonne;
in >> newPersonne;
if (in.eof()) break;
personnes.add(newPersonne);
if (personnes.size() > 1) {
for (int i = 0; i < personnes.size() - 1; ++i)
for (int j = i + 1; j < personnes.size(); ++j) {
string typeRelation = personnes[i].getTypeRelation(personnes[j]);
if (typeRelation != "")
cout << personnes[i].getNom() << " and " << personnes[j].getNom() << " are " << typeRelation << endl;
if (j == personnes.size() -1){
personnes.delete(i); //doesn't work very well, want to delete the first element when finishing the copmarison withe the other elements.
}
}
}
}
I want to delete the first elements of the Array when the second loop reaches its end.
It's tricky with arrays, removing the first item requires you to move everything after it left one (so the 2nd item becomes the 1st item). you can use a loop for this if you want but I think the better option would be to use a different data structure like a Deque http://www.cplusplus.com/reference/deque/deque/
A couple of killers in the Tableau::delete method:
The function will not compile because of the use of the delete keyword as the function's name
elements[index+1] will allow reading elements[nbElements] Which may or may not be out of the array's bounds, but is certainly one more than intended.
Try instead:
template <class T>
void Tableau<T>::remove(size_t index) // size_t is unsigned and prevents input of
// negative numbers. One less test required.
// nbElements should also be made unsigned to match
// function name changed to something legal.
{
assert(index < nbElements); // this also ensures nbElements is > 1
// so nbElements-- will not go out of bounds
nbElements--; // moved above the loop because the index+1 will grab the last element
for( ; index < nbElements; index++) // no need to have an i. Index already does this
{
elements[index] = elements[index+1];
}
}
for (int i = 0; i < personnes.size() - 1; ++i)
// other file
template <class T>
void Tableau<T>::delete (int index)
{
assert(index < nbElements && index >= 0);
for(int i = index; i < nbElements; i++) elements[i] = elements[i+1];
nbElements--;
}
if size() is calculated with nbElements, then choose between :
for (int i (index); i < personnes.size();)
and changing the way you remove empty cases of your Array. (without changing the position of the next person tested)
because i believe you jump 1 person out of two :
you check person i then you replace person i + 1 to person i then you check person i+1 (which is actually person i+2)

C++ Sorting a struct vector alphabetically

I've got a task that I'm stuck on. I need to create a program that reads an input file, stores each word into a vector along with how many times that word was read (hence the struct). Those values then need to print out in alphabetical order.
I've come up with something that I think is along the right lines:
struct WordInfo {
string text;
int count;
} uwords, temp;
string word;
int count = 0; //ignore this. For a different part of the task
vector<WordInfo> uwords;
while (cin >> word) {
bool flag = false;
count += 1;
for (int i = 0; i < uwords.size(); i++) {
if (uwords[i].text == word) {
flag = true;
uwords[i].count += 1;
}
}
if (flag == false) {
if (count == 1) { //stores first word into vector
uwords.push_back(WordInfo());
uwords[0].count = 1;
uwords[0].text = word;
} else {
for (int i = 0; i < uwords.size(); i++) {
if (word < uwords[i].text) {
uwords.push_back(WordInfo());
WordInfo temp = {word, 1};
uwords.insert(uwords.begin() + i, temp);
}
}
}
}
}
Now the problem I'm having, is that when I run the program it appears to get stuck in an infinite loop and I can't see why. Although I've done enough testing to realise it's probably in that last if statement, but my attempts to fix it were no good. Any help is appreciated. Cheers.
EDIT: I forgot to mention, we must use vector class and we're limited in what we can use, and sort is not an option :(
if (word < uwords[i].text) {
uwords.push_back(WordInfo());
WordInfo temp = {word, 1};
uwords.insert(uwords.begin() + i, temp);
}
Take a good look at this piece of code:
First, it will actually insert 2 words into your list; one time an "empty" one with push_back, and one time with insert. And it will do that whenever the current word is smaller than the one at the position i.
And as soon as it has inserted, there's 2 new elements to walk over; one actually being at the current position of i, so in the next iteration, we will again compare the same word - so your loop gets stuck because index i increases by 1 each iteration, but the increase of i only steps over the just inserted element!
For a quick solution, you want to (1) search for the position where the word before is "smaller" than the current one, but the next one is bigger. Something like
if (uwords[i-1].text < word && word < uwords[i].text) {
(2) and you want to get rid of the push_back call.
Furthermore, (3) you can break the loop after the if condition was true - you have already inserted then, no need to iterate further. And (4), with a bit of condition tweaking, the count == 1 can actually be merged into the loop. Modified code part (will replace your whole if (code == false) block - warning, not tested yet):
if (!flag) {
for (int i = 0; i <= uwords.size(); ++i) {
if ((i == 0 || uwords[i-1].text < word) &&
(i == uwords.size() || word < uwords[i].text)) {
WordInfo temp = {word, 1};
uwords.insert(uwords.begin() + i, temp);
break;
}
}
}
You should not push your words nin vector, but in map
std::map<std::string,int>
Since map has comparable keys iterator over map, automaticaly returns sorted range that can be later pushed in vector if needed.

Loop not giving expected answer - unsure about exit/return/break

I am testing a simple piece of code in order to learn about using queues (as well as practizing vectors).
I have written this piece of code:
#include "stdafx.h"
#include <iostream>
#include <queue>
struct msgInfo //contains the attributes as gleaned from the original (IP) message
{
int age;
std::string name;
};
using namespace std;
int main ()
{
vector<vector<queue<msgInfo>>> nodeInc; //container for messages
int qosLevels = 7; //priority levels
int nodes = 5; //number of nodes
vector<queue<msgInfo>> queuesOfNodes(qosLevels);
int i;
for (i=0; i<nodes; i++)
{
nodeInc.push_back(queuesOfNodes);
}
msgInfo potato, tomato, domato, bomato;
potato.age = 2;
potato.name = "dud";
tomato.age = 3;
tomato.name = "bud";
domato.age = 4;
domato.name = "mud";
bomato.age = 5;
bomato.name = "pud";
nodeInc[2][2].push(potato);
nodeInc[2][2].push(tomato);
nodeInc[2][3].push(domato);
nodeInc[2][3].push(bomato);
for (int j = 0; j < 2; j++) //simple loop for testing: for each round, output the age of only one 'msgInfo'
{
cout << j << endl;
for (int k = (qosLevels-1); k >= 0; k--)
{
if (!nodeInc[2][k].empty())
{
cout << nodeInc[2][k].front().age << endl;
nodeInc[2][k].pop();
return 0;
}
else
break;
}
}
}
The output I get is
0
1
but what I am trying to get is
0
4
1
5
What am I doing wrong here? I can't figure out where my logic is wrong - it seems to me that here it should output the first two elements belonging to the highest filled priority level. I think it has to do with how I am exiting the loop - essentially I want each round of the for loop to only output the age of one msgInfo before 'pop'-ing it - but I have tried exit/return/break and it hasn't worked.
edit
I am receiving messages from nodes. These messages need to be put into a queue according to their attributes: node and priority level. I have decided to use a vector<vector<queue<msgInfo>>> to do this -> essentially node < priority level < queue for messages > >. When accessing this container, I need it to output the age of one msgInfo at a time - the msgInfo will be the front of the queue of the highest priority level. Not all priority levels will be filled, so it needs to iterate from highest priority level to lowest in order to find the relevant element.
I need to design a loop that will output these one at a time (because other processing needs to be done between each round of the loop).
The closest I can get to is this:
for (int j = 0; j < 2; j++) //simple loop for testing: for each round, output the age of only one 'msgInfo'
{
cout << j << endl;
for (i = (qosLevels-1); i >= 0; i--)
{
if (!nodeInc[2][i].empty())
{
cout << nodeInc[2][i].front().age << endl;
nodeInc[2][i].pop();
//return 0; <--------DON'T return. this terminates the program
break;
}
//else
// break;
}
}
That returns:
0
4
1
5
As is stated in the comment, invoking return 0; returns from main() and therefore terminates the program ( actually kind of a peaceful exit ).
What do you expect return 0 and break to do?
return 0 exits the entire main function, so your program would end once it encounters a non-empty queue.
break terminates the innermost enclosing loop (which is for (i ...)). In other words, your current logic is:
For each j of 0, 1 do:
If nodeInc[2][qosLevels - 1] is not empty, print its front and exit program; otherwise try no more is and do next j.
I don't know what the intended behaviour is, but based on the "expected output" you gave, you should replace return 0 with break, and omit the else clause entirely.