Why doesn't this out-of-bounds access segfault? - c++

I was testing some code for a class that wraps a 2-dimensional array of structs.
WrapperClass x;
SomeStruct try1 = x.at(0, 0);
SomeStruct try2 = x.at('a', 1);
SomeStruct array[] = {try1, try2};
// There were originally 3 of these test variables above, but I forgot to
// change the loop upper bound when I deleted one
for (int i = 0; i < 3; i++) {
// I added this line after noticing the non-error
std::cout << &array[i] << '\n';
std::cout << array[i].property1 << '\n';
std::cout << array[i].property2 << '\n';
std::cout << array[i].property3 << '\n';
std::cout << "-\n";
}
return 0;
This outputs:
0x7ffdadface08
0
0
0
-
0x7ffdadface14
0
0
0
-
0x7ffdadface20
0
0
0
Why doesn't this code segfault with an "access out of bounds" error or something? I only created 2 structs in the array; why is there suddenly a third one that I can freely and safely access?

Because it's undefined behavior and anything can happen, including no immediate error. I suggest you use containers such as vectors which are bounds-checked by good debug compilers.

Related

Confused with c++ swap function: std::vector<int>().swap(search_indices);

Here is the code, I am very confused. swap function is usually used to exchange the value of two parameters, like a.swap(b) or swap(a, b). What is the meaning of swap here?
std::vector<int> search_indices;
std::vector<float> distances;
int keypointNum = 0;
do
{
keypointNum++;
std::vector<int>().swap(search_indices);
std::vector<float>().swap(distances);
int id;
iterUnseg = unVisitedPtId.begin();
id = *iterUnseg;
indices->indices.push_back(features[id].ptId);
unVisitedPtId.erase(id);
tree.radiusSearch(features[id].pt, _curvature_non_max_radius, search_indices, distances);
for (int i = 0; i < search_indices.size(); ++i)
{
unVisitedPtId.erase(search_indices[i]);
}
} while (!unVisitedPtId.empty());
I have looked for how swap function works, no related explanations.
Given std::vector<int> v; definition, std::vector<int>().swap(v); clears vector v and disposes of the memory it reserved (so that v.capacity() returns 0). Starting from C++11, an arguably better way to write it is:
v.clear();
v.shrink_to_fit();
It is a trick to clear a vector and free all the allocated memory for its elements.
In these statements
std::vector<int>().swap(search_indices);
std::vector<float>().swap(distances);
there are used empty temporary created vectors, std::vector<int>() and std::vector<float>(), that are swapped with the vectors search_indices and distances.
After the calls of the member function swap the both vectors search_indices and distances become empty. In turn the temporary vectors that after the swapping contain the elements of the above two vectors will be destroyed.
This trick is used because if you will just write
search_indices.clear();
distances.clear();
the allocated memory can be preserved. That is the member function capacity can return a non-zero value.
Here is a demonstration program.
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v = { 1, 2, 3, 4, 5 };
std::cout << "v.size() = " << v.size() << '\n';
std::cout << "v.capacity() = " << v.capacity() << '\n';
std::cout << '\n';
v.clear();
std::cout << "v.size() = " << v.size() << '\n';
std::cout << "v.capacity() = " << v.capacity() << '\n';
std::cout << '\n';
std::vector<int>().swap( v );
std::cout << "v.size() = " << v.size() << '\n';
std::cout << "v.capacity() = " << v.capacity() << '\n';
}
The program output is
v.size() = 5
v.capacity() = 5
v.size() = 0
v.capacity() = 5
v.size() = 0
v.capacity() = 0
As you can see after calling the member function swap with the temporary empty vector the capacity of the vector v becomes equal tp 0.
To get the same effect using the method clear you should after calling it also to call the method shrink_to_fit(). For example
v.clear();
v.shrink_to_fit();
It seems that this is a strategy to free up memory. I wrote a test code here:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
std::vector<int> test(9, 0);
std::cout <<test.size() << std::endl;
std::vector<int>().swap(test);
std::cout <<test.size() << std::endl;
cout<<"Hello World";
return 0;
}
The output is:
9
0
Hello World

Why int ia2[10] has a default value of 0 even though it is defined inside a function?

