Debugger not properly working... could this be a problem in my code?

I've always thought that static arrays can't be passed by value in C++. If you just type an array parameter definition without the & operator, it will still be passed by reference, as an actual pointer to the first element of the array.

So far, so good. I'm using Qt Creator as an IDE and I've always coded arrays the same way and used the debugger the same way: if I want to view, let's say the first 10 array elements during debugging, either I add @10 to the expression evaluator or I add a new expression evaluator like this: array_type[10]variable_name. But now both of these methods are failing and I don't know why.

Please bear in mind that I do need to use the struct and array types I'm using, I can't switch them for any wrappers or other types.

I have a struct like this:

1
2
3
4
5
6
7
struct Student
{
    int id;
    string name;
    string email;
    long int phone;
};


and then a static array like this:
Student students[100];

which I'm passing to this function (where I'm running the debugger):
1
2
3
4
5
6
7
string findName(Student students[], int size, int id){
    for (int i=0; i!=size; i++){
        if (students[i].id==id)
            return students[i].name;
    }
    return "";
}


And I'm populating my array with test data like this:
1
2
3
4
5
6
7
8
void populateStudents(Student students[], int &size)
{
    students[0]={14562, "Bill Stewart", "bstewart@example.com", 56723565};
    students[1]={12684, "Joan Murray", "jmurray@example.com", 43560056};
    students[2]={13118, "Alex Taylor", "ataylor@example.com", 64223053};
    students[3]={11902, "Pamela Brandon", "pbrandon@example.com", 74534230};
    size=4;
}


However, even when the program runs successfully and the array items are stored correctly, the debugger only shows me the first element. It even displays some of the elements as being of the Student type while others are Student* type. This is confusing and I'm not sure what's going on.

This is what the debugger shows when I try the first way I described:
https://k61.kn3.net/7/D/5/4/9/1/5F9.png

And this is what happens when I use the second method:
https://k61.kn3.net/B/F/0/2/B/6/F70.png

I've been suggested that my code is wrong but I don't see why. And I don't see why the debugger is not working now, while I can swear I've used it the same way before.
The code you have posted above is fine, technically. I suspect there is a bit of misunderstanding with the arrays.

All arrays are simply a contiguous list of homogeneous elements, such as your Student.

In C and C++, an array is a bit of an odd data type. Arrays have the following information stored with them:

  • address of first element
  • element type
  • number of elements

Arrays cannot be assigned. So passing an array by value causes it to decay to a simple pointer, which leaves you with only the following information:

  • address of (first) element
  • element type

That is, pointers do not have size information. It does not matter if you use [] or not, the following are identical:

1
2
  void f( int xs[] );
  void f( int * xs );

This is why modifying the elements of an argument array (pointer!) modify the elements of the source array — because they are the same exact thing.

It is also why you need an additional argument to pass the available number of elements that can be modified:

1
2
3
4
  void f( int xs[], int n )
  {
    // I can do anything with any xs[z] as long as 0 ≤ z < n.
  }

If you wish to add elements to an array, you are still constrained by the available number of elements in the array. Hence, you will see one of the two:

1
2
3
4
5
  int f( int xs[], int n )  // common
  {
    ...
    return z;  // z is number of elements USED in the available space in the array, 0 ≤ z < n.
  }
1
2
3
4
5
  void f( int xs[], int& n )  // rare
  {
    ...
    n = z;  // update n to the new number of elements USED in the available space in the array
  }

The second method is less common because it leads to accidental abuses where the caller forgets the amount of space AVAILABLE in the array. To wit, use the first method.


Now, C++ has introduced the concept of a reference. But again, arrays are special. You can pass a reference to the array address, which is the same as before, but it also allows you to query information about length.

1
2
3
  template <std::size_t N>
  int g( int (&xs)[ N ] )
  {

This is great, except you should be aware of the bloat this can cause. Use it to query an array’s length and pass it along to the non-reference version:

1
2
3
4
5
  template <std::size_t N>
  int g( int (&xs)[ N ] )
  {
    return f( xs, N );
  }

Beyond the bloat issue and the convenience to the caller, the function is otherwise identical: you got a reference to the pointer to the first element in the array; modifying the elements modifies the source array.

It is convenient for an actual array type, but not for dynamically-allocated arrays, which just give you a pointer to begin with.

1
2
3
4
5
6
7
8
  constexpr int XsAvailable = 10;
  int xs[ XsAvailable ];
  
  int XsUsed = f( xs, XsAvailable );

//or

  int XsUsed = g( xs );
1
2
3
4
5
6
7
8
9
10
11
  constexpr int XsAvailable = 10;
  int* xs = new int[ XsAvailable ];

  int XsUsed = f( xs, XsAvailable );

// int XsUsed = g( xs );  // ← doesn’t work; xs is not an “array type” 
                          //   (it is a pointer to a dynamically-allocated array)

  ...

  delete [] xs;


The Debugger isn’t trying to trick you. All elements of an array are indexed via the array’s pointer. That is,

    xs[7]

is syntactical sugar for

    *(xs + 7)

which gives you a true reference (alias) to the 8th element of the array.

So your Student accesses really are accesses through a Student*.

Hope this helps.
> I've been suggested that my code is wrong but I don't see why.
I don't see your code, only snippets.
I could fill the blanks, but don't want to discover that you filled differently and that's why you have different output.

Bother yourself to make a testcase that we can compile and run and have the same errors (or similar) that you have.


> I add @10 to the expression evaluator or I add a new expression evaluator
> like this: array_type[10]variable_name
I think it may be the case that your IDE is being too helpful.

http://ftp.gnu.org/old-gnu/Manuals/gdb/html_chapter/gdb_9.html#SEC54
If you've got a pointer `p' and want to see it as an array of 42 elements in the debugger, the command would be
(gdb) print *p@42

note the asterisk (*)

Suppose that you've got
1
2
int v[4];
int *p = v;

(gdb) ptype p
type = int *
(gdb) ptype p@4
int *[4]
(gdb) ptype *p@4
int [4]
My guess is that you forgot to put the asterisk (*), so the IDE see it as an array of pointers and, trying to help you, dereference them.
(note that the ones that weren't dereferenced are saw as null)


same for the casting one, you forgot the asterisk.
and by the way, don't lie with castings, your array has 100 elements, no 10.
Topic archived. No new replies allowed.