2

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++

4
  • 2
    The size of your array will always be 100 elements. Use std::vector instead. Commented Mar 17, 2016 at 0:59
  • 1
    The size of the array will always be 100, and the size of the pointer will always be 4 , or 8 on a machine with 64 bit addressing. Commented Mar 17, 2016 at 0:59
  • C is not C++ is not C! And *feature is a pointer, not an array. Commented Mar 17, 2016 at 1:00
  • 1
    Important note: Because feature is a pointer its size will always be the size of a pointer no matter how much stuff it points at. Commented Mar 17, 2016 at 1:00

4 Answers 4

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

Should be

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

Note the brackets.

Side note: The above is not 100% true. Because sizeof is an operator, you don't generally need the brackets, but in this case the code is using two operators, sizeof and * (dereference), and operator precedence needs to be accounted for. Fortunately, you get right-to-left associativity in this case and the dereference comes first.

I recommend using the brackets here because it makes the intent brutally clear to everyone, even those not familiar with the vagaries of C++ Operator Precedence.

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.

Side note: Since the 2017 C++ Standard revision, you should use std::size, cout << std::size(feature) << endl;, to get the size of an array because std::size traps accidentally invoking it on a pointer and refuses to compile, preventing a runtime error.

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;
Sign up to request clarification or add additional context in comments.

2 Comments

This is an amazing answer, thank you for taking the time to write this out
Nice to see an answer that, rather than reprimanding the OP for doing it wrong, actually answers the question.
5

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.

Comments

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.

Comments

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;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.