I'm new to C++ and is trying to learn the concept of arrays. I saw the code and statement below from C++ primer.
As with variables of built-in type, a default-initialized array of
built-in type that is defined inside a function will have undefined
values.
Judging from this statement, the int ia2[10] below is define inside the int main(){} function and therefore should not have default value and all its elements should be undefined. However, when I tried to print out their value, they are all equal to 0, which is the default value for any uninitialised int array.
Why is this happening?
int main() {
string sa2[10]; //all elements are empty strings
int ia2[10]; //all elements are undefined
for (int i = 0; i < 10; i++){
cout << "sa2[" << i << "] " << sa2[i] << endl;
cout << "ia2[" << i << "] " << ia2[i] << endl;
}
}
Output:
sa2[0]
ia2[0] 0
sa2[1]
ia2[1] 0
sa2[2]
ia2[2] 0
sa2[3]
ia2[3] 0
sa2[4]
ia2[4] 0
sa2[5]
ia2[5] 0
sa2[6]
ia2[6] 0
sa2[7]
ia2[7] 0
sa2[8]
ia2[8] 0
sa2[9]
ia2[9] 0
It isn't forced to have some random value. It's undefined what value will be there, so it could be anything, including all zeroed out. Also note that reading the value is undefined behavior.

Range based for loop starts at one instead of zero?

I have just started using range based for loops to simplify my code when using templates. I have come across a strange error and am not sure if this is something that I am missing or if the compiler is making a mistake. I have written a piece of code to illustrate the issue that I am having as well as the output. These are shown below.
Note: I am using the Mingw64 compiler on windows g++ (rev5, Built by MinGW-W64 project) 4.8.1 compiled without optimization with the --std=c++11 flag.
Code:
#include <iostream>
#include <array>
#include <vector>
int main()
{
// Declares an array of size 5 and of type int and intialises.
std::array<int,5> x = {1,2,3,4,5};
std::vector<int> y = {1,2,3,4,5};
// Prints each element
std::cout << "Array:" << std::endl;
std::cout << "x" << "\t" << "i" << std::endl;
for (auto i : x)
{
std::cout << x[i] << "\t" << i << std::endl;
}
std::cout << "Vector" << std::endl;
std::cout << "y" << "\t" << "i" << std::endl;
for (auto i : y)
{
std::cout << y[i] << "\t" << i << std::endl;
}
std::cin.get();
std::cin.get();
return 0;
}
Output:
Array:
x i
2 1
3 2
4 3
5 4
0 5
Vector
y i
2 1
3 2
4 3
5 4
1313429340 5
I would assume that the last line of both the vector and array output is an overflow, and notice how i starts at one instead of zero?? I would have assumed it would behave as described here.
I think you have not understood the syntax correctly
for (auto i : x)
here i is not an index of an array, it is the actual element inside the vector x.
So it is doing its job correctly.
"i" is the actual value in the array and not the index. So it is printing x[1] to x[5] in the first column and 1 to 5 in the second column. To access the values just print "i".
for (auto i : x)
creates copies of elements in x to be used inside your for loop. Use an iterator instead to access elements by their index.
for (size_t i = 0; i < x.size(); i++) {
std::cout << x[i] << "\t" << i << std::endl;
}

Values not written to vector

