1

I need to find the number of elements in a struct array

I have this struct

struct Features {
    int feature1;
    string feature2;
    string feature3;
    string feature4;
    bool feature5;
};

I have then turned it into an array

Features *feature = new Features[100];

I have then entered some values

for(int i = 0; i < 3; i++)
{
    feature[i].feature1 = 5;
    feature[i].feature2 = "test";
    feature[i].feature3 = "test2";
    feature[i].feature4 = "test3";
    feature[i].feature5 = true;
}

now I want to get the size of the array, which should be 3 (2)

How do I do this?

cout << (sizeof feature / sizeof *feature) << endl;

doesn't seem to work as it prints the incorrect value. (It keep printing 4)

Sorry if this is a stupid question, I am still learning c++

jLynx
  • 1,111
  • 3
  • 20
  • 36

4 Answers4

6
cout << (sizeof feature / sizeof *feature) << endl;

Should be

cout << (sizeof(feature) / sizeof(*feature)) << endl;

Note the brackets. Sadly it cannot tell you what you want for a couple of reasons.

  1. feature is a pointer.

A pointer is a location in storage, an address, and all addresses on any system you're likely to encounter system will be the same size and probably 4 or 8 bytes. Let's assume 4 for now and sub it into the equation.

cout << (4 / sizeof(*feature)) << endl;

This will certainly print 0 because *feature is definitely larger than 4 and in integer math 4 / <anything greater than 4> will be truncated to 0.

If feature was defined

Features feature[100];

And unless the size of the data block being pointed to is required to change there is no reason why it shouldn't be. Anyway, now feature is more than just a pointer to some arbitrary block of memory. It is a block of exactly 100 Features. It has size of 100 * sizeof(feature[0]). This is a fundamental difference between an array and a pointer, so next time someone tells you "Arrays are pointers!" you can tell them to go expletive deleted themselves.

For example:

cout << (sizeof(feature) / sizeof(feature[0])) << endl;

will print 100, not the 0 we got back when feature was a pointer. 0 != 100. Array is not pointer. Array can be used like pointer in a lot of circumstances.

Feature feature2d[100][100];
Feature ** feature2dptr = feature2d;

is not one of them. Remember this when you have to pass a 2D array into a function.

  1. An array knows its size but nothing about how much is being used.

From the size we can compute capacity as we did above, but to be frank this is a sucker bet. feature could be defined

constexpr int MAX_FEATURES = 100;
Features feature[MAX_FEATURES];

And then rather than this:

cout << (sizeof(feature) / sizeof(feature[0])) << endl;

we print the much less convoluted

cout << MAX_FEATURES << endl;

But this is still not what we want.

So how do we do this right?

The preferred C++ solution is to use std::vector. vector does all sorts of cool things for you like resize itself and keep a count on how much of it is actually used. Plus it is Rule of Three compliant unlike the typical pointer-and-dynamic-array approach. What is The Rule of Three? Well it's really important. I recommend reading the link.

To define a vector of Features

std::vector<Features> feature;

To store a Feature

Feature temp;
feature.push_back(temp);

Often a better route is to define a constructor for Feature and

feature.emplace_back(feature1, feature2, feature3, feature4, feature5);

because this eliminates the need to create and copy a temporary Feature.

To get the number of Features in feature

feature.size();

Simple, huh?

OK. So some folk think you shouldn't use vector until you're older and more experienced. They want you to suffer through the pit falls of memory management while you are still learning to write a decent, well-structured program and figuring out how to debug the trivial mistakes that new programmers make. I'm not down with this, but it seems to be the educational paradigm that rules the land.

Let's start with the fixed array because it is simple and much less complicated.

constexpr int MAX_FEATURES = 100;
Features feature[MAX_FEATURES];
int num_features = 0;

Every time you need to add a Feature to the array, you first make sure you have room.

if(num_features < MAX_FEATURES)

Then add the Feature

feature[num_features] = new_feature;

and then increment, add one to, num_features.

num_features++;

How many Features do you have?

cout << num_features << endl;

If you absolutely must do this with pointers

int capacity = 100;
Features * feature = new Feature[capacity];
int num_features = 0;

Now you have to maintain capacity and num_features because the only reason you would do something this stupid is to be able to resize the memory block feature points to as required.

if(num_features >= MAX_FEATURES)
{

Make a bigger feature

    capacity = capacity * 1.5; // why 1.5? Because I felt like it.
    Features * bigger_feature = new Features[capacity];

Copy everything from feature to bigger_feature

    for (int index = 0; index < num_features; index++
    {
        bigger_feature[index] = feature[index];
    }

Free the memory used by feature

    delete[] feature;

Replace feature with bigger_feature

    feature = bigger_feature;
}

Now you can

feature[num_features] = new_feature;
num_features++;

Here's that blob again in a nice cut-and-pastable blob:

if(num_features == MAX_FEATURES)
{
    capacity = capacity * 1.5; // why 1.5? Because I felt like it.
    Features * bigger_feature = new Features[capacity];
    for (int index = 0; index < num_features; index++
    {
        bigger_feature[index] = feature[index];
    }
    delete[] feature;
    feature = bigger_feature;
}
feature[num_features] = new_feature;
num_features++;

Blah. And this pointer mishmash is most definitely not Rule of Three compliant so you likely have to write copy and move constructors, assignment and move operators, and a destructor.

At the end when you are done you must

delete[] feature;

How many Features do you have?

cout << num_features << endl;
user4581301
  • 33,082
  • 7
  • 33
  • 54
  • This is an amazing answer, thank you for taking the time to write this out – jLynx Mar 17 '16 at 03:49
  • Nice to see an answer that, rather than reprimanding the OP for doing it wrong, actually answers the question. – nerdguy Aug 30 '21 at 13:57
4

No, actually the size of the array is 100, not 3, because you allocated a 100-element array with new. The fact that you initialized 3 elements in the array doesn't matter. It's still is a 100 element array.

But whether it's 3, or 100, it doesn't matter. It's up to you to keep track of the size of the allocated array. C++ doesn't do it for you.

But if you do want for C++ to keep track of the size of the array, use std::vector. That's what it's there for.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
1

You need to keep track of it. When you allocated enough space for 100 Features and you got exactly that... enough space for 100 Features. Keeping track of how many of them you've subsequently initialized etc is something you need to do.

Harry
  • 11,298
  • 1
  • 29
  • 43
0

I'm sure it's printing the correct value as programmed. But sizeof only tells you how much space is allocated, not how many members contain meaningful values.

If you want a variable size array, use std::vector. Otherwise, keep the setup you have, but initialize a member (such as feature1) to a recognizable value (such as -999 or something else you won't expect to use meaningfully) and then see how far you can loop before finding that value;

Logicrat
  • 4,438
  • 16
  • 22