I am trying to use the new C++11 range based for loops. Here's my program:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
using namespace std;
ofstream logger("log.txt");
void log(string message)
{
logger << message << std::endl;
logger.flush();
}
int main( int argc, char* args[] )
{
log("hello world");
cout << "hello world\n";
log("declare sort me");
int sortMe[10];
log("loop sortMe");
for(int i : sortMe) {
log("in loop " + i);
sortMe[i] = i + 1;
}
}
I'm using clang++ to compile. It compiles with the warning:
clang++ -o mycpp mycpp.cpp
mycpp.cpp:24:12: warning: range-based for loop is a C++11 extension
[-Wc++11-extensions]
for(int i : sortMe) {
^
1 warning generated.
When it runs, I get this output:
hello world
Segmentation fault (core dumped)
According to the log.txt file, the program gets to the for loop, but it never enters the for loop. What am I missing?
This loop:
for(int i : sortMe) {
log("in loop " + i);
sortMe[i] = i + 1;
}
Loops and returns the values stored in the sortMe array, not the indices of the sortMe array. As a result, the lookup sortMe[i] will jump to a totally random index of the array (probably way, way out of bounds), causing the segfault.
If you want to set each element equal to its position, just use a normal for loop:
for (int i = 0; i < 10; i++) {
sortMe[i] = i + 1;
}
Also, as #hmjd noted, the call to log will not work correctly, because you are doing pointer arithmetic on a string, not doing a string concatenation.
Hope this helps!
You're using a range-based for loop where you should be using a standard for loop. The int i in your loop is not the index of the current element, but the value of that element. That is, if your array contained {1, 3, 3, 7}, the value of i at each iteration would be 1, then 3, then 3, then 7. Since your array is uninitialized, you have no idea what the values of i will be and you're getting undefined behaviour.
If you want the index in your for loop, use a standard for loop:
for(int i = 0; i < 10; i++) {
log("in loop " + std::to_string(i));
sortMe[i] = i + 1;
}
Note that to do string concatenation with +, one of your operands will need to be a std::string. Otherwise you are adding i to the pointer that points at the first character in "in loop ".
The call to log() within the for loop is incorrect. The argument is the result of pointer arithmetic, with an unknown int value being used as an offset from the base address of a string literal.
Use std::to_string() to convert an int to a std::string.
Just to mention std:iota, that can be used to set elements of a range to increasing values based of an initial value:
std::iota(std::begin(sortMe), std::end(sortMe), 1);
I think that you expect the range-based loop to do something different from what it does...
If you write for (int var: array) { log(var); } then the code will be executed as many times as there are elements in the array. Each time, var will be equal to one of the elements of array. Note that I use var directly as an array element, and not array[var]!
For instance, if you have int[3] array = { 42, 69, 1337 };, the precedent for loop will log 42, 69 and 1336.
So if I simply do int[3] array;, the precedent for loop will loop the three random integers that were already in memory where the array is being stored... if instead of using var directly I was to use array[var] it would most likely crash because var would not be a valid index for array.
Solution:
Don't get confused with the difference between array elements and indexes...
If you want to manipulate directly the elements of the array:
for(int element : sortMe) {
/* Do something with the element */
}
If you want to use indexes, don't go for a range-based loop:
for(int index = 0; index < 10; ++index) {
/* Do something with the index */
}
You can do what you want the new way, but it is a rather pointless exercise and better done with a regular for loop. The range loop returns values, not references. At least in the way you are using it.
int count = 0;
// Use a reference so we can update sortMe
for (int& i : sortMe) {
i = ++count;
}
On looking at it, it is a little more compact than a normal for loop and strangely I prefer it. ;)
Related
I have the following code written in c++ and the algorithm works when in this scenario. I am knew to c++ and don't understand what I did wrong in my 2nd test.
#include <iostream>
using namespace std;
void bubbleSort(int numbers[], int size) {
for (int i = 0; i<size;i++) {
for (int j=0; j<size;j++) {
if (numbers[j] > numbers[j+1]) {
swap(numbers[j], numbers[j+1]);
}
}
}
}
int main() {
int numbers[] = {7,5,6,4};
bubbleSort(numbers,4);
for (int print = 0; print < 4; print++) {
cout << numbers[print] << endl;
}
return 0;
}
But, fails when I try to put in numbers that are already sorted:
#include <iostream>
using namespace std;
void bubbleSort(int numbers[], int size) {
for (int i = 0; i<size;i++) {
for (int j=0; j<size;j++) {
if (numbers[j] > numbers[j+1]) {
swap(numbers[j], numbers[j+1]);
}
}
}
}
int main() {
int numbers[] = {1,2,3};
bubbleSort(numbers,3);
for (int print = 0; print < 3; print++) {
cout << numbers[print] << endl;
}
return 0;
}
for (int j=0; j<size;j++) {
If size is 3, if the array has three values, for example, this loop iterates with values of j of 0, 1, and 2.
if (numbers[j] > numbers[j+1]) {
When j is 2 this compares numbers[2] with numbers[3].
There is no numbers[3]. This is undefined behavior. The loop is off by 1 value.
Additionally, the overall bubble sort implementation is flawed. In the shown code the inner loop iterates over the entire array (ignoring the off-by-1 bug), every time. In a classical bubble sort the first pass (the first iteration of the outer loop) results in the inner loop iterating over the entire array and "bubbling" the smallest/largest value to the end of the array. On the next pass the inner loop does not need to iterate over the entire array, but only up until the 2nd smallest/largest position of the array. And so on, each pass (the outer loop) results in the inner loop iterating over a smaller, and smaller subset of the array, "bubbling" the corresponding value to the appropriate stop.
In addition to fixing the off-by-1 bug you'll also need to adjust the overall logic of this bubble sort, if you wish to get a perfect grade for your homework assignment.
Implementing bubble sort in its entirety is problematic. In the example code, the inner loop repeatedly iterates over the full array while disregarding the shift by 1. The inner loop iterates over the whole array in a traditional bubble sort's first iteration of the outer loop, "bubbling" the smallest/largest value to the array's end. On the subsequent iteration, the inner loop only has to iterate up to the array's second-smallest/largest point rather than the full array. The inner loop then iterates through a smaller and smaller subset of the array, making bubbles of the associated the associated value to the proper stop with each successive run in the outside loop.
I've recently started learning c++ after 5 years with python and am struggling quite a bit when it comes to loops. the whole for(;;) business.
in python i was used to:
for x in y:
print(x)
> x
> y
> z
however in c++ i seem to need two semi-colons like
for(;;)
what i would like to do is print the paths of my directories given in the below code. Thank you for your time!
#include <windows.h>
#include <string>
#include <iostream>
#pragma comment(lib, "user32.lib")
using namespace std;
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
// -- main
int main(void) {
// -- console
SetConsoleTextAttribute(hConsole, 12);
// -- paths
string ScanDir[2] = {"C:/Users/Stephen/Downloads/", "C:/Users/Stephen/Documents/"};
// -- loops
for (int i = 0; i < ScanDir->length(); ++i) {
string ss = ScanDir[i];
cout << ss.c_str() << "\n";
}
return 0;
}
here is the error:
error screenshot
In C++ arrays are not objects in the OOP sense and do not have methods. They are just a dumb block of memory.
ScanDir->length()
is not getting the length of the array. Instread ScanDir is decaying to a pointer to the first string in the array and length is being called on this string. As a result
for (int i = 0; i < ScanDir->length(); ++i)
iterates length of the first string times, not length of the array, and shoots off the end of the array and into the unknown. This invokes Undefined Behaviour which in this case lead to a crash.
The smart thing to do is use a Range-based for loop
for (const auto & dir: ScanDir) {
cout << dir.c_str() << "\n";
}
which figures out the dimensions for you. Some additional reading on the const auto & bit: What is the correct way of using C++11's range-based for?
You can also use
for (int i = 0; i < std::size(ScanDir); ++i)
if compiling to C++ 17 or better or replace the magic number 2 in
string ScanDir[2] = {"C:/Users/Stephen/Downloads/", "C:/Users/Stephen/Documents/"};
with a constant that can be used wherever the size of the array is required.
Another alternative is replace the array with a smarter container like std::array
std::array<std::string, 2> ScanDir = {"C:/Users/Stephen/Downloads/", "C:/Users/Stephen/Documents/"};
which has a size method.
ScanDir->length() is the length of your strings which is notably greater than 2. You can either use 2 as upper loop boundary or sizeof(ScanDir) / sizeof(ScanDir[0]), or type the loop itself as for(auto const &ss: ScanDir) count << ss.c_str() << '\n';.
I have the following code:
int main()
{
int a[5];
for (int i = 0; i <= 5; i++) {
cin >> a[i];
}
for (int i = 0; i <= 5; i++) {
cout << a[i] << endl;
}
}
The program is supposed to take 6 integers as input and just print them to the output. It works fine for the first five integers but crashes while printing the sixth. As far as I know, in c++ an array defined "a[5]" should have 6 elements since it starts from 0, right? What's causing the crash?
int a[5];
is an array of 5 integers! The indexing is 0, 1, 2, 3, 4.
The reason for this is how the elements live in memory. The index tells you how many spots to jump from the start of the array. So the first element, you have to jump 0 spaces, because it is at the very front of the array. The second element, you have to jump 1 space. Get it?
array start |data|data|data|data|data|<nothing here!>
offset from start | 0| 1| 2| 3| 4| not allowed!!
So by trying to jump into a position that doesn't actually exist in the array, you cause Undefined Behaviour. This means your program is garbage. There is no guarantee at all what might happen. It might crash, or worse, it might appear to work, because you actually hit some memory that is really being used to store a completely different object. Then you end up with some really crazy behaviour that is hard to debug.
A loop over an array should look like this:
for (size_t i = 0; i < arraySize; ++i) // ...
^ always <, never <=
But it is better to use std::vector, which will grow to the size you need, and manage all the memory for you. Then you can use myVector.at(3); to access the data, and it will throw an exception if you make a mistake like you did above. Or better, use the "range-based for loop", which will pull out all the elements for you:
#include <vector>
#include <iostream>
int main()
{
const std::size_t howMany = 6; // how many ints to read
std::vector<int> data;
while (data.size() < howMany) { // haven't read enough yet
int tmp = 0;
std::cin >> tmp;
if (!std::cin) { // somehow reading went wrong!
return 1; // exit the program with an error code
}
data.push_back(tmp); // store the value we just read
}
for (int i : data) { // go through all the stored ints
std::cout << i << '\n';
}
}
(Also, see here for some common beginner mistakes you are making).
I am new to C++, I have a problem of array manipulation. I have an array of X with length 100, I need to fill the value of X with integer value of 1 to 10 (1,2,3,4,5,6,7,8,9,10) randomly.
I know that there will be duplicate, maybe like 1 printed ten times, etc, but that's really what I want.
Here is what I have:
an array of X:
int X[100];
Here is my code snippet:
int* X = NULL;
int* val = NULL;
int length1= 100;
int length2= 10;
X = new int[length1];
val = new int[length2];
int i;
int j;
for (i = 0; i < isi; i++) {
val[i] = i;
for (j = 0; j < length1; j++) {
if (j > i) {
X[j] = val[i];
} else {
X[j] = val[0];
}
cout << "X[" << j << "] = " << X[j] << "\n";
Sleep(1);
}
}
Code above makes the array X from index 0 to 99 has value of 0, then index 0 to 99 has value of 1 and so the other index until the index 0 to 99 has value of 9.
This is not what I want, what I want is to make it (if it is not random) index 0 to 9 has value of 0, then 10 to 19 has value of 1 ... until index 90 to 99 has value of 9. Hope my explanation clear.
I have come to a question in stackoverflow: How would you make an array of 10000 with only values of 1-1000 inclusive?
But still can't resolve my problem my self.
Can someone please give me solution to this.
Thank you in advance
#include <stdlib.h>
int main(int argc, char **argv) {
int r[100];
for (int i = 0; i < 100; ++i) {
r[i] = rand() % 10 + 1;
}
}
For some output, you can #include <iostream> and then std::cout << "r[" << i << "] = " << r[i] << "\n" inside the loop after each assignment.
If you want to seed the random number generator for a different sequence each time, then #include <time.h> and then srand(time(NULL)) before your first call to rand.
You can also use generate function:
#include <iostream>
#include <algorithm>
#include <random>
using namespace std;
int main()
{
int arr[100];
random_device rd;
default_random_engine dre(rd());
uniform_int_distribution<int> uid(0,9);
generate(arr, arr + sizeof(arr) / sizeof(int), [&] () { return uid(dre); });
for (int a : arr)
cout << a << " ";
}
Here are two ways to solve this problem - since this is a learning experience, only pseudo code (and relevant links) are provided. Each "task" can be looked up and solved separately. Note that neither method uses a secondary array.
If the amount of each number in the final result does not need to be the same (eg. 2 might appear 17 times) then consider the following loop-and-assign-random approach. A standard C for-each loop is sufficient.
# for every index pick a random value in [0, 10) and assign it
for i in 0 to last array index:
array[i] = random in range 0, 10
If the amount of numbers need to be the same, then consider filling the array and then shuffling it. The modulus operator is very handy here. (This assumes the array length is a multiple of the group size.)
# fill up array as 0,1,2,3,4,5,6,7,8,9,0,1,2.. (will be 10 groups)
for i in 0 to last array index:
array[i] = i % 10
# and randomly rearrange order
shuffle array
For the shuffle see Fisher-Yates, which even shows a C implementation - there are "more C++" ways, but this is a good technique to learn and practice with loops. (One cool property about Fisher-Yates is that as soon an item is swapped into the current index it is at the final swap location - thus the shuffle loop can be modified to shuffle and immediately perform an action such as displaying the value.)
In both cases a random function should be used; else the numbers will not be .. random.
To loop over the items of a collection the most natural C++ loop is the range based for loop.
In order to assign something to each item, the formal item name should be a reference, thus:
for( auto& item : X )
{
// E.g. assign to item here.
}
This serves up each item of the array, in order, to the code marked by a comment.
There are two different random generators in C++, the old C library one, which is just a pair of functions, and the more general and modern but also not-so-easy-to-grok C++11 thingy. I suggest you google it and try out things. Ask new more specific question if/when stuck.
I think others have pointed it out but you have to first write the pre-compiler directive #include <ctime> and then use the srand function. Most would say don't use that but since you and I are at the basics our teachers, respectively, start us off with that. And it might work with your compiler as well.
Here is a link to learn more about it. I would have commented but I can't.
http://www.cplusplus.com/reference/cstdlib/srand/
I try to make a list of digit of consequence number from 1 to 100; for example, 123456789101112..... However, when I print out the result from the list_result; there is some strange number in my list_result vector. Here the following code:
int main()
{
vector<int> list_num;
vector<int> list_result;
int count =0;
for(int index = 1; index<=100; index++)
{
count = index;
if(index<10)
{
list_result.push_back(index);
}
else
{
while(count!=0)
{
list_num.push_back(count%10);
count=count/10;
}
for(int i=0; i<=list_num.size();i++)
{
list_result.push_back(list_num[list_num.size()-i]);
}
list_num.clear();
}
for(int i = 0; i<=list_result.size(); i++)
{
cout<<list_result[i];
}
}
return 0;
}
Anyone has any ideas? Thank,
Your program exhibits undefined behavior.
for(int i=0; i<=list_num.size();i++)
{
list_result.push_back(list_num[list_num.size()-i]);
}
Valid indexes into list_num are 0 through list_num.size()-1. Yet on the first iteration of this loop, when i == 0, you attempt to access list_num[list_num.size()]. There is no such element.
Igor Tandetnik described an issue in the for loop inside the else block, but I've identified another issue, this time in the output stage of the program.
Remember that indices are zero-based, which means they run from zero to the number of elements minus one. vector::size() returns the total number of elements, in this case 100. Because you're comparing this value with the index using a less-than-or-equal inequality, you end up trying to access element 100 on the final iteration of the loop, and element 100 does not exist since the range of valid indices is 0 to 99. When writing a loop that iterates through an array or vector, you should always compare indices with array/vector sizes using strict inequalities.
In the final for loop, replace the <= with a strict < comparison so that it stops at the actual last element and not afterwards:
for(int i = 0; i<list_result.size(); i++)
{
cout<<list_result[i];
}
Wikipedia has an easy-to-understand explanation of this common programming mistake, known as an off-by-one error.