I'm trying to read pairs values from a file in the constructor of an object.
The file looks like this:
4
1 1
2 2
3 3
4 4
The first number is number of pairs to read.
In some of the lines the values seem to have been correctly written into the vector. In the next they are gone. I am totally confused
inline
BaseInterpolator::BaseInterpolator(std::string data_file_name)
{
std::ifstream in_file(data_file_name);
if (!in_file) {
std::cerr << "Can't open input file " << data_file_name << std::endl;
exit(EXIT_FAILURE);
}
size_t n;
in_file >> n;
xs_.reserve(n);
ys_.reserve(n);
size_t i = 0;
while(in_file >> xs_[i] >> ys_[i])
{
// this line prints correct values i.e. 1 1, 2 2, 3 3, 4 4
std::cout << xs_[i] << " " << ys_[i] << std::endl;
// this lines prints xs_.size() = 0
std::cout << "xs_.size() = " << xs_.size() << std::endl;
if(i + 1 < n)
i += 1;
else
break;
// this line prints 0 0, 0 0, 0 0
std::cout << xs_[i] << " " << ys_[i] << std::endl;
}
// this line prints correct values i.e. 4 4
std::cout << xs_[i] << " " << ys_[i] << std::endl;
// this lines prints xs_.size() = 0
std::cout << "xs_.size() = " << xs_.size() << std::endl;
}
The class is defined thus:
class BaseInterpolator
{
public:
~BaseInterpolator();
BaseInterpolator();
BaseInterpolator(std::vector<double> &xs, std::vector<double> &ys);
BaseInterpolator(std::string data_file_name);
virtual int interpolate(std::vector<double> &x, std::vector<double> &fx) = 0;
virtual int interpolate(std::string input_file_name,
std::string output_file_name) = 0;
protected:
std::vector<double> xs_;
std::vector<double> ys_;
};
You're experiencing undefined behaviour. It seems like it's half working, but that's twice as bad as not working at all.
The problem is this:
xs_.reserve(n);
ys_.reserve(n);
You are only reserving a size, not creating it.
Replace it by :
xs_.resize(n);
ys_.resize(n);
Now, xs[i] with i < n is actually valid.
If in doubt, use xs_.at(i) instead of xs_[i]. It performs an additional boundary check which saves you the trouble from debugging without knowing where to start.
You're using reserve(), which increases capacity (storage space), but does not increase the size of the vector (i.e. it does not add any objects into it). You should use resize() instead. This will take care of size() being 0.
You're printing the xs_[i] and ys_[i] after you increment i. It's natural those will be 0 (or perhaps a random value) - you haven't initialised them yet.
vector::reserve reserve space for further operation but don't change the size of the vector, you should use vector::resize.

CPP: Mysterious error for array initialization and crash?

My program seems to always produce ridiculous errors.
Please provide directions for me. The following code segment cutout all irrelevant parts.
Thanks.
Part A of the code segment seems failed to initialize the array correctly, how to debug?
Part B of the code segment always crash, is there anything i missed?
typedef unsigned long T_PSIZE;
int main()
{
int AG_TOTAL = 6 ;
/* part A1 */
T_PSIZE* cntPeopleByAge = new T_PSIZE[AG_TOTAL + 1];
/* part A2 - originally i use static array like this, but it also fails */
//T_PSIZE cntPeopleByAge T_PSIZE[AG_TOTAL + 1];
for (int i = 0; i < (AG_TOTAL + 1); i++)
{
std::cout << i << ":" << cntPeopleByAge[i] << "\t";
cntPeopleByAge[i] = 0;
std::cout << cntPeopleByAge[i] << "\n";
}
std::cout << "cntPeopleByAge:" << cntPeopleByAge[ AG_TOTAL + 1 ] << "\n";
/* part B */
delete [] cntPeopleByAge;
return 0; // <--- crash here!
}
Sample Output
0:200320 0
1:201581 0
2:201582 0
3:201583 0
4:0 0
5:0 0
cntPeopleByAge:1799119387:0:0
Platform: win 7 x64
Compiler: TDM-GCC x64
for (int i = 0; i < (AG_TOTAL + 1); i++)
{
std::cout << i << ":" << cntPeopleByAge[i] << "\t";
// ^^^^^^^^^^^^^^^^
// You're reading uninitialized memory here
cntPeopleByAge[i] = 0;
std::cout << cntPeopleByAge[i] << "\n";
}
And here
std::cout << "cntPeopleByAge:" << cntPeopleByAge[ AG_TOTAL + 1 ] << "\n";
you're going out of bounds. The last valid index is AG_TOTAL.
You've got undefined behaviour (UB). The errors are only as ridiculous as UB can be.
/* Sorry. but that earlier answer is not correct. The loop correctly starts at zero and ends at < the limit. The problem is that you are declaring an array of pointers, but never allocating memory to the objects that they point to. Your output is showing you addresses not numbers. One way is to allocate the objects as you use them (you must delete them individually as well) */
T_PSIZE* cntPeopleByAge = new T_PSIZE[AG_TOTAL + 1];
for (int i = 0; i < (AG_TOTAL + 1); i++)
{
cntPeopleByAge[i] = new T_PSIZE();
}
What you really want to use is the vector class in the standard library which handles all of this for you:
#include <vector>
std:vector<T_PSIZE *> cntPeopleByAge;
cntPeopleByAgex.resize(AG_TOTAL + 1);
Good luck ...