I want to extend the stl-views.gdb with parray
How can I determine the size (N) of std::array in gdb?
#
# std::array<>
#
define parray
if $argc == 0
help parray
else
set $size = ???
..
Thanks for the help
Try using set $size = $arg0.size().
I have tested with the following code (where .size() is not used explicitly used).
#include <string>
#include <iostream>
#include <array>
int main() {
std::array<int, 3> arr {1,2,3};
std::cout << arr[0] << std::endl;
}
Then the following defined worked
define parray
if $argc == 0
help parray
else
set $size = $arg0.size()
print($size)
end
both with a running process or without a running process (debugging from a core file).
If calling .size() does not work for some reason then we need to see which internal variables of the array we can use. Using p /r arr we can see the arr variable without any pretty-printing. This shows something like
$5 = {
_M_elems = {[0] = 1,
[1] = 2,
[2] = 3}
}
in my machine (code was compiled with gcc 10), but it might be implementation-dependent. We can then try to get the size from _M_elems.
We can then try using the approach here to get the size. That is, using something such as
set $size = sizeof($arg0._M_elems) / sizeof(*$arg0._M_elems)
The gdb define code becomes
define parray
if $argc == 0
help parray
else
set $size = sizeof($arg0._M_elems) / sizeof(*$arg0._M_elems)
print($size)
end
Related
I have a very simple program that I don't know why a crash occurs on exit.
My main function is a simple cout<<"Hello world";
But I've added another cpp file:
system_information.cpp:
system_information::system_information() {
threadid_processid_map[22]=23;
processor_processid_map[128] = { 0L };
processor_threadid_map[128] = { 0L };
}
And the header file looks like:
system_information.h
class system_information{
public:
DWORD processor_processid_map[128];
DWORD processor_threadid_map[128];
unordered_map<DWORD, DWORD> threadid_processid_map;
system_information();
};
And I simply have this file to declare in instance of my class:
parse.cpp:
#include "system_information.h"
system_information sys_info;
My program crashes on exit on crt0at.c at this line:
onexitbegin_new = (_PVFV *) DecodePointer(__onexitbegin);
What am I doing wrong?
I'd say you're slightly confused about what:
processor_processid_map[128] = { 0L };
is actually doing. The fact that you have braces in there seems to indicate you think it will set all values in the array to zero but that is not the case. You can initialise the array that way but assigning to it is a different matter.
What that code is doing is trying to set element number 128 to zero and, since elements are restricted to the range 0..127, what you have there is undefined behaviour.
If you do wish to zero out the entire array, there are a number of ways to do this, including:
// Simple loop.
for (int i = 0; i < sizeof(id_map) / sizeof(*id_map); ++i)
id_map[i] = 0;
// Setting memory.
#include <cstring>
memset(id_map, 0, sizeof(id_map));
// Fill algorithm.
#include <algorithm>
std::fill(id_map, id_map + sizeof(id_map) / sizeof(*id_map), 0);
->Please see my edited question below the horizontal divider:
I was trying to return a string array from a function to another function. The code compiled successfully; however, it failed upon execution. I have included my code below:
string Occupant::LoadDataFunction()
{
string array[5] = {"hello", "you", "are", "a", "human"};
return array[5];
}
void Occupant::LoadData()
{
string loc_array[5];
loc_array[5] = Occupant::LoadDataFunction();
string park_array[5];
park_array[5] = Occupant::LoadDataFunction();
string lease_array[5];
lease_array[5] = Occupant::LoadDataFunction();
}
When I debugged the code, I found out that the problem was in the return statement of the function:
return array[5]
The debugger had the following output:
Signal = SIGSEGV (Segmentation Fault)
this = { Occupant * const | 0x61ff2f} 0x61ff2f
array = {std::_cxx11::basic_string< char, std::char_traits, std::allocator> [5]}
Can someone tell me what is wrong with my return statement, why it is causing a segmentation error? Thanks
** I know there are many other similar questions on the web, but none of them involved a segmentation fault in the return statement Therefore, I would appreciate it if this question is not marked as a duplicate. If you need any more information, just inform me in the comments box. Thanks for your help!
EDIT Thanks everyone, I didn't notice that glitch I just fixed it. I actually wanted to return the entire array, I did it with pointers this time. Here's my code:
string* Occupant::LoadDataFunction()
{
string* array = new string[5];
array[0] = "hello";
array[1] = "hello";
array[2] = "hello";
array[3] = "hello";
array[4] = "hello";
return array;
}
void Occupant::LoadData()
{
string **loc_array = new string*[5];
loc_array[5] = Occupant::LoadDataFunction();
string **park_array = new string*[5];
park_array[5] = Occupant::LoadDataFunction();
string **lease_array = new string*[5];
lease_array[5] = Occupant::LoadDataFunction();
for (int i = 0; i < 5; i++)
{
cout << &loc_array[i] << " : location" << endl;
cout << &park_array[i] << " : parking" << endl;
cout << &lease_array[i] << " : leased" << endl;
}
}
The problem now is that when I run the code, rather than printing hello fifteen times in total, it prints the memory address. Here's what I got:
0xf56d50 : location
0xf56df8 : parking
0xf56ea0 : leased
0xf56d54 : location
0xf56dfc : parking
0xf56ea4 : leased
0xf56d58 : location
0xf56e00 : parking
0xf56ea8 : leased
0xf56d5c : location
0xf56e04 : parking
0xf56eac : leased
0xf56d60 : location
0xf56e08 : parking
0xf56eb0 : leased
I expected a "Hello" word outputted wherever a memory address is outputted. Can anyone explain this now? Thanks for all your answers!
To return an array, use std::array, as a std::array is copyable and assignable, unlike a vanilla array.
#include <array>
#include <algorithm>
typedef std::array<std::string, 5> Array5Strings;
Array5Strings LoadDataFunction()
{
Array5Strings ret;
std::fill(ret.begin(), ret.end(), "hello");
return ret;
}
Also, I used std::fill to quickly set the items to "hello".
Live Example
If for some weird reason you can't use std::array, then the other alternative is to create a struct that contains an array of 5 strings, and return the struct. A struct is copyable, thus can be returned directly from a function.
#include <algorithm>
#include <string>
#include <algorithm>
#include <iostream>
struct Array5Strings
{
std::string sArray[5];
};
Array5Strings LoadDataFunction()
{
Array5Strings ret;
std::fill(std::begin(ret.sArray), std::end(ret.sArray), "hello");
return ret;
}
int main()
{
Array5Strings val = LoadDataFunction();
std::cout << val.sArray[0]; // prints the first value
}
Live Example
Regardless of which you choose, note that there are no pointers involved.
You are accessing the arrays using out of bounds index.
When you have an array declared as:
string loc_array[5];
the valid indices are 0 - 4.
Use of
loc_array[5] = Occupant::LoadDataFunction();
is cause for undefined behavior. I suspect you meant to use:
loc_array[4] = Occupant::LoadDataFunction();
Similarly, you need to use:
park_array[4] = Occupant::LoadDataFunction();
and
lease_array[4] = Occupant::LoadDataFunction();
You also need to change Occupant::LoadDataFunction.
string Occupant::LoadDataFunction()
{
string array[5] = {"hello", "you", "are", "a", "human"};
return array[4];
}
Update
The updated implementation of of Occupant::LoadDataFunction is better but there are still problems.
Each time the function gets called, you are allocating an array of strings. It's not clear whether that's the intention. If that's the intention, then the calling code has to take responsibility for deallocating that memory.
The calling code still suffers from out our bounds memory access. The line
string **loc_array = new string*[5];
allocates memory for 5 string*. The valid indices for loc_array is still 0 - 4. Hence,
loc_array[5] = Occupant::LoadDataFunction();
suffers from out of bounds memory access problem. It's not clear how you wish to use the return value of Occupant::LoadDataFunction. Hence, I am not able to suggest a way to solve the problem.
The lines
park_array[5] = Occupant::LoadDataFunction();
lease_array[5] = Occupant::LoadDataFunction();
suffer from the same problem.
Try returning array[4]. There is no array[5], since arrays start at index 0.
The range of an array of size N is from 0 to N-1. So the 5 is out of the range. And you may want to return an array as a result, but the array is constructed in the function LoadData, after the function is executed, the array is invalid. You may use dynamic allocation for your purpose or use a global variable.
When you use the dynamic allocation array, you can just use string* instead of string**, and you should release the allocated memory.
#include <iostream>
using namespace std;
int main()
{
int *array1 = new int [5]();
int *array2 = new int [7]();
array1[2] = 3;// or anychange
array2[2] = 3;// to both arrays
if (array1==array2)
{
//if all values of the both arrays are equal
}
else
{
//if all values of the both arrays are not equal
}
return 0;
}
I have two dynamically allocated array using new (the size may or may not be same). Now I want to compare all elements of array (if size and elements are same, then true, if not either of these then false).
How to do in C++? (not interested using vector in my problem scenario)
First off, I would like to encourage you to use std::vector for dynamically allocated arrays. They will free the allocated memory safely and automatically and you can always retrieve their size without extra manual book-keeping.
Once you have that, you can compare the two arrays in the following way:
#include <vector>
int main()
{
std::vector<int> v1 = { 1, 2, 3 };
std::vector<int> v2 = { 1, 2, 3, 4 };
const bool theyAreEqual = v1 == v2;
}
Comparing two pointers as you did, only compares the addresses of the first elements and not the sizes and the contents of the dynamic arrays elementwise. That's one of the reasons, that it's much safer to use std::vector instead of C-style arrays.
array1 == array2 compares pointers. They will never be equal. Furthermore, you can't know how many elements is in a dynamically allocated array, unless you're:
having its size stored separately
using sentinel value to determine its end - you choose a value (e.g. -1) to represent end of the array (like c-style strings usually use \0)
Then you'll be able to know how many elements to iterate over, comparing the elements of both arrays.
Here is a way to resolve it, but I highly recommend vectors, in cases like this.
You need the length and a bool for checking. check is true for default and arrays should be allocated with length1 and length2.
//...
if (length1 != length2) check = false;
else for (int i = 0; i < length1; i++)
{
if (array1[i] != array2[i])
{
check = false;
break;
}
}
if (check)
//...
I followed up on Ralph comment, because I also wanted to see what std::equal did, and the == operator of std::vector does the right thing, and surprisingly simpler to use than the std::equal operator. If you use the latter, you will need to make sure to user begin()/end() for both arrays (It is a C++14 version of std::equal), or add v1.size() == v2.size() &&...
#include <algorithm>
#include <vector>
int main()
{
std::vector<int> v1 = { 1, 2, 3 };
std::vector<int> v2 = { 1, 2, 3, 4 };
std::vector<int> v3 = { 1, 2, 3 };
const bool theyAreEqualv1v2 = v1 == v2;
const bool theyAreEqualv1v3 = v1 == v3;
const bool theyAreEqualStdv1v2 = std::equal(v1.begin(),v1.end(), v2.begin(),v2.end());
const bool theyAreEqualStdv1v2bad = std::equal(v1.begin(),v1.end(), v2.begin());
const bool theyAreEqualStdv1v3 = std::equal(v1.begin(),v1.end(), v3.begin(),v3.end());
// std::equal according to http://en.cppreference.com/w/cpp/algorithm/equal actually
// only compares the first range thus you would really need begin()/end() for both arrays
printf("equal v1v2: %d\n",theyAreEqualv1v2);
printf("equal v1v3: %d\n",theyAreEqualv1v3);
printf("std::equal v1v2: %d\n",theyAreEqualStdv1v2);
printf("std::equal v1v2 bad: %d\n",theyAreEqualStdv1v2bad);
printf("std::equal v1v3: %d\n",theyAreEqualStdv1v3);
return 0;
}
clang++ -std=c++14 -stdlib=libc++ c.cpp
output:
equal v1v2: 0
equal v1v3: 1
std::equal v1v2: 0
std::equal v1v2 bad: 1
std::equal v1v3: 1
In my code, I have a STL vector which holds pointers to objects.
The reason why I coded like this is because I must manipulate the objects itself from different places.
std::vector<Object*> objects;
for (int i = 0; i < 10; i++) {
Object* o = new Object(i);
objects.push_back(o);
}
This code is assuming that Object is an object which takes in an integer as a constructor parameter. Assuming that I breakpoint with my GDB after the for loop ends, what do I have to do in order to view the objects within my vector easily?
When I do "p objects" it only lists the pointer addresses which is totally expected, but I want to see the integer variable that each object holds as well. I tried "p objects[0]" but this returns "Could not find operator[]".
Has anyone ran into this problem? or know how I can get around this?
My goal is to be able to look inside what objects actually hold from GDB when those object's pointers are stored in a STL vector.
This is certainly implemented defined, but for GCC, you can do:
print **(v._M_impl._M_start)#1
Where v refers to the vector, and 1 refers to the index. You need to dereference twice to get the value.
struct Object
{
int n;
Object(int n)
: n(n) { }
};
int main()
{
std::vector<Object*> v;
v.push_back(new Object{42});
v.size(); // where we breakpoint
// release our memory at some point
}
And our test run:
(gdb) break 16
Breakpoint 1 at 0x400aae: file test.cpp, line 16.
(gdb) run
Starting program: a.out
Breakpoint 1, main () at test.cpp:16
16 v.size(); // where we breakpoint
(gdb) print v
$1 = {<std::_Vector_base<Object*, std::allocator<Object*> >> = {
_M_impl = {<std::allocator<Object*>> = {<__gnu_cxx::new_allocator<Object*>> = {<No data fields>}, <No data fields>}, _M_start = 0x604030, _M_finish = 0x604038, _M_end_of_storage = 0x604038}}, <No data fields>}
(gdb) print **(v._M_impl._M_start)#1
$2 = {{n = 42}}
Here is a function that prints the values one after another:
define pv
set $pvPOS_ = 0
while $arg0._M_impl._M_start + $pvPOS_ != $arg0._M_impl._M_finish
print **($arg0._M_impl._M_start + $pvPOS_)
set $pvPOS_ = $pvPOS_ + 1
end
end
Used as pv my_vec
I have declared an array of 10 pointers to characters.out of 10 I have initialised only 3.
When I print the array using %s following \n then it gives output as follows:
hi
hello
how
segmentation fault
but if I dont use \n then it gives output as follows:
hihellohow(null)...(7 times).
can somebody explain this please?
CODE 1
#include <stdio.h>
void main()
{
char *a[10] = {"hi", "hello", "how"};
int i = 0, j = 0;
a[0] = "hey";
for (i = 0;i < 10; i++)
printf("%s\n", a[i]);
}
CODE 2
#include <stdio.h>
void main()
{
char *a[10] = {"hi", "hello", "how"};
int i = 0, j = 0;
a[0] = "hey";
for (i = 0;i < 10; i++)
printf("%s", a[i]);
}
As you said yourself, you don't initialize your array elements past the third, so they are automatically initialized to null pointers. Trying to print those null pointers is Undefined Behaviour and thus anything can happen (including a segfault as in your first example, or appearing to work as in your second example).
In both cases, your code is wrong, and it is pointless to try to explain why random things (again, segfault or appearing to work) happen.
Actually, it may come from your compiler. If you use GCC, this page explains that printf("%s\n", s) is optimized as puts(s). The page shows a bug report from 2004, but I can reproduce the bug with GCC-4.7.2 under Windows. While printf has guards against null pointers, puts seems to have none, hence the different behaviour depending on newline.
However, as already said by syam, giving a null pointer as a string is not standard and can cause anything to happen. Here it's just that GCC is friendly, printing (null) instead of simply crash.
Both cases are incorrect, they attempt to print the contents of null pointers, which doesn't make any sense. You are invoking undefined behavior where anything can happen.
The line char *a[10] = {"hi", "hello", "how"}; is guaranteed by the C standard to get initialized in the following manner:
a[0] -> "hi"
a[1] -> "hello"
a[2] -> "how"
a[3] -> NULL
...
a[9] -> NULL